aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/llcombobox.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llcombobox.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/llui/llcombobox.cpp1153
1 files changed, 1153 insertions, 0 deletions
diff --git a/linden/indra/llui/llcombobox.cpp b/linden/indra/llui/llcombobox.cpp
new file mode 100644
index 0000000..b19be9a
--- /dev/null
+++ b/linden/indra/llui/llcombobox.cpp
@@ -0,0 +1,1153 @@
1/**
2 * @file llcombobox.cpp
3 * @brief LLComboBox base class
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28// A control that displays the name of the chosen item, which when
29// clicked shows a scrolling box of options.
30
31#include "linden_common.h"
32
33// file includes
34#include "llcombobox.h"
35
36// common includes
37#include "llstring.h"
38
39// newview includes
40#include "llbutton.h"
41#include "llkeyboard.h"
42#include "llscrolllistctrl.h"
43#include "llwindow.h"
44#include "llfloater.h"
45#include "llscrollbar.h"
46#include "llcontrol.h"
47#include "llfocusmgr.h"
48#include "lllineeditor.h"
49#include "v2math.h"
50
51// Globals
52S32 LLCOMBOBOX_HEIGHT = 0;
53S32 LLCOMBOBOX_WIDTH = 0;
54
55LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label,
56 void (*commit_callback)(LLUICtrl*,void*),
57 void *callback_userdata,
58 S32 list_width
59 )
60: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata,
61 FOLLOWS_LEFT | FOLLOWS_TOP),
62 mDrawButton(TRUE),
63 mTextEntry(NULL),
64 mArrowImage(NULL),
65 mAllowTextEntry(FALSE),
66 mMaxChars(20),
67 mTextEntryTentative(TRUE),
68 mPrearrangeCallback( NULL ),
69 mTextEntryCallback( NULL ),
70 mListWidth(list_width)
71{
72 // For now, all comboboxes don't take keyboard focus when clicked.
73 // This might change if it is part of a modal dialog.
74 // mKeyboardFocusOnClick = FALSE;
75
76 // Revert to standard behavior. When this control's parent is hidden, it needs to
77 // hide this ctrl--which won't just happen automatically since when LLComboBox is
78 // showing its list, it's also set to TopView. When keyboard focus is cleared all
79 // controls (including this one) know that they are no longer editing.
80 mKeyboardFocusOnClick = TRUE;
81
82 LLRect r;
83 r.setOriginAndSize(0, 0, rect.getWidth(), rect.getHeight());
84
85 // Always use text box
86 // Text label button
87 mButton = new LLSquareButton("comboxbox button",
88 r, label, NULL, LLString::null,
89 &LLComboBox::onButtonClick, this);
90 mButton->setFont(LLFontGL::sSansSerifSmall);
91 mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
92 mButton->setHAlign( LLFontGL::LEFT );
93
94 const S32 ARROW_WIDTH = 16;
95 mButton->setRightHPad( ARROW_WIDTH );
96 addChild(mButton);
97
98 // Default size, will be set by arrange() call in button callback.
99 if (list_width == 0)
100 {
101 list_width = mRect.getWidth() + SCROLLBAR_SIZE;
102 }
103 r.setOriginAndSize(0, 16, list_width, 220);
104
105 // disallow multiple selection
106 mList = new LLScrollListCtrl(
107 "ComboBox", r,
108 &LLComboBox::onItemSelected, this, FALSE);
109 mList->setVisible(FALSE);
110 mList->setBgWriteableColor( LLColor4(1,1,1,1) );
111 mList->setCommitOnKeyboardMovement(FALSE);
112 addChild(mList);
113
114 LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
115 mBorder = new LLViewBorder( "combo border", border_rect );
116 addChild( mBorder );
117 mBorder->setFollows(FOLLOWS_LEFT|FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
118
119 LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") );
120 mArrowImage = LLUI::sImageProvider->getUIImageByID(arrow_image_id);
121}
122
123
124LLComboBox::~LLComboBox()
125{
126 // children automatically deleted, including mMenu, mButton
127}
128
129// virtual
130LLXMLNodePtr LLComboBox::getXML(bool save_children) const
131{
132 LLXMLNodePtr node = LLUICtrl::getXML();
133
134 // Attributes
135
136 node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry);
137
138 node->createChild("max_chars", TRUE)->setIntValue(mMaxChars);
139
140 // Contents
141
142 std::vector<LLScrollListItem*> data_list = mList->getAllData();
143 std::vector<LLScrollListItem*>::iterator data_itor;
144 for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
145 {
146 LLScrollListItem* item = *data_itor;
147 LLScrollListCell* cell = item->getColumn(0);
148 if (cell)
149 {
150 LLXMLNodePtr item_node = node->createChild("combo_item", FALSE);
151 LLSD value = item->getValue();
152 item_node->createChild("value", TRUE)->setStringValue(value.asString());
153 item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
154 item_node->setStringValue(cell->getText());
155 }
156 }
157
158 return node;
159}
160
161// static
162LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
163{
164 LLString name("combo_box");
165 node->getAttributeString("name", name);
166
167 LLString label("");
168 node->getAttributeString("label", label);
169
170 LLRect rect;
171 createRect(node, rect, parent, LLRect());
172
173 BOOL allow_text_entry = FALSE;
174 node->getAttributeBOOL("allow_text_entry", allow_text_entry);
175
176 S32 max_chars = 20;
177 node->getAttributeS32("max_chars", max_chars);
178
179 LLUICtrlCallback callback = NULL;
180
181 LLComboBox* combo_box = new LLComboBox(name,
182 rect,
183 label,
184 callback,
185 NULL);
186 combo_box->setAllowTextEntry(allow_text_entry, max_chars);
187
188 combo_box->initFromXML(node, parent);
189
190 const LLString& contents = node->getValue();
191
192 if (contents.find_first_not_of(" \n\t") != contents.npos)
193 {
194 llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl;
195 }
196 else
197 {
198 LLXMLNodePtr child;
199 for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
200 {
201 if (child->hasName("combo_item"))
202 {
203 LLString label = child->getTextContents();
204
205 LLString value = label;
206 child->getAttributeString("value", value);
207
208 combo_box->add(label, LLSD(value) );
209 }
210 }
211 }
212
213 combo_box->selectFirstItem();
214
215 return combo_box;
216}
217
218void LLComboBox::setEnabled(BOOL enabled)
219{
220 LLUICtrl::setEnabled(enabled);
221 mButton->setEnabled(enabled);
222}
223
224// *HACK: these are all hacks to support the fact that the combobox
225// has mouse capture so we can hide the list when we don't handle the
226// mouse up event
227BOOL LLComboBox::handleHover(S32 x, S32 y, MASK mask)
228{
229 if (mList->getVisible())
230 {
231 S32 local_x, local_y;
232 LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
233 if (mList->pointInView(local_x, local_y))
234 {
235 return mList->handleHover(local_x, local_y, mask);
236 }
237 }
238 return LLUICtrl::handleHover(x, y, mask);
239}
240
241BOOL LLComboBox::handleMouseDown(S32 x, S32 y, MASK mask)
242{
243 if (mList->getVisible())
244 {
245 S32 local_x, local_y;
246 LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
247 if (mList->pointInView(local_x, local_y))
248 {
249 return mList->handleMouseDown(local_x, local_y, mask);
250 }
251 }
252 BOOL has_focus_now = hasFocus();
253 BOOL handled = LLUICtrl::handleMouseDown(x, y, mask);
254 if (handled && !has_focus_now)
255 {
256 onFocusReceived();
257 }
258
259 return handled;
260}
261
262BOOL LLComboBox::handleRightMouseDown(S32 x, S32 y, MASK mask)
263{
264 if (mList->getVisible())
265 {
266 S32 local_x, local_y;
267 LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
268 if (mList->pointInView(local_x, local_y))
269 {
270 return mList->handleRightMouseDown(local_x, local_y, mask);
271 }
272 }
273 return LLUICtrl::handleRightMouseDown(x, y, mask);
274}
275
276BOOL LLComboBox::handleRightMouseUp(S32 x, S32 y, MASK mask)
277{
278 if (mList->getVisible())
279 {
280 S32 local_x, local_y;
281 LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
282 if (mList->pointInView(local_x, local_y))
283 {
284 return mList->handleRightMouseUp(local_x, local_y, mask);
285 }
286 }
287 return LLUICtrl::handleRightMouseUp(x, y, mask);
288}
289
290BOOL LLComboBox::handleDoubleClick(S32 x, S32 y, MASK mask)
291{
292 if (mList->getVisible())
293 {
294 S32 local_x, local_y;
295 LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
296 if (mList->pointInView(local_x, local_y))
297 {
298 return mList->handleDoubleClick(local_x, local_y, mask);
299 }
300 }
301 return LLUICtrl::handleDoubleClick(x, y, mask);
302}
303
304BOOL LLComboBox::handleMouseUp(S32 x, S32 y, MASK mask)
305{
306 BOOL handled = childrenHandleMouseUp(x, y, mask) != NULL;
307
308 if (!handled && mList->getVisible())
309 {
310 S32 local_x, local_y;
311 LLView::localPointToOtherView(x, y, &local_x, &local_y, mList);
312 if (mList->pointInView(local_x, local_y))
313 {
314 handled = mList->handleMouseUp(local_x, local_y, mask);
315 }
316 }
317
318 if( !handled && gFocusMgr.getMouseCapture() == this )
319 {
320 // Mouse events that we didn't handle cause the list to be hidden.
321 // Eat mouse event, regardless of where on the screen it happens.
322 hideList();
323 handled = TRUE;
324 }
325
326 return handled;
327}
328
329void LLComboBox::clear()
330{
331 if (mTextEntry)
332 {
333 mTextEntry->setText("");
334 }
335 mButton->setLabelSelected("");
336 mButton->setLabelUnselected("");
337 mButton->setDisabledLabel("");
338 mButton->setDisabledSelectedLabel("");
339 mList->deselectAllItems();
340}
341
342void LLComboBox::onCommit()
343{
344 if (mAllowTextEntry && getCurrentIndex() != -1)
345 {
346 // we have selected an existing item, blitz the manual text entry with
347 // the properly capitalized item
348 mTextEntry->setValue(getSimple());
349 mTextEntry->setTentative(FALSE);
350 }
351 LLUICtrl::onCommit();
352}
353
354// add item "name" to menu
355void LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
356{
357 mList->addSimpleItem(name, pos, enabled);
358 mList->selectFirstItem();
359}
360
361// add item "name" with a unique id to menu
362void LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
363{
364 mList->addSimpleItem(name, LLSD(id), pos, enabled);
365 mList->selectFirstItem();
366}
367
368// add item "name" with attached userdata
369void LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
370{
371 LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled);
372 item->setUserdata( userdata );
373 mList->selectFirstItem();
374}
375
376// add item "name" with attached generic data
377void LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
378{
379 mList->addSimpleItem(name, value, pos, enabled);
380 mList->selectFirstItem();
381}
382
383
384void LLComboBox::sortByName()
385{
386 mList->sortByColumn(0, TRUE);
387}
388
389
390// Choose an item with a given name in the menu.
391// Returns TRUE if the item was found.
392BOOL LLComboBox::setSimple(const LLString& name)
393{
394 BOOL found = mList->selectSimpleItem(name, FALSE);
395
396 if (found)
397 {
398 setLabel(name);
399 }
400
401 return found;
402}
403
404// virtual
405void LLComboBox::setValue(const LLSD& value)
406{
407 BOOL found = mList->selectByValue(value);
408 if (found)
409 {
410 LLScrollListItem* item = mList->getFirstSelected();
411 if (item)
412 {
413 setLabel( mList->getSimpleSelectedItem() );
414 }
415 }
416}
417
418const LLString& LLComboBox::getSimple() const
419{
420 const LLString& res = mList->getSimpleSelectedItem();
421 if (res.empty() && mAllowTextEntry)
422 {
423 return mTextEntry->getText();
424 }
425 else
426 {
427 return res;
428 }
429}
430
431const LLString& LLComboBox::getSimpleSelectedItem(S32 column) const
432{
433 return mList->getSimpleSelectedItem(column);
434}
435
436// virtual
437LLSD LLComboBox::getValue() const
438{
439 LLScrollListItem* item = mList->getFirstSelected();
440 if( item )
441 {
442 return item->getValue();
443 }
444 else if (mAllowTextEntry)
445 {
446 return mTextEntry->getValue();
447 }
448 else
449 {
450 return LLSD();
451 }
452}
453
454void LLComboBox::setLabel(const LLString& name)
455{
456 if ( mAllowTextEntry )
457 {
458 mTextEntry->setText(name);
459 if (mList->selectSimpleItem(name, FALSE))
460 {
461 mTextEntry->setTentative(FALSE);
462 }
463 else
464 {
465 mTextEntry->setTentative(mTextEntryTentative);
466 }
467 }
468 else
469 {
470 mButton->setLabelUnselected(name);
471 mButton->setLabelSelected(name);
472 mButton->setDisabledLabel(name);
473 mButton->setDisabledSelectedLabel(name);
474 }
475}
476
477
478BOOL LLComboBox::remove(const LLString& name)
479{
480 BOOL found = mList->selectSimpleItem(name);
481
482 if (found)
483 {
484 LLScrollListItem* item = mList->getFirstSelected();
485 if (item)
486 {
487 mList->deleteSingleItem(mList->getItemIndex(item));
488 }
489 }
490
491 return found;
492}
493
494BOOL LLComboBox::remove(S32 index)
495{
496 if (index < mList->getItemCount())
497 {
498 mList->deleteSingleItem(index);
499 return TRUE;
500 }
501 return FALSE;
502}
503
504// Keyboard focus lost.
505void LLComboBox::onFocusLost()
506{
507 hideList();
508 // if valid selection
509 if (mAllowTextEntry && getCurrentIndex() != -1)
510 {
511 mTextEntry->selectAll();
512 }
513}
514
515void LLComboBox::setButtonVisible(BOOL visible)
516{
517 mButton->setVisible(visible);
518 mDrawButton = visible;
519 if (mTextEntry)
520 {
521 LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
522 if (visible)
523 {
524 text_entry_rect.mRight -= mArrowImage->getWidth() + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
525 }
526 //mTextEntry->setRect(text_entry_rect);
527 mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
528 }
529}
530
531void LLComboBox::draw()
532{
533 if( getVisible() )
534 {
535 mBorder->setKeyboardFocusHighlight(hasFocus());
536
537 mButton->setEnabled(mEnabled /*&& !mList->isEmpty()*/);
538
539 // Draw children
540 LLUICtrl::draw();
541
542 if (mDrawButton)
543 {
544 // Paste the graphic on the right edge
545 if (!mArrowImage.isNull())
546 {
547 S32 left = mRect.getWidth() - mArrowImage->getWidth() - LLUI::sConfigGroup->getS32("DropShadowButton");
548
549 gl_draw_image( left, 0, mArrowImage,
550 LLColor4::white);
551 }
552 }
553 }
554}
555
556BOOL LLComboBox::setCurrentByIndex( S32 index )
557{
558 BOOL found = mList->selectNthItem( index );
559 if (found)
560 {
561 setLabel(mList->getSimpleSelectedItem());
562 }
563 return found;
564}
565
566S32 LLComboBox::getCurrentIndex() const
567{
568 LLScrollListItem* item = mList->getFirstSelected();
569 if( item )
570 {
571 return mList->getItemIndex( item );
572 }
573 return -1;
574}
575
576
577void* LLComboBox::getCurrentUserdata()
578{
579 LLScrollListItem* item = mList->getFirstSelected();
580 if( item )
581 {
582 return item->getUserdata();
583 }
584 return NULL;
585}
586
587
588void LLComboBox::showList()
589{
590 // Make sure we don't go off top of screen.
591 LLCoordWindow window_size;
592 getWindow()->getSize(&window_size);
593 //HACK: shouldn't have to know about scale here
594 mList->arrange( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );
595
596 // Move rect so it hangs off the bottom of this view
597 LLRect rect = mList->getRect();
598
599 rect.setLeftTopAndSize(0, 0, rect.getWidth(), rect.getHeight() );
600 mList->setRect(rect);
601
602 // Make sure that we can see the whole list
603 LLRect floater_area_screen;
604 LLRect floater_area_local;
605 gFloaterView->getParent()->localRectToScreen( gFloaterView->getRect(), &floater_area_screen );
606 screenRectToLocal( floater_area_screen, &floater_area_local );
607 mList->translateIntoRect( floater_area_local, FALSE );
608
609 // Make sure we didn't go off bottom of screen
610 S32 x, y;
611 mList->localPointToScreen(0, 0, &x, &y);
612
613 if (y < 0)
614 {
615 mList->translate(0, -y);
616 }
617
618 gFocusMgr.setMouseCapture( this, LLComboBox::onMouseCaptureLost );
619 // NB: this call will trigger the focuslost callback which will hide the list, so do it first
620 // before finally showing the list
621
622 if (!mList->getFirstSelected())
623 {
624 // if nothing is selected, select the first item
625 // so that the callback is not immediately triggered on setFocus()
626 mList->selectFirstItem();
627 }
628 gFocusMgr.setKeyboardFocus(mList, onListFocusLost);
629
630 // Show the list and push the button down
631 mButton->setToggleState(TRUE);
632 mList->setVisible(TRUE);
633
634 gFocusMgr.setTopView(mList, LLComboBox::onTopViewLost );
635
636}
637
638void LLComboBox::hideList()
639{
640 mButton->setToggleState(FALSE);
641 mList->setVisible(FALSE);
642 mList->highlightNthItem(-1);
643
644 if( gFocusMgr.getTopView() == mList )
645 {
646 gFocusMgr.setTopView(NULL, NULL);
647 }
648
649 if( gFocusMgr.getMouseCapture() == this )
650 {
651 gFocusMgr.setMouseCapture( NULL, NULL );
652 }
653
654 if( gFocusMgr.getKeyboardFocus() == mList )
655 {
656 if (mAllowTextEntry)
657 {
658 mTextEntry->setFocus(TRUE);
659 }
660 else
661 {
662 setFocus(TRUE);
663 }
664 }
665}
666
667
668
669//------------------------------------------------------------------
670// static functions
671//------------------------------------------------------------------
672
673// static
674void LLComboBox::onButtonClick(void *userdata)
675{
676 LLComboBox *self = (LLComboBox *)userdata;
677
678 if (!self->mList->getVisible())
679 {
680 LLScrollListItem* last_selected_item = self->mList->getLastSelectedItem();
681 if (last_selected_item)
682 {
683 // highlight the original selection before potentially selecting a new item
684 self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item));
685 }
686
687 if( self->mPrearrangeCallback )
688 {
689 self->mPrearrangeCallback( self, self->mCallbackUserData );
690 }
691
692 if (self->mList->getItemCount() != 0)
693 {
694 self->showList();
695 }
696
697 if (self->mKeyboardFocusOnClick && !self->hasFocus())
698 {
699 self->setFocus( TRUE );
700 }
701 }
702 else
703 {
704 // hide and release keyboard focus
705 self->hideList();
706
707 self->onCommit();
708 }
709}
710
711
712
713// static
714void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
715{
716 // Note: item is the LLScrollListCtrl
717 LLComboBox *self = (LLComboBox *) userdata;
718
719 const LLString& name = self->mList->getSimpleSelectedItem();
720
721 self->hideList();
722
723 S32 cur_id = self->getCurrentIndex();
724 if (cur_id != -1)
725 {
726 self->setLabel(self->mList->getSimpleSelectedItem());
727
728 if (self->mAllowTextEntry)
729 {
730 self->mTextEntry->setText(name);
731 self->mTextEntry->setTentative(FALSE);
732 gFocusMgr.setKeyboardFocus(self->mTextEntry, NULL);
733 self->mTextEntry->selectAll();
734 }
735 else
736 {
737 self->mButton->setLabelUnselected( name );
738 self->mButton->setLabelSelected( name );
739 self->mButton->setDisabledLabel( name );
740 self->mButton->setDisabledSelectedLabel( name );
741 }
742 }
743 self->onCommit();
744}
745
746// static
747void LLComboBox::onTopViewLost(LLView* old_focus)
748{
749 LLComboBox *self = (LLComboBox *) old_focus->getParent();
750 self->hideList();
751}
752
753
754// static
755void LLComboBox::onMouseCaptureLost(LLMouseHandler*)
756{
757 // Can't hide the list here. If the list scrolls off the screen,
758 // and you click in the arrow buttons of the scroll bar, they must capture
759 // the mouse to handle scrolling-while-mouse-down.
760}
761
762BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
763{
764
765 LLString tool_tip;
766
767 if (LLUI::sShowXUINames)
768 {
769 tool_tip = getShowNamesToolTip();
770 }
771 else
772 {
773 tool_tip = mToolTipMsg;
774 }
775
776 if( getVisible() && pointInView( x, y ) )
777 {
778 if( !tool_tip.empty() )
779 {
780 msg = tool_tip;
781
782 // Convert rect local to screen coordinates
783 localPointToScreen(
784 0, 0,
785 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
786 localPointToScreen(
787 mRect.getWidth(), mRect.getHeight(),
788 &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
789 }
790 return TRUE;
791 }
792 return FALSE;
793}
794
795BOOL LLComboBox::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
796{
797 BOOL result = FALSE;
798 if (gFocusMgr.childHasKeyboardFocus(this))
799 {
800 //give list a chance to pop up and handle key
801 LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
802 if (last_selected_item)
803 {
804 // highlight the original selection before potentially selecting a new item
805 mList->highlightNthItem(mList->getItemIndex(last_selected_item));
806 }
807 result = mList->handleKeyHere(key, mask, FALSE);
808 // if selection has changed, pop open list
809 if (mList->getLastSelectedItem() != last_selected_item)
810 {
811 showList();
812 }
813 }
814 return result;
815}
816
817BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent)
818{
819 BOOL result = FALSE;
820 if (gFocusMgr.childHasKeyboardFocus(this))
821 {
822 // space bar just shows the list
823 if (' ' != uni_char )
824 {
825 LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
826 if (last_selected_item)
827 {
828 // highlight the original selection before potentially selecting a new item
829 mList->highlightNthItem(mList->getItemIndex(last_selected_item));
830 }
831 result = mList->handleUnicodeCharHere(uni_char, called_from_parent);
832 if (mList->getLastSelectedItem() != last_selected_item)
833 {
834 showList();
835 }
836 }
837 }
838 return result;
839}
840
841void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
842{
843 LLRect rect( 0, mRect.getHeight(), mRect.getWidth(), 0);
844 if (allow && !mAllowTextEntry)
845 {
846 S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
847 mButton->setRect(LLRect( mRect.getWidth() - mArrowImage->getWidth() - 2 * shadow_size,
848 rect.mTop, rect.mRight, rect.mBottom));
849 mButton->setTabStop(FALSE);
850
851 // clear label on button
852 LLString cur_label = mButton->getLabelSelected();
853 setLabel("");
854 if (!mTextEntry)
855 {
856 LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
857 text_entry_rect.mRight -= mArrowImage->getWidth() + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
858 mTextEntry = new LLLineEditor("combo_text_entry",
859 text_entry_rect,
860 "",
861 LLFontGL::sSansSerifSmall,
862 max_chars,
863 onTextCommit,
864 onTextEntry,
865 NULL,
866 this,
867 NULL, // prevalidate func
868 LLViewBorder::BEVEL_NONE,
869 LLViewBorder::STYLE_LINE,
870 0); // no border
871 mTextEntry->setSelectAllonFocusReceived(TRUE);
872 mTextEntry->setHandleEditKeysDirectly(TRUE);
873 mTextEntry->setCommitOnFocusLost(FALSE);
874 mTextEntry->setText(cur_label);
875 mTextEntry->setIgnoreTab(TRUE);
876 addChild(mTextEntry);
877 mMaxChars = max_chars;
878 }
879 else
880 {
881 mTextEntry->setVisible(TRUE);
882 }
883 }
884 else if (!allow && mAllowTextEntry)
885 {
886 mButton->setRect(rect);
887 mButton->setTabStop(TRUE);
888
889 if (mTextEntry)
890 {
891 mTextEntry->setVisible(FALSE);
892 }
893 }
894 mAllowTextEntry = allow;
895 mTextEntryTentative = set_tentative;
896}
897
898void LLComboBox::setTextEntry(const LLString& text)
899{
900 if (mTextEntry)
901 {
902 mTextEntry->setText(text);
903 updateSelection();
904 }
905}
906
907//static
908void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
909{
910 LLComboBox* self = (LLComboBox*)user_data;
911
912 if (self->mTextEntryCallback)
913 {
914 (*self->mTextEntryCallback)(line_editor, self->mCallbackUserData);
915 }
916
917 KEY key = gKeyboard->currentKey();
918 if (key == KEY_BACKSPACE ||
919 key == KEY_DELETE)
920 {
921 if (self->mList->selectSimpleItem(line_editor->getText(), FALSE))
922 {
923 line_editor->setTentative(FALSE);
924 }
925 else
926 {
927 line_editor->setTentative(self->mTextEntryTentative);
928 }
929 return;
930 }
931
932 if (key == KEY_LEFT ||
933 key == KEY_RIGHT)
934 {
935 return;
936 }
937
938 if (key == KEY_DOWN)
939 {
940 self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1));
941 if (!self->mList->getVisible())
942 {
943 if( self->mPrearrangeCallback )
944 {
945 self->mPrearrangeCallback( self, self->mCallbackUserData );
946 }
947
948 if (self->mList->getItemCount() != 0)
949 {
950 self->showList();
951 }
952 }
953 line_editor->selectAll();
954 line_editor->setTentative(FALSE);
955 }
956 else if (key == KEY_UP)
957 {
958 self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1));
959 if (!self->mList->getVisible())
960 {
961 if( self->mPrearrangeCallback )
962 {
963 self->mPrearrangeCallback( self, self->mCallbackUserData );
964 }
965
966 if (self->mList->getItemCount() != 0)
967 {
968 self->showList();
969 }
970 }
971 line_editor->selectAll();
972 line_editor->setTentative(FALSE);
973 }
974 else
975 {
976 // RN: presumably text entry
977 self->updateSelection();
978 }
979}
980
981void LLComboBox::updateSelection()
982{
983 LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor());
984 // user-entered portion of string, based on assumption that any selected
985 // text was a result of auto-completion
986 LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText();
987 LLString full_string = mTextEntry->getText();
988
989 // go ahead and arrange drop down list on first typed character, even
990 // though we aren't showing it... some code relies on prearrange
991 // callback to populate content
992 if( mTextEntry->getWText().size() == 1 )
993 {
994 if (mPrearrangeCallback)
995 {
996 mPrearrangeCallback( this, mCallbackUserData );
997 }
998 }
999
1000 if (mList->selectSimpleItem(full_string, FALSE))
1001 {
1002 mTextEntry->setTentative(FALSE);
1003 }
1004 else if (!mList->selectSimpleItemByPrefix(left_wstring, FALSE))
1005 {
1006 mList->deselectAllItems();
1007 mTextEntry->setText(wstring_to_utf8str(user_wstring));
1008 mTextEntry->setTentative(mTextEntryTentative);
1009 }
1010 else
1011 {
1012 LLWString selected_item = utf8str_to_wstring(mList->getSimpleSelectedItem());
1013 LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
1014 mTextEntry->setText(wstring_to_utf8str(wtext));
1015 mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
1016 mTextEntry->endSelection();
1017 mTextEntry->setTentative(FALSE);
1018 }
1019}
1020
1021//static
1022void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data)
1023{
1024 LLComboBox* self = (LLComboBox*)user_data;
1025 LLString text = self->mTextEntry->getText();
1026 self->setSimple(text);
1027 self->onCommit();
1028 self->mTextEntry->selectAll();
1029}
1030
1031void LLComboBox::setFocus(BOOL b)
1032{
1033 LLUICtrl::setFocus(b);
1034
1035 if (b)
1036 {
1037 mList->clearSearchString();
1038 }
1039}
1040
1041//============================================================================
1042// LLCtrlListInterface functions
1043
1044S32 LLComboBox::getItemCount() const
1045{
1046 return mList->getItemCount();
1047}
1048
1049void LLComboBox::addColumn(const LLSD& column, EAddPosition pos)
1050{
1051 mList->clearColumns();
1052 mList->addColumn(column, pos);
1053}
1054
1055void LLComboBox::clearColumns()
1056{
1057 mList->clearColumns();
1058}
1059
1060void LLComboBox::setColumnLabel(const LLString& column, const LLString& label)
1061{
1062 mList->setColumnLabel(column, label);
1063}
1064
1065LLScrollListItem* LLComboBox::addElement(const LLSD& value, EAddPosition pos, void* userdata)
1066{
1067 return mList->addElement(value, pos, userdata);
1068}
1069
1070LLScrollListItem* LLComboBox::addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id)
1071{
1072 return mList->addSimpleElement(value, pos, id);
1073}
1074
1075void LLComboBox::clearRows()
1076{
1077 mList->clearRows();
1078}
1079
1080void LLComboBox::sortByColumn(LLString name, BOOL ascending)
1081{
1082}
1083
1084//============================================================================
1085//LLCtrlSelectionInterface functions
1086
1087BOOL LLComboBox::setCurrentByID(const LLUUID& id)
1088{
1089 BOOL found = mList->selectByID( id );
1090
1091 if (found)
1092 {
1093 setLabel(mList->getSimpleSelectedItem());
1094 }
1095
1096 return found;
1097}
1098
1099LLUUID LLComboBox::getCurrentID()
1100{
1101 return mList->getStringUUIDSelectedItem();
1102}
1103BOOL LLComboBox::setSelectedByValue(LLSD value, BOOL selected)
1104{
1105 BOOL found = mList->setSelectedByValue(value, selected);
1106 if (found)
1107 {
1108 setLabel(mList->getSimpleSelectedItem());
1109 }
1110 return found;
1111}
1112
1113LLSD LLComboBox::getSimpleSelectedValue()
1114{
1115 return mList->getSimpleSelectedValue();
1116}
1117
1118BOOL LLComboBox::isSelected(LLSD value)
1119{
1120 return mList->isSelected(value);
1121}
1122
1123BOOL LLComboBox::operateOnSelection(EOperation op)
1124{
1125 if (op == OP_DELETE)
1126 {
1127 mList->deleteSelectedItems();
1128 return TRUE;
1129 }
1130 return FALSE;
1131}
1132
1133BOOL LLComboBox::operateOnAll(EOperation op)
1134{
1135 if (op == OP_DELETE)
1136 {
1137 clearRows();
1138 return TRUE;
1139 }
1140 return FALSE;
1141}
1142
1143//static
1144void LLComboBox::onListFocusLost(LLUICtrl* old_focus)
1145{
1146 // if focus is going to nothing (user hit ESC), take it back
1147 LLComboBox* combo = (LLComboBox*)old_focus->getParent();
1148 combo->hideList();
1149 if (gFocusMgr.getKeyboardFocus() == NULL)
1150 {
1151 combo->focusFirstItem();
1152 }
1153}