aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/llcombobox.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:45:27 -0500
committerJacek Antonelli2008-08-15 23:45:27 -0500
commita8a62201ba762e98dff92cf49033e577fc34d8d4 (patch)
tree11f8513c5cdc222f2fac0c93eb724c089803c200 /linden/indra/llui/llcombobox.cpp
parentSecond Life viewer sources 1.18.6.4-RC (diff)
downloadmeta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.zip
meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.gz
meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.bz2
meta-impy-a8a62201ba762e98dff92cf49033e577fc34d8d4.tar.xz
Second Life viewer sources 1.19.0.0
Diffstat (limited to '')
-rw-r--r--linden/indra/llui/llcombobox.cpp514
1 files changed, 325 insertions, 189 deletions
diff --git a/linden/indra/llui/llcombobox.cpp b/linden/indra/llui/llcombobox.cpp
index cfdcf58..22b5033 100644
--- a/linden/indra/llui/llcombobox.cpp
+++ b/linden/indra/llui/llcombobox.cpp
@@ -12,12 +12,12 @@
12 * ("GPL"), unless you have obtained a separate licensing agreement 12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of 13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or 14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlife.com/developers/opensource/gplv2 15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 * 16 *
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlife.com/developers/opensource/flossexception 20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 21 *
22 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
@@ -55,17 +55,16 @@
55// Globals 55// Globals
56S32 LLCOMBOBOX_HEIGHT = 0; 56S32 LLCOMBOBOX_HEIGHT = 0;
57S32 LLCOMBOBOX_WIDTH = 0; 57S32 LLCOMBOBOX_WIDTH = 0;
58 58S32 MAX_COMBO_WIDTH = 500;
59
59LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label, 60LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label,
60 void (*commit_callback)(LLUICtrl*,void*), 61 void (*commit_callback)(LLUICtrl*,void*),
61 void *callback_userdata 62 void *callback_userdata
62 ) 63 )
63: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata, 64: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata,
64 FOLLOWS_LEFT | FOLLOWS_TOP), 65 FOLLOWS_LEFT | FOLLOWS_TOP),
65 mDrawArrow(TRUE),
66 mTextEntry(NULL), 66 mTextEntry(NULL),
67 mArrowImage(NULL), 67 mArrowImage(NULL),
68 mArrowImageWidth(8),
69 mAllowTextEntry(FALSE), 68 mAllowTextEntry(FALSE),
70 mMaxChars(20), 69 mMaxChars(20),
71 mTextEntryTentative(TRUE), 70 mTextEntryTentative(TRUE),
@@ -73,55 +72,43 @@ LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString
73 mPrearrangeCallback( NULL ), 72 mPrearrangeCallback( NULL ),
74 mTextEntryCallback( NULL ) 73 mTextEntryCallback( NULL )
75{ 74{
76 // For now, all comboboxes don't take keyboard focus when clicked.
77 // This might change if it is part of a modal dialog.
78 // mKeyboardFocusOnClick = FALSE;
79
80 // Revert to standard behavior. When this control's parent is hidden, it needs to
81 // hide this ctrl--which won't just happen automatically since when LLComboBox is
82 // showing its list, it's also set to TopCtrl. When keyboard focus is cleared all
83 // controls (including this one) know that they are no longer editing.
84 mKeyboardFocusOnClick = TRUE;
85
86 LLRect r;
87 r.setOriginAndSize(0, 0, rect.getWidth(), rect.getHeight());
88
89 // Always use text box 75 // Always use text box
90 // Text label button 76 // Text label button
91 mButton = new LLSquareButton("comboxbox button", 77 mButton = new LLButton("comboxbox button",
92 r, label, NULL, LLString::null, 78 LLRect(), label, NULL, LLString::null,
93 NULL, this); 79 NULL, this);
80 mButton->setImageUnselected("square_btn_32x128.tga");
81 mButton->setImageSelected("square_btn_selected_32x128.tga");
82 mButton->setImageDisabled("square_btn_32x128.tga");
83 mButton->setImageDisabledSelected("square_btn_selected_32x128.tga");
84 mButton->setScaleImage(TRUE);
85
94 mButton->setMouseDownCallback(onButtonDown); 86 mButton->setMouseDownCallback(onButtonDown);
95 mButton->setFont(LLFontGL::sSansSerifSmall); 87 mButton->setFont(LLFontGL::sSansSerifSmall);
96 mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); 88 mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
97 mButton->setHAlign( LLFontGL::LEFT ); 89 mButton->setHAlign( LLFontGL::LEFT );
98 90 mButton->setRightHPad(2);
99 const S32 ARROW_WIDTH = 16;
100 mButton->setRightHPad( ARROW_WIDTH );
101 addChild(mButton); 91 addChild(mButton);
102 92
103 // Default size, will be set by arrange() call in button callback.
104 S32 list_width = mRect.getWidth() + SCROLLBAR_SIZE;
105 r.setOriginAndSize(0, 16, list_width, 220);
106
107 // disallow multiple selection 93 // disallow multiple selection
108 mList = new LLScrollListCtrl( 94 mList = new LLScrollListCtrl(
109 "ComboBox", r, 95 "ComboBox", LLRect(),
110 &LLComboBox::onItemSelected, this, FALSE); 96 &LLComboBox::onItemSelected, this, FALSE);
111 mList->setVisible(FALSE); 97 mList->setVisible(FALSE);
112 mList->setBgWriteableColor( LLColor4(1,1,1,1) ); 98 mList->setBgWriteableColor( LLColor4(1,1,1,1) );
113 mList->setCommitOnKeyboardMovement(FALSE); 99 mList->setCommitOnKeyboardMovement(FALSE);
114 mList->setFocusChangedCallback(onListFocusChanged);
115 addChild(mList); 100 addChild(mList);
116 101
117 LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0); 102 LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
118 mBorder = new LLViewBorder( "combo border", border_rect ); 103 mBorder = new LLViewBorder( "combo border", border_rect );
119 addChild( mBorder ); 104 addChild( mBorder );
120 mBorder->setFollows(FOLLOWS_LEFT|FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM); 105 mBorder->setFollowsAll();
121 106
122 LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") ); 107 LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") );
123 mArrowImage = LLUI::sImageProvider->getUIImageByID(arrow_image_id); 108 mArrowImage = LLUI::sImageProvider->getImageByID(arrow_image_id);
124 mArrowImageWidth = llmax(8,mArrowImage->getWidth(0)); // In case image hasn't loaded yet 109 mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT);
110
111 updateLayout();
125} 112}
126 113
127 114
@@ -155,7 +142,7 @@ LLXMLNodePtr LLComboBox::getXML(bool save_children) const
155 LLSD value = item->getValue(); 142 LLSD value = item->getValue();
156 item_node->createChild("value", TRUE)->setStringValue(value.asString()); 143 item_node->createChild("value", TRUE)->setStringValue(value.asString());
157 item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled()); 144 item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
158 item_node->setStringValue(cell->getText()); 145 item_node->setStringValue(cell->getValue().asString());
159 } 146 }
160 } 147 }
161 148
@@ -272,34 +259,46 @@ void LLComboBox::resetDirty()
272 259
273 260
274// add item "name" to menu 261// add item "name" to menu
275void LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled) 262LLScrollListItem* LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
276{ 263{
277 mList->addSimpleItem(name, pos, enabled); 264 LLScrollListItem* item = mList->addSimpleElement(name, pos);
265 item->setEnabled(enabled);
278 mList->selectFirstItem(); 266 mList->selectFirstItem();
267 return item;
279} 268}
280 269
281// add item "name" with a unique id to menu 270// add item "name" with a unique id to menu
282void LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled ) 271LLScrollListItem* LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
283{ 272{
284 mList->addSimpleItem(name, LLSD(id), pos, enabled); 273 LLScrollListItem* item = mList->addSimpleElement(name, pos, id);
274 item->setEnabled(enabled);
285 mList->selectFirstItem(); 275 mList->selectFirstItem();
276 return item;
286} 277}
287 278
288// add item "name" with attached userdata 279// add item "name" with attached userdata
289void LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled ) 280LLScrollListItem* LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
290{ 281{
291 LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled); 282 LLScrollListItem* item = mList->addSimpleElement(name, pos);
283 item->setEnabled(enabled);
292 item->setUserdata( userdata ); 284 item->setUserdata( userdata );
293 mList->selectFirstItem(); 285 mList->selectFirstItem();
286 return item;
294} 287}
295 288
296// add item "name" with attached generic data 289// add item "name" with attached generic data
297void LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled ) 290LLScrollListItem* LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
298{ 291{
299 mList->addSimpleItem(name, value, pos, enabled); 292 LLScrollListItem* item = mList->addSimpleElement(name, pos, value);
293 item->setEnabled(enabled);
300 mList->selectFirstItem(); 294 mList->selectFirstItem();
295 return item;
301} 296}
302 297
298LLScrollListItem* LLComboBox::addSeparator(EAddPosition pos)
299{
300 return mList->addSeparator(pos);
301}
303 302
304void LLComboBox::sortByName() 303void LLComboBox::sortByName()
305{ 304{
@@ -311,7 +310,7 @@ void LLComboBox::sortByName()
311// Returns TRUE if the item was found. 310// Returns TRUE if the item was found.
312BOOL LLComboBox::setSimple(const LLStringExplicit& name) 311BOOL LLComboBox::setSimple(const LLStringExplicit& name)
313{ 312{
314 BOOL found = mList->selectSimpleItem(name, FALSE); 313 BOOL found = mList->selectItemByLabel(name, FALSE);
315 314
316 if (found) 315 if (found)
317 { 316 {
@@ -330,14 +329,14 @@ void LLComboBox::setValue(const LLSD& value)
330 LLScrollListItem* item = mList->getFirstSelected(); 329 LLScrollListItem* item = mList->getFirstSelected();
331 if (item) 330 if (item)
332 { 331 {
333 setLabel( mList->getSimpleSelectedItem() ); 332 setLabel( mList->getSelectedItemLabel() );
334 } 333 }
335 } 334 }
336} 335}
337 336
338const LLString& LLComboBox::getSimple() const 337const LLString LLComboBox::getSimple() const
339{ 338{
340 const LLString& res = mList->getSimpleSelectedItem(); 339 const LLString res = mList->getSelectedItemLabel();
341 if (res.empty() && mAllowTextEntry) 340 if (res.empty() && mAllowTextEntry)
342 { 341 {
343 return mTextEntry->getText(); 342 return mTextEntry->getText();
@@ -348,9 +347,9 @@ const LLString& LLComboBox::getSimple() const
348 } 347 }
349} 348}
350 349
351const LLString& LLComboBox::getSimpleSelectedItem(S32 column) const 350const LLString LLComboBox::getSelectedItemLabel(S32 column) const
352{ 351{
353 return mList->getSimpleSelectedItem(column); 352 return mList->getSelectedItemLabel(column);
354} 353}
355 354
356// virtual 355// virtual
@@ -373,10 +372,10 @@ LLSD LLComboBox::getValue() const
373 372
374void LLComboBox::setLabel(const LLStringExplicit& name) 373void LLComboBox::setLabel(const LLStringExplicit& name)
375{ 374{
376 if ( mAllowTextEntry ) 375 if ( mTextEntry )
377 { 376 {
378 mTextEntry->setText(name); 377 mTextEntry->setText(name);
379 if (mList->selectSimpleItem(name, FALSE)) 378 if (mList->selectItemByLabel(name, FALSE))
380 { 379 {
381 mTextEntry->setTentative(FALSE); 380 mTextEntry->setTentative(FALSE);
382 } 381 }
@@ -385,7 +384,8 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
385 mTextEntry->setTentative(mTextEntryTentative); 384 mTextEntry->setTentative(mTextEntryTentative);
386 } 385 }
387 } 386 }
388 else 387
388 if (!mAllowTextEntry)
389 { 389 {
390 mButton->setLabelUnselected(name); 390 mButton->setLabelUnselected(name);
391 mButton->setLabelSelected(name); 391 mButton->setLabelSelected(name);
@@ -397,7 +397,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
397 397
398BOOL LLComboBox::remove(const LLString& name) 398BOOL LLComboBox::remove(const LLString& name)
399{ 399{
400 BOOL found = mList->selectSimpleItem(name); 400 BOOL found = mList->selectItemByLabel(name);
401 401
402 if (found) 402 if (found)
403 { 403 {
@@ -433,16 +433,21 @@ void LLComboBox::onFocusLost()
433 LLUICtrl::onFocusLost(); 433 LLUICtrl::onFocusLost();
434} 434}
435 435
436void LLComboBox::onLostTop()
437{
438 hideList();
439}
440
441
436void LLComboBox::setButtonVisible(BOOL visible) 442void LLComboBox::setButtonVisible(BOOL visible)
437{ 443{
438 mButton->setVisible(visible); 444 mButton->setVisible(visible);
439 mDrawArrow = visible;
440 if (mTextEntry) 445 if (mTextEntry)
441 { 446 {
442 LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0); 447 LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
443 if (visible) 448 if (visible)
444 { 449 {
445 text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); 450 text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth(0)) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
446 } 451 }
447 //mTextEntry->setRect(text_entry_rect); 452 //mTextEntry->setRect(text_entry_rect);
448 mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); 453 mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
@@ -457,22 +462,8 @@ void LLComboBox::draw()
457 462
458 mButton->setEnabled(mEnabled /*&& !mList->isEmpty()*/); 463 mButton->setEnabled(mEnabled /*&& !mList->isEmpty()*/);
459 464
460 // Draw children 465 // Draw children normally
461 LLUICtrl::draw(); 466 LLUICtrl::draw();
462
463 if (mDrawArrow)
464 {
465 // Paste the graphic on the right edge
466 if (!mArrowImage.isNull())
467 {
468 S32 arrow_height = llmin(mRect.getHeight(), mArrowImage->getHeight());
469 S32 arrow_width = llround((F32)mArrowImage->getWidth() * ((F32)arrow_height / (F32)mArrowImage->getHeight()));
470
471 S32 left = mRect.getWidth() - mArrowImage->getWidth() - LLUI::sConfigGroup->getS32("DropShadowButton");
472
473 gl_draw_scaled_image( left, 0, arrow_width, arrow_height, mArrowImage, LLColor4::white);
474 }
475 }
476 } 467 }
477} 468}
478 469
@@ -481,7 +472,7 @@ BOOL LLComboBox::setCurrentByIndex( S32 index )
481 BOOL found = mList->selectNthItem( index ); 472 BOOL found = mList->selectNthItem( index );
482 if (found) 473 if (found)
483 { 474 {
484 setLabel(mList->getSimpleSelectedItem()); 475 setLabel(mList->getSelectedItemLabel());
485 } 476 }
486 return found; 477 return found;
487} 478}
@@ -497,6 +488,67 @@ S32 LLComboBox::getCurrentIndex() const
497} 488}
498 489
499 490
491void LLComboBox::updateLayout()
492{
493 LLRect rect = getLocalRect();
494 if (mAllowTextEntry)
495 {
496 S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
497 mButton->setRect(LLRect( mRect.getWidth() - llmax(8,mArrowImage->getWidth(0)) - 2 * shadow_size,
498 rect.mTop, rect.mRight, rect.mBottom));
499 mButton->setTabStop(FALSE);
500
501 if (!mTextEntry)
502 {
503 LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
504 text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth(0)) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
505 // clear label on button
506 LLString cur_label = mButton->getLabelSelected();
507 mTextEntry = new LLLineEditor("combo_text_entry",
508 text_entry_rect,
509 "",
510 LLFontGL::sSansSerifSmall,
511 mMaxChars,
512 onTextCommit,
513 onTextEntry,
514 NULL,
515 this,
516 NULL, // prevalidate func
517 LLViewBorder::BEVEL_NONE,
518 LLViewBorder::STYLE_LINE,
519 0); // no border
520 mTextEntry->setSelectAllonFocusReceived(TRUE);
521 mTextEntry->setHandleEditKeysDirectly(TRUE);
522 mTextEntry->setCommitOnFocusLost(FALSE);
523 mTextEntry->setText(cur_label);
524 mTextEntry->setIgnoreTab(TRUE);
525 mTextEntry->setFollowsAll();
526 addChild(mTextEntry);
527 }
528 else
529 {
530 mTextEntry->setVisible(TRUE);
531 mTextEntry->setMaxTextLength(mMaxChars);
532 }
533
534 // clear label on button
535 setLabel(LLString::null);
536
537 mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
538 }
539 else if (!mAllowTextEntry)
540 {
541 mButton->setRect(rect);
542 mButton->setTabStop(TRUE);
543
544 if (mTextEntry)
545 {
546 mTextEntry->setVisible(FALSE);
547 }
548 mButton->setFollowsAll();
549 }
550}
551
500void* LLComboBox::getCurrentUserdata() 552void* LLComboBox::getCurrentUserdata()
501{ 553{
502 LLScrollListItem* item = mList->getFirstSelected(); 554 LLScrollListItem* item = mList->getFirstSelected();
@@ -514,7 +566,7 @@ void LLComboBox::showList()
514 LLCoordWindow window_size; 566 LLCoordWindow window_size;
515 getWindow()->getSize(&window_size); 567 getWindow()->getSize(&window_size);
516 //HACK: shouldn't have to know about scale here 568 //HACK: shouldn't have to know about scale here
517 mList->arrange( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 ); 569 mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
518 570
519 // Make sure that we can see the whole list 571 // Make sure that we can see the whole list
520 LLRect root_view_local; 572 LLRect root_view_local;
@@ -523,7 +575,9 @@ void LLComboBox::showList()
523 575
524 LLRect rect = mList->getRect(); 576 LLRect rect = mList->getRect();
525 577
526 S32 list_width = mRect.getWidth() + SCROLLBAR_SIZE; 578 S32 min_width = mRect.getWidth();
579 S32 max_width = llmax(min_width, MAX_COMBO_WIDTH);
580 S32 list_width = llclamp(mList->getMaxContentWidth(), min_width, max_width);
527 581
528 if (mListPosition == BELOW) 582 if (mListPosition == BELOW)
529 { 583 {
@@ -583,12 +637,6 @@ void LLComboBox::showList()
583 mList->translate(0, -y); 637 mList->translate(0, -y);
584 } 638 }
585 639
586 // pass mouse capture on to list if button is depressed
587 if (mButton->hasMouseCapture())
588 {
589 gFocusMgr.setMouseCapture(mList);
590 }
591
592 // NB: this call will trigger the focuslost callback which will hide the list, so do it first 640 // NB: this call will trigger the focuslost callback which will hide the list, so do it first
593 // before finally showing the list 641 // before finally showing the list
594 642
@@ -604,24 +652,29 @@ void LLComboBox::showList()
604 mButton->setToggleState(TRUE); 652 mButton->setToggleState(TRUE);
605 mList->setVisible(TRUE); 653 mList->setVisible(TRUE);
606 654
607 gFocusMgr.setTopCtrl(mList); 655 setUseBoundingRect(TRUE);
656 gFocusMgr.setTopCtrl(this);
608} 657}
609 658
610void LLComboBox::hideList() 659void LLComboBox::hideList()
611{ 660{
661 //*HACK: store the original value explicitly somewhere, not just in label
662 LLString orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected();
663
664 // assert selection in list
665 mList->selectItemByLabel(orig_selection, FALSE);
666
612 mButton->setToggleState(FALSE); 667 mButton->setToggleState(FALSE);
613 mList->setVisible(FALSE); 668 mList->setVisible(FALSE);
614 mList->highlightNthItem(-1); 669 mList->highlightNthItem(-1);
615 670
616 if( gFocusMgr.getTopCtrl() == mList ) 671 setUseBoundingRect(FALSE);
672 if( gFocusMgr.getTopCtrl() == this )
617 { 673 {
618 gFocusMgr.setTopCtrl(NULL); 674 gFocusMgr.setTopCtrl(NULL);
619 } 675 }
620
621 //mList->setFocus(FALSE);
622} 676}
623 677
624
625//------------------------------------------------------------------ 678//------------------------------------------------------------------
626// static functions 679// static functions
627//------------------------------------------------------------------ 680//------------------------------------------------------------------
@@ -650,21 +703,20 @@ void LLComboBox::onButtonDown(void *userdata)
650 self->showList(); 703 self->showList();
651 } 704 }
652 705
653 if (self->mKeyboardFocusOnClick && !self->hasFocus()) 706 self->setFocus( TRUE );
707
708 // pass mouse capture on to list if button is depressed
709 if (self->mButton->hasMouseCapture())
654 { 710 {
655 self->setFocus( TRUE ); 711 gFocusMgr.setMouseCapture(self->mList);
656 } 712 }
657 } 713 }
658 else 714 else
659 { 715 {
660 // hide and release keyboard focus
661 self->hideList(); 716 self->hideList();
662
663 self->onCommit();
664 } 717 }
665}
666
667 718
719}
668 720
669// static 721// static
670void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata) 722void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
@@ -672,7 +724,7 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
672 // Note: item is the LLScrollListCtrl 724 // Note: item is the LLScrollListCtrl
673 LLComboBox *self = (LLComboBox *) userdata; 725 LLComboBox *self = (LLComboBox *) userdata;
674 726
675 const LLString& name = self->mList->getSimpleSelectedItem(); 727 const LLString name = self->mList->getSelectedItemLabel();
676 728
677 S32 cur_id = self->getCurrentIndex(); 729 S32 cur_id = self->getCurrentIndex();
678 if (cur_id != -1) 730 if (cur_id != -1)
@@ -681,40 +733,24 @@ void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
681 733
682 if (self->mAllowTextEntry) 734 if (self->mAllowTextEntry)
683 { 735 {
684 gFocusMgr.setKeyboardFocus(self->mTextEntry, NULL); 736 gFocusMgr.setKeyboardFocus(self->mTextEntry);
685 self->mTextEntry->selectAll(); 737 self->mTextEntry->selectAll();
686 } 738 }
687 } 739 }
688 else 740 else
689 { 741 {
690 // invalid selection, just restore existing value 742 // invalid selection, just restore existing value
691 self->mList->selectSimpleItem(self->mButton->getLabelSelected()); 743 LLString orig_selection = self->mAllowTextEntry ? self->mTextEntry->getText() : self->mButton->getLabelSelected();
744
745 self->mList->selectItemByLabel(orig_selection);
692 } 746 }
693 self->onCommit(); 747 self->onCommit();
694 748
695 self->hideList(); 749 self->hideList();
696} 750}
697 751
698// static
699void LLComboBox::onListFocusChanged(LLUICtrl* list, void* user_data)
700{
701 LLComboBox *self = (LLComboBox *) list->getParent();
702 // user not manipulating list or clicking on drop down button
703 if (!self->mList->hasFocus() && !self->mButton->hasMouseCapture())
704 {
705 //*HACK: store the original value explicitly somewhere, not just in label
706 LLString orig_selection = self->mAllowTextEntry ? self->mTextEntry->getText() : self->mButton->getLabelSelected();
707
708 self->hideList();
709
710 // reassert original selection
711 self->mList->selectSimpleItem(orig_selection, FALSE);
712 }
713}
714
715BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) 752BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
716{ 753{
717
718 LLString tool_tip; 754 LLString tool_tip;
719 755
720 if (LLUI::sShowXUINames) 756 if (LLUI::sShowXUINames)
@@ -726,23 +762,19 @@ BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_
726 tool_tip = mToolTipMsg; 762 tool_tip = mToolTipMsg;
727 } 763 }
728 764
729 if( getVisible() && pointInView( x, y ) ) 765 if( !tool_tip.empty() )
730 { 766 {
731 if( !tool_tip.empty() ) 767 msg = tool_tip;
732 { 768
733 msg = tool_tip; 769 // Convert rect local to screen coordinates
734 770 localPointToScreen(
735 // Convert rect local to screen coordinates 771 0, 0,
736 localPointToScreen( 772 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
737 0, 0, 773 localPointToScreen(
738 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); 774 mRect.getWidth(), mRect.getHeight(),
739 localPointToScreen( 775 &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
740 mRect.getWidth(), mRect.getHeight(),
741 &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
742 }
743 return TRUE;
744 } 776 }
745 return FALSE; 777 return TRUE;
746} 778}
747 779
748BOOL LLComboBox::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) 780BOOL LLComboBox::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
@@ -793,63 +825,11 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent
793 825
794void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative) 826void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
795{ 827{
796 LLRect rect( 0, mRect.getHeight(), mRect.getWidth(), 0);
797 if (allow && !mAllowTextEntry)
798 {
799 S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
800 mButton->setRect(LLRect( mRect.getWidth() - mArrowImageWidth - 2 * shadow_size,
801 rect.mTop, rect.mRight, rect.mBottom));
802 mButton->setTabStop(FALSE);
803
804 // clear label on button
805 LLString cur_label = mButton->getLabelSelected();
806 setLabel(LLString::null);
807 if (!mTextEntry)
808 {
809 LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
810 text_entry_rect.mRight -= mArrowImageWidth + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
811 mTextEntry = new LLLineEditor("combo_text_entry",
812 text_entry_rect,
813 "",
814 LLFontGL::sSansSerifSmall,
815 max_chars,
816 onTextCommit,
817 onTextEntry,
818 NULL,
819 this,
820 NULL, // prevalidate func
821 LLViewBorder::BEVEL_NONE,
822 LLViewBorder::STYLE_LINE,
823 0); // no border
824 mTextEntry->setSelectAllonFocusReceived(TRUE);
825 mTextEntry->setHandleEditKeysDirectly(TRUE);
826 mTextEntry->setCommitOnFocusLost(FALSE);
827 mTextEntry->setText(cur_label);
828 mTextEntry->setIgnoreTab(TRUE);
829 mTextEntry->setFollowsAll();
830 addChild(mTextEntry);
831 mMaxChars = max_chars;
832 }
833 else
834 {
835 mTextEntry->setVisible(TRUE);
836 }
837
838 mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
839 }
840 else if (!allow && mAllowTextEntry)
841 {
842 mButton->setRect(rect);
843 mButton->setTabStop(TRUE);
844
845 if (mTextEntry)
846 {
847 mTextEntry->setVisible(FALSE);
848 }
849 mButton->setFollowsAll();
850 }
851 mAllowTextEntry = allow; 828 mAllowTextEntry = allow;
852 mTextEntryTentative = set_tentative; 829 mTextEntryTentative = set_tentative;
830 mMaxChars = max_chars;
831
832 updateLayout();
853} 833}
854 834
855void LLComboBox::setTextEntry(const LLStringExplicit& text) 835void LLComboBox::setTextEntry(const LLStringExplicit& text)
@@ -875,7 +855,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
875 if (key == KEY_BACKSPACE || 855 if (key == KEY_BACKSPACE ||
876 key == KEY_DELETE) 856 key == KEY_DELETE)
877 { 857 {
878 if (self->mList->selectSimpleItem(line_editor->getText(), FALSE)) 858 if (self->mList->selectItemByLabel(line_editor->getText(), FALSE))
879 { 859 {
880 line_editor->setTentative(FALSE); 860 line_editor->setTentative(FALSE);
881 } 861 }
@@ -955,11 +935,11 @@ void LLComboBox::updateSelection()
955 } 935 }
956 } 936 }
957 937
958 if (mList->selectSimpleItem(full_string, FALSE)) 938 if (mList->selectItemByLabel(full_string, FALSE))
959 { 939 {
960 mTextEntry->setTentative(FALSE); 940 mTextEntry->setTentative(FALSE);
961 } 941 }
962 else if (!mList->selectSimpleItemByPrefix(left_wstring, FALSE)) 942 else if (!mList->selectItemByPrefix(left_wstring, FALSE))
963 { 943 {
964 mList->deselectAllItems(); 944 mList->deselectAllItems();
965 mTextEntry->setText(wstring_to_utf8str(user_wstring)); 945 mTextEntry->setText(wstring_to_utf8str(user_wstring));
@@ -967,7 +947,7 @@ void LLComboBox::updateSelection()
967 } 947 }
968 else 948 else
969 { 949 {
970 LLWString selected_item = utf8str_to_wstring(mList->getSimpleSelectedItem()); 950 LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel());
971 LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size()); 951 LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
972 mTextEntry->setText(wstring_to_utf8str(wtext)); 952 mTextEntry->setText(wstring_to_utf8str(wtext));
973 mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size()); 953 mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
@@ -993,6 +973,10 @@ void LLComboBox::setFocus(BOOL b)
993 if (b) 973 if (b)
994 { 974 {
995 mList->clearSearchString(); 975 mList->clearSearchString();
976 if (mList->getVisible())
977 {
978 mList->setFocus(TRUE);
979 }
996 } 980 }
997} 981}
998 982
@@ -1048,7 +1032,7 @@ BOOL LLComboBox::setCurrentByID(const LLUUID& id)
1048 1032
1049 if (found) 1033 if (found)
1050 { 1034 {
1051 setLabel(mList->getSimpleSelectedItem()); 1035 setLabel(mList->getSelectedItemLabel());
1052 } 1036 }
1053 1037
1054 return found; 1038 return found;
@@ -1063,14 +1047,14 @@ BOOL LLComboBox::setSelectedByValue(LLSD value, BOOL selected)
1063 BOOL found = mList->setSelectedByValue(value, selected); 1047 BOOL found = mList->setSelectedByValue(value, selected);
1064 if (found) 1048 if (found)
1065 { 1049 {
1066 setLabel(mList->getSimpleSelectedItem()); 1050 setLabel(mList->getSelectedItemLabel());
1067 } 1051 }
1068 return found; 1052 return found;
1069} 1053}
1070 1054
1071LLSD LLComboBox::getSimpleSelectedValue() 1055LLSD LLComboBox::getSelectedValue()
1072{ 1056{
1073 return mList->getSimpleSelectedValue(); 1057 return mList->getSelectedValue();
1074} 1058}
1075 1059
1076BOOL LLComboBox::isSelected(LLSD value) 1060BOOL LLComboBox::isSelected(LLSD value)
@@ -1097,3 +1081,155 @@ BOOL LLComboBox::operateOnAll(EOperation op)
1097 } 1081 }
1098 return FALSE; 1082 return FALSE;
1099} 1083}
1084
1085
1086
1087//
1088// LLFlyoutButton
1089//
1090
1091const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
1092
1093LLFlyoutButton::LLFlyoutButton(
1094 const LLString& name,
1095 const LLRect &rect,
1096 const LLString& label,
1097 void (*commit_callback)(LLUICtrl*, void*) ,
1098 void *callback_userdata)
1099: LLComboBox(name, rect, LLString::null, commit_callback, callback_userdata),
1100 mToggleState(FALSE),
1101 mActionButton(NULL)
1102{
1103 // Always use text box
1104 // Text label button
1105 mActionButton = new LLButton("flyout_button_main",
1106 LLRect(), label, NULL, LLString::null,
1107 NULL, this);
1108 mActionButton->setScaleImage(TRUE);
1109
1110 mActionButton->setClickedCallback(onActionButtonClick);
1111 mActionButton->setFollowsAll();
1112 mActionButton->setHAlign( LLFontGL::HCENTER );
1113 mActionButton->setLabel(label);
1114 addChild(mActionButton);
1115
1116 mActionButtonImage = LLUI::getUIImageByName("flyout_btn_left.tga");
1117 mExpanderButtonImage = LLUI::getUIImageByName("flyout_btn_right.tga");
1118 mActionButtonImageSelected = LLUI::getUIImageByName("flyout_btn_left_selected.tga");
1119 mExpanderButtonImageSelected = LLUI::getUIImageByName("flyout_btn_right_selected.tga");
1120
1121 mActionButton->setImageSelected(mActionButtonImageSelected);
1122 mActionButton->setImageUnselected(mActionButtonImage);
1123 mActionButton->setImageDisabled(LLPointer<LLUIImage>(NULL));
1124 mActionButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
1125
1126 mButton->setImageSelected(mExpanderButtonImageSelected);
1127 mButton->setImageUnselected(mExpanderButtonImage);
1128 mButton->setImageDisabled(LLPointer<LLUIImage>(NULL));
1129 mButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
1130 mButton->setRightHPad(6);
1131
1132 mBorder->setVisible(FALSE);
1133
1134 updateLayout();
1135}
1136
1137//static
1138LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
1139{
1140 LLString name = "flyout_button";
1141 node->getAttributeString("name", name);
1142
1143 LLString label("");
1144 node->getAttributeString("label", label);
1145
1146 LLRect rect;
1147 createRect(node, rect, parent, LLRect());
1148
1149 LLUICtrlCallback callback = NULL;
1150
1151 LLFlyoutButton* flyout_button = new LLFlyoutButton(name,
1152 rect,
1153 label,
1154 callback,
1155 NULL);
1156
1157 LLString list_position;
1158 node->getAttributeString("list_position", list_position);
1159 if (list_position == "below")
1160 {
1161 flyout_button->mListPosition = BELOW;
1162 }
1163 else if (list_position == "above")
1164 {
1165 flyout_button->mListPosition = ABOVE;
1166 }
1167
1168
1169 flyout_button->initFromXML(node, parent);
1170
1171 LLXMLNodePtr child;
1172 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
1173 {
1174 if (child->hasName("flyout_button_item"))
1175 {
1176 LLString label = child->getTextContents();
1177
1178 LLString value = label;
1179 child->getAttributeString("value", value);
1180
1181 flyout_button->add(label, LLSD(value) );
1182 }
1183 }
1184
1185 flyout_button->updateLayout();
1186
1187 return flyout_button;
1188}
1189
1190void LLFlyoutButton::updateLayout()
1191{
1192 LLComboBox::updateLayout();
1193
1194 mButton->setOrigin(mRect.getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
1195 mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, mRect.getHeight());
1196 mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
1197 mButton->setTabStop(FALSE);
1198 mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
1199
1200 mActionButton->setOrigin(0, 0);
1201 mActionButton->reshape(mRect.getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, mRect.getHeight());
1202}
1203
1204//static
1205void LLFlyoutButton::onActionButtonClick(void *user_data)
1206{
1207 LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data;
1208 // remember last list selection?
1209 buttonp->mList->deselect();
1210 buttonp->onCommit();
1211}
1212
1213void LLFlyoutButton::draw()
1214{
1215 mActionButton->setToggleState(mToggleState);
1216 mButton->setToggleState(mToggleState);
1217
1218 //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
1219 // the label reflects the last selected item, for now we have to manually remove the label
1220 mButton->setLabel(LLString::null);
1221 LLComboBox::draw();
1222}
1223
1224void LLFlyoutButton::setEnabled(BOOL enabled)
1225{
1226 mActionButton->setEnabled(enabled);
1227 LLComboBox::setEnabled(enabled);
1228}
1229
1230
1231void LLFlyoutButton::setToggleState(BOOL state)
1232{
1233 mToggleState = state;
1234}
1235