aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llui')
-rw-r--r--linden/indra/llui/llalertdialog.cpp9
-rw-r--r--linden/indra/llui/llbutton.cpp78
-rw-r--r--linden/indra/llui/llbutton.h7
-rw-r--r--linden/indra/llui/llfloater.cpp73
-rw-r--r--linden/indra/llui/llfloater.h10
-rw-r--r--linden/indra/llui/lllineeditor.cpp81
-rw-r--r--linden/indra/llui/lllineeditor.h10
-rw-r--r--linden/indra/llui/llmemberlistener.h1
-rw-r--r--linden/indra/llui/llpanel.cpp17
-rw-r--r--linden/indra/llui/llpanel.h2
-rw-r--r--linden/indra/llui/llscrolllistctrl.cpp51
-rw-r--r--linden/indra/llui/llscrolllistctrl.h8
-rw-r--r--linden/indra/llui/lltabcontainer.cpp54
-rw-r--r--linden/indra/llui/lltabcontainer.h7
-rw-r--r--linden/indra/llui/lltexteditor.cpp57
-rw-r--r--linden/indra/llui/lltexteditor.h3
-rw-r--r--linden/indra/llui/llui.h91
-rw-r--r--linden/indra/llui/lluictrlfactory.cpp11
-rw-r--r--linden/indra/llui/lluictrlfactory.h4
-rw-r--r--linden/indra/llui/llview.cpp20
-rw-r--r--linden/indra/llui/llview.h4
21 files changed, 517 insertions, 81 deletions
diff --git a/linden/indra/llui/llalertdialog.cpp b/linden/indra/llui/llalertdialog.cpp
index 547efae..8950fcd 100644
--- a/linden/indra/llui/llalertdialog.cpp
+++ b/linden/indra/llui/llalertdialog.cpp
@@ -783,10 +783,11 @@ bool LLAlertDialog::parseAlerts(const LLString& xml_filename, LLControlGroup* se
783 // label= 783 // label=
784 LLString name; 784 LLString name;
785 child->getAttributeString("name", name); 785 child->getAttributeString("name", name);
786 if (name.empty()) 786
787 { 787 //always set to alert_name for the sake of i18n
788 name = alert_name; 788 //if (name.empty())
789 } 789 name = alert_name;
790
790 if (xml_template) 791 if (xml_template)
791 { 792 {
792 xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_DEFAULT; 793 xml_template->mIgnorable = LLAlertDialog::IGNORE_USE_DEFAULT;
diff --git a/linden/indra/llui/llbutton.cpp b/linden/indra/llui/llbutton.cpp
index 1d44537..de8b82e 100644
--- a/linden/indra/llui/llbutton.cpp
+++ b/linden/indra/llui/llbutton.cpp
@@ -615,6 +615,56 @@ void LLButton::draw()
615 gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE); 615 gl_rect_2d(0, mRect.getHeight(), mRect.getWidth(), 0, LLColor4::pink1, FALSE);
616 } 616 }
617 617
618 // draw overlay image
619 if (mImageOverlay.notNull())
620 {
621 const S32 IMG_PAD = 4;
622 // get max width and height (discard level 0)
623 S32 overlay_width = mImageOverlay->getWidth(0);
624 S32 overlay_height = mImageOverlay->getHeight(0);
625
626 F32 scale_factor = llmin((F32)mRect.getWidth() / (F32)overlay_width, (F32)mRect.getHeight() / (F32)overlay_height, 1.f);
627 overlay_width = llround((F32)overlay_width * scale_factor);
628 overlay_height = llround((F32)overlay_height * scale_factor);
629
630 S32 center_x = getLocalRect().getCenterX();
631 S32 center_y = getLocalRect().getCenterY();
632
633 switch(mImageOverlayAlignment)
634 {
635 case LLFontGL::LEFT:
636 gl_draw_scaled_image(
637 IMG_PAD,
638 center_y - (overlay_height / 2),
639 overlay_width,
640 overlay_height,
641 mImageOverlay,
642 LLColor4::white);
643 break;
644 case LLFontGL::HCENTER:
645 gl_draw_scaled_image(
646 center_x - (overlay_width / 2),
647 center_y - (overlay_height / 2),
648 overlay_width,
649 overlay_height,
650 mImageOverlay,
651 LLColor4::white);
652 break;
653 case LLFontGL::RIGHT:
654 gl_draw_scaled_image(
655 mRect.getWidth() - IMG_PAD - overlay_width,
656 center_y - (overlay_height / 2),
657 overlay_width,
658 overlay_height,
659 mImageOverlay,
660 LLColor4::white);
661 break;
662 default:
663 // draw nothing
664 break;
665 }
666 }
667
618 // Draw label 668 // Draw label
619 if( !label.empty() ) 669 if( !label.empty() )
620 { 670 {
@@ -826,6 +876,21 @@ void LLButton::setHoverImages( const LLString& image_name, const LLString& selec
826 setImageHoverSelected(selected_name); 876 setImageHoverSelected(selected_name);
827} 877}
828 878
879void LLButton::setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment)
880{
881 if (image_name.empty())
882 {
883 mImageOverlay = NULL;
884 }
885 else
886 {
887 LLUUID overlay_image_id = LLUI::findAssetUUIDByName(image_name);
888 mImageOverlay = LLUI::sImageProvider->getUIImageByID(overlay_image_id);
889 mImageOverlayAlignment = alignment;
890 }
891}
892
893
829void LLButton::onMouseCaptureLost() 894void LLButton::onMouseCaptureLost()
830{ 895{
831 mMouseDownTimer.stop(); 896 mMouseDownTimer.stop();
@@ -998,6 +1063,18 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
998 LLString image_disabled; 1063 LLString image_disabled;
999 if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled); 1064 if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled);
1000 1065
1066 LLString image_overlay;
1067 node->getAttributeString("image_overlay", image_overlay);
1068
1069 LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER;
1070 LLString image_overlay_alignment_string;
1071 if (node->hasAttribute("image_overlay_alignment"))
1072 {
1073 node->getAttributeString("image_overlay_alignment", image_overlay_alignment_string);
1074 image_overlay_alignment = LLFontGL::hAlignFromName(image_overlay_alignment_string);
1075 }
1076
1077
1001 LLButton *button = new LLButton(name, 1078 LLButton *button = new LLButton(name,
1002 LLRect(), 1079 LLRect(),
1003 image_unselected, 1080 image_unselected,
@@ -1020,6 +1097,7 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
1020 1097
1021 if(image_disabled != LLString::null) button->setImageDisabled(image_disabled); 1098 if(image_disabled != LLString::null) button->setImageDisabled(image_disabled);
1022 1099
1100 if(image_overlay != LLString::null) button->setImageOverlay(image_overlay, image_overlay_alignment);
1023 1101
1024 if (node->hasAttribute("halign")) 1102 if (node->hasAttribute("halign"))
1025 { 1103 {
diff --git a/linden/indra/llui/llbutton.h b/linden/indra/llui/llbutton.h
index 44e8776..6e11779 100644
--- a/linden/indra/llui/llbutton.h
+++ b/linden/indra/llui/llbutton.h
@@ -142,6 +142,10 @@ public:
142 142
143 void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } 143 void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; }
144 144
145 void setImageOverlay(const LLString &image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER);
146 LLPointer<LLImageGL> getImageOverlay() { return mImageOverlay; }
147
148
145 virtual void setValue(const LLSD& value ); 149 virtual void setValue(const LLSD& value );
146 virtual LLSD getValue() const; 150 virtual LLSD getValue() const;
147 151
@@ -202,6 +206,9 @@ protected:
202 F32 mHeldDownDelay; // seconds, after which held-down callbacks get called 206 F32 mHeldDownDelay; // seconds, after which held-down callbacks get called
203 S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called 207 S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called
204 208
209 LLPointer<LLImageGL> mImageOverlay;
210 LLFontGL::HAlign mImageOverlayAlignment;
211
205 LLPointer<LLImageGL> mImageUnselected; 212 LLPointer<LLImageGL> mImageUnselected;
206 LLUIString mUnselectedLabel; 213 LLUIString mUnselectedLabel;
207 LLColor4 mUnselectedLabelColor; 214 LLColor4 mUnselectedLabelColor;
diff --git a/linden/indra/llui/llfloater.cpp b/linden/indra/llui/llfloater.cpp
index df44a58..6ab182f 100644
--- a/linden/indra/llui/llfloater.cpp
+++ b/linden/indra/llui/llfloater.cpp
@@ -575,17 +575,20 @@ void LLFloater::close(bool app_quitting)
575 cleanupHandles(); 575 cleanupHandles();
576 gFocusMgr.clearLastFocusForGroup(this); 576 gFocusMgr.clearLastFocusForGroup(this);
577 577
578 // Do this early, so UI controls will commit before the 578 if (hasFocus())
579 // window is taken down.
580 releaseFocus();
581
582 // give focus to dependee floater if it exists, and we had focus first
583 if (isDependent())
584 { 579 {
585 LLFloater* dependee = LLFloater::getFloaterByHandle(mDependeeHandle); 580 // Do this early, so UI controls will commit before the
586 if (dependee && !dependee->isDead()) 581 // window is taken down.
582 releaseFocus();
583
584 // give focus to dependee floater if it exists, and we had focus first
585 if (isDependent())
587 { 586 {
588 dependee->setFocus(TRUE); 587 LLFloater* dependee = LLFloater::getFloaterByHandle(mDependeeHandle);
588 if (dependee && !dependee->isDead())
589 {
590 dependee->setFocus(TRUE);
591 }
589 } 592 }
590 } 593 }
591 594
@@ -1170,6 +1173,28 @@ BOOL LLFloater::getEditModeEnabled()
1170 return sEditModeEnabled; 1173 return sEditModeEnabled;
1171} 1174}
1172 1175
1176//static
1177void LLFloater::show(LLFloater* floaterp)
1178{
1179 if (floaterp) floaterp->open();
1180}
1181
1182//static
1183void LLFloater::hide(LLFloater* floaterp)
1184{
1185 if (floaterp) floaterp->close();
1186}
1187
1188//static
1189BOOL LLFloater::visible(LLFloater* floaterp)
1190{
1191 if (floaterp)
1192 {
1193 return floaterp->isInVisibleChain();
1194 }
1195 return FALSE;
1196}
1197
1173// static 1198// static
1174void LLFloater::onClickMinimize(void *userdata) 1199void LLFloater::onClickMinimize(void *userdata)
1175{ 1200{
@@ -2372,7 +2397,7 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
2372LLMultiFloater::LLMultiFloater() : 2397LLMultiFloater::LLMultiFloater() :
2373 mTabContainer(NULL), 2398 mTabContainer(NULL),
2374 mTabPos(LLTabContainerCommon::TOP), 2399 mTabPos(LLTabContainerCommon::TOP),
2375 mAutoResize(FALSE) 2400 mAutoResize(TRUE)
2376{ 2401{
2377 2402
2378} 2403}
@@ -2380,7 +2405,7 @@ LLMultiFloater::LLMultiFloater() :
2380LLMultiFloater::LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos) : 2405LLMultiFloater::LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos) :
2381 mTabContainer(NULL), 2406 mTabContainer(NULL),
2382 mTabPos(tab_pos), 2407 mTabPos(tab_pos),
2383 mAutoResize(FALSE) 2408 mAutoResize(TRUE)
2384{ 2409{
2385 2410
2386} 2411}
@@ -2594,15 +2619,12 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
2594 floaterp->setCanResize(FALSE); 2619 floaterp->setCanResize(FALSE);
2595 floaterp->setCanDrag(FALSE); 2620 floaterp->setCanDrag(FALSE);
2596 2621
2597 S32 new_width = llmax(mRect.getWidth(), floaterp->getRect().getWidth());
2598 S32 new_height = llmax(mRect.getHeight(), floaterp->getRect().getHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
2599
2600 reshape(new_width, new_height);
2601
2602 //add the panel, add it to proper maps 2622 //add the panel, add it to proper maps
2603 mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); 2623 mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point);
2604 mFloaterDataMap[floaterp->getHandle()] = floater_data; 2624 mFloaterDataMap[floaterp->getHandle()] = floater_data;
2605 2625
2626 resizeToContents();
2627
2606 if ( select_added_floater ) 2628 if ( select_added_floater )
2607 { 2629 {
2608 mTabContainer->selectLastTab(); 2630 mTabContainer->selectLastTab();
@@ -2676,10 +2698,7 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp)
2676 floaterp->setBackgroundVisible(TRUE); 2698 floaterp->setBackgroundVisible(TRUE);
2677 floaterp->setHost(NULL); 2699 floaterp->setHost(NULL);
2678 2700
2679 if (mAutoResize) 2701 resizeToContents();
2680 {
2681 resizeToContents();
2682 }
2683 2702
2684 tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); 2703 tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
2685} 2704}
@@ -2729,7 +2748,8 @@ BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
2729 if (key == 'W') 2748 if (key == 'W')
2730 { 2749 {
2731 LLFloater* floater = getActiveFloater(); 2750 LLFloater* floater = getActiveFloater();
2732 if (floater && floater->canClose()) 2751 // is user closeable and is system closeable
2752 if (floater && floater->canClose() && floater->isCloseable())
2733 { 2753 {
2734 floater->close(); 2754 floater->close();
2735 } 2755 }
@@ -2848,10 +2868,17 @@ void LLMultiFloater::resizeToContents()
2848 2868
2849 S32 cur_height = mRect.getHeight(); 2869 S32 cur_height = mRect.getHeight();
2850 2870
2851 reshape(new_width, new_height); 2871 if (mAutoResize)
2872 {
2873 reshape(new_width, new_height);
2874 }
2875 else
2876 {
2877 reshape(llmax(new_min_width, mRect.getWidth()), llmax(new_min_height, mRect.getHeight()));
2878 }
2852 2879
2853 // make sure upper left corner doesn't move 2880 // make sure upper left corner doesn't move
2854 translate(0, cur_height - new_height); 2881 translate(0, cur_height - mRect.getHeight());
2855 2882
2856 // Try to keep whole view onscreen, don't allow partial offscreen. 2883 // Try to keep whole view onscreen, don't allow partial offscreen.
2857 gFloaterView->adjustToFitScreen(this, FALSE); 2884 gFloaterView->adjustToFitScreen(this, FALSE);
diff --git a/linden/indra/llui/llfloater.h b/linden/indra/llui/llfloater.h
index cd45762..8b610e3 100644
--- a/linden/indra/llui/llfloater.h
+++ b/linden/indra/llui/llfloater.h
@@ -212,6 +212,10 @@ public:
212 static BOOL getEditModeEnabled(); 212 static BOOL getEditModeEnabled();
213 static LLMultiFloater* getFloaterHost() {return sHostp; } 213 static LLMultiFloater* getFloaterHost() {return sHostp; }
214 214
215 static void show(LLFloater* floaterp);
216 static void hide(LLFloater* floaterp);
217 static BOOL visible(LLFloater* floaterp);
218
215 static LLFloater* getFloaterByHandle(LLViewHandle handle); 219 static LLFloater* getFloaterByHandle(LLViewHandle handle);
216 220
217protected: 221protected:
@@ -279,7 +283,6 @@ protected:
279 std::vector<LLView*> mMinimizedHiddenChildren; 283 std::vector<LLView*> mMinimizedHiddenChildren;
280}; 284};
281 285
282
283///////////////////////////////////////////////////////////// 286/////////////////////////////////////////////////////////////
284// LLFloaterView 287// LLFloaterView
285// Parent of all floating panels 288// Parent of all floating panels
@@ -354,8 +357,8 @@ public:
354 LLMultiFloater(); 357 LLMultiFloater();
355 LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos); 358 LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos);
356 LLMultiFloater(const LLString& name); 359 LLMultiFloater(const LLString& name);
357 LLMultiFloater(const LLString& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = FALSE); 360 LLMultiFloater(const LLString& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
358 LLMultiFloater(const LLString& name, const LLString& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = FALSE); 361 LLMultiFloater(const LLString& name, const LLString& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE);
359 virtual ~LLMultiFloater(); 362 virtual ~LLMultiFloater();
360 363
361 virtual BOOL postBuild(); 364 virtual BOOL postBuild();
@@ -416,3 +419,4 @@ extern LLFloaterView* gFloaterView;
416 419
417#endif // LL_FLOATER_H 420#endif // LL_FLOATER_H
418 421
422
diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp
index a2cd9af..44616b9 100644
--- a/linden/indra/llui/lllineeditor.cpp
+++ b/linden/indra/llui/lllineeditor.cpp
@@ -157,6 +157,14 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
157{ 157{
158 llassert( max_length_bytes > 0 ); 158 llassert( max_length_bytes > 0 );
159 159
160 // line history support:
161 // - initialize line history list
162 mLineHistory.insert( mLineHistory.end(), "" );
163 // - disable line history by default
164 mHaveHistory = FALSE;
165 // - reset current history line pointer
166 mCurrentHistoryLine = 0;
167
160 if (font) 168 if (font)
161 { 169 {
162 mGLFont = font; 170 mGLFont = font;
@@ -229,10 +237,33 @@ void LLLineEditor::onFocusLost()
229 237
230void LLLineEditor::onCommit() 238void LLLineEditor::onCommit()
231{ 239{
240 // put current line into the line history
241 updateHistory();
242
232 LLUICtrl::onCommit(); 243 LLUICtrl::onCommit();
233 selectAll(); 244 selectAll();
234} 245}
235 246
247// line history support
248void LLLineEditor::updateHistory()
249{
250 // On history enabled line editors, remember committed line and
251 // reset current history line number.
252 // Be sure only to remember lines that are not empty and that are
253 // different from the last on the list.
254 if( mHaveHistory && mText.length() && ( mLineHistory.empty() || getText() != mLineHistory.back() ) )
255 {
256 // discard possible empty line at the end of the history
257 // inserted by setText()
258 if( !mLineHistory.back().length() )
259 {
260 mLineHistory.pop_back();
261 }
262 mLineHistory.insert( mLineHistory.end(), getText() );
263 mCurrentHistoryLine = mLineHistory.size() - 1;
264 }
265}
266
236void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent) 267void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
237{ 268{
238 LLUICtrl::reshape(width, height, called_from_parent ); 269 LLUICtrl::reshape(width, height, called_from_parent );
@@ -240,6 +271,10 @@ void LLLineEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
240 mMaxHPixels = mRect.getWidth() - 2 * (mBorderThickness + UI_LINEEDITOR_H_PAD) + 1 - mBorderRight; 271 mMaxHPixels = mRect.getWidth() - 2 * (mBorderThickness + UI_LINEEDITOR_H_PAD) + 1 - mBorderRight;
241} 272}
242 273
274void LLLineEditor::setEnableLineHistory( BOOL enabled )
275{
276 mHaveHistory = enabled;
277}
243 278
244void LLLineEditor::setEnabled(BOOL enabled) 279void LLLineEditor::setEnabled(BOOL enabled)
245{ 280{
@@ -300,6 +335,13 @@ void LLLineEditor::setText(const LLString &new_text)
300 deselect(); 335 deselect();
301 } 336 }
302 setCursor(llmin((S32)mText.length(), getCursor())); 337 setCursor(llmin((S32)mText.length(), getCursor()));
338
339 // Newly set text goes always in the last line of history.
340 // Possible empty strings (as with chat line) will be deleted later.
341 mLineHistory.insert( mLineHistory.end(), new_text );
342 // Set current history line to end of history.
343 mCurrentHistoryLine = mLineHistory.size() - 1;
344
303 mPrevText = mText; 345 mPrevText = mText;
304} 346}
305 347
@@ -1086,6 +1128,45 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask)
1086 } 1128 }
1087 break; 1129 break;
1088 1130
1131 // handle ctrl-uparrow if we have a history enabled line editor.
1132 case KEY_UP:
1133 if( mHaveHistory && ( MASK_CONTROL & mask ) )
1134 {
1135 if( mCurrentHistoryLine > 0 )
1136 {
1137 mText.assign( mLineHistory[ --mCurrentHistoryLine ] );
1138 setCursor(llmin((S32)mText.length(), getCursor()));
1139 }
1140 else
1141 {
1142 reportBadKeystroke();
1143 }
1144 handled = TRUE;
1145 }
1146 break;
1147
1148 // handle ctrl-downarrow if we have a history enabled line editor
1149 case KEY_DOWN:
1150 if( mHaveHistory && ( MASK_CONTROL & mask ) )
1151 {
1152 if( !mLineHistory.empty() && mCurrentHistoryLine < mLineHistory.size() - 1 )
1153 {
1154 mText.assign( mLineHistory[ ++mCurrentHistoryLine ] );
1155 setCursor(llmin((S32)mText.length(), getCursor()));
1156 }
1157 else
1158 {
1159 reportBadKeystroke();
1160 }
1161 handled = TRUE;
1162 }
1163 break;
1164
1165 case KEY_RETURN:
1166 // store sent line in history
1167 updateHistory();
1168 break;
1169
1089 case KEY_ESCAPE: 1170 case KEY_ESCAPE:
1090 if (mRevertOnEsc && mText.getString() != mPrevText) 1171 if (mRevertOnEsc && mText.getString() != mPrevText)
1091 { 1172 {
diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h
index 65c75ab..e715737 100644
--- a/linden/indra/llui/lllineeditor.h
+++ b/linden/indra/llui/lllineeditor.h
@@ -36,6 +36,7 @@
36// Clipboard (cut, copy, and paste) 36// Clipboard (cut, copy, and paste)
37// Horizontal scrolling to allow strings longer than widget size allows 37// Horizontal scrolling to allow strings longer than widget size allows
38// Pre-validation (limit which keys can be used) 38// Pre-validation (limit which keys can be used)
39// Optional line history so previous entries can be recalled by CTRL UP/DOWN
39 40
40 41
41#ifndef LL_LLLINEEDITOR_H 42#ifndef LL_LLLINEEDITOR_H
@@ -206,6 +207,10 @@ public:
206 207
207 static BOOL postvalidateFloat(const LLString &str); 208 static BOOL postvalidateFloat(const LLString &str);
208 209
210 // line history support:
211 void setEnableLineHistory( BOOL enabled ); // switches line history on or off
212 void updateHistory(); // stores current line in history
213
209protected: 214protected:
210 void removeChar(); 215 void removeChar();
211 void addChar(const llwchar c); 216 void addChar(const llwchar c);
@@ -224,6 +229,11 @@ protected:
224 LLString mPrevText; // Saved string for 'ESC' revert 229 LLString mPrevText; // Saved string for 'ESC' revert
225 LLUIString mLabel; // text label that is visible when no user text provided 230 LLUIString mLabel; // text label that is visible when no user text provided
226 231
232 // line history support:
233 BOOL mHaveHistory; // flag for enabled line history
234 std::vector<LLString> mLineHistory; // line history storage
235 U32 mCurrentHistoryLine; // currently browsed history line
236
227 LLViewBorder* mBorder; 237 LLViewBorder* mBorder;
228 const LLFontGL* mGLFont; 238 const LLFontGL* mGLFont;
229 S32 mMaxLengthChars; // Max number of characters 239 S32 mMaxLengthChars; // Max number of characters
diff --git a/linden/indra/llui/llmemberlistener.h b/linden/indra/llui/llmemberlistener.h
index 92e7278..bc67519 100644
--- a/linden/indra/llui/llmemberlistener.h
+++ b/linden/indra/llui/llmemberlistener.h
@@ -37,7 +37,6 @@ class LLMemberListener : public LLSimpleListener
37{ 37{
38public: 38public:
39 LLMemberListener() : mPtr(NULL), mRegisteredName("") { } 39 LLMemberListener() : mPtr(NULL), mRegisteredName("") { }
40 ~LLMemberListener() { }
41 40
42 void registerListener(T *pointer, const LLString& register_name) 41 void registerListener(T *pointer, const LLString& register_name)
43 { 42 {
diff --git a/linden/indra/llui/llpanel.cpp b/linden/indra/llui/llpanel.cpp
index f0b5b25..dfa3f8a 100644
--- a/linden/indra/llui/llpanel.cpp
+++ b/linden/indra/llui/llpanel.cpp
@@ -589,7 +589,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parentp, LLUICtrlFactory *fa
589 return panelp; 589 return panelp;
590} 590}
591 591
592void LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) 592BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
593{ 593{
594 LLString name("panel"); 594 LLString name("panel");
595 node->getAttributeString("name", name); 595 node->getAttributeString("name", name);
@@ -605,12 +605,23 @@ void LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
605 605
606 LLString xml_filename; 606 LLString xml_filename;
607 node->getAttributeString("filename", xml_filename); 607 node->getAttributeString("filename", xml_filename);
608
609 BOOL didPost;
610
608 if (!xml_filename.empty()) 611 if (!xml_filename.empty())
609 { 612 {
610 factory->buildPanel(this, xml_filename, NULL); 613 didPost = factory->buildPanel(this, xml_filename, NULL);
614 } else {
615 didPost = FALSE;
611 } 616 }
612 617
613 postBuild(); 618 if (!didPost)
619 {
620 postBuild();
621 didPost = TRUE;
622 }
623
624 return didPost;
614} 625}
615 626
616void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp) 627void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parentp)
diff --git a/linden/indra/llui/llpanel.h b/linden/indra/llui/llpanel.h
index 9da942e..fea3eee 100644
--- a/linden/indra/llui/llpanel.h
+++ b/linden/indra/llui/llpanel.h
@@ -135,7 +135,7 @@ public:
135 135
136 virtual LLXMLNodePtr getXML(bool save_children = true) const; 136 virtual LLXMLNodePtr getXML(bool save_children = true) const;
137 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); 137 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
138 void initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); 138 BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory);
139 void setPanelParameters(LLXMLNodePtr node, LLView *parentp); 139 void setPanelParameters(LLXMLNodePtr node, LLView *parentp);
140 140
141 // ** Wrappers for setting child properties by name ** -TomY 141 // ** Wrappers for setting child properties by name ** -TomY
diff --git a/linden/indra/llui/llscrolllistctrl.cpp b/linden/indra/llui/llscrolllistctrl.cpp
index 22987dc..fd98bd5 100644
--- a/linden/indra/llui/llscrolllistctrl.cpp
+++ b/linden/indra/llui/llscrolllistctrl.cpp
@@ -99,7 +99,7 @@ protected:
99// LLScrollListIcon 99// LLScrollListIcon
100// 100//
101LLScrollListIcon::LLScrollListIcon(LLImageGL* icon, S32 width, LLUUID image_id) : 101LLScrollListIcon::LLScrollListIcon(LLImageGL* icon, S32 width, LLUUID image_id) :
102mIcon(icon), mImageUUID(image_id.asString()) 102mIcon(icon), mColor(LLColor4::white), mImageUUID(image_id.asString())
103{ 103{
104 if (width) 104 if (width)
105 { 105 {
@@ -115,6 +115,16 @@ LLScrollListIcon::~LLScrollListIcon()
115{ 115{
116} 116}
117 117
118void LLScrollListIcon::setColor(const LLColor4& color)
119{
120 mColor = color;
121}
122
123void LLScrollListIcon::drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const
124{
125 gl_draw_image(0, 0, mIcon, mColor);
126}
127
118// 128//
119// LLScrollListCheck 129// LLScrollListCheck
120// 130//
@@ -208,6 +218,15 @@ LLScrollListText::~LLScrollListText()
208 delete mColor; 218 delete mColor;
209} 219}
210 220
221void LLScrollListText::setColor(const LLColor4& color)
222{
223 if (!mColor)
224 {
225 mColor = new LLColor4();
226 }
227 *mColor = color;
228}
229
211void LLScrollListText::setText(const LLString& text) 230void LLScrollListText::setText(const LLString& text)
212{ 231{
213 mText = text; 232 mText = text;
@@ -2809,6 +2828,8 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
2809 LLString fontname = (*itor)["font"].asString(); 2828 LLString fontname = (*itor)["font"].asString();
2810 LLString fontstyle = (*itor)["font-style"].asString(); 2829 LLString fontstyle = (*itor)["font-style"].asString();
2811 LLString type = (*itor)["type"].asString(); 2830 LLString type = (*itor)["type"].asString();
2831 BOOL has_color = (*itor).has("color");
2832 LLColor4 color = ((*itor)["color"]);
2812 2833
2813 const LLFontGL *font = gResMgr->getRes(fontname); 2834 const LLFontGL *font = gResMgr->getRes(fontname);
2814 if (!font) 2835 if (!font)
@@ -2821,21 +2842,41 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& value, EAddPosition p
2821 { 2842 {
2822 LLUUID image_id = value.asUUID(); 2843 LLUUID image_id = value.asUUID();
2823 LLImageGL* icon = LLUI::sImageProvider->getUIImageByID(image_id); 2844 LLImageGL* icon = LLUI::sImageProvider->getUIImageByID(image_id);
2824 new_item->setColumn(index, new LLScrollListIcon(icon, width, image_id)); 2845 LLScrollListIcon* cell = new LLScrollListIcon(icon, width, image_id);
2846 if (has_color)
2847 {
2848 cell->setColor(color);
2849 }
2850 new_item->setColumn(index, cell);
2825 } 2851 }
2826 else if (type == "checkbox") 2852 else if (type == "checkbox")
2827 { 2853 {
2828 LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(value.asString(), 2854 LLCheckBoxCtrl* ctrl = new LLCheckBoxCtrl(value.asString(),
2829 LLRect(0, 0, width, width), "label"); 2855 LLRect(0, 0, width, width), "label");
2830 new_item->setColumn(index, new LLScrollListCheck(ctrl,width)); 2856 LLScrollListCheck* cell = new LLScrollListCheck(ctrl,width);
2857 if (has_color)
2858 {
2859 cell->setColor(color);
2860 }
2861 new_item->setColumn(index, cell);
2831 } 2862 }
2832 else if (type == "separator") 2863 else if (type == "separator")
2833 { 2864 {
2834 new_item->setColumn(index, new LLScrollListSeparator(width)); 2865 LLScrollListSeparator* cell = new LLScrollListSeparator(width);
2866 if (has_color)
2867 {
2868 cell->setColor(color);
2869 }
2870 new_item->setColumn(index, cell);
2835 } 2871 }
2836 else 2872 else
2837 { 2873 {
2838 new_item->setColumn(index, new LLScrollListText(value.asString(), font, width, font_style, font_alignment)); 2874 LLScrollListText* cell = new LLScrollListText(value.asString(), font, width, font_style, font_alignment);
2875 if (has_color)
2876 {
2877 cell->setColor(color);
2878 }
2879 new_item->setColumn(index, cell);
2839 if (columnp->mHeader && !value.asString().empty()) 2880 if (columnp->mHeader && !value.asString().empty())
2840 { 2881 {
2841 columnp->mHeader->setHasResizableElement(TRUE); 2882 columnp->mHeader->setHasResizableElement(TRUE);
diff --git a/linden/indra/llui/llscrolllistctrl.h b/linden/indra/llui/llscrolllistctrl.h
index eed07b8..429985b 100644
--- a/linden/indra/llui/llscrolllistctrl.h
+++ b/linden/indra/llui/llscrolllistctrl.h
@@ -63,6 +63,7 @@ public:
63 virtual void setWidth(S32 width) = 0; 63 virtual void setWidth(S32 width) = 0;
64 virtual void highlightText(S32 offset, S32 num_chars) {} 64 virtual void highlightText(S32 offset, S32 num_chars) {}
65 virtual BOOL isText() = 0; 65 virtual BOOL isText() = 0;
66 virtual void setColor(const LLColor4&) = 0;
66 67
67 virtual BOOL handleClick() { return FALSE; } 68 virtual BOOL handleClick() { return FALSE; }
68 virtual void setEnabled(BOOL enable) { } 69 virtual void setEnabled(BOOL enable) { }
@@ -77,6 +78,7 @@ public:
77 virtual S32 getWidth() const {return mWidth;} 78 virtual S32 getWidth() const {return mWidth;}
78 virtual S32 getHeight() const { return 5; }; 79 virtual S32 getHeight() const { return 5; };
79 virtual void setWidth(S32 width) {mWidth = width; } 80 virtual void setWidth(S32 width) {mWidth = width; }
81 virtual void setColor(const LLColor4&) {};
80 virtual BOOL isText() { return FALSE; } 82 virtual BOOL isText() { return FALSE; }
81 83
82protected: 84protected:
@@ -97,6 +99,7 @@ public:
97 virtual const BOOL getVisible() const { return mVisible; } 99 virtual const BOOL getVisible() const { return mVisible; }
98 virtual void highlightText(S32 offset, S32 num_chars) {mHighlightOffset = offset; mHighlightCount = num_chars;} 100 virtual void highlightText(S32 offset, S32 num_chars) {mHighlightOffset = offset; mHighlightCount = num_chars;}
99 void setText(const LLString& text); 101 void setText(const LLString& text);
102 virtual void setColor(const LLColor4&);
100 virtual BOOL isText() { return TRUE; } 103 virtual BOOL isText() { return TRUE; }
101 104
102private: 105private:
@@ -120,18 +123,20 @@ class LLScrollListIcon : public LLScrollListCell
120public: 123public:
121 LLScrollListIcon( LLImageGL* icon, S32 width = 0, LLUUID image_id = LLUUID::null); 124 LLScrollListIcon( LLImageGL* icon, S32 width = 0, LLUUID image_id = LLUUID::null);
122 /*virtual*/ ~LLScrollListIcon(); 125 /*virtual*/ ~LLScrollListIcon();
123 virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const { gl_draw_image(0, 0, mIcon); } 126 virtual void drawToWidth(S32 width, const LLColor4& color, const LLColor4& highlight_color) const;
124 virtual S32 getWidth() const { return mWidth; } 127 virtual S32 getWidth() const { return mWidth; }
125 virtual S32 getHeight() const { return mIcon->getHeight(); } 128 virtual S32 getHeight() const { return mIcon->getHeight(); }
126 virtual const LLString& getText() const { return mImageUUID; } 129 virtual const LLString& getText() const { return mImageUUID; }
127 virtual const LLString& getTextLower() const { return mImageUUID; } 130 virtual const LLString& getTextLower() const { return mImageUUID; }
128 virtual void setWidth(S32 width) { mWidth = width; } 131 virtual void setWidth(S32 width) { mWidth = width; }
132 virtual void setColor(const LLColor4&);
129 virtual BOOL isText() { return FALSE; } 133 virtual BOOL isText() { return FALSE; }
130 134
131private: 135private:
132 LLPointer<LLImageGL> mIcon; 136 LLPointer<LLImageGL> mIcon;
133 LLString mImageUUID; 137 LLString mImageUUID;
134 S32 mWidth; 138 S32 mWidth;
139 LLColor4 mColor;
135}; 140};
136 141
137class LLScrollListCheck : public LLScrollListCell 142class LLScrollListCheck : public LLScrollListCell
@@ -146,6 +151,7 @@ public:
146 151
147 virtual BOOL handleClick(); 152 virtual BOOL handleClick();
148 virtual void setEnabled(BOOL enable) { if (mCheckBox) mCheckBox->setEnabled(enable); } 153 virtual void setEnabled(BOOL enable) { if (mCheckBox) mCheckBox->setEnabled(enable); }
154 virtual void setColor(const LLColor4& color) {};
149 155
150 LLCheckBoxCtrl* getCheckBox() { return mCheckBox; } 156 LLCheckBoxCtrl* getCheckBox() { return mCheckBox; }
151 virtual BOOL isText() { return FALSE; } 157 virtual BOOL isText() { return FALSE; }
diff --git a/linden/indra/llui/lltabcontainer.cpp b/linden/indra/llui/lltabcontainer.cpp
index 61cfde4..44940ae 100644
--- a/linden/indra/llui/lltabcontainer.cpp
+++ b/linden/indra/llui/lltabcontainer.cpp
@@ -77,7 +77,8 @@ LLTabContainerCommon::LLTabContainerCommon(
77 mCallbackUserdata( callback_userdata ), 77 mCallbackUserdata( callback_userdata ),
78 mTitleBox(NULL), 78 mTitleBox(NULL),
79 mTopBorderHeight(LLPANEL_BORDER_WIDTH), 79 mTopBorderHeight(LLPANEL_BORDER_WIDTH),
80 mTabPosition(pos) 80 mTabPosition(pos),
81 mLockedTabCount(0)
81{ 82{
82 setMouseOpaque(FALSE); 83 setMouseOpaque(FALSE);
83} 84}
@@ -142,6 +143,13 @@ void LLTabContainerCommon::addPlaceholder(LLPanel* child, const LLString& label)
142 addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); 143 addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE);
143} 144}
144 145
146void LLTabContainerCommon::lockTabs()
147{
148 // count current tabs and ensure no new tabs get
149 // inserted between them
150 mLockedTabCount = getTabCount();
151}
152
145void LLTabContainerCommon::removeTabPanel(LLPanel* child) 153void LLTabContainerCommon::removeTabPanel(LLPanel* child)
146{ 154{
147 BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); 155 BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this);
@@ -164,6 +172,10 @@ void LLTabContainerCommon::removeTabPanel(LLPanel* child)
164 break; 172 break;
165 } 173 }
166 } 174 }
175
176 // make sure we don't have more locked tabs than we have tabs
177 mLockedTabCount = llmin(getTabCount(), mLockedTabCount);
178
167 if (mCurrentTabIdx >= (S32)mTabList.size()) 179 if (mCurrentTabIdx >= (S32)mTabList.size())
168 { 180 {
169 mCurrentTabIdx = mTabList.size()-1; 181 mCurrentTabIdx = mTabList.size()-1;
@@ -526,6 +538,15 @@ void LLTabContainerCommon::setTabPanelFlashing(LLPanel* child, BOOL state )
526 } 538 }
527} 539}
528 540
541void LLTabContainerCommon::setTabImage(LLPanel* child, std::string img_name)
542{
543 LLTabTuple* tuple = getTabByPanel(child);
544 if( tuple )
545 {
546 tuple->mButton->setImageOverlay(img_name, LLFontGL::RIGHT);
547 }
548}
549
529void LLTabContainerCommon::setTitle(const LLString& title) 550void LLTabContainerCommon::setTitle(const LLString& title)
530{ 551{
531 if (mTitleBox) 552 if (mTitleBox)
@@ -687,12 +708,12 @@ void LLTabContainerCommon::insertTuple(LLTabTuple * tuple, eInsertionPoint inser
687 { 708 {
688 case START: 709 case START:
689 // insert the new tab in the front of the list 710 // insert the new tab in the front of the list
690 mTabList.insert(mTabList.begin(), tuple); 711 mTabList.insert(mTabList.begin() + mLockedTabCount, tuple);
691 break; 712 break;
692 case RIGHT_OF_CURRENT: 713 case RIGHT_OF_CURRENT:
693 // insert the new tab after the current tab 714 // insert the new tab after the current tab (but not before mLockedTabCount)
694 { 715 {
695 tuple_list_t::iterator current_iter = mTabList.begin() + mCurrentTabIdx + 1; 716 tuple_list_t::iterator current_iter = mTabList.begin() + llmax(mLockedTabCount, mCurrentTabIdx + 1);
696 mTabList.insert(current_iter, tuple); 717 mTabList.insert(current_iter, tuple);
697 } 718 }
698 break; 719 break;
@@ -1249,6 +1270,7 @@ void LLTabContainer::draw()
1249 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) 1270 for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
1250 { 1271 {
1251 LLTabTuple* tuple = *iter; 1272 LLTabTuple* tuple = *iter;
1273
1252 tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 ); 1274 tuple->mButton->translate( left - tuple->mButton->getRect().mLeft, 0 );
1253 left += tuple->mButton->getRect().getWidth(); 1275 left += tuple->mButton->getRect().getWidth();
1254 1276
@@ -1596,3 +1618,27 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag
1596 1618
1597 return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); 1619 return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip);
1598} 1620}
1621
1622void LLTabContainer::setTabImage(LLPanel* child, std::string image_name)
1623{
1624 LLTabTuple* tuple = getTabByPanel(child);
1625 if( tuple )
1626 {
1627 tuple->mButton->setImageOverlay(image_name, LLFontGL::RIGHT);
1628
1629 const LLFontGL* fontp = gResMgr->getRes( LLFONT_SANSSERIF_SMALL );
1630 // remove current width from total tab strip width
1631 mTotalTabWidth -= tuple->mButton->getRect().getWidth();
1632
1633 S32 image_overlay_width = tuple->mButton->getImageOverlay().notNull() ?
1634 tuple->mButton->getImageOverlay()->getWidth(0) :
1635 0;
1636 tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + image_overlay_width, mMinTabWidth, mMaxTabWidth),
1637 tuple->mButton->getRect().getHeight());
1638 // add back in button width to total tab strip width
1639 mTotalTabWidth += tuple->mButton->getRect().getWidth();
1640
1641 // tabs have changed size, might need to scroll to see current tab
1642 updateMaxScrollPos();
1643 }
1644} \ No newline at end of file
diff --git a/linden/indra/llui/lltabcontainer.h b/linden/indra/llui/lltabcontainer.h
index 5fe6bc5..7d501d2 100644
--- a/linden/indra/llui/lltabcontainer.h
+++ b/linden/indra/llui/lltabcontainer.h
@@ -87,7 +87,8 @@ public:
87 BOOL placeholder = FALSE, 87 BOOL placeholder = FALSE,
88 eInsertionPoint insertion_point = END) = 0; 88 eInsertionPoint insertion_point = END) = 0;
89 virtual void addPlaceholder(LLPanel* child, const LLString& label); 89 virtual void addPlaceholder(LLPanel* child, const LLString& label);
90 90 virtual void lockTabs();
91
91 virtual void enableTabButton(S32 which, BOOL enable); 92 virtual void enableTabButton(S32 which, BOOL enable);
92 93
93 virtual void removeTabPanel( LLPanel* child ); 94 virtual void removeTabPanel( LLPanel* child );
@@ -113,6 +114,7 @@ public:
113 114
114 BOOL getTabPanelFlashing(LLPanel* child); 115 BOOL getTabPanelFlashing(LLPanel* child);
115 void setTabPanelFlashing(LLPanel* child, BOOL state); 116 void setTabPanelFlashing(LLPanel* child, BOOL state);
117 virtual void setTabImage(LLPanel* child, std::string img_name);
116 void setTitle( const LLString& title ); 118 void setTitle( const LLString& title );
117 const LLString getPanelTitle(S32 index); 119 const LLString getPanelTitle(S32 index);
118 120
@@ -180,6 +182,7 @@ protected:
180 182
181 S32 mTopBorderHeight; 183 S32 mTopBorderHeight;
182 TabPosition mTabPosition; 184 TabPosition mTabPosition;
185 S32 mLockedTabCount;
183 186
184protected: 187protected:
185 void scrollPrev(); 188 void scrollPrev();
@@ -221,7 +224,7 @@ public:
221 /*virtual*/ void removeTabPanel( LLPanel* child ); 224 /*virtual*/ void removeTabPanel( LLPanel* child );
222 225
223 /*virtual*/ void setPanelTitle(S32 index, const LLString& title); 226 /*virtual*/ void setPanelTitle(S32 index, const LLString& title);
224 227 /*virtual*/ void setTabImage(LLPanel* child, std::string img_name);
225 /*virtual*/ void setRightTabBtnOffset( S32 offset ); 228 /*virtual*/ void setRightTabBtnOffset( S32 offset );
226 229
227 /*virtual*/ void setMinTabWidth(S32 width); 230 /*virtual*/ void setMinTabWidth(S32 width);
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp
index ba991c2..80205d3 100644
--- a/linden/indra/llui/lltexteditor.cpp
+++ b/linden/indra/llui/lltexteditor.cpp
@@ -309,6 +309,9 @@ LLTextEditor::LLTextEditor(
309{ 309{
310 mSourceID.generate(); 310 mSourceID.generate();
311 311
312 // reset desired x cursor position
313 mDesiredXPixel = -1;
314
312 if (font) 315 if (font)
313 { 316 {
314 mGLFont = font; 317 mGLFont = font;
@@ -348,7 +351,7 @@ LLTextEditor::LLTextEditor(
348 mBorder = new LLViewBorder( "text ed border", LLRect(0, mRect.getHeight(), mRect.getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER ); 351 mBorder = new LLViewBorder( "text ed border", LLRect(0, mRect.getHeight(), mRect.getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER );
349 addChild( mBorder ); 352 addChild( mBorder );
350 353
351 setText(default_text); 354 appendText(default_text, FALSE, FALSE);
352 355
353 mParseHTML=FALSE; 356 mParseHTML=FALSE;
354 mHTML=""; 357 mHTML="";
@@ -914,6 +917,8 @@ void LLTextEditor::setCursorPos(S32 offset)
914{ 917{
915 mCursorPos = llclamp(offset, 0, (S32)getLength()); 918 mCursorPos = llclamp(offset, 0, (S32)getLength());
916 updateScrollFromCursor(); 919 updateScrollFromCursor();
920 // reset desired x cursor position
921 mDesiredXPixel = -1;
917} 922}
918 923
919 924
@@ -2645,7 +2650,8 @@ void LLTextEditor::drawSelectionBackground()
2645 { 2650 {
2646 LLGLSNoTexture no_texture; 2651 LLGLSNoTexture no_texture;
2647 const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor; 2652 const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor;
2648 glColor3f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2] ); 2653 F32 alpha = hasFocus() ? 1.f : 0.5f;
2654 glColor4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
2649 2655
2650 if( selection_left_y == selection_right_y ) 2656 if( selection_left_y == selection_right_y )
2651 { 2657 {
@@ -3098,6 +3104,9 @@ void LLTextEditor::changePage( S32 delta )
3098 S32 line, offset; 3104 S32 line, offset;
3099 getLineAndOffset( mCursorPos, &line, &offset ); 3105 getLineAndOffset( mCursorPos, &line, &offset );
3100 3106
3107 // get desired x position to remember previous position
3108 S32 desired_x_pixel = mDesiredXPixel;
3109
3101 // allow one line overlap 3110 // allow one line overlap
3102 S32 page_size = mScrollbar->getPageSize() - 1; 3111 S32 page_size = mScrollbar->getPageSize() - 1;
3103 if( delta == -1 ) 3112 if( delta == -1 )
@@ -3112,6 +3121,10 @@ void LLTextEditor::changePage( S32 delta )
3112 setCursorPos(getPos( line + page_size, offset )); 3121 setCursorPos(getPos( line + page_size, offset ));
3113 mScrollbar->setDocPos( mScrollbar->getDocPos() + page_size ); 3122 mScrollbar->setDocPos( mScrollbar->getDocPos() + page_size );
3114 } 3123 }
3124
3125 // put desired position into remember-buffer after setCursorPos()
3126 mDesiredXPixel = desired_x_pixel;
3127
3115 if (mOnScrollEndCallback && mOnScrollEndData && (mScrollbar->getDocPos() == mScrollbar->getDocPosMax())) 3128 if (mOnScrollEndCallback && mOnScrollEndData && (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()))
3116 { 3129 {
3117 mOnScrollEndCallback(mOnScrollEndData); 3130 mOnScrollEndCallback(mOnScrollEndData);
@@ -3127,9 +3140,13 @@ void LLTextEditor::changeLine( S32 delta )
3127 3140
3128 S32 line_start = getLineStart(line); 3141 S32 line_start = getLineStart(line);
3129 3142
3130 S32 desired_x_pixel; 3143 // set desired x position to remembered previous position
3131 3144 S32 desired_x_pixel = mDesiredXPixel;
3132 desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems ); 3145 // if remembered position was reset (thus -1), calculate new one here
3146 if( desired_x_pixel == -1 )
3147 {
3148 desired_x_pixel = mGLFont->getWidth(mWText.c_str(), line_start, offset, mAllowEmbeddedItems );
3149 }
3133 3150
3134 S32 new_line = 0; 3151 S32 new_line = 0;
3135 if( (delta < 0) && (line > 0 ) ) 3152 if( (delta < 0) && (line > 0 ) )
@@ -3165,6 +3182,9 @@ void LLTextEditor::changeLine( S32 delta )
3165 mAllowEmbeddedItems); 3182 mAllowEmbeddedItems);
3166 3183
3167 setCursorPos (getPos( new_line, new_offset )); 3184 setCursorPos (getPos( new_line, new_offset ));
3185
3186 // put desired position into remember-buffer after setCursorPos()
3187 mDesiredXPixel = desired_x_pixel;
3168 unbindEmbeddedChars( mGLFont ); 3188 unbindEmbeddedChars( mGLFont );
3169} 3189}
3170 3190
@@ -3358,6 +3378,14 @@ void LLTextEditor::appendColoredText(const LLString &new_text,
3358 style.setVisible(true); 3378 style.setVisible(true);
3359 style.setColor(color); 3379 style.setColor(color);
3360 style.setFontName(font_name); 3380 style.setFontName(font_name);
3381 appendStyledText(new_text, allow_undo, prepend_newline, &style);
3382}
3383
3384void LLTextEditor::appendStyledText(const LLString &new_text,
3385 bool allow_undo,
3386 bool prepend_newline,
3387 const LLStyle* style)
3388{
3361 if(mParseHTML) 3389 if(mParseHTML)
3362 { 3390 {
3363 3391
@@ -3368,10 +3396,13 @@ void LLTextEditor::appendColoredText(const LLString &new_text,
3368 LLStyle html; 3396 LLStyle html;
3369 html.setVisible(true); 3397 html.setVisible(true);
3370 html.setColor(mLinkColor); 3398 html.setColor(mLinkColor);
3371 html.setFontName(font_name); 3399 if (style)
3400 {
3401 html.setFontName(style->getFontString());
3402 }
3372 html.mUnderline = TRUE; 3403 html.mUnderline = TRUE;
3373 3404
3374 if (start > 0) appendText(text.substr(0,start),allow_undo, prepend_newline, &style); 3405 if (start > 0) appendText(text.substr(0,start),allow_undo, prepend_newline, style);
3375 html.setLinkHREF(text.substr(start,end-start)); 3406 html.setLinkHREF(text.substr(start,end-start));
3376 appendText(text.substr(start, end-start),allow_undo, prepend_newline, &html); 3407 appendText(text.substr(start, end-start),allow_undo, prepend_newline, &html);
3377 if (end < (S32)text.length()) 3408 if (end < (S32)text.length())
@@ -3384,22 +3415,14 @@ void LLTextEditor::appendColoredText(const LLString &new_text,
3384 break; 3415 break;
3385 } 3416 }
3386 } 3417 }
3387 if (end < (S32)text.length()) appendText(text,allow_undo, prepend_newline, &style); 3418 if (end < (S32)text.length()) appendText(text,allow_undo, prepend_newline, style);
3388 } 3419 }
3389 else 3420 else
3390 { 3421 {
3391 appendText(new_text, allow_undo, prepend_newline, &style); 3422 appendText(new_text, allow_undo, prepend_newline, style);
3392 } 3423 }
3393} 3424}
3394 3425
3395void LLTextEditor::appendStyledText(const LLString &new_text,
3396 bool allow_undo,
3397 bool prepend_newline,
3398 const LLStyle &style)
3399{
3400 appendText(new_text, allow_undo, prepend_newline, &style);
3401}
3402
3403// Appends new text to end of document 3426// Appends new text to end of document
3404void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool prepend_newline, 3427void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool prepend_newline,
3405 const LLStyle* segment_style) 3428 const LLStyle* segment_style)
diff --git a/linden/indra/llui/lltexteditor.h b/linden/indra/llui/lltexteditor.h
index 32375be..ebe8ac3 100644
--- a/linden/indra/llui/lltexteditor.h
+++ b/linden/indra/llui/lltexteditor.h
@@ -159,7 +159,7 @@ public:
159 // if styled text starts a line, you need to prepend a newline. 159 // if styled text starts a line, you need to prepend a newline.
160 void appendStyledText(const LLString &new_text, bool allow_undo, 160 void appendStyledText(const LLString &new_text, bool allow_undo,
161 bool prepend_newline, 161 bool prepend_newline,
162 const LLStyle &style); 162 const LLStyle* style);
163 163
164 // Removes text from the end of document 164 // Removes text from the end of document
165 // Does not change highlight or cursor position. 165 // Does not change highlight or cursor position.
@@ -359,6 +359,7 @@ protected:
359 undo_stack_t mUndoStack; 359 undo_stack_t mUndoStack;
360 360
361 S32 mCursorPos; // I-beam is just after the mCursorPos-th character. 361 S32 mCursorPos; // I-beam is just after the mCursorPos-th character.
362 S32 mDesiredXPixel; // X pixel position where the user wants the cursor to be
362 LLRect mTextRect; // The rect in which text is drawn. Excludes borders. 363 LLRect mTextRect; // The rect in which text is drawn. Excludes borders.
363 // List of offsets and segment index of the start of each line. Always has at least one node (0). 364 // List of offsets and segment index of the start of each line. Always has at least one node (0).
364 struct line_info 365 struct line_info
diff --git a/linden/indra/llui/llui.h b/linden/indra/llui/llui.h
index 6b8a86a..3085bd9 100644
--- a/linden/indra/llui/llui.h
+++ b/linden/indra/llui/llui.h
@@ -275,4 +275,95 @@ typedef enum e_widget_type
275 WIDGET_TYPE_COUNT 275 WIDGET_TYPE_COUNT
276} EWidgetType; 276} EWidgetType;
277 277
278// Manages generation of UI elements by LLSD, such that there is
279// only one instance per uniquely identified LLSD parameter
280// Class T is the instance type being managed, and INSTANCE_ADDAPTOR
281// wraps an instance of the class with handlers for show/hide semantics, etc.
282template <class T, class INSTANCE_ADAPTOR = T>
283class LLUIInstanceMgr
284{
285public:
286 LLUIInstanceMgr()
287 {
288 }
289
290 virtual ~LLUIInstanceMgr()
291 {
292 }
293
294 // default show and hide methods
295 static T* showInstance(const LLSD& seed)
296 {
297 T* instance = INSTANCE_ADAPTOR::getInstance(seed);
298 INSTANCE_ADAPTOR::show(instance);
299 return instance;
300 }
301
302 static void hideInstance(const LLSD& seed)
303 {
304 T* instance = INSTANCE_ADAPTOR::getInstance(seed);
305 INSTANCE_ADAPTOR::hide(instance);
306 }
307
308 static void toggleInstance(const LLSD& seed)
309 {
310 if (!INSTANCE_ADAPTOR::instanceVisible(seed))
311 {
312 INSTANCE_ADAPTOR::showInstance(seed);
313 }
314 else
315 {
316 INSTANCE_ADAPTOR::hideInstance(seed);
317 }
318 }
319
320 static BOOL instanceVisible(const LLSD& seed)
321 {
322 T* instance = INSTANCE_ADAPTOR::findInstance(seed);
323 return instance != NULL && INSTANCE_ADAPTOR::visible(instance);
324 }
325
326 static T* getInstance(const LLSD& seed)
327 {
328 T* instance = INSTANCE_ADAPTOR::findInstance(seed);
329 if (instance == NULL)
330 {
331 instance = INSTANCE_ADAPTOR::createInstance(seed);
332 }
333 return instance;
334 }
335};
336
337// Creates a UI singleton by ignoring the identifying parameter
338// and always generating the same instance via the LLUIInstanceMgr interface.
339// Note that since UI elements can be destroyed by their hierarchy, this singleton
340// pattern uses a static pointer to an instance that will be re-created as needed.
341template <class T, class INSTANCE_ADAPTOR = T>
342class LLUISingleton: public LLUIInstanceMgr<T, INSTANCE_ADAPTOR>
343{
344public:
345 // default constructor assumes T is derived from LLUISingleton (a true singleton)
346 LLUISingleton() : LLUIInstanceMgr<T, INSTANCE_ADAPTOR>() { sInstance = (T*)this; }
347 ~LLUISingleton() { sInstance = NULL; }
348
349 static T* findInstance(const LLSD& seed)
350 {
351 return sInstance;
352 }
353
354 static T* createInstance(const LLSD& seed)
355 {
356 if (sInstance == NULL)
357 {
358 sInstance = new T(seed);
359 }
360 return sInstance;
361 }
362
363protected:
364 static T* sInstance;
365};
366
367template <class T, class U> T* LLUISingleton<T,U>::sInstance = NULL;
368
278#endif 369#endif
diff --git a/linden/indra/llui/lluictrlfactory.cpp b/linden/indra/llui/lluictrlfactory.cpp
index 475ef2e..79f7313 100644
--- a/linden/indra/llui/lluictrlfactory.cpp
+++ b/linden/indra/llui/lluictrlfactory.cpp
@@ -370,21 +370,22 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const LLString& filename)
370//----------------------------------------------------------------------------- 370//-----------------------------------------------------------------------------
371// buildPanel() 371// buildPanel()
372//----------------------------------------------------------------------------- 372//-----------------------------------------------------------------------------
373void LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename, 373BOOL LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename,
374 const LLCallbackMap::map_t* factory_map) 374 const LLCallbackMap::map_t* factory_map)
375{ 375{
376 BOOL didPost = FALSE;
376 LLXMLNodePtr root; 377 LLXMLNodePtr root;
377 378
378 if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) 379 if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
379 { 380 {
380 return; 381 return didPost;
381 } 382 }
382 383
383 // root must be called panel 384 // root must be called panel
384 if( !root->hasName("panel" ) ) 385 if( !root->hasName("panel" ) )
385 { 386 {
386 llwarns << "Root node should be named panel in : " << filename << llendl; 387 llwarns << "Root node should be named panel in : " << filename << llendl;
387 return; 388 return didPost;
388 } 389 }
389 390
390 if (factory_map) 391 if (factory_map)
@@ -392,7 +393,7 @@ void LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename,
392 mFactoryStack.push_front(factory_map); 393 mFactoryStack.push_front(factory_map);
393 } 394 }
394 395
395 panelp->initPanelXML(root, NULL, this); 396 didPost = panelp->initPanelXML(root, NULL, this);
396 397
397 if (LLUI::sShowXUINames) 398 if (LLUI::sShowXUINames)
398 { 399 {
@@ -406,6 +407,8 @@ void LLUICtrlFactory::buildPanel(LLPanel* panelp, const LLString &filename,
406 { 407 {
407 mFactoryStack.pop_front(); 408 mFactoryStack.pop_front();
408 } 409 }
410
411 return didPost;
409} 412}
410 413
411//----------------------------------------------------------------------------- 414//-----------------------------------------------------------------------------
diff --git a/linden/indra/llui/lluictrlfactory.h b/linden/indra/llui/lluictrlfactory.h
index 18b0ba9..eaae754 100644
--- a/linden/indra/llui/lluictrlfactory.h
+++ b/linden/indra/llui/lluictrlfactory.h
@@ -80,8 +80,8 @@ public:
80 void buildFloater(LLFloater* floaterp, const LLString &filename, 80 void buildFloater(LLFloater* floaterp, const LLString &filename,
81 const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE); 81 const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE);
82 82
83 void buildPanel(LLPanel* panelp, const LLString &filename, 83 BOOL buildPanel(LLPanel* panelp, const LLString &filename,
84 const LLCallbackMap::map_t* factory_map = NULL); 84 const LLCallbackMap::map_t* factory_map = NULL);
85 85
86 LLMenuGL *buildMenu(const LLString &filename, LLView* parentp); 86 LLMenuGL *buildMenu(const LLString &filename, LLView* parentp);
87 87
diff --git a/linden/indra/llui/llview.cpp b/linden/indra/llui/llview.cpp
index d150e10..22d426a 100644
--- a/linden/indra/llui/llview.cpp
+++ b/linden/indra/llui/llview.cpp
@@ -194,8 +194,10 @@ LLView::~LLView()
194 for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor) 194 for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
195 { 195 {
196 (*itor).second->clearDispatchers(); 196 (*itor).second->clearDispatchers();
197 delete (*itor).second;
198 } 197 }
198
199 std::for_each(mFloaterControls.begin(), mFloaterControls.end(),
200 DeletePairedPointer());
199} 201}
200 202
201// virtual 203// virtual
@@ -367,22 +369,25 @@ void LLView::addChildAtEnd(LLView* child, S32 tab_group)
367} 369}
368 370
369// remove the specified child from the view, and set it's parent to NULL. 371// remove the specified child from the view, and set it's parent to NULL.
370void LLView::removeChild( LLView* child ) 372void LLView::removeChild(LLView* child, BOOL deleteIt)
371{ 373{
372 if (child->mParentView == this) 374 if (child->mParentView == this)
373 { 375 {
374 mChildList.remove( child ); 376 mChildList.remove( child );
375 child->mParentView = NULL; 377 child->mParentView = NULL;
378 if (child->isCtrl())
379 {
380 removeCtrl((LLUICtrl*)child);
381 }
382 if (deleteIt)
383 {
384 delete child;
385 }
376 } 386 }
377 else 387 else
378 { 388 {
379 llerrs << "LLView::removeChild called with non-child" << llendl; 389 llerrs << "LLView::removeChild called with non-child" << llendl;
380 } 390 }
381
382 if (child->isCtrl())
383 {
384 removeCtrl((LLUICtrl*)child);
385 }
386} 391}
387 392
388void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group) 393void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
@@ -2507,7 +2512,6 @@ void LLView::deregisterEventListener(LLString name)
2507 dispatch_list_t::iterator itor = mDispatchList.find(name); 2512 dispatch_list_t::iterator itor = mDispatchList.find(name);
2508 if (itor != mDispatchList.end()) 2513 if (itor != mDispatchList.end())
2509 { 2514 {
2510 delete itor->second;
2511 mDispatchList.erase(itor); 2515 mDispatchList.erase(itor);
2512 } 2516 }
2513} 2517}
diff --git a/linden/indra/llui/llview.h b/linden/indra/llui/llview.h
index cb9a35c..c7664eb 100644
--- a/linden/indra/llui/llview.h
+++ b/linden/indra/llui/llview.h
@@ -241,7 +241,7 @@ public:
241 void addChild(LLView* view, S32 tab_group = 0); 241 void addChild(LLView* view, S32 tab_group = 0);
242 void addChildAtEnd(LLView* view, S32 tab_group = 0); 242 void addChildAtEnd(LLView* view, S32 tab_group = 0);
243 // remove the specified child from the view, and set it's parent to NULL. 243 // remove the specified child from the view, and set it's parent to NULL.
244 void removeChild( LLView* view ); 244 void removeChild(LLView* view, BOOL deleteIt = FALSE);
245 245
246 virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group); 246 virtual void addCtrl( LLUICtrl* ctrl, S32 tab_group);
247 virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group); 247 virtual void addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group);
@@ -484,7 +484,7 @@ protected:
484 LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); 484 LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask);
485 LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask); 485 LLView* childrenHandleRightMouseUp(S32 x, S32 y, MASK mask);
486 486
487 typedef std::map<LLString, LLSimpleListener*> dispatch_list_t; 487 typedef std::map<LLString, LLPointer<LLSimpleListener> > dispatch_list_t;
488 dispatch_list_t mDispatchList; 488 dispatch_list_t mDispatchList;
489 489
490protected: 490protected: