summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llaccordionctrl.cpp17
-rw-r--r--indra/llui/llaccordionctrl.h2
-rw-r--r--indra/llui/llaccordionctrltab.h10
-rw-r--r--indra/llui/llbutton.cpp13
-rw-r--r--indra/llui/llbutton.h4
-rw-r--r--indra/llui/llcheckboxctrl.h2
-rw-r--r--indra/llui/llcombobox.cpp17
-rw-r--r--indra/llui/llflatlistview.cpp49
-rw-r--r--indra/llui/llflatlistview.h11
-rw-r--r--indra/llui/llfloater.cpp3
-rw-r--r--indra/llui/llfloater.h4
-rw-r--r--indra/llui/llfolderview.cpp29
-rw-r--r--indra/llui/llfolderview.h2
-rw-r--r--indra/llui/llfolderviewitem.cpp4
-rw-r--r--indra/llui/llfolderviewmodel.cpp4
-rw-r--r--indra/llui/llfolderviewmodel.h2
-rw-r--r--indra/llui/lllineeditor.cpp116
-rw-r--r--indra/llui/lllineeditor.h20
-rw-r--r--indra/llui/llmenugl.cpp7
-rw-r--r--indra/llui/llmodaldialog.cpp5
-rw-r--r--indra/llui/llmultisliderctrl.cpp2
-rw-r--r--indra/llui/llnotifications.cpp4
-rw-r--r--indra/llui/llnotifications.h1
-rw-r--r--indra/llui/llresmgr.cpp14
-rw-r--r--indra/llui/llscrolllistcell.h2
-rw-r--r--indra/llui/llscrolllistctrl.cpp4
-rw-r--r--indra/llui/llsliderctrl.cpp2
-rw-r--r--indra/llui/lltabcontainer.cpp31
-rw-r--r--indra/llui/lltabcontainer.h4
-rw-r--r--indra/llui/lltextbase.cpp21
-rw-r--r--indra/llui/lltextbase.h5
-rw-r--r--indra/llui/lltexteditor.cpp72
-rw-r--r--indra/llui/lltexteditor.h4
-rw-r--r--indra/llui/lltextvalidate.cpp764
-rw-r--r--indra/llui/lltextvalidate.h83
-rw-r--r--indra/llui/lltimectrl.cpp41
-rw-r--r--indra/llui/lltimectrl.h26
-rw-r--r--indra/llui/lltoolbar.cpp3
-rw-r--r--indra/llui/lltransutil.cpp10
-rw-r--r--indra/llui/llui.h2
-rw-r--r--indra/llui/lluictrl.cpp2
-rw-r--r--indra/llui/lluictrl.h1
-rw-r--r--indra/llui/llview.cpp28
-rw-r--r--indra/llui/llview.h6
-rw-r--r--indra/llui/llviewmodel.cpp35
-rw-r--r--indra/llui/llviewmodel.h6
46 files changed, 902 insertions, 592 deletions
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index 0a82bed896..e18c40e7c3 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -936,3 +936,20 @@ S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 availabl
expanded_tab_height /= num_expanded;
return expanded_tab_height;
}
+
+void LLAccordionCtrl::collapseAllTabs()
+{
+ if (mAccordionTabs.size() > 0)
+ {
+ for (size_t i = 0; i < mAccordionTabs.size(); ++i)
+ {
+ LLAccordionCtrlTab *tab = mAccordionTabs[i];
+
+ if (tab->getDisplayChildren())
+ {
+ tab->setDisplayChildren(false);
+ }
+ }
+ arrange();
+ }
+}
diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h
index 6a1989afba..f226d38bed 100644
--- a/indra/llui/llaccordionctrl.h
+++ b/indra/llui/llaccordionctrl.h
@@ -122,6 +122,8 @@ public:
void setComparator(const LLTabComparator* comp) { mTabComparator = comp; }
void sort();
+ void collapseAllTabs();
+
/**
* Sets filter substring as a search_term for help text when there are no any visible tabs.
*/
diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h
index 896a34cac4..496c34c38b 100644
--- a/indra/llui/llaccordionctrltab.h
+++ b/indra/llui/llaccordionctrltab.h
@@ -126,12 +126,12 @@ public:
void setSelected(bool is_selected);
- bool getCollapsible() {return mCollapsible;};
+ bool getCollapsible() { return mCollapsible; };
- void setCollapsible(bool collapsible) {mCollapsible = collapsible;};
+ void setCollapsible(bool collapsible) { mCollapsible = collapsible; };
void changeOpenClose(bool is_open);
- void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;};
+ void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; };
bool canOpenClose() const { return mCanOpenClose; };
virtual BOOL postBuild();
@@ -142,8 +142,8 @@ public:
void draw();
- void storeOpenCloseState ();
- void restoreOpenCloseState ();
+ void storeOpenCloseState();
+ void restoreOpenCloseState();
protected:
LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&);
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 9ef019840a..b93b92a2e7 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -58,10 +58,11 @@ static LLDefaultChildRegistry::Register<LLButton> r("button");
template class LLButton* LLView::getChild<class LLButton>(
const std::string& name, BOOL recurse) const;
-// globals loaded from settings.xml
-S32 LLBUTTON_H_PAD = 0;
-S32 BTN_HEIGHT_SMALL= 0;
-S32 BTN_HEIGHT = 0;
+// globals
+S32 LLBUTTON_H_PAD = 4;
+S32 BTN_HEIGHT_SMALL= 23;
+S32 BTN_HEIGHT = 23;
+S32 BTN_DROP_SHADOW = 2;
LLButton::Params::Params()
: label_selected("label_selected"), // requires is_toggle true
@@ -92,8 +93,8 @@ LLButton::Params::Params()
image_overlay_disabled_color("image_overlay_disabled_color", LLColor4::white % 0.3f),
image_overlay_selected_color("image_overlay_selected_color", LLColor4::white),
flash_color("flash_color"),
- pad_right("pad_right", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
- pad_left("pad_left", LLUI::getInstance()->mSettingGroups["config"]->getS32("ButtonHPad")),
+ pad_right("pad_right", LLBUTTON_H_PAD),
+ pad_left("pad_left", LLBUTTON_H_PAD),
pad_bottom("pad_bottom"),
click_callback("click_callback"),
mouse_down_callback("mouse_down_callback"),
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 257159f64f..ecb08d1f23 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -43,10 +43,10 @@
//
// PLEASE please use these "constants" when building your own buttons.
-// They are loaded from settings.xml at run time.
extern S32 LLBUTTON_H_PAD;
extern S32 BTN_HEIGHT_SMALL;
extern S32 BTN_HEIGHT;
+extern S32 BTN_DROP_SHADOW;
//
// Helpful functions
@@ -251,7 +251,7 @@ public:
void setFont(const LLFontGL *font)
{ mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); }
const LLFontGL* getFont() const { return mGLFont; }
-
+ const std::string& getText() const { return getCurrentLabel().getString(); }
S32 getLastDrawCharsCount() const { return mLastDrawCharsCount; }
bool labelIsTruncated() const;
diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h
index eb5bd5b6da..ba3c723fcb 100644
--- a/indra/llui/llcheckboxctrl.h
+++ b/indra/llui/llcheckboxctrl.h
@@ -117,7 +117,7 @@ public:
std::string getLabel() const;
void setFont( const LLFontGL* font ) { mFont = font; }
- const LLFontGL* getFont() { return mFont; }
+ const LLFontGL* getFont() const { return mFont; }
virtual void setControlName(const std::string& control_name, LLView* context);
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 9ca05a16f3..8bf1bb9c9f 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -188,6 +188,8 @@ LLComboBox::~LLComboBox()
// explicitly disconect this signal, since base class destructor might fire top lost
mTopLostSignalConnection.disconnect();
mImageLoadedConnection.disconnect();
+
+ LLUI::getInstance()->removePopup(this);
}
@@ -482,8 +484,6 @@ void LLComboBox::onFocusLost()
void LLComboBox::setButtonVisible(BOOL visible)
{
- static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
-
mButton->setVisible(visible);
if (mTextEntry)
{
@@ -491,7 +491,7 @@ void LLComboBox::setButtonVisible(BOOL visible)
if (visible)
{
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
+ text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
}
//mTextEntry->setRect(text_entry_rect);
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -530,19 +530,18 @@ void LLComboBox::setEnabledByValue(const LLSD& value, BOOL enabled)
void LLComboBox::createLineEditor(const LLComboBox::Params& p)
{
- static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
LLRect rect = getLocalRect();
if (mAllowTextEntry)
{
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- S32 shadow_size = drop_shadow_button;
+ S32 shadow_size = BTN_DROP_SHADOW;
mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
mButton->setTabStop(FALSE);
mButton->setHAlign(LLFontGL::HCENTER);
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
- text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
+ text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
// clear label on button
std::string cur_label = mButton->getLabelSelected();
LLLineEditor::Params params = p.combo_editor;
@@ -1081,13 +1080,11 @@ void LLComboBox::onSetHighlight() const
void LLComboBox::imageLoaded()
{
- static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0);
-
if (mAllowTextEntry)
{
LLRect rect = getLocalRect();
S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- S32 shadow_size = drop_shadow_button;
+ S32 shadow_size = BTN_DROP_SHADOW;
mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
if (mButton->getVisible())
@@ -1096,7 +1093,7 @@ void LLComboBox::imageLoaded()
if (mTextEntry)
{
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
- text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button;
+ text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * BTN_DROP_SHADOW;
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
}
}
diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp
index 460bd0945b..fd4c33df30 100644
--- a/indra/llui/llflatlistview.cpp
+++ b/indra/llui/llflatlistview.cpp
@@ -1361,26 +1361,28 @@ void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show)
mForceShowingUnmatchedItems = show;
}
-void LLFlatListViewEx::setFilterSubString(const std::string& filter_str)
+void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent)
{
if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString))
{
mFilterSubString = filter_str;
updateNoItemsMessage(mFilterSubString);
- filterItems();
+ filterItems(false, notify_parent);
}
}
-void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
+bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
{
- if (!item) return;
+ if (!item)
+ return false;
+
+ BOOL visible = TRUE;
// 0 signifies that filter is matched,
// i.e. we don't hide items that don't support 'match_filter' action, separators etc.
if (0 == item->notify(action))
{
mHasMatchedItems = true;
- item->setVisible(true);
}
else
{
@@ -1388,34 +1390,45 @@ void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
if (!mForceShowingUnmatchedItems)
{
selectItem(item, false);
+ visible = FALSE;
}
- item->setVisible(mForceShowingUnmatchedItems);
}
+
+ if (item->getVisible() != visible)
+ {
+ item->setVisible(visible);
+ return true;
+ }
+
+ return false;
}
-void LLFlatListViewEx::filterItems()
+void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent)
{
- typedef std::vector <LLPanel*> item_panel_list_t;
-
std::string cur_filter = mFilterSubString;
LLStringUtil::toUpper(cur_filter);
LLSD action;
action.with("match_filter", cur_filter);
- item_panel_list_t items;
- getItems(items);
-
mHasMatchedItems = false;
- item_panel_list_t::iterator iter = items.begin(), iter_end = items.end();
- while (iter < iter_end)
+ bool visibility_changed = false;
+ pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end();
+ while (iter != iter_end)
{
- LLPanel* pItem = *(iter++);
- updateItemVisibility(pItem, action);
+ LLPanel* pItem = (*(iter++))->first;
+ visibility_changed |= updateItemVisibility(pItem, action);
}
- sort();
- notifyParentItemsRectChanged();
+ if (re_sort)
+ {
+ sort();
+ }
+
+ if (visibility_changed && notify_parent)
+ {
+ notifyParentItemsRectChanged();
+ }
}
bool LLFlatListViewEx::hasMatchedItems()
diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h
index d47c1cf333..adb0e3e553 100644
--- a/indra/llui/llflatlistview.h
+++ b/indra/llui/llflatlistview.h
@@ -300,6 +300,7 @@ public:
virtual S32 notify(const LLSD& info) ;
virtual ~LLFlatListView();
+
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
@@ -375,7 +376,9 @@ protected:
LLRect getLastSelectedItemRect();
- void ensureSelectedVisible();
+ void ensureSelectedVisible();
+
+ const pairs_list_t& getItemPairs() { return mItemPairs; }
private:
@@ -482,14 +485,14 @@ public:
/**
* Sets up new filter string and filters the list.
*/
- void setFilterSubString(const std::string& filter_str);
+ void setFilterSubString(const std::string& filter_str, bool notify_parent);
std::string getFilterSubString() { return mFilterSubString; }
/**
* Filters the list, rearranges and notifies parent about shape changes.
* Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
*/
- void filterItems();
+ void filterItems(bool re_sort, bool notify_parent);
/**
* Returns true if last call of filterItems() found at least one matching item
@@ -513,7 +516,7 @@ protected:
* @param item - item we are changing
* @param item - action - parameters to determin visibility from
*/
- void updateItemVisibility(LLPanel* item, const LLSD &action);
+ bool updateItemVisibility(LLPanel* item, const LLSD &action);
private:
std::string mNoFilteredItemsMsg;
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index de3de53569..5787bc5929 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -2039,10 +2039,9 @@ void LLFloater::drawShadow(LLPanel* panel)
S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH;
S32 bottom = LLPANEL_BORDER_WIDTH;
- static LLUICachedControl<S32> shadow_offset_S32 ("DropShadowFloater", 0);
static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow");
LLColor4 shadow_color = shadow_color_cached;
- F32 shadow_offset = (F32)shadow_offset_S32;
+ F32 shadow_offset = (F32)DROP_SHADOW_FLOATER;
if (!panel->isBackgroundOpaque())
{
diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h
index 88f9e77777..17dde69de7 100644
--- a/indra/llui/llfloater.h
+++ b/indra/llui/llfloater.h
@@ -61,6 +61,10 @@ const BOOL CLOSE_NO = FALSE;
const BOOL ADJUST_VERTICAL_YES = TRUE;
const BOOL ADJUST_VERTICAL_NO = FALSE;
+const F32 CONTEXT_CONE_IN_ALPHA = 0.f;
+const F32 CONTEXT_CONE_OUT_ALPHA = 1.f;
+const F32 CONTEXT_CONE_FADE_TIME = .08f;
+
namespace LLFloaterEnums
{
enum EOpenPositioning
diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp
index 650ae9ae75..23891cad7f 100644
--- a/indra/llui/llfolderview.cpp
+++ b/indra/llui/llfolderview.cpp
@@ -220,7 +220,7 @@ LLFolderView::LLFolderView(const Params& p)
params.font(getLabelFontForStyle(LLFontGL::NORMAL));
params.max_length.bytes(DB_INV_ITEM_NAME_STR_LEN);
params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2));
- params.prevalidate_callback(&LLTextValidate::validateASCIIPrintableNoPipe);
+ params.prevalidator(&LLTextValidate::validateASCIIPrintableNoPipe);
params.commit_on_focus_lost(true);
params.visible(false);
mRenamer = LLUICtrlFactory::create<LLLineEditor> (params);
@@ -256,7 +256,13 @@ LLFolderView::LLFolderView(const Params& p)
// Destroys the object
LLFolderView::~LLFolderView( void )
{
- closeRenamer();
+ mRenamerTopLostSignalConnection.disconnect();
+ if (mRenamer)
+ {
+ // instead of using closeRenamer remove it directly,
+ // since it might already be hidden
+ LLUI::getInstance()->removePopup(mRenamer);
+ }
// The release focus call can potentially call the
// scrollcontainer, which can potentially be called with a partly
@@ -335,9 +341,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
void LLFolderView::filter( LLFolderViewFilter& filter )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
- static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
- static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1);
- filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100));
+ const S32 TIME_VISIBLE = 10; // in milliseconds
+ const S32 TIME_INVISIBLE = 1;
+ filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? TIME_VISIBLE : TIME_INVISIBLE), 1, 100));
// Note: we filter the model, not the view
getViewModelItem()->filter(filter);
@@ -765,7 +771,7 @@ void LLFolderView::removeSelectedItems()
}
else
{
- LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL;
+ LL_DEBUGS() << "Cannot delete " << item->getName() << LL_ENDL;
return;
}
}
@@ -1072,7 +1078,10 @@ void LLFolderView::startRenamingSelectedItem( void )
mRenamer->setVisible( TRUE );
// set focus will fail unless item is visible
mRenamer->setFocus( TRUE );
- mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this));
+ if (!mRenamerTopLostSignalConnection.connected())
+ {
+ mRenamerTopLostSignalConnection = mRenamer->setTopLostCallback(boost::bind(&LLFolderView::onRenamerLost, this));
+ }
LLUI::getInstance()->addPopup(mRenamer);
}
}
@@ -1598,7 +1607,11 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
void LLFolderView::deleteAllChildren()
{
- closeRenamer();
+ mRenamerTopLostSignalConnection.disconnect();
+ if (mRenamer)
+ {
+ LLUI::getInstance()->removePopup(mRenamer);
+ }
if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die();
mPopupMenuHandle.markDead();
mScrollContainer = NULL;
diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h
index 5f8a173889..f3c23ffc17 100644
--- a/indra/llui/llfolderview.h
+++ b/indra/llui/llfolderview.h
@@ -345,6 +345,8 @@ protected:
LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar;
LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;
+ boost::signals2::connection mRenamerTopLostSignalConnection;
+
bool mForceArrange;
public:
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index bc9469cfad..de4fce86de 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -601,15 +601,13 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
{
- static LLCachedControl<S32> drag_and_drop_threshold(*LLUI::getInstance()->mSettingGroups["config"],"DragAndDropDistanceThreshold", 3);
-
mIsMouseOverTitle = (y > (getRect().getHeight() - mItemHeight));
if( hasMouseCapture() && isMovable() )
{
LLFolderView* root = getRoot();
- if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > drag_and_drop_threshold() * drag_and_drop_threshold()
+ if( (x - mDragStartX) * (x - mDragStartX) + (y - mDragStartY) * (y - mDragStartY) > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
&& root->getAllowDrag()
&& root->getCurSelectedItem()
&& root->startDrag())
diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp
index f217b743a0..96aca62927 100644
--- a/indra/llui/llfolderviewmodel.cpp
+++ b/indra/llui/llfolderviewmodel.cpp
@@ -48,8 +48,8 @@ std::string LLFolderViewModelCommon::getStatusText(bool is_empty_folder)
void LLFolderViewModelCommon::filter()
{
- static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10);
- getFilter().resetTime(llclamp(max_time(), 1, 100));
+ const S32 MAX_FILTER_TIME = 10;
+ getFilter().resetTime(MAX_FILTER_TIME);
mFolderView->getViewModelItem()->filter(getFilter());
}
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index 551a60e097..0f11560790 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -170,7 +170,7 @@ public:
virtual BOOL isItemMovable( void ) const = 0; // Can be moved to another folder
virtual void move( LLFolderViewModelItem* parent_listener ) = 0;
- virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed
+ virtual BOOL isItemRemovable( bool check_worn = true ) const = 0; // Can be destroyed
virtual BOOL removeItem() = 0;
virtual void removeBatch(std::vector<LLFolderViewModelItem*>& batch) = 0;
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 453fa29e7c..406cc36119 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -82,9 +82,9 @@ template class LLLineEditor* LLView::getChild<class LLLineEditor>(
LLLineEditor::Params::Params()
: max_length(""),
- keystroke_callback("keystroke_callback"),
- prevalidate_callback("prevalidate_callback"),
- prevalidate_input_callback("prevalidate_input_callback"),
+ keystroke_callback("keystroke_callback"),
+ prevalidator("prevalidator"),
+ input_prevalidator("input_prevalidator"),
background_image("background_image"),
background_image_disabled("background_image_disabled"),
background_image_focused("background_image_focused"),
@@ -96,6 +96,7 @@ LLLineEditor::Params::Params()
commit_on_focus_lost("commit_on_focus_lost", true),
ignore_tab("ignore_tab", true),
is_password("is_password", false),
+ allow_emoji("allow_emoji", true),
cursor_color("cursor_color"),
use_bg_color("use_bg_color", false),
bg_color("bg_color"),
@@ -111,6 +112,8 @@ LLLineEditor::Params::Params()
default_text("default_text")
{
changeDefault(mouse_opaque, true);
+ addSynonym(prevalidator, "prevalidate_callback");
+ addSynonym(input_prevalidator, "prevalidate_input_callback");
addSynonym(select_on_focus, "select_all_on_focus_received");
addSynonym(border, "border");
addSynonym(label, "watermark_text");
@@ -142,6 +145,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mIgnoreArrowKeys( FALSE ),
mIgnoreTab( p.ignore_tab ),
mDrawAsterixes( p.is_password ),
+ mAllowEmoji( p.allow_emoji ),
mSpellCheck( p.spellcheck ),
mSpellCheckStart(-1),
mSpellCheckEnd(-1),
@@ -157,6 +161,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
mUseBgColor(p.use_bg_color),
mHaveHistory(FALSE),
mReplaceNewlinesWithSpaces( TRUE ),
+ mPrevalidator(p.prevalidator()),
+ mInputPrevalidator(p.input_prevalidator()),
mLabel(p.label),
mCursorColor(p.cursor_color()),
mBgColor(p.bg_color()),
@@ -210,8 +216,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)
}
mSpellCheckTimer.reset();
- setPrevalidateInput(p.prevalidate_input_callback());
- setPrevalidate(p.prevalidate_callback());
+ updateAllowingLanguageInput();
}
LLLineEditor::~LLLineEditor()
@@ -416,8 +421,13 @@ void LLLineEditor::setText(const LLStringExplicit &new_text, bool use_size_limit
all_selected = all_selected || (len == 0 && hasFocus() && mSelectAllonFocusReceived);
std::string truncated_utf8 = new_text;
+ if (!mAllowEmoji)
+ {
+ // Cut emoji symbols if exist
+ utf8str_remove_emojis(truncated_utf8);
+ }
if (use_size_limit && truncated_utf8.size() > (U32)mMaxLengthBytes)
- {
+ {
truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes);
}
mText.assign(truncated_utf8);
@@ -589,13 +599,21 @@ void LLLineEditor::replaceWithSuggestion(U32 index)
{
if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) )
{
+ LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
+ if (!mAllowEmoji)
+ {
+ // Cut emoji symbols if exist
+ wstring_remove_emojis(suggestion);
+ }
+ if (suggestion.empty())
+ return;
+
deselect();
// Delete the misspelled word
mText.erase(it->first, it->second - it->first);
// Insert the suggestion in its place
- LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
mText.insert(it->first, suggestion);
setCursor(it->first + (S32)suggestion.length());
@@ -958,9 +976,11 @@ void LLLineEditor::removeChar()
}
}
-
void LLLineEditor::addChar(const llwchar uni_char)
{
+ if (!mAllowEmoji && LLStringOps::isEmoji(uni_char))
+ return;
+
llwchar new_c = uni_char;
if (hasSelection())
{
@@ -1193,11 +1213,12 @@ void LLLineEditor::cut()
deleteSelection();
// Validate new string and rollback the if needed.
- BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
- if( need_to_rollback )
+ BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
rollback.doRollback( this );
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
else
{
@@ -1260,6 +1281,11 @@ void LLLineEditor::pasteHelper(bool is_primary)
if (!paste.empty())
{
+ if (!mAllowEmoji)
+ {
+ wstring_remove_emojis(paste);
+ }
+
if (!prevalidateInput(paste))
return;
@@ -1321,11 +1347,12 @@ void LLLineEditor::pasteHelper(bool is_primary)
deselect();
// Validate new string and rollback the if needed.
- BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
- if( need_to_rollback )
+ BOOL need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
rollback.doRollback( this );
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
else
{
@@ -1568,19 +1595,27 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
deselect();
}
- BOOL need_to_rollback = FALSE;
+ bool prevalidator_failed = false;
// If read-only, don't allow changes
- need_to_rollback |= (mReadOnly && (mText.getString() == rollback.getText()));
+ bool need_to_rollback = mReadOnly && (mText.getString() == rollback.getText());
// Validate new string and rollback the keystroke if needed.
- need_to_rollback |= (mPrevalidateFunc && !mPrevalidateFunc(mText.getWString()));
+ if (!need_to_rollback && mPrevalidator)
+ {
+ prevalidator_failed = !mPrevalidator.validate(mText.getWString());
+ need_to_rollback |= prevalidator_failed;
+ }
if (need_to_rollback)
{
rollback.doRollback(this);
LLUI::getInstance()->reportBadKeystroke();
+ if (prevalidator_failed)
+ {
+ mPrevalidator.showLastErrorUsingTimeout();
+ }
}
// Notify owner if requested
@@ -1627,20 +1662,18 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
deselect();
- BOOL need_to_rollback = FALSE;
-
// Validate new string and rollback the keystroke if needed.
- need_to_rollback |= ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
-
- if( need_to_rollback )
+ bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
rollback.doRollback( this );
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
// Notify owner if requested
- if( !need_to_rollback && handled )
+ if (!need_to_rollback && handled)
{
// HACK! The only usage of this callback doesn't do anything with the character.
// We'll have to do something about this if something ever changes! - Doug
@@ -1670,7 +1703,7 @@ void LLLineEditor::doDelete()
deleteSelection();
}
else if ( getCursor() < mText.length())
- {
+ {
const LLWString& text_to_delete = mText.getWString().substr(getCursor(), 1);
if (!prevalidateInput(text_to_delete))
@@ -1683,11 +1716,12 @@ void LLLineEditor::doDelete()
}
// Validate new string and rollback the if needed.
- BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
- if( need_to_rollback )
+ bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(mText.getWString());
+ if (need_to_rollback)
{
- rollback.doRollback( this );
+ rollback.doRollback(this);
LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
}
else
{
@@ -1740,19 +1774,6 @@ void LLLineEditor::drawBackground()
}
//virtual
-const std::string LLLineEditor::getToolTip() const
-{
- if (sDebugUnicode)
- {
- std::string text = getText();
- std::string tooltip = utf8str_showBytesUTF8(text);
- return tooltip;
- }
-
- return LLUICtrl::getToolTip();
-}
-
-//virtual
void LLLineEditor::draw()
{
F32 alpha = getDrawContext().mAlpha;
@@ -2232,7 +2253,7 @@ void LLLineEditor::setFocus( BOOL new_state )
// fine on 1.15.0.2, since all prevalidate func reject any
// non-ASCII characters. I'm not sure on future versions,
// however.
- getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL);
+ getWindow()->allowLanguageTextInput(this, !mPrevalidator);
}
}
@@ -2251,26 +2272,21 @@ void LLLineEditor::setRect(const LLRect& rect)
}
}
-void LLLineEditor::setPrevalidate(LLTextValidate::validate_func_t func)
+void LLLineEditor::setPrevalidate(LLTextValidate::Validator validator)
{
- mPrevalidateFunc = func;
+ mPrevalidator = validator;
updateAllowingLanguageInput();
}
-void LLLineEditor::setPrevalidateInput(LLTextValidate::validate_func_t func)
+void LLLineEditor::setPrevalidateInput(LLTextValidate::Validator validator)
{
- mPrevalidateInputFunc = func;
+ mInputPrevalidator = validator;
updateAllowingLanguageInput();
}
bool LLLineEditor::prevalidateInput(const LLWString& wstr)
{
- if (mPrevalidateInputFunc && !mPrevalidateInputFunc(wstr))
- {
- return false;
- }
-
- return true;
+ return mInputPrevalidator.validate(wstr);
}
// static
@@ -2412,7 +2428,7 @@ void LLLineEditor::updateAllowingLanguageInput()
// test app, no window available
return;
}
- if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL)
+ if (hasFocus() && !mReadOnly && !mDrawAsterixes && !mPrevalidator)
{
window->allowLanguageTextInput(this, TRUE);
}
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index 5794b3c35a..15eb789897 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -76,8 +76,8 @@ public:
Optional<MaxLength> max_length;
Optional<keystroke_callback_t> keystroke_callback;
- Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
- Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_input_callback;
+ Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator;
+ Optional<LLTextValidate::Validator, LLTextValidate::Validators> input_prevalidator;
Optional<LLViewBorder::Params> border;
@@ -93,6 +93,7 @@ public:
bg_image_always_focused,
show_label_focused,
is_password,
+ allow_emoji,
use_bg_color;
// colors
@@ -175,7 +176,6 @@ public:
void onSpellCheckSettingsChange();
// view overrides
- /*virtual*/ const std::string getToolTip() const override;
/*virtual*/ void draw() override;
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
/*virtual*/ void onFocusReceived() override;
@@ -203,7 +203,7 @@ public:
void setText(const LLStringExplicit &new_text);
- const std::string& getText() const { return mText.getString(); }
+ const std::string& getText() const override { return mText.getString(); }
LLWString getWText() const { return mText.getWString(); }
LLWString getConvertedText() const; // trimmed text with paragraphs converted to newlines
@@ -235,12 +235,13 @@ public:
const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor.get(); }
const LLColor4& getTentativeFgColor() const { return mTentativeFgColor.get(); }
- const LLFontGL* getFont() const { return mGLFont; }
+ const LLFontGL* getFont() const override { return mGLFont; }
void setFont(const LLFontGL* font);
void setIgnoreArrowKeys(BOOL b) { mIgnoreArrowKeys = b; }
void setIgnoreTab(BOOL b) { mIgnoreTab = b; }
void setPassDelete(BOOL b) { mPassDelete = b; }
+ void setAllowEmoji(BOOL b) { mAllowEmoji = b; }
void setDrawAsterixes(BOOL b);
// get the cursor position of the beginning/end of the prev/next word in the text
@@ -267,12 +268,12 @@ public:
void setTextPadding(S32 left, S32 right);
// Prevalidation controls which keystrokes can affect the editor
- void setPrevalidate( LLTextValidate::validate_func_t func );
+ void setPrevalidate(LLTextValidate::Validator validator);
// This method sets callback that prevents from:
// - deleting, selecting, typing, cutting, pasting characters that are not valid.
// Also callback that this method sets differs from setPrevalidate in a way that it validates just inputed
// symbols, before existing text is modified, but setPrevalidate validates line after it was modified.
- void setPrevalidateInput(LLTextValidate::validate_func_t func);
+ void setPrevalidateInput(LLTextValidate::Validator validator);
static BOOL postvalidateFloat(const std::string &str);
bool prevalidateInput(const LLWString& wstr);
@@ -374,8 +375,8 @@ protected:
std::list<std::pair<U32, U32> > mMisspellRanges;
std::vector<std::string> mSuggestionList;
- LLTextValidate::validate_func_t mPrevalidateFunc;
- LLTextValidate::validate_func_t mPrevalidateInputFunc;
+ LLTextValidate::Validator mPrevalidator;
+ LLTextValidate::Validator mInputPrevalidator;
LLFrameTimer mKeystrokeTimer;
LLTimer mTripleClickTimer;
@@ -403,6 +404,7 @@ protected:
BOOL mShowImageFocused;
BOOL mShowLabelFocused;
+ bool mAllowEmoji;
bool mUseBgColor;
LLWString mPreeditWString;
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index fececa15cf..0803f0bd12 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -66,8 +66,8 @@
LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL;
view_listener_t::listener_map_t view_listener_t::sListeners;
-S32 MENU_BAR_HEIGHT = 0;
-S32 MENU_BAR_WIDTH = 0;
+S32 MENU_BAR_HEIGHT = 18;
+S32 MENU_BAR_WIDTH = 410;
///============================================================================
/// Local function declarations, constants, enums, and typedefs
@@ -3234,10 +3234,9 @@ void LLMenuGL::draw( void )
}
if (mDropShadowed && !mTornOff)
{
- static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0);
static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
- color_drop_shadow, drop_shadow_floater );
+ color_drop_shadow, DROP_SHADOW_FLOATER);
}
if( mBgVisible )
diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp
index 3e5978eb59..c4dacd777e 100644
--- a/indra/llui/llmodaldialog.cpp
+++ b/indra/llui/llmodaldialog.cpp
@@ -67,6 +67,8 @@ LLModalDialog::~LLModalDialog()
{
LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL;
}
+
+ LLUI::getInstance()->removePopup(this);
}
// virtual
@@ -284,10 +286,9 @@ BOOL LLModalDialog::handleKeyHere(KEY key, MASK mask )
void LLModalDialog::draw()
{
static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
- static LLUICachedControl<S32> shadow_lines ("DropShadowFloater", 0);
gl_drop_shadow( 0, getRect().getHeight(), getRect().getWidth(), 0,
- shadow_color, shadow_lines);
+ shadow_color, DROP_SHADOW_FLOATER);
LLFloater::draw();
diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp
index b3df7c154b..b651d85970 100644
--- a/indra/llui/llmultisliderctrl.cpp
+++ b/indra/llui/llmultisliderctrl.cpp
@@ -138,7 +138,7 @@ LLMultiSliderCtrl::LLMultiSliderCtrl(const LLMultiSliderCtrl::Params& p)
params.font(p.font);
params.max_length.bytes(MAX_STRING_LENGTH);
params.commit_callback.function(LLMultiSliderCtrl::onEditorCommit);
- params.prevalidate_callback(&LLTextValidate::validateFloat);
+ params.prevalidator(&LLTextValidate::validateFloat);
params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
mEditor->setFocusReceivedCallback( boost::bind(LLMultiSliderCtrl::onEditorGainFocus, _1, this) );
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index d736aa6634..25062f2cad 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -88,6 +88,7 @@ LLNotificationForm::FormInput::FormInput()
: type("type"),
text("text"),
max_length_chars("max_length_chars"),
+ allow_emoji("allow_emoji"),
width("width", 0),
value("value")
{}
@@ -1553,6 +1554,7 @@ bool LLNotifications::loadTemplates()
if (!success || root.isNull() || !root->hasName( "notifications" ))
{
+ LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL;
return false;
}
@@ -1563,6 +1565,7 @@ bool LLNotifications::loadTemplates()
if(!params.validateBlock())
{
+ LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LL_ERRS() << "Problem reading XUI from UI Notifications file: " << base_filename << LL_ENDL;
return false;
}
@@ -1629,6 +1632,7 @@ bool LLNotifications::loadVisibilityRules()
if(!params.validateBlock())
{
+ LLError::LLUserWarningMsg::show(LLTrans::getString("MBMissingFile"));
LL_ERRS() << "Problem reading UI Notification Visibility Rules file: " << full_filename << LL_ENDL;
return false;
}
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 4d9a33f1d7..d44be65841 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -201,6 +201,7 @@ public:
Mandatory<std::string> type;
Optional<S32> width;
Optional<S32> max_length_chars;
+ Optional<bool> allow_emoji;
Optional<std::string> text;
Optional<std::string> value;
diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp
index d65c220974..f18569d47f 100644
--- a/indra/llui/llresmgr.cpp
+++ b/indra/llui/llresmgr.cpp
@@ -47,9 +47,9 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id )
mLocale = locale_id;
}
-char LLResMgr::getDecimalPoint() const
+char LLResMgr::getDecimalPoint() const
{
- char decimal = localeconv()->decimal_point[0];
+ char decimal = localeconv()->decimal_point[0];
#if LL_DARWIN
// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
@@ -62,9 +62,9 @@ char LLResMgr::getDecimalPoint() const
return decimal;
}
-char LLResMgr::getThousandsSeparator() const
+char LLResMgr::getThousandsSeparator() const
{
- char separator = localeconv()->thousands_sep[0];
+ char separator = localeconv()->thousands_sep[0];
#if LL_DARWIN
// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
@@ -79,7 +79,7 @@ char LLResMgr::getThousandsSeparator() const
char LLResMgr::getMonetaryDecimalPoint() const
{
- char decimal = localeconv()->mon_decimal_point[0];
+ char decimal = localeconv()->mon_decimal_point[0];
#if LL_DARWIN
// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
@@ -92,9 +92,9 @@ char LLResMgr::getMonetaryDecimalPoint() const
return decimal;
}
-char LLResMgr::getMonetaryThousandsSeparator() const
+char LLResMgr::getMonetaryThousandsSeparator() const
{
- char separator = localeconv()->mon_thousands_sep[0];
+ char separator = localeconv()->mon_thousands_sep[0];
#if LL_DARWIN
// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped.
diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h
index 2588da2331..117489fead 100644
--- a/indra/llui/llscrolllistcell.h
+++ b/indra/llui/llscrolllistcell.h
@@ -81,7 +81,7 @@ public:
alt_value("alt_value", ""),
label("label"),
tool_tip("tool_tip", ""),
- font("font", LLFontGL::getFontSansSerifSmall()),
+ font("font", LLFontGL::getFontEmojiSmall()),
font_color("font_color", LLColor4::black),
color("color", LLColor4::white),
font_halign("halign", LLFontGL::LEFT)
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index f982dc99e8..2a6e33fff6 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1810,7 +1810,7 @@ BOOL LLScrollListCtrl::handleToolTip(S32 x, S32 y, MASK mask)
// display tooltip exactly over original cell, in same font
LLToolTipMgr::instance().show(LLToolTip::Params()
.message(hit_cell->getToolTip())
- .font(LLFontGL::getFontSansSerifSmall())
+ .font(LLFontGL::getFontEmojiSmall())
.pos(LLCoordGL(sticky_rect.mLeft - 5, sticky_rect.mTop + 6))
.delay_time(0.2f)
.sticky_rect(sticky_rect));
@@ -3294,7 +3294,7 @@ LLScrollListItem* LLScrollListCtrl::addSimpleElement(const std::string& value, E
item_params.value(entry_id);
item_params.columns.add()
.value(value)
- .font(LLFontGL::getFontSansSerifSmall());
+ .font(LLFontGL::getFontEmojiSmall());
return addRow(item_params, pos);
}
diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp
index d80a434f22..e6cb739702 100644
--- a/indra/llui/llsliderctrl.cpp
+++ b/indra/llui/llsliderctrl.cpp
@@ -167,7 +167,7 @@ LLSliderCtrl::LLSliderCtrl(const LLSliderCtrl::Params& p)
}
line_p.commit_callback.function(&LLSliderCtrl::onEditorCommit);
- line_p.prevalidate_callback(&LLTextValidate::validateFloat);
+ line_p.prevalidator(&LLTextValidate::validateFloat);
mEditor = LLUICtrlFactory::create<LLLineEditor>(line_p);
mEditor->setFocusReceivedCallback( boost::bind(&LLSliderCtrl::onEditorGainFocus, _1, this ));
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index cb36f72f6e..be40a5bb4f 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -225,7 +225,8 @@ LLTabContainer::Params::Params()
tabs_flashing_color("tabs_flashing_color"),
tab_icon_ctrl_pad("tab_icon_ctrl_pad", 0),
use_ellipses("use_ellipses"),
- font_halign("halign")
+ font_halign("halign"),
+ use_tab_offset("use_tab_offset", false)
{}
LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
@@ -264,7 +265,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)
mTabIconCtrlPad(p.tab_icon_ctrl_pad),
mEnableTabsFlashing(p.enable_tabs_flashing),
mTabsFlashingColor(p.tabs_flashing_color),
- mUseTabEllipses(p.use_ellipses)
+ mUseTabEllipses(p.use_ellipses),
+ mUseTabOffset(p.use_tab_offset)
{
static LLUICachedControl<S32> tabcntr_vert_tab_min_width ("UITabCntrVertTabMinWidth", 0);
@@ -1023,11 +1025,10 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
}
else
{
- tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH * 3,
- tab_panel_top,
- getRect().getWidth() - LLPANEL_BORDER_WIDTH * 2,
- tab_panel_bottom );
- }
+ S32 left_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 3 : LLPANEL_BORDER_WIDTH;
+ S32 right_offset = mUseTabOffset ? LLPANEL_BORDER_WIDTH * 2 : LLPANEL_BORDER_WIDTH;
+ tab_panel_rect = LLRect(left_offset, tab_panel_top, getRect().getWidth() - right_offset, tab_panel_bottom);
+ }
child->setFollowsAll();
child->translate( tab_panel_rect.mLeft - child->getRect().mLeft, tab_panel_rect.mBottom - child->getRect().mBottom);
child->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE );
@@ -1516,25 +1517,23 @@ BOOL LLTabContainer::selectTab(S32 which)
LLTabTuple* selected_tuple = getTab(which);
if (!selected_tuple)
- {
return FALSE;
- }
-
+
LLSD cbdata;
if (selected_tuple->mTabPanel)
cbdata = selected_tuple->mTabPanel->getName();
- BOOL res = FALSE;
- if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) )
+ BOOL result = FALSE;
+ if (!mValidateSignal || (*mValidateSignal)(this, cbdata))
{
- res = setTab(which);
- if (res && mCommitSignal)
+ result = setTab(which);
+ if (result && mCommitSignal)
{
(*mCommitSignal)(this, cbdata);
}
}
-
- return res;
+
+ return result;
}
// private
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index aa4a08c4ff..7d6fd15927 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -121,6 +121,8 @@ public:
*/
Optional<S32> tab_icon_ctrl_pad;
+ Optional<bool> use_tab_offset;
+
Params();
};
@@ -321,6 +323,8 @@ private:
S32 mTabIconCtrlPad;
bool mUseTabEllipses;
LLFrameTimer mMouseDownTimer;
+
+ bool mUseTabOffset;
};
#endif // LL_TABCONTAINER_H
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 7ccf025a19..feac3400c7 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -915,7 +915,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
if (!emoji_style)
{
emoji_style = new LLStyle(getStyleParams());
- emoji_style->setFont(LLFontGL::getFontEmoji());
+ emoji_style->setFont(LLFontGL::getFontEmojiLarge());
}
S32 new_seg_start = pos + text_kitty;
@@ -1287,19 +1287,6 @@ BOOL LLTextBase::handleToolTip(S32 x, S32 y, MASK mask)
}
//virtual
-const std::string LLTextBase::getToolTip() const
-{
- if (sDebugUnicode)
- {
- std::string text = getText();
- std::string tooltip = utf8str_showBytesUTF8(text);
- return tooltip;
- }
-
- return LLUICtrl::getToolTip();
-}
-
-//virtual
void LLTextBase::reshape(S32 width, S32 height, BOOL called_from_parent)
{
if (width != getRect().getWidth() || height != getRect().getHeight() || LLView::sForceReshape)
@@ -2182,10 +2169,10 @@ void LLTextBase::setText(const LLStringExplicit &utf8str, const LLStyle::Params&
onValueChange(0, getLength());
}
-//virtual
-std::string LLTextBase::getText() const
+// virtual
+const std::string& LLTextBase::getText() const
{
- return getViewModel()->getValue().asString();
+ return getViewModel()->getStringValue();
}
// IDEVO - icons can be UI image names or UUID sent from
diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h
index 9d3c54fbee..d65e3bfd7c 100644
--- a/indra/llui/lltextbase.h
+++ b/indra/llui/lltextbase.h
@@ -366,7 +366,6 @@ public:
/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask) override;
// LLView interface
- /*virtual*/ const std::string getToolTip() const override;
/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override;
/*virtual*/ void draw() override;
@@ -422,7 +421,7 @@ public:
// Text accessors
// TODO: add optional style parameter
virtual void setText(const LLStringExplicit &utf8str , const LLStyle::Params& input_params = LLStyle::Params()); // uses default style
- virtual std::string getText() const;
+ /*virtual*/ const std::string& getText() const override;
void setMaxTextLength(S32 length) { mMaxTextByteLength = length; }
S32 getMaxTextLength() { return mMaxTextByteLength; }
@@ -495,7 +494,7 @@ public:
bool scrolledToStart();
bool scrolledToEnd();
- const LLFontGL* getFont() const { return mFont; }
+ const LLFontGL* getFont() const override { return mFont; }
virtual void appendLineBreakSegment(const LLStyle::Params& style_params);
virtual void appendImageSegment(const LLStyle::Params& style_params);
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 092739a538..875a5faa2b 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -232,17 +232,18 @@ private:
///////////////////////////////////////////////////////////////////
LLTextEditor::Params::Params()
: default_text("default_text"),
- prevalidate_callback("prevalidate_callback"),
+ prevalidator("prevalidator"),
embedded_items("embedded_items", false),
ignore_tab("ignore_tab", true),
auto_indent("auto_indent", true),
default_color("default_color"),
- commit_on_focus_lost("commit_on_focus_lost", false),
+ commit_on_focus_lost("commit_on_focus_lost", false),
show_context_menu("show_context_menu"),
show_emoji_helper("show_emoji_helper"),
enable_tooltip_paste("enable_tooltip_paste")
{
- addSynonym(prevalidate_callback, "text_type");
+ addSynonym(prevalidator, "prevalidate_callback");
+ addSynonym(prevalidator, "text_type");
}
LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
@@ -253,16 +254,17 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
mLastCmd( NULL ),
mDefaultColor( p.default_color() ),
mAutoIndent(p.auto_indent),
+ mParseOnTheFly(false),
mCommitOnFocusLost( p.commit_on_focus_lost),
mAllowEmbeddedItems( p.embedded_items ),
mMouseDownX(0),
mMouseDownY(0),
mTabsToNextField(p.ignore_tab),
- mPrevalidateFunc(p.prevalidate_callback()),
+ mPrevalidator(p.prevalidator()),
mShowContextMenu(p.show_context_menu),
mShowEmojiHelper(p.show_emoji_helper),
mEnableTooltipPaste(p.enable_tooltip_paste),
- mPassDelete(FALSE),
+ mPassDelete(false),
mKeepSelectionOnReturn(false)
{
mSourceID.generate();
@@ -278,7 +280,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
addChild( mBorder );
setText(p.default_text());
- mParseOnTheFly = TRUE;
+ mParseOnTheFly = true;
}
void LLTextEditor::initFromParams( const LLTextEditor::Params& p)
@@ -319,11 +321,13 @@ LLTextEditor::~LLTextEditor()
void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params)
{
// validate incoming text if necessary
- if (mPrevalidateFunc)
+ if (mPrevalidator)
{
- LLWString test_text = utf8str_to_wstring(utf8str);
- if (!mPrevalidateFunc(test_text))
+ if (!mPrevalidator.validate(utf8str))
{
+ LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
+
// not valid text, nothing to do
return;
}
@@ -332,9 +336,9 @@ void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Param
blockUndo();
deselect();
- mParseOnTheFly = FALSE;
+ mParseOnTheFly = false;
LLTextBase::setText(utf8str, input_params);
- mParseOnTheFly = TRUE;
+ mParseOnTheFly = true;
resetDirty();
}
@@ -609,7 +613,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
// Disabling parsing on the fly to avoid updating text segments
// until all indentation commands are executed.
- mParseOnTheFly = FALSE;
+ mParseOnTheFly = false;
// Find each start-of-line and indent it
do
@@ -636,7 +640,7 @@ void LLTextEditor::indentSelectedLines( S32 spaces )
}
while( cur < right );
- mParseOnTheFly = TRUE;
+ mParseOnTheFly = true;
if( (right < getLength()) && (text[right] == '\n') )
{
@@ -685,7 +689,7 @@ void LLTextEditor::insertEmoji(llwchar emoji)
{
LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL;
auto styleParams = LLStyle::Params();
- styleParams.font = LLFontGL::getFontEmoji();
+ styleParams.font = LLFontGL::getFontEmojiLarge();
auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this);
insert(mCursorPos, LLWString(1, emoji), false, segment);
setCursorPos(mCursorPos + 1);
@@ -986,10 +990,12 @@ S32 LLTextEditor::execute( TextCmd* cmd )
mUndoStack.push_front(cmd);
mLastCmd = cmd;
- bool need_to_rollback = mPrevalidateFunc
- && !mPrevalidateFunc(getViewModel()->getDisplay());
+ bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(getViewModel()->getDisplay());
if (need_to_rollback)
{
+ LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
+
// get rid of this last command and clean up undo stack
undo();
@@ -1125,16 +1131,15 @@ void LLTextEditor::removeChar()
// Add a single character to the text
S32 LLTextEditor::addChar(S32 pos, llwchar wc)
{
- if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc )) > mMaxTextByteLength)
+ if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength)
{
- make_ui_sound("UISndBadKeystroke");
+ LLUI::getInstance()->reportBadKeystroke();
return 0;
}
if (mLastCmd && mLastCmd->canExtend(pos))
{
- S32 delta = 0;
- if (mPrevalidateFunc)
+ if (mPrevalidator)
{
// get a copy of current text contents
LLWString test_string(getViewModel()->getDisplay());
@@ -1142,28 +1147,31 @@ S32 LLTextEditor::addChar(S32 pos, llwchar wc)
// modify text contents as if this addChar succeeded
llassert(pos <= (S32)test_string.size());
test_string.insert(pos, 1, wc);
- if (!mPrevalidateFunc( test_string))
+ if (!mPrevalidator.validate(test_string))
{
+ LLUI::getInstance()->reportBadKeystroke();
+ mPrevalidator.showLastErrorUsingTimeout();
return 0;
}
}
+
+ S32 delta = 0;
mLastCmd->extendAndExecute(this, pos, wc, &delta);
return delta;
}
- else
- {
- return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
- }
+
+ return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));
}
void LLTextEditor::addChar(llwchar wc)
{
- if( !getEnabled() )
+ if (!getEnabled())
{
return;
}
- if( hasSelection() )
+
+ if (hasSelection())
{
deleteSelection(TRUE);
}
@@ -1508,7 +1516,13 @@ void LLTextEditor::pastePrimary()
// paste from primary (itsprimary==true) or clipboard (itsprimary==false)
void LLTextEditor::pasteHelper(bool is_primary)
{
- mParseOnTheFly = FALSE;
+ struct BoolReset
+ {
+ BoolReset(bool& value) : mValuePtr(&value) { *mValuePtr = false; }
+ ~BoolReset() { *mValuePtr = true; }
+ bool* mValuePtr;
+ } reset(mParseOnTheFly);
+
bool can_paste_it;
if (is_primary)
{
@@ -1550,7 +1564,6 @@ void LLTextEditor::pasteHelper(bool is_primary)
deselect();
onKeyStroke();
- mParseOnTheFly = TRUE;
}
@@ -2694,6 +2707,7 @@ BOOL LLTextEditor::importBuffer(const char* buffer, S32 length )
char* text = new char[ text_len + 1];
if (text == NULL)
{
+ LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Memory allocation failure." << LL_ENDL;
return FALSE;
}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 521405ec25..ded1444008 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -54,7 +54,7 @@ public:
struct Params : public LLInitParam::Block<Params, LLTextBase::Params>
{
Optional<std::string> default_text;
- Optional<LLTextValidate::validate_func_t, LLTextValidate::ValidateTextNamedFuncs> prevalidate_callback;
+ Optional<LLTextValidate::Validator, LLTextValidate::Validators> prevalidator;
Optional<bool> embedded_items,
ignore_tab,
@@ -337,7 +337,7 @@ private:
LLCoordGL mLastIMEPosition; // Last position of the IME editor
keystroke_signal_t mKeystrokeSignal;
- LLTextValidate::validate_func_t mPrevalidateFunc;
+ LLTextValidate::Validator mPrevalidator;
LLHandle<LLContextMenu> mContextMenuHandle;
}; // end class LLTextEditor
diff --git a/indra/llui/lltextvalidate.cpp b/indra/llui/lltextvalidate.cpp
index bfe0a5bb5d..9e27ed6232 100644
--- a/indra/llui/lltextvalidate.cpp
+++ b/indra/llui/lltextvalidate.cpp
@@ -27,330 +27,452 @@
// Text editor widget to let users enter a single line.
#include "linden_common.h"
-
+
#include "lltextvalidate.h"
+
+#include "llnotificationsutil.h"
+#include "lltrans.h"
+
#include "llresmgr.h" // for LLLocale
namespace LLTextValidate
{
- void ValidateTextNamedFuncs::declareValues()
- {
- declare("ascii", validateASCII);
- declare("float", validateFloat);
- declare("int", validateInt);
- declare("positive_s32", validatePositiveS32);
- declare("non_negative_s32", validateNonNegativeS32);
- declare("alpha_num", validateAlphaNum);
- declare("alpha_num_space", validateAlphaNumSpace);
- declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe);
- declare("ascii_printable_no_space", validateASCIIPrintableNoSpace);
- declare("ascii_with_newline", validateASCIIWithNewLine);
- }
-
- // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
- // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
- // the simple reasons that intermediate states may be invalid even if the final result is valid.
- //
- bool validateFloat(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool success = TRUE;
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- if( 0 < len )
- {
- // May be a comma or period, depending on the locale
- llwchar decimal_point = (llwchar)LLResMgr::getInstance()->getDecimalPoint();
-
- S32 i = 0;
-
- // First character can be a negative sign
- if( '-' == trimmed[0] )
- {
- i++;
- }
-
- for( ; i < len; i++ )
- {
- if( (decimal_point != trimmed[i] ) && !LLStringOps::isDigit( trimmed[i] ) )
- {
- success = FALSE;
- break;
- }
- }
- }
-
- return success;
- }
-
- // Limits what characters can be used to [1234567890-] with [-] only valid in the first position.
- // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
- // the simple reasons that intermediate states may be invalid even if the final result is valid.
- //
- bool validateInt(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool success = TRUE;
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- if( 0 < len )
- {
- S32 i = 0;
-
- // First character can be a negative sign
- if( '-' == trimmed[0] )
- {
- i++;
- }
-
- for( ; i < len; i++ )
- {
- if( !LLStringOps::isDigit( trimmed[i] ) )
- {
- success = FALSE;
- break;
- }
- }
- }
-
- return success;
- }
-
- bool validatePositiveS32(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- bool success = TRUE;
- if(0 < len)
- {
- if(('-' == trimmed[0]) || ('0' == trimmed[0]))
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(trimmed[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10);
- if (val <= 0)
- {
- success = FALSE;
- }
- }
- return success;
- }
-
- bool validateNonNegativeS32(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString trimmed = str;
- LLWStringUtil::trim(trimmed);
- S32 len = trimmed.length();
- bool success = TRUE;
- if(0 < len)
- {
- if('-' == trimmed[0])
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(trimmed[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(trimmed).c_str(), NULL, 10);
- if (val < 0)
- {
- success = FALSE;
- }
- }
- return success;
- }
-
- bool validateNonNegativeS32NoSpace(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- LLWString test_str = str;
- S32 len = test_str.length();
- bool success = TRUE;
- if(0 < len)
- {
- if('-' == test_str[0])
- {
- success = FALSE;
- }
- S32 i = 0;
- while(success && (i < len))
- {
- if(!LLStringOps::isDigit(test_str[i]) || LLStringOps::isSpace(test_str[i++]))
- {
- success = FALSE;
- }
- }
- }
- if (success)
- {
- S32 val = strtol(wstring_to_utf8str(test_str).c_str(), NULL, 10);
- if (val < 0)
- {
- success = FALSE;
- }
- }
- return success;
- }
-
- bool validateAlphaNum(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if( !LLStringOps::isAlnum((char)str[len]) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- bool validateAlphaNumSpace(const LLWString &str)
- {
- LLLocale locale(LLLocale::USER_LOCALE);
-
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- if(!(LLStringOps::isAlnum((char)str[len]) || (' ' == str[len])))
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- // Used for most names of things stored on the server, due to old file-formats
- // that used the pipe (|) for multiline text storage. Examples include
- // inventory item names, parcel names, object names, etc.
- bool validateASCIIPrintableNoPipe(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- llwchar wc = str[len];
- if (wc < 0x20
- || wc > 0x7f
- || wc == '|')
- {
- rv = FALSE;
- break;
- }
- if(!(wc == ' '
- || LLStringOps::isAlnum((char)wc)
- || LLStringOps::isPunct((char)wc) ) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
-
- // Used for avatar names
- bool validateASCIIPrintableNoSpace(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- if(len == 0) return rv;
- while(len--)
- {
- llwchar wc = str[len];
- if (wc < 0x20
- || wc > 0x7f
- || LLStringOps::isSpace(wc))
- {
- rv = FALSE;
- break;
- }
- if( !(LLStringOps::isAlnum((char)str[len]) ||
- LLStringOps::isPunct((char)str[len]) ) )
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- bool validateASCII(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- while(len--)
- {
- if (str[len] < 0x20 || str[len] > 0x7f)
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
-
- bool validateASCIINoLeadingSpace(const LLWString &str)
- {
- if (LLStringOps::isSpace(str[0]))
- {
- return FALSE;
- }
- return validateASCII(str);
- }
-
- // Used for multiline text stored on the server.
- // Example is landmark description in Places SP.
- bool validateASCIIWithNewLine(const LLWString &str)
- {
- bool rv = TRUE;
- S32 len = str.length();
- while(len--)
- {
- if ((str[len] < 0x20 && str[len] != 0xA) || str[len] > 0x7f)
- {
- rv = FALSE;
- break;
- }
- }
- return rv;
- }
+
+static S32 strtol(const std::string& str) { return ::strtol(str.c_str(), NULL, 10); }
+static S32 strtol(const LLWString& str) { return ::strtol(wstring_to_utf8str(str).c_str(), NULL, 10); }
+
+static LLSD llsd(const std::string& str) { return LLSD(str); }
+static LLSD llsd(const LLWString& str) { return LLSD(wstring_to_utf8str(str)); }
+template <class CHAR>
+LLSD llsd(CHAR ch) { return llsd(std::basic_string<CHAR>(1, ch)); }
+
+void ValidatorImpl::setLastErrorShowTime()
+{
+ mLastErrorShowTime = (U32Seconds)LLTimer::getTotalTime();
+}
+
+void Validator::showLastErrorUsingTimeout(U32 timeout)
+{
+ if (mImpl && (U32Seconds)LLTimer::getTotalTime() >= mImpl->getLastErrorShowTime() + timeout)
+ {
+ mImpl->setLastErrorShowTime();
+ std::string reason = LLTrans::getString(mImpl->getLastErrorName(), mImpl->getLastErrorValues());
+ LLNotificationsUtil::add("InvalidKeystroke", LLSD().with("REASON", reason));
+ }
}
+
+// Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
+// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
+// the simple reasons that intermediate states may be invalid even if the final result is valid.
+class ValidatorFloat : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR> &str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string<CHAR> trimmed = str;
+ LLStringUtilBase<CHAR>::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ // May be a comma or period, depending on the locale
+ CHAR decimal_point = LLResMgr::getInstance()->getDecimalPoint();
+
+ S32 i = 0;
+
+ // First character can be a negative sign
+ if ('-' == trimmed.front())
+ {
+ i++;
+ }
+
+ for (; i < len; i++)
+ {
+ CHAR ch = trimmed[i];
+ if ((decimal_point != ch) && !LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigitOrDot", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorFloatImpl;
+Validator validateFloat(validatorFloatImpl);
+
+// Limits what characters can be used to [1234567890-] with [-] only valid in the first position.
+// Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
+// the simple reasons that intermediate states may be invalid even if the final result is valid.
+class ValidatorInt : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR> &str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string<CHAR> trimmed = str;
+ LLStringUtilBase<CHAR>::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ S32 i = 0;
+
+ // First character can be a negative sign
+ if ('-' == trimmed.front())
+ {
+ i++;
+ }
+
+ for (; i < len; i++)
+ {
+ CHAR ch = trimmed[i];
+ if (!LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorIntImpl;
+Validator validateInt(validatorIntImpl);
+
+class ValidatorPositiveS32 : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string<CHAR> trimmed = str;
+ LLStringUtilBase<CHAR>::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ CHAR ch = trimmed.front();
+
+ if (('-' == ch) || ('0' == ch))
+ {
+ return setError("Validator_ShouldNotBeMinusOrZero", LLSD().with("CH", llsd(ch)));
+ }
+
+ for (S32 i = 0; i < len; ++i)
+ {
+ ch = trimmed[i];
+ if (!LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ S32 val = strtol(trimmed);
+ if (val <= 0)
+ {
+ return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed)));
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorPositiveS32Impl;
+Validator validatePositiveS32(validatorPositiveS32Impl);
+
+class ValidatorNonNegativeS32 : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string<CHAR> trimmed = str;
+ LLStringUtilBase<CHAR>::trim(trimmed);
+ S32 len = trimmed.length();
+ if (0 < len)
+ {
+ CHAR ch = trimmed.front();
+
+ if ('-' == ch)
+ {
+ return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch)));
+ }
+
+ for (S32 i = 0; i < len; ++i)
+ {
+ ch = trimmed[i];
+ if (!LLStringOps::isDigit(ch))
+ {
+ return setError("Validator_ShouldBeDigit", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ S32 val = strtol(trimmed);
+ if (val < 0)
+ {
+ return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(trimmed)));
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorNonNegativeS32Impl;
+Validator validateNonNegativeS32(validatorNonNegativeS32Impl);
+
+class ValidatorNonNegativeS32NoSpace : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ std::basic_string<CHAR> test_str = str;
+ S32 len = test_str.length();
+ if (0 < len)
+ {
+ CHAR ch = test_str.front();
+
+ if ('-' == ch)
+ {
+ return setError("Validator_ShouldNotBeMinus", LLSD().with("CH", llsd(ch)));
+ }
+
+ for (S32 i = 0; i < len; ++i)
+ {
+ ch = test_str[i];
+ if (!LLStringOps::isDigit(ch) || LLStringOps::isSpace(ch))
+ {
+ return setError("Validator_ShouldBeDigitNotSpace", LLSD().with("NR", i + 1).with("CH", llsd(ch)));
+ }
+ }
+ }
+
+ S32 val = strtol(test_str);
+ if (val < 0)
+ {
+ return setError("Validator_InvalidNumericString", LLSD().with("STR", llsd(test_str)));
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorNonNegativeS32NoSpaceImpl;
+Validator validateNonNegativeS32NoSpace(validatorNonNegativeS32NoSpaceImpl);
+
+class ValidatorAlphaNum : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (!LLStringOps::isAlnum(ch))
+ {
+ return setError("Validator_ShouldBeDigitOrAlpha", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorAlphaNumImpl;
+Validator validateAlphaNum(validatorAlphaNumImpl);
+
+class ValidatorAlphaNumSpace : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ LLLocale locale(LLLocale::USER_LOCALE);
+
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (!LLStringOps::isAlnum(ch) && (' ' != ch))
+ {
+ return setError("Validator_ShouldBeDigitOrAlphaOrSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorAlphaNumSpaceImpl;
+Validator validateAlphaNumSpace(validatorAlphaNumSpaceImpl);
+
+// Used for most names of things stored on the server, due to old file-formats
+// that used the pipe (|) for multiline text storage. Examples include
+// inventory item names, parcel names, object names, etc.
+class ValidatorASCIIPrintableNoPipe : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (ch < 0x20 || ch > 0x7f || ch == '|' ||
+ (ch != ' ' && !LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch)))
+ {
+ return setError("Validator_ShouldBeDigitOrAlphaOrPunct", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorASCIIPrintableNoPipeImpl;
+Validator validateASCIIPrintableNoPipe(validatorASCIIPrintableNoPipeImpl);
+
+// Used for avatar names
+class ValidatorASCIIPrintableNoSpace : public ValidatorImpl
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (ch <= 0x20 || ch > 0x7f || LLStringOps::isSpace(ch) ||
+ (!LLStringOps::isAlnum(ch) && !LLStringOps::isPunct(ch)))
+ {
+ return setError("Validator_ShouldBeDigitOrAlphaOrPunctNotSpace", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorASCIIPrintableNoSpaceImpl;
+Validator validateASCIIPrintableNoSpace(validatorASCIIPrintableNoSpaceImpl);
+
+class ValidatorASCII : public ValidatorImpl
+{
+protected:
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if (ch < 0x20 || ch > 0x7f)
+ {
+ return setError("Validator_ShouldBeASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorASCIIImpl;
+Validator validateASCII(validatorASCIIImpl);
+
+class ValidatorASCIINoLeadingSpace : public ValidatorASCII
+{
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ if (LLStringOps::isSpace(str.front()))
+ {
+ return false;
+ }
+
+ return ValidatorASCII::validate<CHAR>(str);
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorASCIINoLeadingSpaceImpl;
+Validator validateASCIINoLeadingSpace(validatorASCIINoLeadingSpaceImpl);
+
+class ValidatorASCIIWithNewLine : public ValidatorImpl
+{
+ // Used for multiline text stored on the server.
+ // Example is landmark description in Places SP.
+ template <class CHAR>
+ bool validate(const std::basic_string<CHAR>& str)
+ {
+ S32 len = str.length();
+ while (len--)
+ {
+ CHAR ch = str[len];
+
+ if ((ch < 0x20 && ch != 0xA) || ch > 0x7f)
+ {
+ return setError("Validator_ShouldBeNewLineOrASCII", LLSD().with("NR", len + 1).with("CH", llsd(ch)));
+ }
+ }
+
+ return resetError();
+ }
+
+public:
+ /*virtual*/ bool validate(const std::string& str) override { return validate<char>(str); }
+ /*virtual*/ bool validate(const LLWString& str) override { return validate<llwchar>(str); }
+} validatorASCIIWithNewLineImpl;
+Validator validateASCIIWithNewLine(validatorASCIIWithNewLineImpl);
+
+void Validators::declareValues()
+{
+ declare("ascii", validateASCII);
+ declare("float", validateFloat);
+ declare("int", validateInt);
+ declare("positive_s32", validatePositiveS32);
+ declare("non_negative_s32", validateNonNegativeS32);
+ declare("alpha_num", validateAlphaNum);
+ declare("alpha_num_space", validateAlphaNumSpace);
+ declare("ascii_printable_no_pipe", validateASCIIPrintableNoPipe);
+ declare("ascii_printable_no_space", validateASCIIPrintableNoSpace);
+ declare("ascii_with_newline", validateASCIIWithNewLine);
+}
+
+} // namespace LLTextValidate
diff --git a/indra/llui/lltextvalidate.h b/indra/llui/lltextvalidate.h
index e2b6c313d6..2c2941de7f 100644
--- a/indra/llui/lltextvalidate.h
+++ b/indra/llui/lltextvalidate.h
@@ -34,27 +34,68 @@
namespace LLTextValidate
{
- typedef boost::function<BOOL (const LLWString &wstr)> validate_func_t;
-
- struct ValidateTextNamedFuncs
- : public LLInitParam::TypeValuesHelper<validate_func_t, ValidateTextNamedFuncs>
- {
- static void declareValues();
- };
-
- bool validateFloat(const LLWString &str );
- bool validateInt(const LLWString &str );
- bool validatePositiveS32(const LLWString &str);
- bool validateNonNegativeS32(const LLWString &str);
- bool validateNonNegativeS32NoSpace(const LLWString &str);
- bool validateAlphaNum(const LLWString &str );
- bool validateAlphaNumSpace(const LLWString &str );
- bool validateASCIIPrintableNoPipe(const LLWString &str);
- bool validateASCIIPrintableNoSpace(const LLWString &str);
- bool validateASCII(const LLWString &str);
- bool validateASCIINoLeadingSpace(const LLWString &str);
- bool validateASCIIWithNewLine(const LLWString &str);
-}
+ class ValidatorImpl
+ {
+ public:
+ ValidatorImpl() {}
+ virtual ~ValidatorImpl() {}
+ virtual bool validate(const std::string& str) = 0;
+ virtual bool validate(const LLWString& str) = 0;
+
+ bool setError(std::string name, LLSD values = LLSD()) { return mLastErrorName = name, mLastErrorValues = values, false; }
+ bool resetError() { return mLastErrorName.clear(), mLastErrorValues.clear(), true; }
+ const std::string& getLastErrorName() const { return mLastErrorName; }
+ const LLSD& getLastErrorValues() const { return mLastErrorValues; }
+
+ void setLastErrorShowTime();
+ U32 getLastErrorShowTime() const { return mLastErrorShowTime; }
+
+ protected:
+ std::string mLastErrorName;
+ LLSD mLastErrorValues;
+ U32 mLastErrorShowTime { 0 };
+ };
+
+ class Validator
+ {
+ public:
+ Validator() : mImpl(nullptr) {}
+ Validator(ValidatorImpl& impl) : mImpl(&impl) {}
+ Validator(const Validator& validator) : mImpl(validator.mImpl) {}
+ Validator(const Validator* validator) : mImpl(validator->mImpl) {}
+
+ bool validate(const std::string& str) const { return !mImpl || mImpl->validate(str); }
+ bool validate(const LLWString& str) const { return !mImpl || mImpl->validate(str); }
+
+ operator bool() const { return mImpl; }
+
+ static const U32 SHOW_LAST_ERROR_TIMEOUT_SEC = 30;
+ void showLastErrorUsingTimeout(U32 timeout = SHOW_LAST_ERROR_TIMEOUT_SEC);
+
+ private:
+ ValidatorImpl* mImpl;
+ };
+
+ // Available validators
+ extern Validator validateFloat;
+ extern Validator validateInt;
+ extern Validator validatePositiveS32;
+ extern Validator validateNonNegativeS32;
+ extern Validator validateNonNegativeS32NoSpace;
+ extern Validator validateAlphaNum;
+ extern Validator validateAlphaNumSpace;
+ extern Validator validateASCIIPrintableNoPipe;
+ extern Validator validateASCIIPrintableNoSpace;
+ extern Validator validateASCII;
+ extern Validator validateASCIINoLeadingSpace;
+ extern Validator validateASCIIWithNewLine;
+
+ // Add available validators to the internal map
+ struct Validators : public LLInitParam::TypeValuesHelper<Validator, Validators>
+ {
+ static void declareValues();
+ };
+};
#endif
diff --git a/indra/llui/lltimectrl.cpp b/indra/llui/lltimectrl.cpp
index 516057f8fd..564d0b6264 100644
--- a/indra/llui/lltimectrl.cpp
+++ b/indra/llui/lltimectrl.cpp
@@ -49,6 +49,36 @@ const U32 HOURS_MAX = 12;
const U32 MINUTES_PER_HOUR = 60;
const U32 MINUTES_PER_DAY = 24 * MINUTES_PER_HOUR;
+class LLTimeValidatorImpl : public LLTextValidate::ValidatorImpl
+{
+public:
+ // virtual
+ bool validate(const std::string& str) override
+ {
+ std::string hours = LLTimeCtrl::getHoursString(str);
+ if (!LLTimeCtrl::isHoursStringValid(hours))
+ return setError("ValidatorInvalidHours", LLSD().with("STR", hours));
+
+ std::string minutes = LLTimeCtrl::getMinutesString(str);
+ if (!LLTimeCtrl::isMinutesStringValid(minutes))
+ return setError("ValidatorInvalidMinutes", LLSD().with("STR", minutes));
+
+ std::string ampm = LLTimeCtrl::getAMPMString(str);
+ if (!LLTimeCtrl::isPMAMStringValid(ampm))
+ return setError("ValidatorInvalidAMPM", LLSD().with("STR", ampm));
+
+ return resetError();
+ }
+
+ // virtual
+ bool validate(const LLWString& wstr) override
+ {
+ std::string str = wstring_to_utf8str(wstr);
+
+ return validate(str);
+ }
+} validateTimeImpl;
+LLTextValidate::Validator validateTime(validateTimeImpl);
LLTimeCtrl::Params::Params()
: label_width("label_width"),
@@ -111,7 +141,7 @@ LLTimeCtrl::LLTimeCtrl(const LLTimeCtrl::Params& p)
params.keystroke_callback(boost::bind(&LLTimeCtrl::onTextEntry, this, _1));
mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
mEditor->setPrevalidateInput(LLTextValidate::validateNonNegativeS32NoSpace);
- mEditor->setPrevalidate(boost::bind(&LLTimeCtrl::isTimeStringValid, this, _1));
+ mEditor->setPrevalidate(validateTime);
mEditor->setText(LLStringExplicit("12:00 AM"));
addChild(mEditor);
@@ -247,15 +277,6 @@ void LLTimeCtrl::onTextEntry(LLLineEditor* line_editor)
mTime = h24 * MINUTES_PER_HOUR + m;
}
-bool LLTimeCtrl::isTimeStringValid(const LLWString &wstr)
-{
- std::string str = wstring_to_utf8str(wstr);
-
- return isHoursStringValid(getHoursString(str)) &&
- isMinutesStringValid(getMinutesString(str)) &&
- isPMAMStringValid(getAMPMString(str));
-}
-
void LLTimeCtrl::increaseMinutes()
{
mTime = (mTime + mSnapToMin) % MINUTES_PER_DAY - (mTime % mSnapToMin);
diff --git a/indra/llui/lltimectrl.h b/indra/llui/lltimectrl.h
index b5f268c76a..1c8ac78289 100644
--- a/indra/llui/lltimectrl.h
+++ b/indra/llui/lltimectrl.h
@@ -60,6 +60,18 @@ public:
void setTime24(F32 time); // 0.0 - 23.98(3)
+ static std::string getHoursString(const std::string& str);
+ static std::string getMinutesString(const std::string& str);
+ static std::string getAMPMString(const std::string& str);
+
+ static bool isHoursStringValid(const std::string& str);
+ static bool isMinutesStringValid(const std::string& str);
+ static bool isPMAMStringValid(const std::string& str);
+
+ static U32 parseHours(const std::string& str);
+ static U32 parseMinutes(const std::string& str);
+ static bool parseAMPM(const std::string& str);
+
protected:
LLTimeCtrl(const Params&);
friend class LLUICtrlFactory;
@@ -87,8 +99,6 @@ private:
void onDownBtn();
void onTextEntry(LLLineEditor* line_editor);
- bool isTimeStringValid(const LLWString& wstr);
-
void increaseMinutes();
void increaseHours();
@@ -102,18 +112,6 @@ private:
EEditingPart getEditingPart();
- static std::string getHoursString(const std::string& str);
- static std::string getMinutesString(const std::string& str);
- static std::string getAMPMString(const std::string& str);
-
- static bool isHoursStringValid(const std::string& str);
- static bool isMinutesStringValid(const std::string& str);
- static bool isPMAMStringValid(const std::string& str);
-
- static U32 parseHours(const std::string& str);
- static U32 parseMinutes(const std::string& str);
- static bool parseAMPM(const std::string& str);
-
class LLTextBox* mLabelBox;
class LLLineEditor* mEditor;
diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp
index 2707f7a15c..58ecf3e603 100644
--- a/indra/llui/lltoolbar.cpp
+++ b/indra/llui/lltoolbar.cpp
@@ -1134,8 +1134,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask)
BOOL handled = FALSE;
S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY);
- static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3);
- if (mouse_distance_squared > drag_threshold * drag_threshold
+ if (mouse_distance_squared > DRAG_N_DROP_DISTANCE_THRESHOLD * DRAG_N_DROP_DISTANCE_THRESHOLD
&& hasMouseCapture() &&
mStartDragItemCallback && mHandleDragItemCallback)
{
diff --git a/indra/llui/lltransutil.cpp b/indra/llui/lltransutil.cpp
index 5da722a72b..06760c4196 100644
--- a/indra/llui/lltransutil.cpp
+++ b/indra/llui/lltransutil.cpp
@@ -44,8 +44,13 @@ bool LLTransUtil::parseStrings(const std::string& xml_filename, const std::set<s
bool success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root, LLDir::ALL_SKINS);
if (!success)
{
- gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
- LL_ERRS() << "Couldn't load string table " << xml_filename << ". Please reinstall viewer from https://secondlife.com/support/downloads/ and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL;
+ //gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
+ const std::string error_string =
+ "Second Life viewer couldn't access some of the files it needs and will be closed."
+ "\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and "
+ "contact https://support.secondlife.com if issue persists after reinstall.";
+ LLError::LLUserWarningMsg::show(error_string);
+ LL_ERRS() << "Couldn't load string table " << xml_filename << " " << errno << LL_ENDL;
return false;
}
@@ -60,6 +65,7 @@ bool LLTransUtil::parseLanguageStrings(const std::string& xml_filename)
if (!success)
{
+ LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Couldn't load localization table " << xml_filename << LL_ENDL;
return false;
}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 86b23c8c93..34a82387cd 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -53,7 +53,7 @@ class LLWindow;
class LLView;
class LLHelp;
-
+const S32 DRAG_N_DROP_DISTANCE_THRESHOLD = 3;
// this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim)
enum EDragAndDropType
{
diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp
index 7eb9ae69fb..c7fcbaec1c 100644
--- a/indra/llui/lluictrl.cpp
+++ b/indra/llui/lluictrl.cpp
@@ -80,7 +80,7 @@ LLUICtrl::Params::Params()
mouseenter_callback("mouseenter_callback"),
mouseleave_callback("mouseleave_callback"),
control_name("control_name"),
- font("font", LLFontGL::getFontSansSerif()),
+ font("font", LLFontGL::getFontEmojiMedium()),
font_halign("halign"),
font_valign("valign"),
length("length"), // ignore LLXMLNode cruft
diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h
index cffb9933d4..4c47256519 100644
--- a/indra/llui/lluictrl.h
+++ b/indra/llui/lluictrl.h
@@ -41,6 +41,7 @@
const BOOL TAKE_FOCUS_YES = TRUE;
const BOOL TAKE_FOCUS_NO = FALSE;
+const S32 DROP_SHADOW_FLOATER = 5;
class LLUICtrl
: public LLView, public boost::signals2::trackable
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 139eb17efa..1a80a69293 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -898,6 +898,34 @@ F32 LLView::getTooltipTimeout()
: tooltip_delay);
}
+// virtual
+const std::string LLView::getToolTip() const
+{
+ if (sDebugUnicode)
+ {
+ std::string text = getText();
+ if (!text.empty())
+ {
+ const std::string& name = getName();
+ std::string tooltip = llformat("Name: \"%s\"", name.c_str());
+
+ if (const LLFontGL* font = getFont())
+ {
+ tooltip += llformat("\nFont: %s (%s)",
+ font->getFontDesc().getName().c_str(),
+ font->getFontDesc().getSize().c_str()
+ );
+ }
+
+ tooltip += "\n\n" + utf8str_showBytesUTF8(text);
+
+ return tooltip;
+ }
+ }
+
+ return mToolTipMsg.getString();
+}
+
BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask)
{
BOOL handled = FALSE;
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 6e16d41cba..c023cc95b7 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -243,8 +243,10 @@ public:
ECursorType getHoverCursor() { return mHoverCursor; }
- static F32 getTooltipTimeout();
- virtual const std::string getToolTip() const { return mToolTipMsg.getString(); }
+ static F32 getTooltipTimeout();
+ virtual const std::string getToolTip() const;
+ virtual const std::string& getText() const { return LLStringUtil::null; }
+ virtual const LLFontGL* getFont() const { return nullptr; }
void sendChildToFront(LLView* child);
void sendChildToBack(LLView* child);
diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp
index a400eb70c0..41082a2848 100644
--- a/indra/llui/llviewmodel.cpp
+++ b/indra/llui/llviewmodel.cpp
@@ -81,7 +81,7 @@ void LLTextViewModel::setValue(const LLSD& value)
{
// approximate LLSD storage usage
LLViewModel::setValue(value);
- mDisplay = utf8str_to_wstring(value.asString());
+ mDisplay = utf8str_to_wstring(mStringValue = value.asString());
// mDisplay and mValue agree
mUpdateFromDisplay = false;
@@ -101,23 +101,34 @@ void LLTextViewModel::setDisplay(const LLWString& value)
mUpdateFromDisplay = true;
}
-LLSD LLTextViewModel::getValue() const
+inline void updateFromDisplayIfNeeded(const LLTextViewModel* model)
{
- // Has anyone called setDisplay() since the last setValue()? If so, have
- // to convert mDisplay back to UTF8.
- if (mUpdateFromDisplay)
+ // Has anyone called setDisplay() since the last setValue()?
+ // If so, have to convert mDisplay back to UTF8.
+ if (model->mUpdateFromDisplay)
{
- // The fact that we're lazily updating fields in this object should be
- // transparent to clients, which is why this method is left
- // conventionally const. Nor do we particularly want to make these
- // members mutable. Just cast away constness in this one place.
- LLTextViewModel* nthis = const_cast<LLTextViewModel*>(this);
+ // The fact that we're lazily updating fields
+ // in this object should be transparent to clients,
+ // which is why this method is left conventionally const.
+ // Nor do we particularly want to make these members mutable.
+ // Just cast away constness in this one place.
+ LLTextViewModel* nthis = const_cast<LLTextViewModel*>(model);
nthis->mUpdateFromDisplay = false;
- nthis->mValue = wstring_to_utf8str(mDisplay);
+ nthis->mValue = nthis->mStringValue = wstring_to_utf8str(model->mDisplay);
}
- return LLViewModel::getValue();
}
+LLSD LLTextViewModel::getValue() const
+{
+ updateFromDisplayIfNeeded(this);
+ return mValue;
+}
+
+const std::string& LLTextViewModel::getStringValue() const
+{
+ updateFromDisplayIfNeeded(this);
+ return mStringValue;
+}
////////////////////////////////////////////////////////////////////////////
diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h
index e7dceb6c31..ffd67f455d 100644
--- a/indra/llui/llviewmodel.h
+++ b/indra/llui/llviewmodel.h
@@ -100,6 +100,7 @@ public:
// LLViewModel functions
virtual void setValue(const LLSD& value);
virtual LLSD getValue() const;
+ const std::string& getStringValue() const;
// New functions
/// Get the stored value in string form
@@ -114,12 +115,17 @@ public:
void setDisplay(const LLWString& value);
private:
+ std::string mStringValue;
+
/// To avoid converting every widget's stored value from LLSD to LLWString
/// every frame, cache the converted value
LLWString mDisplay;
+
/// As the user edits individual characters (setDisplay()), defer
/// LLWString-to-UTF8 conversions until s/he's done.
bool mUpdateFromDisplay;
+
+ friend void updateFromDisplayIfNeeded(const LLTextViewModel* model);
};
/**