Merge viewer-bear

master
Ansariel 2017-04-19 21:43:58 +02:00
commit 95fcf065c1
25 changed files with 547 additions and 176 deletions

View File

@ -337,6 +337,7 @@ public:
static void addCRLF(string_type& string);
static void removeCRLF(string_type& string);
static void removeWindowsCR(string_type& string);
static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab );
static void replaceNonstandardASCII( string_type& string, T replacement );
@ -1327,6 +1328,28 @@ void LLStringUtilBase<T>::removeCRLF(string_type& string)
//static
template<class T>
void LLStringUtilBase<T>::removeWindowsCR(string_type& string)
{
const T LF = 10;
const T CR = 13;
size_type cr_count = 0;
size_type len = string.size();
size_type i;
for( i = 0; i < len - cr_count - 1; i++ )
{
if( string[i+cr_count] == CR && string[i+cr_count+1] == LF)
{
cr_count++;
}
string[i] = string[i+cr_count];
}
string.erase(i, cr_count);
}
//static
template<class T>
void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacement )
{
size_type found_pos = 0;

View File

@ -40,7 +40,8 @@
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/finder.hpp>
void encode_character(std::ostream& ostr, std::string::value_type val)
// static
void LLURI::encodeCharacter(std::ostream& ostr, std::string::value_type val)
{
ostr << "%"
@ -95,7 +96,7 @@ std::string LLURI::escape(
}
else
{
encode_character(ostr, c);
encodeCharacter(ostr, c);
}
}
}
@ -106,7 +107,7 @@ std::string LLURI::escape(
c = *it;
if(allowed.find(c) == std::string::npos)
{
encode_character(ostr, c);
encodeCharacter(ostr, c);
}
else
{

View File

@ -121,6 +121,14 @@ public:
/** @name Escaping Utilities */
//@{
/**
* @brief 'Escape' symbol into stream
*
* @param ostr Output stream.
* @param val Symbol to encode.
*/
static void encodeCharacter(std::ostream& ostr, std::string::value_type val);
/**
* @brief Escape the string passed except for unreserved
*

View File

@ -339,6 +339,8 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
}
face = LLVolumeFace();
face.mExtents[0].set(v[0], v[1], v[2]);
face.mExtents[1].set(v[0], v[1], v[2]);
point_map.clear();
}
}
@ -583,6 +585,8 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
}
face = LLVolumeFace();
face.mExtents[0].set(v[0], v[1], v[2]);
face.mExtents[1].set(v[0], v[1], v[2]);
verts.clear();
indices.clear();
point_map.clear();

View File

@ -1617,8 +1617,8 @@ void LLTextBase::reflow()
segment_set_t::iterator seg_iter = mSegments.begin();
S32 seg_offset = 0;
S32 line_start_index = 0;
const S32 text_available_width = mVisibleTextRect.getWidth() - mHPad; // reserve room for margin
S32 remaining_pixels = text_available_width;
const F32 text_available_width = mVisibleTextRect.getWidth() - mHPad; // reserve room for margin
F32 remaining_pixels = text_available_width;
S32 line_count = 0;
// find and erase line info structs starting at start_index and going to end of document
@ -1644,14 +1644,15 @@ void LLTextBase::reflow()
S32 cur_index = segment->getStart() + seg_offset;
// ask segment how many character fit in remaining space
S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, remaining_pixels) : S32_MAX,
S32 character_count = segment->getNumChars(getWordWrap() ? llmax(0, ll_round(remaining_pixels)) : S32_MAX,
seg_offset,
cur_index - line_start_index,
S32_MAX,
line_count - seg_line_offset);
S32 segment_width, segment_height;
bool force_newline = segment->getDimensions(seg_offset, character_count, segment_width, segment_height);
F32 segment_width;
S32 segment_height;
bool force_newline = segment->getDimensionsF32(seg_offset, character_count, segment_width, segment_height);
// grow line height as necessary based on reported height of this segment
line_height = llmax(line_height, segment_height);
remaining_pixels -= segment_width;
@ -1660,11 +1661,13 @@ void LLTextBase::reflow()
S32 last_segment_char_on_line = segment->getStart() + seg_offset;
S32 text_actual_width = text_available_width - remaining_pixels;
// Note: make sure text will fit in width - use ceil, but also make sure
// ceil is used only once per line
S32 text_actual_width = llceil(text_available_width - remaining_pixels);
S32 text_left = getLeftOffset(text_actual_width);
LLRect line_rect(text_left,
cur_top,
text_left + text_actual_width,
text_left + text_actual_width,
cur_top - line_height);
// if we didn't finish the current segment...
@ -3304,7 +3307,15 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc
LLTextSegment::~LLTextSegment()
{}
bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const { width = 0; height = 0; return false;}
bool LLTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const { width = 0; height = 0; return false; }
bool LLTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
{
F32 fwidth = 0;
bool result = getDimensionsF32(first_char, num_chars, fwidth, height);
width = ll_round(fwidth);
return result;
}
S32 LLTextSegment::getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const { return 0; }
S32 LLTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const { return 0; }
void LLTextSegment::updateLayout(const LLTextBase& editor) {}
@ -3552,7 +3563,7 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip)
mTooltip = tooltip;
}
bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
bool LLNormalTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
height = 0;
width = 0;
@ -3561,7 +3572,7 @@ bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt
height = mFontHeight;
const LLWString &text = getWText();
// if last character is a newline, then return true, forcing line break
width = mStyle->getFont()->getWidth(text.c_str(), mStart + first_char, num_chars);
width = mStyle->getFont()->getWidthF32(text.c_str(), mStart + first_char, num_chars);
}
return false;
}
@ -3742,7 +3753,7 @@ LLInlineViewSegment::~LLInlineViewSegment()
mView->die();
}
bool LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
if (first_char == 0 && num_chars == 0)
{
@ -3829,7 +3840,7 @@ LLLineBreakTextSegment::LLLineBreakTextSegment(LLStyleConstSP style,S32 pos):LLT
LLLineBreakTextSegment::~LLLineBreakTextSegment()
{
}
bool LLLineBreakTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
bool LLLineBreakTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
width = 0;
height = mFontHeight;
@ -3858,7 +3869,7 @@ LLImageTextSegment::~LLImageTextSegment()
static const S32 IMAGE_HPAD = 3;
bool LLImageTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
bool LLImageTextSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
width = 0;
height = mStyle->getFont()->getLineHeight();

View File

@ -61,8 +61,9 @@ public:
mEnd(end)
{}
virtual ~LLTextSegment();
bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
virtual bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
virtual bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
/**
@ -126,7 +127,7 @@ public:
LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
virtual ~LLNormalTextSegment();
/*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
/*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const;
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
@ -212,7 +213,7 @@ public:
LLInlineViewSegment(const Params& p, S32 start, S32 end);
~LLInlineViewSegment();
/*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
/*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
/*virtual*/ void updateLayout(const class LLTextBase& editor);
/*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
@ -236,7 +237,7 @@ public:
LLLineBreakTextSegment(LLStyleConstSP style,S32 pos);
LLLineBreakTextSegment(S32 pos);
~LLLineBreakTextSegment();
bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars, S32 line_ind) const;
F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);
@ -249,7 +250,7 @@ class LLImageTextSegment : public LLTextSegment
public:
LLImageTextSegment(LLStyleConstSP style,S32 pos,class LLTextBase& editor);
~LLImageTextSegment();
bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const;
S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 char_offset, S32 max_chars, S32 line_ind) const;
F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRectf& draw_rect);

View File

@ -2835,7 +2835,7 @@ BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst)
if (utf16str)
{
dst = utf16str_to_wstring(utf16str);
LLWStringUtil::removeCRLF(dst);
LLWStringUtil::removeWindowsCR(dst);
GlobalUnlock(h_data);
success = TRUE;
}

View File

@ -3089,6 +3089,17 @@
<key>Value</key>
<string>default</string>
</map>
<key>ChatAutocompleteGestures</key>
<map>
<key>Comment</key>
<string>Auto-complete gestures in nearby chat</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>ChatBarStealsFocus</key>
<map>
<key>Comment</key>
@ -12763,6 +12774,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</integer>
</map>
<key>MaxAttachmentComplexity</key>
<map>
<key>Comment</key>
<string>Attachment's render weight limit</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1.0E6</real>
</map>
<key>ComplexityChangesPopUpDelay</key>
<map>
<key>Comment</key>
@ -13372,17 +13394,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<real>0.02</real>
</map>
<key>ScriptDialogPerObject</key>
<map>
<key>Comment</key>
<string>Controls how script dialogs from the same object are handled (0 = one dialog per object, 1 = one dialog per channel per object, 2 = unconstrained)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>ScriptHelpFollowsCursor</key>
<map>
<key>Comment</key>
@ -13405,6 +13416,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>ScriptDialogLimitations</key>
<map>
<key>Comment</key>
<string>Limits amount of dialogs per script (0 - per object, 1 - per channel, 2 - per channel for attachments, 3 - per channel for HUDs, 4 -unconstrained for HUDs)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>SecondLifeEnterprise</key>
<map>
<key>Comment</key>

View File

@ -3307,6 +3307,30 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar()
removeItemsFromAvatar(ids_to_remove);
}
class LLUpdateOnCOFLinkRemove : public LLInventoryCallback
{
public:
LLUpdateOnCOFLinkRemove(const LLUUID& remove_item_id, LLPointer<LLInventoryCallback> cb = NULL):
mItemID(remove_item_id),
mCB(cb)
{
}
/* virtual */ void fire(const LLUUID& item_id)
{
// just removed cof link, "(wear)" suffix depends on presence of link, so update label
gInventory.addChangedMask(LLInventoryObserver::LABEL, mItemID);
if (mCB.notNull())
{
mCB->fire(item_id);
}
}
private:
LLUUID mItemID;
LLPointer<LLInventoryCallback> mCB;
};
//void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb)
// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7)
void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInventoryCallback> cb, bool immediate_delete)
@ -3330,13 +3354,22 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer<LLInve
{
RLV_ASSERT(rlvPredCanRemoveItem(item));
}
remove_inventory_item(item->getUUID(), cb, immediate_delete);
// [/RLVa:KB]
// bool immediate_delete = false;
// if (item->getType() == LLAssetType::AT_OBJECT)
// {
// immediate_delete = true;
// // Immediate delete
// remove_inventory_item(item->getUUID(), cb, true);
// gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
// }
// else
// {
// // Delayed delete
// // Pointless to update item_id label here since link still exists and first notifyObservers
// // call will restore (wear) suffix, mark for update after deletion
// LLPointer<LLUpdateOnCOFLinkRemove> cb_label = new LLUpdateOnCOFLinkRemove(item_id, cb);
// remove_inventory_item(item->getUUID(), cb_label, false);
// }
remove_inventory_item(item->getUUID(), cb, immediate_delete);
}
}
}

View File

@ -44,7 +44,7 @@ public:
mExpanderLabel(more_text)
{}
/*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
// more label always spans width of text box
if (num_chars == 0)

View File

@ -495,7 +495,8 @@ void LLFloaterIMNearbyChat::onChatBoxKeystroke()
KEY key = gKeyboard->currentKey();
// Ignore "special" keys, like backspace, arrows, etc.
if (length > 1
if (gSavedSettings.getBOOL("ChatAutocompleteGestures")
&& length > 1
&& raw_text[0] == '/'
&& key < KEY_SPECIAL)
{

View File

@ -1339,6 +1339,10 @@ LLModelPreview::~LLModelPreview()
mPreviewAvatar->markDead();
//*HACK : *TODO : turn this back on when we understand why this crashes
//glodShutdown();
if(mModelLoader)
{
mModelLoader->shutdown();
}
}
U32 LLModelPreview::calcResourceCost()

View File

@ -3015,86 +3015,94 @@ void LLIMMgr::addMessage(
LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id, false, is_offline_msg);
LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(new_session_id);
skip_message &= !session->isGroupSessionType(); // Do not skip group chats...
if(skip_message)
if (session)
{
gIMMgr->leaveSession(new_session_id);
}
// When we get a new IM, and if you are a god, display a bit
// of information about the source. This is to help liaisons
// when answering questions.
if(gAgent.isGodlike())
{
// *TODO:translate (low priority, god ability)
std::ostringstream bonus_info;
bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " "
<< parent_estate_id
<< ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "")
<< ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : "");
// once we have web-services (or something) which returns
// information about a region id, we can print this out
// and even have it link to map-teleport or something.
//<< "*** region_id: " << region_id << std::endl
//<< "*** position: " << position << std::endl;
LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str());
}
// Logically it would make more sense to reject the session sooner, in another area of the
// code, but the session has to be established inside the server before it can be left.
if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden)
{
LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL;
if(!gIMMgr->leaveSession(new_session_id))
skip_message &= !session->isGroupSessionType(); // Do not skip group chats...
if (skip_message)
{
LL_INFOS() << "Session " << new_session_id << " does not exist." << LL_ENDL;
gIMMgr->leaveSession(new_session_id);
}
return;
}
// <FS:PP> Configurable IM sounds
// //Play sound for new conversations
// if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE))
if (dialog != IM_NOTHING_SPECIAL)
{
is_group_chat = gAgent.isInGroup(new_session_id);
}
// <FS:PP> Option to automatically ignore and leave all conference (ad-hoc) chats
static LLCachedControl<bool> ignoreAdHocSessions(gSavedSettings, "FSIgnoreAdHocSessions");
if (dialog != IM_NOTHING_SPECIAL && !is_group_chat && ignoreAdHocSessions && !from_linden)
{
static LLCachedControl<bool> dontIgnoreAdHocFromFriends(gSavedSettings, "FSDontIgnoreAdHocFromFriends");
if (!dontIgnoreAdHocFromFriends || (dontIgnoreAdHocFromFriends && LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL))
// When we get a new IM, and if you are a god, display a bit
// of information about the source. This is to help liaisons
// when answering questions.
if (gAgent.isGodlike())
{
static LLCachedControl<bool> reportIgnoredAdHocSession(gSavedSettings, "FSReportIgnoredAdHocSession");
LL_INFOS() << "Ignoring conference (ad-hoc) chat from " << new_session_id.asString() << LL_ENDL;
// *TODO:translate (low priority, god ability)
std::ostringstream bonus_info;
bonus_info << LLTrans::getString("***") + " " + LLTrans::getString("IMParentEstate") + ":" + " "
<< parent_estate_id
<< ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "")
<< ((parent_estate_id == 5) ? "," + LLTrans::getString("IMTeen") : "");
// once we have web-services (or something) which returns
// information about a region id, we can print this out
// and even have it link to map-teleport or something.
//<< "*** region_id: " << region_id << std::endl
//<< "*** position: " << position << std::endl;
LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str());
}
// Logically it would make more sense to reject the session sooner, in another area of the
// code, but the session has to be established inside the server before it can be left.
if (LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !from_linden)
{
LL_WARNS() << "Leaving IM session from initiating muted resident " << from << LL_ENDL;
if (!gIMMgr->leaveSession(new_session_id))
{
LL_WARNS() << "Ad-hoc session " << new_session_id.asString() << " does not exist." << LL_ENDL;
}
else if (reportIgnoredAdHocSession)
{
report_to_nearby_chat(LLTrans::getString("IgnoredAdHocSession"));
LL_INFOS() << "Session " << new_session_id << " does not exist." << LL_ENDL;
}
return;
}
}
// </FS:PP>
if(!do_not_disturb && PlayModeUISndNewIncomingIMSession != 0 && dialog == IM_NOTHING_SPECIAL)
{
make_ui_sound("UISndNewIncomingIMSession");
// <FS:PP> Configurable IM sounds
// //Play sound for new conversations
// if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE))
if (dialog != IM_NOTHING_SPECIAL)
{
is_group_chat = gAgent.isInGroup(new_session_id);
}
// <FS:PP> Option to automatically ignore and leave all conference (ad-hoc) chats
static LLCachedControl<bool> ignoreAdHocSessions(gSavedSettings, "FSIgnoreAdHocSessions");
if (dialog != IM_NOTHING_SPECIAL && !is_group_chat && ignoreAdHocSessions && !from_linden)
{
static LLCachedControl<bool> dontIgnoreAdHocFromFriends(gSavedSettings, "FSDontIgnoreAdHocFromFriends");
if (!dontIgnoreAdHocFromFriends || (dontIgnoreAdHocFromFriends && LLAvatarTracker::instance().getBuddyInfo(other_participant_id) == NULL))
{
static LLCachedControl<bool> reportIgnoredAdHocSession(gSavedSettings, "FSReportIgnoredAdHocSession");
LL_INFOS() << "Ignoring conference (ad-hoc) chat from " << new_session_id.asString() << LL_ENDL;
if (!gIMMgr->leaveSession(new_session_id))
{
LL_WARNS() << "Ad-hoc session " << new_session_id.asString() << " does not exist." << LL_ENDL;
}
else if (reportIgnoredAdHocSession)
{
report_to_nearby_chat(LLTrans::getString("IgnoredAdHocSession"));
}
return;
}
}
// </FS:PP>
if(!do_not_disturb && PlayModeUISndNewIncomingIMSession != 0 && dialog == IM_NOTHING_SPECIAL)
{
make_ui_sound("UISndNewIncomingIMSession");
}
else if(!do_not_disturb && PlayModeUISndNewIncomingGroupIMSession != 0 && dialog != IM_NOTHING_SPECIAL && is_group_chat)
{
make_ui_sound("UISndNewIncomingGroupIMSession");
}
else if(!do_not_disturb && PlayModeUISndNewIncomingConfIMSession != 0 && dialog != IM_NOTHING_SPECIAL && !is_group_chat)
{
make_ui_sound("UISndNewIncomingConfIMSession");
}
}
else if(!do_not_disturb && PlayModeUISndNewIncomingGroupIMSession != 0 && dialog != IM_NOTHING_SPECIAL && is_group_chat)
else
{
make_ui_sound("UISndNewIncomingGroupIMSession");
}
else if(!do_not_disturb && PlayModeUISndNewIncomingConfIMSession != 0 && dialog != IM_NOTHING_SPECIAL && !is_group_chat)
{
make_ui_sound("UISndNewIncomingConfIMSession");
// Failed to create a session, most likely due to empty name (name cache failed?)
LL_WARNS() << "Failed to create IM session " << fixed_session_name << LL_ENDL;
}
}
else if(!do_not_disturb && PlayModeUISndNewIncomingIMSession == 2 && dialog == IM_NOTHING_SPECIAL)
@ -3503,7 +3511,7 @@ void LLIMMgr::inviteToSession(
LLIncomingCallDialog::processCallResponse(1, payload);
return;
}
else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat))
else if (LLMuteList::getInstance()->isMuted(caller_id, LLMute::flagAll & ~LLMute::flagVoiceChat) && !voice_invite)
{
LL_INFOS() << "Rejecting session invite from initiating muted resident " << caller_name << LL_ENDL;
return;

View File

@ -77,13 +77,6 @@
// * Review the download rate throttling. Slow then fast?
// Detect bandwidth usage and speed up when it drops?
//
// * A lot of calls to notifyObservers(). It looks like
// these could be collapsed by maintaining a 'dirty'
// bit and there appears to be an attempt to do this.
// But it isn't used or is used in a limited fashion.
// Are there semanic issues requiring a call after certain
// updateItem() calls?
//
// * An error on a fetch could be due to one item in the batch.
// If the batch were broken up, perhaps more of the inventory
// would download. (Handwave here, not certain this is an
@ -556,6 +549,12 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
{
// Process completed background HTTP requests
gInventory.handleResponses(false);
// Just processed a bunch of items.
// Note: do we really need notifyObservers() here?
// OnIdle it will be called anyway due to Add flag for processed item.
// It seems like in some cases we are updaiting on fail (no flag),
// but is there anything to update?
gInventory.notifyObservers();
}
if ((mFetchCount > max_concurrent_fetches) ||
@ -874,7 +873,6 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res
titem->setParent(lost_uuid);
titem->updateParentOnServer(FALSE);
gInventory.updateItem(titem);
gInventory.notifyObservers();
}
}
}
@ -947,8 +945,6 @@ void BGFolderHttpHandler::processData(LLSD & content, LLCore::HttpResponse * res
{
fetcher->setAllFoldersFetched();
}
gInventory.notifyObservers();
}
@ -991,7 +987,6 @@ void BGFolderHttpHandler::processFailure(LLCore::HttpStatus status, LLCore::Http
fetcher->setAllFoldersFetched();
}
}
gInventory.notifyObservers();
}
@ -1029,7 +1024,6 @@ void BGFolderHttpHandler::processFailure(const char * const reason, LLCore::Http
fetcher->setAllFoldersFetched();
}
}
gInventory.notifyObservers();
}

View File

@ -71,7 +71,8 @@ const std::string LL_IM_FROM("from");
const std::string LL_IM_FROM_ID("from_id");
const std::string LL_TRANSCRIPT_FILE_EXTENSION("txt");
const static std::string IM_SEPARATOR(": ");
const static char IM_SYMBOL_SEPARATOR(':');
const static std::string IM_SEPARATOR(std::string() + IM_SYMBOL_SEPARATOR + " ");
const static std::string NEW_LINE("\n");
const static std::string NEW_LINE_SPACE_PREFIX("\n ");
const static std::string TWO_SPACES(" ");
@ -980,7 +981,7 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
}
if (im[LL_IM_TIME].isDefined())
{
{
std::string timestamp = im[LL_IM_TIME].asString();
boost::trim(timestamp);
ostr << '[' << timestamp << ']' << TWO_SPACES;
@ -993,9 +994,29 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
{
std::string from = im[LL_IM_FROM].asString();
boost::trim(from);
if (from.size())
std::size_t found = from.find(IM_SYMBOL_SEPARATOR);
std::size_t len = from.size();
std::size_t start = 0;
while (found != std::string::npos)
{
ostr << from << IM_SEPARATOR;
std::size_t sub_len = found - start;
if (sub_len > 0)
{
ostr << from.substr(start, sub_len);
}
LLURI::encodeCharacter(ostr, IM_SYMBOL_SEPARATOR);
start = found + 1;
found = from.find(IM_SYMBOL_SEPARATOR, start);
}
if (start < len)
{
std::string str_end = from.substr(start, len - start);
ostr << str_end;
}
if (len > 0)
{
ostr << IM_SEPARATOR;
}
}
@ -1007,7 +1028,7 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const
boost::replace_all(im_text, NEW_LINE, NEW_LINE_SPACE_PREFIX);
ostr << im_text;
}
}
}
bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params)
{
@ -1083,7 +1104,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params
if (!boost::regex_match(stuff, name_and_text, NAME_AND_TEXT)) return false;
bool has_name = name_and_text[IDX_NAME].matched;
std::string name = name_and_text[IDX_NAME];
std::string name = LLURI::unescape(name_and_text[IDX_NAME]);
// <FS:Ansariel> Handle the case an IM was stored in nearby chat history
if (name == "IM:")
@ -1121,7 +1142,7 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params
if (divider_pos != std::string::npos && divider_pos < (stuff.length() - NAME_TEXT_DIVIDER.length()))
{
im[LL_IM_FROM] = stuff.substr(0, divider_pos);
im[LL_IM_FROM] = LLURI::unescape(stuff.substr(0, divider_pos));
im[LL_IM_TEXT] = stuff.substr(divider_pos + NAME_TEXT_DIVIDER.length());
return true;
}

View File

@ -3672,7 +3672,15 @@ void LLMeshRepository::notifyLoadedMeshes()
//popup queued error messages from background threads
while (!mUploadErrorQ.empty())
{
LLNotificationsUtil::add("MeshUploadError", mUploadErrorQ.front());
LLSD substitutions(mUploadErrorQ.front());
if (substitutions.has("DETAILS"))
{
LLNotificationsUtil::add("MeshUploadErrorDetails", substitutions);
}
else
{
LLNotificationsUtil::add("MeshUploadError", substitutions);
}
mUploadErrorQ.pop();
}

View File

@ -40,6 +40,7 @@
#include "lltoastnotifypanel.h"
#include "lltoastscripttextbox.h"
#include "lltrans.h"
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llfloaterimsession.h"
@ -69,6 +70,7 @@ LLUUID notification_id_to_object_id(const LLUUID& notification_id)
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
LLScriptFloater::LLScriptFloater(const LLSD& key)
: LLDockableFloater(NULL, true, key)
, mScriptForm(NULL)
@ -425,6 +427,15 @@ void LLScriptFloater::hideToastsIfNeeded()
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
LLScriptFloaterManager::LLScriptFloaterManager()
// <FS:Zi> script dialogs position
: mNavigationPanelPad(-1), // The height of the favorite and navigation panels might not be known yet
mFavoritesPanelPad(-1) // so don't fill the values in here yet, but remember to do it at first use
// </FS:Zi>
{
gSavedSettings.getControl("ScriptDialogLimitations")->getCommitSignal()->connect(boost::bind(&clearScriptNotifications));
}
void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
{
if(notification_id.isNull())
@ -444,49 +455,78 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
// LLDialog can spawn only one instance, LLLoadURL and LLGiveInventory can spawn unlimited number of instances
if(OBJ_SCRIPT == obj_type)
{
// // If an Object spawns more-than-one floater, only the newest one is shown.
// // The previous is automatically closed.
// script_notification_map_t::const_iterator it = findUsingObjectId(object_id);
// [SL:KB] - Patch: UI-ScriptDialog | Checked: 2011-01-17 (Catznip-2.4.0h) | Added: Catznip-2.4.0h
static LLCachedControl<U32> script_dialog_limitations(gSavedSettings, "ScriptDialogLimitations", 0);
script_notification_map_t::const_iterator it = mNotifications.end();
switch (gSavedSettings.getS32("ScriptDialogPerObject"))
switch (script_dialog_limitations)
{
case 0: // One script dialog per object (viewer 2 default)
case SCRIPT_PER_CHANNEL:
{
// If an Object spawns more-than-one floater per channel, only the newest one is shown.
// The previous is automatically closed.
LLNotificationPtr notification = LLNotifications::instance().find(notification_id);
if (notification)
{
it = findUsingObjectIdAndChannel(object_id, notification->getPayload()["chat_channel"].asInteger());
}
break;
}
case SCRIPT_ATTACHMENT_PER_CHANNEL:
{
LLViewerObject* objectp = gObjectList.findObject(object_id);
if (objectp && objectp->getAttachmentItemID().notNull()) //in user inventory
{
LLNotificationPtr notification = LLNotifications::instance().find(notification_id);
if (notification)
{
it = findUsingObjectIdAndChannel(object_id, notification->getPayload()["chat_channel"].asInteger());
}
}
else
{
// If an Object spawns more-than-one floater, only the newest one is shown.
// The previous is automatically closed.
it = findUsingObjectId(object_id);
}
break;
case 1: // One script dialog per reply channel per object
}
case SCRIPT_HUD_PER_CHANNEL:
{
LLViewerObject* objectp = gObjectList.findObject(object_id);
if (objectp && objectp->isHUDAttachment())
{
// We'll allow an object to have more than one script dialog floater open, but we'll limit it to one per chat channel
// (in practice a lot of objects open a new listen channel for each new dialog but it still reduces chiclets somewhat)
LLNotificationPtr newNotif = LLNotifications::instance().find(notification_id);
if (newNotif)
LLNotificationPtr notification = LLNotifications::instance().find(notification_id);
if (notification)
{
S32 nNewChannel = newNotif->getPayload()["chat_channel"].asInteger();
for (it = mNotifications.begin(); it != mNotifications.end(); ++it)
{
if (it->second == object_id)
{
LLNotificationPtr curNotif = LLNotifications::instance().find(it->first);
if (curNotif)
{
S32 nCurChannel = curNotif->getPayload()["chat_channel"].asInteger();
if (nNewChannel == nCurChannel)
break;
}
}
}
it = findUsingObjectIdAndChannel(object_id, notification->getPayload()["chat_channel"].asInteger());
}
}
else
{
it = findUsingObjectId(object_id);
}
break;
case 2: // Unconstrained
}
case SCRIPT_HUD_UNCONSTRAINED:
{
LLViewerObject* objectp = gObjectList.findObject(object_id);
if (objectp && objectp->isHUDAttachment())
{
// don't remove existing floaters
break;
}
else
{
it = findUsingObjectId(object_id);
}
break;
}
case SCRIPT_PER_OBJECT:
default:
{
// If an Object spawns more-than-one floater, only the newest one is shown.
// The previous is automatically closed.
it = findUsingObjectId(object_id);
break;
}
}
// [/SL:KB]
if(it != mNotifications.end())
{
@ -494,7 +534,7 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
if (NULL != chiclet_panelp)
{
LLIMChiclet * chicletp = chiclet_panelp->findChiclet<LLIMChiclet>(it->first);
if(NULL != chicletp)
if (NULL != chicletp)
{
// Pass the new_message icon state further.
set_new_message = chicletp->getShowNewMessagesIcon();
@ -503,7 +543,7 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)
}
LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", it->first);
if(floater)
if (floater)
{
// Generate chiclet with a "new message" indicator if a docked window was opened but not in focus. See EXT-3142.
set_new_message |= !floater->hasFocus();
@ -709,6 +749,23 @@ LLScriptFloaterManager::script_notification_map_t::const_iterator LLScriptFloate
return mNotifications.end();
}
LLScriptFloaterManager::script_notification_map_t::const_iterator LLScriptFloaterManager::findUsingObjectIdAndChannel(const LLUUID& object_id, S32 im_channel)
{
script_notification_map_t::const_iterator it = mNotifications.begin();
for (; mNotifications.end() != it; ++it)
{
if (object_id == it->second)
{
LLNotificationPtr notification = LLNotifications::instance().find(it->first);
if (notification && (im_channel == notification->getPayload()["chat_channel"].asInteger()))
{
return it;
}
}
}
return mNotifications.end();
}
void LLScriptFloaterManager::saveFloaterPosition(const LLUUID& object_id, const FloaterPositionInfo& fpi)
{
if(object_id.notNull())
@ -742,15 +799,34 @@ void LLScriptFloaterManager::setFloaterVisible(const LLUUID& notification_id, bo
}
}
// <FS:Zi> script dialogs position
// Since we can't initialize the member variables in the class itself,
// we need to do that in the constructor -Zi
LLScriptFloaterManager::LLScriptFloaterManager()
: mNavigationPanelPad(-1), // The height of the favorite and navigation panels might not be known yet
mFavoritesPanelPad(-1) // so don't fill the values in here yet, but remember to do it at first use
//static
void LLScriptFloaterManager::clearScriptNotifications()
{
LLScriptFloaterManager* inst = LLScriptFloaterManager::getInstance();
static const object_type_map TYPE_MAP = initObjectTypeMap();
script_notification_map_t::const_iterator ntf_it = inst->mNotifications.begin();
while (inst->mNotifications.end() != ntf_it)
{
LLUUID notification_id = ntf_it->first;
ntf_it++; // onRemoveNotification() erases notification
LLNotificationPtr notification = LLNotifications::instance().find(notification_id);
if (notification)
{
object_type_map::const_iterator map_it = TYPE_MAP.find(notification->getName());
if (map_it != TYPE_MAP.end() && map_it->second == OBJ_SCRIPT)
{
if (notification != NULL && !notification->isCancelled())
{
LLNotificationsUtil::cancel(notification);
}
inst->onRemoveNotification(notification_id);
}
}
}
}
// <FS:Zi> script dialogs position
S32 LLScriptFloaterManager::getTopPad()
{
// initialize if needed

View File

@ -41,8 +41,6 @@ class LLScriptFloaterManager : public LLSingleton<LLScriptFloaterManager>
// *TODO
// LLScriptFloaterManager and LLScriptFloater will need some refactoring after we
// know how script notifications should look like.
// <FS:Zi> script dialogs position
//LLSINGLETON_EMPTY_CTOR(LLScriptFloaterManager);
LLSINGLETON(LLScriptFloaterManager);
public:
@ -55,6 +53,15 @@ public:
OBJ_UNKNOWN
}EObjectType;
typedef enum e_limitation_type
{
SCRIPT_PER_OBJECT = 0,
SCRIPT_PER_CHANNEL = 1,
SCRIPT_ATTACHMENT_PER_CHANNEL,
SCRIPT_HUD_PER_CHANNEL,
SCRIPT_HUD_UNCONSTRAINED
}ELimitationType;
/**
* Handles new notifications.
* Saves notification and object ids, removes old notification if needed, creates script chiclet
@ -106,6 +113,11 @@ public:
protected:
/**
* Removes all script-dialog notifications
*/
static void clearScriptNotifications();
typedef std::map<std::string, EObjectType> object_type_map;
static object_type_map initObjectTypeMap();
@ -114,6 +126,7 @@ protected:
typedef std::map<LLUUID, LLUUID> script_notification_map_t;
script_notification_map_t::const_iterator findUsingObjectId(const LLUUID& object_id);
script_notification_map_t::const_iterator findUsingObjectIdAndChannel(const LLUUID& object_id, S32 im_channel);
private:

View File

@ -6379,6 +6379,24 @@ BOOL LLViewerObject::isTempAttachment() const
return (mID.notNull() && (mID == mAttachmentItemID));
}
BOOL LLViewerObject::isHiglightedOrBeacon() const
{
if (LLFloaterReg::instanceVisible("beacons") && (gPipeline.getRenderBeacons(NULL) || gPipeline.getRenderHighlights(NULL)))
{
BOOL has_media = (getMediaType() == LLViewerObject::MEDIA_SET);
BOOL is_scripted = !isAvatar() && !getParent() && flagScripted();
BOOL is_physical = !isAvatar() && flagUsePhysics();
return (isParticleSource() && gPipeline.getRenderParticleBeacons(NULL))
|| (isAudioSource() && gPipeline.getRenderSoundBeacons(NULL))
|| (has_media && gPipeline.getRenderMOAPBeacons(NULL))
|| (is_scripted && gPipeline.getRenderScriptedBeacons(NULL))
|| (is_scripted && flagHandleTouch() && gPipeline.getRenderScriptedTouchBeacons(NULL))
|| (is_physical && gPipeline.getRenderPhysicalBeacons(NULL));
}
return FALSE;
}
const LLUUID &LLViewerObject::getAttachmentItemID() const
{

View File

@ -178,6 +178,8 @@ public:
virtual BOOL isHUDAttachment() const { return FALSE; }
virtual BOOL isTempAttachment() const;
virtual BOOL isHiglightedOrBeacon() const;
virtual void updateRadius() {};
virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius()
@ -395,7 +397,7 @@ public:
// Create if necessary
LLAudioSource *getAudioSource(const LLUUID& owner_id);
bool isAudioSource() {return mAudioSourcep != NULL;}
BOOL isAudioSource() const {return mAudioSourcep != NULL;}
U8 getMediaType() const;
void setMediaType(U8 media_type);

View File

@ -214,7 +214,7 @@ public:
mToolTip = inv_item->getName() + '\n' + inv_item->getDescription();
}
/*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const
/*virtual*/ bool getDimensionsF32(S32 first_char, S32 num_chars, F32& width, S32& height) const
{
if (num_chars == 0)
{
@ -223,7 +223,7 @@ public:
}
else
{
width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidth(mLabel.c_str());
width = EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidthF32(mLabel.c_str());
height = llmax(mImage->getHeight(), mStyle->getFont()->getLineHeight());
}
return false;

View File

@ -134,7 +134,7 @@ const F32 MAX_HOVER_Z = 2.0f;
const F32 MIN_HOVER_Z = -2.0f;
const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;
const F32 MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
using namespace LLAvatarAppearanceDefines;
@ -9918,6 +9918,9 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
* the official viewer for consideration.
*****************************************************************/
static const U32 COMPLEXITY_BODY_PART_COST = 200;
static LLCachedControl<F32> max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity");
F32 max_attachment_complexity = max_complexity_setting;
max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY);
// Diagnostic list of all textures on our avatar
// <FS:Ansariel> Disable useless diagnostics
@ -10008,7 +10011,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
<< " children: " << attachment_children_cost
<< LL_ENDL;
// Limit attachment complexity to avoid signed integer flipping of the wearer's ACI
cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, MAX_ATTACHMENT_COMPLEXITY);
cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity);
}
}
}

View File

@ -4061,7 +4061,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
start_face = face;
end_face = face+1;
}
pick_transparent |= isHiglightedOrBeacon();
bool special_cursor = specialHoverCursor();
for (S32 i = start_face; i < end_face; ++i)
{

View File

@ -908,6 +908,108 @@ Please invite members within 48 hours.
yestext="Create group for L$[COST]"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupInaccessible"
type="alertmodal">
This group is not accessible to you.
<tag>group_id</tag>
<tag>success</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupError"
type="alertmodal">
Error processing your group membership request.
<tag>group_id</tag>
<tag>success</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupError"
type="alertmodal">
Unable to join group: [reason]
<tag>group_id</tag>
<tag>success</tag>
<tag>reason</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupTrialUser"
type="alertmodal">
Sorry, trial users can't join groups.
<tag>group_id</tag>
<tag>success</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupMaxGroups"
type="alertmodal">
You cannot join '[group_name]':
You are already a member of [group_count] groups, the maximum number allowed is [max_groups]
<tag>success</tag>
<tag>group_id</tag>
<tag>group_name</tag>
<tag>group_count</tag>
<tag>max_groups</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupClosedEnrollment"
type="alertmodal">
You cannot join '[group_name]':
The group no longer has open enrollment.
<tag>group_id</tag>
<tag>success</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupSuccess"
type="alertmodal">
You have been added to the group
<tag>group_id</tag>
<tag>success</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="JoinGroupInsufficientFunds"
type="alertmodal">
Unable to transfer the required L$ [membership_fee] membership fee.
<tag>group_id</tag>
<tag>success</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="LandBuyPass"
@ -9140,12 +9242,22 @@ Select residents to share with.
</notification>
<notification
name="MeshUploadError"
name="MeshUploadErrorDetails"
icon="alert.tga"
type="alert">
[LABEL] failed to upload: [MESSAGE] [IDENTIFIER]
[DETAILS] See Firestorm.log for details
</notification>
<notification
name="MeshUploadError"
icon="alert.tga"
type="alert">
[LABEL] failed to upload: [MESSAGE]
[IDENTIFIER]
See Firestorm.log for details
</notification>
<notification
name="MeshUploadPermError"

View File

@ -294,7 +294,7 @@
Script Dialogs per Object:
</text>
<combo_box
control_name="ScriptDialogPerObject"
control_name="ScriptDialogLimitations"
height="23"
layout="topleft"
left_pad="10"
@ -306,13 +306,21 @@
name="ScriptDialogOption_0"
value="0"/>
<combo_box.item
label="One per Object &amp; Channel"
label="One per Channel"
name="ScriptDialogOption_1"
value="1"/>
<combo_box.item
label="Unconstrained"
label="One per Channel for Attachments"
name="ScriptDialogOption_2"
value="2"/>
<combo_box.item
label="One per Channel for HUDs"
name="ScriptDialogOption_3"
value="3"/>
<combo_box.item
label="Unconstrained"
name="ScriptDialogOption_4"
value="5"/>
</combo_box>
<check_box
control_name="FSRemoveScriptBlockButton"