00001
00032
00033
00034
00035 #include "linden_common.h"
00036
00037
00038 #include "llcombobox.h"
00039
00040
00041 #include "llstring.h"
00042
00043
00044 #include "llbutton.h"
00045 #include "llkeyboard.h"
00046 #include "llscrolllistctrl.h"
00047 #include "llwindow.h"
00048 #include "llfloater.h"
00049 #include "llscrollbar.h"
00050 #include "llcontrol.h"
00051 #include "llfocusmgr.h"
00052 #include "lllineeditor.h"
00053 #include "v2math.h"
00054
00055
00056 S32 LLCOMBOBOX_HEIGHT = 0;
00057 S32 LLCOMBOBOX_WIDTH = 0;
00058 S32 MAX_COMBO_WIDTH = 500;
00059
00060 static LLRegisterWidget<LLComboBox> r1("combo_box");
00061
00062 LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label,
00063 void (*commit_callback)(LLUICtrl*,void*),
00064 void *callback_userdata
00065 )
00066 : LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata,
00067 FOLLOWS_LEFT | FOLLOWS_TOP),
00068 mTextEntry(NULL),
00069 mArrowImage(NULL),
00070 mAllowTextEntry(FALSE),
00071 mMaxChars(20),
00072 mTextEntryTentative(TRUE),
00073 mListPosition(BELOW),
00074 mPrearrangeCallback( NULL ),
00075 mTextEntryCallback( NULL )
00076 {
00077
00078
00079 mButton = new LLButton(label,
00080 LLRect(),
00081 LLString::null,
00082 NULL, this);
00083 mButton->setImageUnselected("square_btn_32x128.tga");
00084 mButton->setImageSelected("square_btn_selected_32x128.tga");
00085 mButton->setImageDisabled("square_btn_32x128.tga");
00086 mButton->setImageDisabledSelected("square_btn_selected_32x128.tga");
00087 mButton->setScaleImage(TRUE);
00088
00089 mButton->setMouseDownCallback(onButtonDown);
00090 mButton->setFont(LLFontGL::sSansSerifSmall);
00091 mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
00092 mButton->setHAlign( LLFontGL::LEFT );
00093 mButton->setRightHPad(2);
00094 addChild(mButton);
00095
00096
00097 mList = new LLScrollListCtrl(
00098 "ComboBox", LLRect(),
00099 &LLComboBox::onItemSelected, this, FALSE);
00100 mList->setVisible(FALSE);
00101 mList->setBgWriteableColor( LLColor4(1,1,1,1) );
00102 mList->setCommitOnKeyboardMovement(FALSE);
00103 addChild(mList);
00104
00105 mArrowImage = LLUI::sImageProvider->getUIImage("combobox_arrow.tga");
00106 mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT);
00107
00108 updateLayout();
00109 }
00110
00111
00112 LLComboBox::~LLComboBox()
00113 {
00114
00115 }
00116
00117
00118 LLXMLNodePtr LLComboBox::getXML(bool save_children) const
00119 {
00120 LLXMLNodePtr node = LLUICtrl::getXML();
00121
00122
00123
00124 node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry);
00125
00126 node->createChild("max_chars", TRUE)->setIntValue(mMaxChars);
00127
00128
00129
00130 std::vector<LLScrollListItem*> data_list = mList->getAllData();
00131 std::vector<LLScrollListItem*>::iterator data_itor;
00132 for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
00133 {
00134 LLScrollListItem* item = *data_itor;
00135 LLScrollListCell* cell = item->getColumn(0);
00136 if (cell)
00137 {
00138 LLXMLNodePtr item_node = node->createChild("combo_item", FALSE);
00139 LLSD value = item->getValue();
00140 item_node->createChild("value", TRUE)->setStringValue(value.asString());
00141 item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
00142 item_node->setStringValue(cell->getValue().asString());
00143 }
00144 }
00145
00146 return node;
00147 }
00148
00149
00150 LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00151 {
00152 LLString name("combo_box");
00153 node->getAttributeString("name", name);
00154
00155 LLString label("");
00156 node->getAttributeString("label", label);
00157
00158 LLRect rect;
00159 createRect(node, rect, parent, LLRect());
00160
00161 BOOL allow_text_entry = FALSE;
00162 node->getAttributeBOOL("allow_text_entry", allow_text_entry);
00163
00164 S32 max_chars = 20;
00165 node->getAttributeS32("max_chars", max_chars);
00166
00167 LLUICtrlCallback callback = NULL;
00168
00169 LLComboBox* combo_box = new LLComboBox(name,
00170 rect,
00171 label,
00172 callback,
00173 NULL);
00174 combo_box->setAllowTextEntry(allow_text_entry, max_chars);
00175
00176 combo_box->initFromXML(node, parent);
00177
00178 const LLString& contents = node->getValue();
00179
00180 if (contents.find_first_not_of(" \n\t") != contents.npos)
00181 {
00182 llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl;
00183 }
00184 else
00185 {
00186 LLXMLNodePtr child;
00187 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
00188 {
00189 if (child->hasName("combo_item"))
00190 {
00191 LLString label = child->getTextContents();
00192
00193 LLString value = label;
00194 child->getAttributeString("value", value);
00195
00196 combo_box->add(label, LLSD(value) );
00197 }
00198 }
00199 }
00200
00201 combo_box->selectFirstItem();
00202
00203 return combo_box;
00204 }
00205
00206 void LLComboBox::setEnabled(BOOL enabled)
00207 {
00208 LLView::setEnabled(enabled);
00209 mButton->setEnabled(enabled);
00210 }
00211
00212 void LLComboBox::clear()
00213 {
00214 if (mTextEntry)
00215 {
00216 mTextEntry->setText(LLString::null);
00217 }
00218 mButton->setLabelSelected(LLString::null);
00219 mButton->setLabelUnselected(LLString::null);
00220 mButton->setDisabledLabel(LLString::null);
00221 mButton->setDisabledSelectedLabel(LLString::null);
00222 mList->deselectAllItems();
00223 }
00224
00225 void LLComboBox::onCommit()
00226 {
00227 if (mAllowTextEntry && getCurrentIndex() != -1)
00228 {
00229
00230
00231 mTextEntry->setValue(getSimple());
00232 mTextEntry->setTentative(FALSE);
00233 }
00234 LLUICtrl::onCommit();
00235 }
00236
00237
00238 BOOL LLComboBox::isDirty() const
00239 {
00240 BOOL grubby = FALSE;
00241 if ( mList )
00242 {
00243 grubby = mList->isDirty();
00244 }
00245 return grubby;
00246 }
00247
00248
00249 void LLComboBox::resetDirty()
00250 {
00251 if ( mList )
00252 {
00253 mList->resetDirty();
00254 }
00255 }
00256
00257
00258
00259 LLScrollListItem* LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
00260 {
00261 LLScrollListItem* item = mList->addSimpleElement(name, pos);
00262 item->setEnabled(enabled);
00263 mList->selectFirstItem();
00264 return item;
00265 }
00266
00267
00268 LLScrollListItem* LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
00269 {
00270 LLScrollListItem* item = mList->addSimpleElement(name, pos, id);
00271 item->setEnabled(enabled);
00272 mList->selectFirstItem();
00273 return item;
00274 }
00275
00276
00277 LLScrollListItem* LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
00278 {
00279 LLScrollListItem* item = mList->addSimpleElement(name, pos);
00280 item->setEnabled(enabled);
00281 item->setUserdata( userdata );
00282 mList->selectFirstItem();
00283 return item;
00284 }
00285
00286
00287 LLScrollListItem* LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
00288 {
00289 LLScrollListItem* item = mList->addSimpleElement(name, pos, value);
00290 item->setEnabled(enabled);
00291 mList->selectFirstItem();
00292 return item;
00293 }
00294
00295 LLScrollListItem* LLComboBox::addSeparator(EAddPosition pos)
00296 {
00297 return mList->addSeparator(pos);
00298 }
00299
00300 void LLComboBox::sortByName()
00301 {
00302 mList->sortByColumn(0, TRUE);
00303 }
00304
00305
00306
00307
00308 BOOL LLComboBox::setSimple(const LLStringExplicit& name)
00309 {
00310 BOOL found = mList->selectItemByLabel(name, FALSE);
00311
00312 if (found)
00313 {
00314 setLabel(name);
00315 }
00316
00317 return found;
00318 }
00319
00320
00321 void LLComboBox::setValue(const LLSD& value)
00322 {
00323 BOOL found = mList->selectByValue(value);
00324 if (found)
00325 {
00326 LLScrollListItem* item = mList->getFirstSelected();
00327 if (item)
00328 {
00329 setLabel( mList->getSelectedItemLabel() );
00330 }
00331 }
00332 }
00333
00334 const LLString LLComboBox::getSimple() const
00335 {
00336 const LLString res = mList->getSelectedItemLabel();
00337 if (res.empty() && mAllowTextEntry)
00338 {
00339 return mTextEntry->getText();
00340 }
00341 else
00342 {
00343 return res;
00344 }
00345 }
00346
00347 const LLString LLComboBox::getSelectedItemLabel(S32 column) const
00348 {
00349 return mList->getSelectedItemLabel(column);
00350 }
00351
00352
00353 LLSD LLComboBox::getValue() const
00354 {
00355 LLScrollListItem* item = mList->getFirstSelected();
00356 if( item )
00357 {
00358 return item->getValue();
00359 }
00360 else if (mAllowTextEntry)
00361 {
00362 return mTextEntry->getValue();
00363 }
00364 else
00365 {
00366 return LLSD();
00367 }
00368 }
00369
00370 void LLComboBox::setLabel(const LLStringExplicit& name)
00371 {
00372 if ( mTextEntry )
00373 {
00374 mTextEntry->setText(name);
00375 if (mList->selectItemByLabel(name, FALSE))
00376 {
00377 mTextEntry->setTentative(FALSE);
00378 }
00379 else
00380 {
00381 mTextEntry->setTentative(mTextEntryTentative);
00382 }
00383 }
00384
00385 if (!mAllowTextEntry)
00386 {
00387 mButton->setLabelUnselected(name);
00388 mButton->setLabelSelected(name);
00389 mButton->setDisabledLabel(name);
00390 mButton->setDisabledSelectedLabel(name);
00391 }
00392 }
00393
00394
00395 BOOL LLComboBox::remove(const LLString& name)
00396 {
00397 BOOL found = mList->selectItemByLabel(name);
00398
00399 if (found)
00400 {
00401 LLScrollListItem* item = mList->getFirstSelected();
00402 if (item)
00403 {
00404 mList->deleteSingleItem(mList->getItemIndex(item));
00405 }
00406 }
00407
00408 return found;
00409 }
00410
00411 BOOL LLComboBox::remove(S32 index)
00412 {
00413 if (index < mList->getItemCount())
00414 {
00415 mList->deleteSingleItem(index);
00416 return TRUE;
00417 }
00418 return FALSE;
00419 }
00420
00421
00422 void LLComboBox::onFocusLost()
00423 {
00424 hideList();
00425
00426 if (mAllowTextEntry && getCurrentIndex() != -1)
00427 {
00428 mTextEntry->selectAll();
00429 }
00430 LLUICtrl::onFocusLost();
00431 }
00432
00433 void LLComboBox::onLostTop()
00434 {
00435 hideList();
00436 }
00437
00438
00439 void LLComboBox::setButtonVisible(BOOL visible)
00440 {
00441 mButton->setVisible(visible);
00442 if (mTextEntry)
00443 {
00444 LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
00445 if (visible)
00446 {
00447 text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
00448 }
00449
00450 mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
00451 }
00452 }
00453
00454 void LLComboBox::draw()
00455 {
00456 mButton->setEnabled(getEnabled() );
00457
00458
00459 LLUICtrl::draw();
00460 }
00461
00462 BOOL LLComboBox::setCurrentByIndex( S32 index )
00463 {
00464 BOOL found = mList->selectNthItem( index );
00465 if (found)
00466 {
00467 setLabel(mList->getSelectedItemLabel());
00468 }
00469 return found;
00470 }
00471
00472 S32 LLComboBox::getCurrentIndex() const
00473 {
00474 LLScrollListItem* item = mList->getFirstSelected();
00475 if( item )
00476 {
00477 return mList->getItemIndex( item );
00478 }
00479 return -1;
00480 }
00481
00482
00483 void LLComboBox::updateLayout()
00484 {
00485 LLRect rect = getLocalRect();
00486 if (mAllowTextEntry)
00487 {
00488 S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
00489 mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size,
00490 rect.mTop, rect.mRight, rect.mBottom));
00491 mButton->setTabStop(FALSE);
00492
00493 if (!mTextEntry)
00494 {
00495 LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
00496 text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
00497
00498 LLString cur_label = mButton->getLabelSelected();
00499 mTextEntry = new LLLineEditor("combo_text_entry",
00500 text_entry_rect,
00501 "",
00502 LLFontGL::sSansSerifSmall,
00503 mMaxChars,
00504 onTextCommit,
00505 onTextEntry,
00506 NULL,
00507 this);
00508 mTextEntry->setSelectAllonFocusReceived(TRUE);
00509 mTextEntry->setHandleEditKeysDirectly(TRUE);
00510 mTextEntry->setCommitOnFocusLost(FALSE);
00511 mTextEntry->setText(cur_label);
00512 mTextEntry->setIgnoreTab(TRUE);
00513 mTextEntry->setFollowsAll();
00514 addChild(mTextEntry);
00515 }
00516 else
00517 {
00518 mTextEntry->setVisible(TRUE);
00519 mTextEntry->setMaxTextLength(mMaxChars);
00520 }
00521
00522
00523 setLabel(LLString::null);
00524
00525 mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
00526 }
00527 else if (!mAllowTextEntry)
00528 {
00529 mButton->setRect(rect);
00530 mButton->setTabStop(TRUE);
00531
00532 if (mTextEntry)
00533 {
00534 mTextEntry->setVisible(FALSE);
00535 }
00536 mButton->setFollowsAll();
00537 }
00538 }
00539
00540 void* LLComboBox::getCurrentUserdata()
00541 {
00542 LLScrollListItem* item = mList->getFirstSelected();
00543 if( item )
00544 {
00545 return item->getUserdata();
00546 }
00547 return NULL;
00548 }
00549
00550
00551 void LLComboBox::showList()
00552 {
00553
00554 LLCoordWindow window_size;
00555 getWindow()->getSize(&window_size);
00556
00557 mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
00558
00559
00560 LLRect root_view_local;
00561 LLView* root_view = getRootView();
00562 root_view->localRectToOtherView(root_view->getLocalRect(), &root_view_local, this);
00563
00564 LLRect rect = mList->getRect();
00565
00566 S32 min_width = getRect().getWidth();
00567 S32 max_width = llmax(min_width, MAX_COMBO_WIDTH);
00568
00569 mList->calcColumnWidths();
00570 S32 list_width = llclamp(mList->getMaxContentWidth(), min_width, max_width);
00571
00572 if (mListPosition == BELOW)
00573 {
00574 if (rect.getHeight() <= -root_view_local.mBottom)
00575 {
00576
00577 rect.setLeftTopAndSize(0, 0, list_width, rect.getHeight() );
00578 }
00579 else
00580 {
00581
00582 if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight())
00583 {
00584
00585 rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight()));
00586 }
00587 else
00588 {
00589
00590 rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight()));
00591 }
00592 }
00593 }
00594 else
00595 {
00596 if (rect.getHeight() <= root_view_local.mTop - getRect().getHeight())
00597 {
00598
00599 rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight()));
00600 }
00601 else
00602 {
00603
00604 if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight())
00605 {
00606
00607 rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight()));
00608 }
00609 else
00610 {
00611
00612 rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight()));
00613 }
00614 }
00615
00616 }
00617 mList->setOrigin(rect.mLeft, rect.mBottom);
00618 mList->reshape(rect.getWidth(), rect.getHeight());
00619 mList->translateIntoRect(root_view_local, FALSE);
00620
00621
00622 S32 x, y;
00623 mList->localPointToScreen(0, 0, &x, &y);
00624
00625 if (y < 0)
00626 {
00627 mList->translate(0, -y);
00628 }
00629
00630
00631
00632
00633 mList->setFocus(TRUE);
00634
00635
00636
00637
00638 gFocusMgr.setTopCtrl(this);
00639
00640
00641 mButton->setToggleState(TRUE);
00642 mList->setVisible(TRUE);
00643
00644 setUseBoundingRect(TRUE);
00645 }
00646
00647 void LLComboBox::hideList()
00648 {
00649
00650 LLString orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected();
00651
00652
00653 mList->selectItemByLabel(orig_selection, FALSE);
00654
00655 mButton->setToggleState(FALSE);
00656 mList->setVisible(FALSE);
00657 mList->highlightNthItem(-1);
00658
00659 setUseBoundingRect(FALSE);
00660 if( gFocusMgr.getTopCtrl() == this )
00661 {
00662 gFocusMgr.setTopCtrl(NULL);
00663 }
00664 }
00665
00666
00667
00668
00669
00670
00671 void LLComboBox::onButtonDown(void *userdata)
00672 {
00673 LLComboBox *self = (LLComboBox *)userdata;
00674
00675 if (!self->mList->getVisible())
00676 {
00677 LLScrollListItem* last_selected_item = self->mList->getLastSelectedItem();
00678 if (last_selected_item)
00679 {
00680
00681 self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item));
00682 }
00683
00684 if( self->mPrearrangeCallback )
00685 {
00686 self->mPrearrangeCallback( self, self->mCallbackUserData );
00687 }
00688
00689 if (self->mList->getItemCount() != 0)
00690 {
00691 self->showList();
00692 }
00693
00694 self->setFocus( TRUE );
00695
00696
00697 if (self->mButton->hasMouseCapture())
00698 {
00699 gFocusMgr.setMouseCapture(self->mList);
00700 }
00701 }
00702 else
00703 {
00704 self->hideList();
00705 }
00706
00707 }
00708
00709
00710 void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
00711 {
00712
00713 LLComboBox *self = (LLComboBox *) userdata;
00714
00715 const LLString name = self->mList->getSelectedItemLabel();
00716
00717 S32 cur_id = self->getCurrentIndex();
00718 if (cur_id != -1)
00719 {
00720 self->setLabel(name);
00721
00722 if (self->mAllowTextEntry)
00723 {
00724 gFocusMgr.setKeyboardFocus(self->mTextEntry);
00725 self->mTextEntry->selectAll();
00726 }
00727 }
00728
00729
00730 self->hideList();
00731
00732
00733 self->onCommit();
00734 }
00735
00736 BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
00737 {
00738 LLString tool_tip;
00739
00740 if(LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen))
00741 {
00742 return TRUE;
00743 }
00744
00745 if (LLUI::sShowXUINames)
00746 {
00747 tool_tip = getShowNamesToolTip();
00748 }
00749 else
00750 {
00751 tool_tip = getToolTip();
00752 if (tool_tip.empty())
00753 {
00754 tool_tip = getSelectedItemLabel();
00755 }
00756 }
00757
00758 if( !tool_tip.empty() )
00759 {
00760 msg = tool_tip;
00761
00762
00763 localPointToScreen(
00764 0, 0,
00765 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
00766 localPointToScreen(
00767 getRect().getWidth(), getRect().getHeight(),
00768 &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
00769 }
00770 return TRUE;
00771 }
00772
00773 BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)
00774 {
00775 BOOL result = FALSE;
00776 if (hasFocus())
00777 {
00778
00779 LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
00780 if (last_selected_item)
00781 {
00782
00783 mList->highlightNthItem(mList->getItemIndex(last_selected_item));
00784 }
00785 result = mList->handleKeyHere(key, mask);
00786
00787 if (mList->getLastSelectedItem() != last_selected_item)
00788 {
00789 showList();
00790 }
00791 }
00792 return result;
00793 }
00794
00795 BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char)
00796 {
00797 BOOL result = FALSE;
00798 if (gFocusMgr.childHasKeyboardFocus(this))
00799 {
00800
00801 if (' ' != uni_char )
00802 {
00803 LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
00804 if (last_selected_item)
00805 {
00806
00807 mList->highlightNthItem(mList->getItemIndex(last_selected_item));
00808 }
00809 result = mList->handleUnicodeCharHere(uni_char);
00810 if (mList->getLastSelectedItem() != last_selected_item)
00811 {
00812 showList();
00813 }
00814 }
00815 }
00816 return result;
00817 }
00818
00819 void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
00820 {
00821 mAllowTextEntry = allow;
00822 mTextEntryTentative = set_tentative;
00823 mMaxChars = max_chars;
00824
00825 updateLayout();
00826 }
00827
00828 void LLComboBox::setTextEntry(const LLStringExplicit& text)
00829 {
00830 if (mTextEntry)
00831 {
00832 mTextEntry->setText(text);
00833 updateSelection();
00834 }
00835 }
00836
00837
00838 void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
00839 {
00840 LLComboBox* self = (LLComboBox*)user_data;
00841
00842 if (self->mTextEntryCallback)
00843 {
00844 (*self->mTextEntryCallback)(line_editor, self->mCallbackUserData);
00845 }
00846
00847 KEY key = gKeyboard->currentKey();
00848 if (key == KEY_BACKSPACE ||
00849 key == KEY_DELETE)
00850 {
00851 if (self->mList->selectItemByLabel(line_editor->getText(), FALSE))
00852 {
00853 line_editor->setTentative(FALSE);
00854 }
00855 else
00856 {
00857 line_editor->setTentative(self->mTextEntryTentative);
00858 self->mList->deselectAllItems();
00859 }
00860 return;
00861 }
00862
00863 if (key == KEY_LEFT ||
00864 key == KEY_RIGHT)
00865 {
00866 return;
00867 }
00868
00869 if (key == KEY_DOWN)
00870 {
00871 self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1));
00872 if (!self->mList->getVisible())
00873 {
00874 if( self->mPrearrangeCallback )
00875 {
00876 self->mPrearrangeCallback( self, self->mCallbackUserData );
00877 }
00878
00879 if (self->mList->getItemCount() != 0)
00880 {
00881 self->showList();
00882 }
00883 }
00884 line_editor->selectAll();
00885 line_editor->setTentative(FALSE);
00886 }
00887 else if (key == KEY_UP)
00888 {
00889 self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1));
00890 if (!self->mList->getVisible())
00891 {
00892 if( self->mPrearrangeCallback )
00893 {
00894 self->mPrearrangeCallback( self, self->mCallbackUserData );
00895 }
00896
00897 if (self->mList->getItemCount() != 0)
00898 {
00899 self->showList();
00900 }
00901 }
00902 line_editor->selectAll();
00903 line_editor->setTentative(FALSE);
00904 }
00905 else
00906 {
00907
00908 self->updateSelection();
00909 }
00910 }
00911
00912 void LLComboBox::updateSelection()
00913 {
00914 LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor());
00915
00916
00917 LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText();
00918 LLString full_string = mTextEntry->getText();
00919
00920
00921
00922
00923 if( mTextEntry->getWText().size() == 1 )
00924 {
00925 if (mPrearrangeCallback)
00926 {
00927 mPrearrangeCallback( this, mCallbackUserData );
00928 }
00929 }
00930
00931 if (mList->selectItemByLabel(full_string, FALSE))
00932 {
00933 mTextEntry->setTentative(FALSE);
00934 }
00935 else if (!mList->selectItemByPrefix(left_wstring, FALSE))
00936 {
00937 mList->deselectAllItems();
00938 mTextEntry->setText(wstring_to_utf8str(user_wstring));
00939 mTextEntry->setTentative(mTextEntryTentative);
00940 }
00941 else
00942 {
00943 LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel());
00944 LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
00945 mTextEntry->setText(wstring_to_utf8str(wtext));
00946 mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
00947 mTextEntry->endSelection();
00948 mTextEntry->setTentative(FALSE);
00949 }
00950 }
00951
00952
00953 void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data)
00954 {
00955 LLComboBox* self = (LLComboBox*)user_data;
00956 LLString text = self->mTextEntry->getText();
00957 self->setSimple(text);
00958 self->onCommit();
00959 self->mTextEntry->selectAll();
00960 }
00961
00962 void LLComboBox::setFocus(BOOL b)
00963 {
00964 LLUICtrl::setFocus(b);
00965
00966 if (b)
00967 {
00968 mList->clearSearchString();
00969 if (mList->getVisible())
00970 {
00971 mList->setFocus(TRUE);
00972 }
00973 }
00974 }
00975
00976
00977
00978
00979 S32 LLComboBox::getItemCount() const
00980 {
00981 return mList->getItemCount();
00982 }
00983
00984 void LLComboBox::addColumn(const LLSD& column, EAddPosition pos)
00985 {
00986 mList->clearColumns();
00987 mList->addColumn(column, pos);
00988 }
00989
00990 void LLComboBox::clearColumns()
00991 {
00992 mList->clearColumns();
00993 }
00994
00995 void LLComboBox::setColumnLabel(const LLString& column, const LLString& label)
00996 {
00997 mList->setColumnLabel(column, label);
00998 }
00999
01000 LLScrollListItem* LLComboBox::addElement(const LLSD& value, EAddPosition pos, void* userdata)
01001 {
01002 return mList->addElement(value, pos, userdata);
01003 }
01004
01005 LLScrollListItem* LLComboBox::addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id)
01006 {
01007 return mList->addSimpleElement(value, pos, id);
01008 }
01009
01010 void LLComboBox::clearRows()
01011 {
01012 mList->clearRows();
01013 }
01014
01015 void LLComboBox::sortByColumn(LLString name, BOOL ascending)
01016 {
01017 }
01018
01019
01020
01021
01022 BOOL LLComboBox::setCurrentByID(const LLUUID& id)
01023 {
01024 BOOL found = mList->selectByID( id );
01025
01026 if (found)
01027 {
01028 setLabel(mList->getSelectedItemLabel());
01029 }
01030
01031 return found;
01032 }
01033
01034 LLUUID LLComboBox::getCurrentID() const
01035 {
01036 return mList->getStringUUIDSelectedItem();
01037 }
01038 BOOL LLComboBox::setSelectedByValue(const LLSD& value, BOOL selected)
01039 {
01040 BOOL found = mList->setSelectedByValue(value, selected);
01041 if (found)
01042 {
01043 setLabel(mList->getSelectedItemLabel());
01044 }
01045 return found;
01046 }
01047
01048 LLSD LLComboBox::getSelectedValue()
01049 {
01050 return mList->getSelectedValue();
01051 }
01052
01053 BOOL LLComboBox::isSelected(const LLSD& value) const
01054 {
01055 return mList->isSelected(value);
01056 }
01057
01058 BOOL LLComboBox::operateOnSelection(EOperation op)
01059 {
01060 if (op == OP_DELETE)
01061 {
01062 mList->deleteSelectedItems();
01063 return TRUE;
01064 }
01065 return FALSE;
01066 }
01067
01068 BOOL LLComboBox::operateOnAll(EOperation op)
01069 {
01070 if (op == OP_DELETE)
01071 {
01072 clearRows();
01073 return TRUE;
01074 }
01075 return FALSE;
01076 }
01077
01078 BOOL LLComboBox::selectItemRange( S32 first, S32 last )
01079 {
01080 return mList->selectItemRange(first, last);
01081 }
01082
01083
01084
01085
01086
01087
01088 static LLRegisterWidget<LLFlyoutButton> r2("flyout_button");
01089
01090 const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
01091
01092 LLFlyoutButton::LLFlyoutButton(
01093 const LLString& name,
01094 const LLRect &rect,
01095 const LLString& label,
01096 void (*commit_callback)(LLUICtrl*, void*) ,
01097 void *callback_userdata)
01098 : LLComboBox(name, rect, LLString::null, commit_callback, callback_userdata),
01099 mToggleState(FALSE),
01100 mActionButton(NULL)
01101 {
01102
01103
01104 mActionButton = new LLButton(label,
01105 LLRect(), LLString::null, NULL, this);
01106 mActionButton->setScaleImage(TRUE);
01107
01108 mActionButton->setClickedCallback(onActionButtonClick);
01109 mActionButton->setFollowsAll();
01110 mActionButton->setHAlign( LLFontGL::HCENTER );
01111 mActionButton->setLabel(label);
01112 addChild(mActionButton);
01113
01114 mActionButtonImage = LLUI::getUIImage("flyout_btn_left.tga");
01115 mExpanderButtonImage = LLUI::getUIImage("flyout_btn_right.tga");
01116 mActionButtonImageSelected = LLUI::getUIImage("flyout_btn_left_selected.tga");
01117 mExpanderButtonImageSelected = LLUI::getUIImage("flyout_btn_right_selected.tga");
01118 mActionButtonImageDisabled = LLUI::getUIImage("flyout_btn_left_disabled.tga");
01119 mExpanderButtonImageDisabled = LLUI::getUIImage("flyout_btn_right_disabled.tga");
01120
01121 mActionButton->setImageSelected(mActionButtonImageSelected);
01122 mActionButton->setImageUnselected(mActionButtonImage);
01123 mActionButton->setImageDisabled(mActionButtonImageDisabled);
01124 mActionButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
01125
01126 mButton->setImageSelected(mExpanderButtonImageSelected);
01127 mButton->setImageUnselected(mExpanderButtonImage);
01128 mButton->setImageDisabled(mExpanderButtonImageDisabled);
01129 mButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
01130 mButton->setRightHPad(6);
01131
01132 updateLayout();
01133 }
01134
01135
01136 LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
01137 {
01138 LLString name = "flyout_button";
01139 node->getAttributeString("name", name);
01140
01141 LLString label("");
01142 node->getAttributeString("label", label);
01143
01144 LLRect rect;
01145 createRect(node, rect, parent, LLRect());
01146
01147 LLUICtrlCallback callback = NULL;
01148
01149 LLFlyoutButton* flyout_button = new LLFlyoutButton(name,
01150 rect,
01151 label,
01152 callback,
01153 NULL);
01154
01155 LLString list_position;
01156 node->getAttributeString("list_position", list_position);
01157 if (list_position == "below")
01158 {
01159 flyout_button->mListPosition = BELOW;
01160 }
01161 else if (list_position == "above")
01162 {
01163 flyout_button->mListPosition = ABOVE;
01164 }
01165
01166
01167 flyout_button->initFromXML(node, parent);
01168
01169 LLXMLNodePtr child;
01170 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
01171 {
01172 if (child->hasName("flyout_button_item"))
01173 {
01174 LLString label = child->getTextContents();
01175
01176 LLString value = label;
01177 child->getAttributeString("value", value);
01178
01179 flyout_button->add(label, LLSD(value) );
01180 }
01181 }
01182
01183 flyout_button->updateLayout();
01184
01185 return flyout_button;
01186 }
01187
01188 void LLFlyoutButton::updateLayout()
01189 {
01190 LLComboBox::updateLayout();
01191
01192 mButton->setOrigin(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
01193 mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
01194 mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
01195 mButton->setTabStop(FALSE);
01196 mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
01197
01198 mActionButton->setOrigin(0, 0);
01199 mActionButton->reshape(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
01200 }
01201
01202
01203 void LLFlyoutButton::onActionButtonClick(void *user_data)
01204 {
01205 LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data;
01206
01207 buttonp->mList->deselect();
01208 buttonp->onCommit();
01209 }
01210
01211 void LLFlyoutButton::draw()
01212 {
01213 mActionButton->setToggleState(mToggleState);
01214 mButton->setToggleState(mToggleState);
01215
01216
01217
01218 mButton->setLabel(LLString::null);
01219 LLComboBox::draw();
01220 }
01221
01222 void LLFlyoutButton::setEnabled(BOOL enabled)
01223 {
01224 mActionButton->setEnabled(enabled);
01225 LLComboBox::setEnabled(enabled);
01226 }
01227
01228
01229 void LLFlyoutButton::setToggleState(BOOL state)
01230 {
01231 mToggleState = state;
01232 }
01233