00001
00033
00034 #include "linden_common.h"
00035 #include "lluictrl.h"
00036 #include "llfocusmgr.h"
00037 #include "llpanel.h"
00038
00039 static LLRegisterWidget<LLUICtrl> r("ui_ctrl");
00040
00041 LLFocusableElement::LLFocusableElement()
00042 : mFocusLostCallback(NULL),
00043 mFocusReceivedCallback(NULL),
00044 mFocusChangedCallback(NULL),
00045 mFocusCallbackUserData(NULL)
00046 {
00047 }
00048
00049
00050 LLFocusableElement::~LLFocusableElement()
00051 {
00052 }
00053
00054 void LLFocusableElement::onFocusReceived()
00055 {
00056 if( mFocusReceivedCallback )
00057 {
00058 mFocusReceivedCallback( this, mFocusCallbackUserData );
00059 }
00060 if( mFocusChangedCallback )
00061 {
00062 mFocusChangedCallback( this, mFocusCallbackUserData );
00063 }
00064 }
00065
00066 void LLFocusableElement::onFocusLost()
00067 {
00068 if( mFocusLostCallback )
00069 {
00070 mFocusLostCallback( this, mFocusCallbackUserData );
00071 }
00072
00073 if( mFocusChangedCallback )
00074 {
00075 mFocusChangedCallback( this, mFocusCallbackUserData );
00076 }
00077 }
00078
00079 BOOL LLFocusableElement::hasFocus() const
00080 {
00081 return FALSE;
00082 }
00083
00084 void LLFocusableElement::setFocus(BOOL b)
00085 {
00086 }
00087
00088
00089
00090 LLUICtrl::LLUICtrl() :
00091 mCommitCallback(NULL),
00092 mLostTopCallback(NULL),
00093 mValidateCallback(NULL),
00094 mCallbackUserData(NULL),
00095 mTentative(FALSE),
00096 mTabStop(TRUE),
00097 mIsChrome(FALSE)
00098 {
00099 }
00100
00101 LLUICtrl::LLUICtrl(const LLString& name, const LLRect& rect, BOOL mouse_opaque,
00102 void (*on_commit_callback)(LLUICtrl*, void*),
00103 void* callback_userdata,
00104 U32 reshape)
00105 :
00106
00107 LLView( name, rect, mouse_opaque, reshape ),
00108 mCommitCallback( on_commit_callback) ,
00109 mLostTopCallback( NULL ),
00110 mValidateCallback( NULL ),
00111 mCallbackUserData( callback_userdata ),
00112 mTentative( FALSE ),
00113 mTabStop( TRUE ),
00114 mIsChrome(FALSE)
00115 {
00116 }
00117
00118 LLUICtrl::~LLUICtrl()
00119 {
00120 gFocusMgr.releaseFocusIfNeeded( this );
00121
00122 if( gFocusMgr.getTopCtrl() == this )
00123 {
00124 llwarns << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << llendl;
00125 gFocusMgr.removeTopCtrlWithoutCallback( this );
00126 }
00127 }
00128
00129 void LLUICtrl::onCommit()
00130 {
00131 if( mCommitCallback )
00132 {
00133 mCommitCallback( this, mCallbackUserData );
00134 }
00135 }
00136
00137
00138 BOOL LLUICtrl::isCtrl() const
00139 {
00140 return TRUE;
00141 }
00142
00143
00144 LLSD LLUICtrl::getValue() const
00145 {
00146 return LLSD();
00147 }
00148
00149
00150 BOOL LLUICtrl::setTextArg( const LLString& key, const LLStringExplicit& text )
00151 {
00152 return FALSE;
00153 }
00154
00155
00156 BOOL LLUICtrl::setLabelArg( const LLString& key, const LLStringExplicit& text )
00157 {
00158 return FALSE;
00159 }
00160
00161
00162 LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface()
00163 {
00164 return NULL;
00165 }
00166
00167
00168 LLCtrlListInterface* LLUICtrl::getListInterface()
00169 {
00170 return NULL;
00171 }
00172
00173
00174 LLCtrlScrollInterface* LLUICtrl::getScrollInterface()
00175 {
00176 return NULL;
00177 }
00178
00179 BOOL LLUICtrl::hasFocus() const
00180 {
00181 return (gFocusMgr.childHasKeyboardFocus(this));
00182 }
00183
00184 void LLUICtrl::setFocus(BOOL b)
00185 {
00186
00187 if (!getEnabled())
00188 {
00189 return;
00190 }
00191 if( b )
00192 {
00193 if (!hasFocus())
00194 {
00195 gFocusMgr.setKeyboardFocus( this );
00196 }
00197 }
00198 else
00199 {
00200 if( gFocusMgr.childHasKeyboardFocus(this))
00201 {
00202 gFocusMgr.setKeyboardFocus( NULL );
00203 }
00204 }
00205 }
00206
00207 void LLUICtrl::onFocusReceived()
00208 {
00209
00210 LLFocusableElement::onFocusReceived();
00211
00212
00213 LLView* viewp = getParent();
00214 LLUICtrl* last_focus = gFocusMgr.getLastKeyboardFocus();
00215
00216 while (viewp && !viewp->isCtrl())
00217 {
00218 viewp = viewp->getParent();
00219 }
00220
00221
00222 LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
00223 if (ctrlp && (!last_focus || !last_focus->hasAncestor(ctrlp)))
00224 {
00225 ctrlp->onFocusReceived();
00226 }
00227 }
00228
00229 void LLUICtrl::onFocusLost()
00230 {
00231
00232 LLFocusableElement::onFocusLost();
00233
00234
00235 LLView* viewp = getParent();
00236 while (viewp && !viewp->isCtrl())
00237 {
00238 viewp = viewp->getParent();
00239 }
00240
00241
00242 LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
00243
00244 if (ctrlp && !ctrlp->hasFocus())
00245 {
00246 ctrlp->onFocusLost();
00247 }
00248 }
00249
00250 void LLUICtrl::onLostTop()
00251 {
00252 if (mLostTopCallback)
00253 {
00254 mLostTopCallback(this, mCallbackUserData);
00255 }
00256 }
00257
00258
00259
00260 void LLUICtrl::setTabStop( BOOL b )
00261 {
00262 mTabStop = b;
00263 }
00264
00265
00266 BOOL LLUICtrl::hasTabStop() const
00267 {
00268 return mTabStop;
00269 }
00270
00271
00272 BOOL LLUICtrl::acceptsTextInput() const
00273 {
00274 return FALSE;
00275 }
00276
00277
00278 BOOL LLUICtrl::isDirty() const
00279 {
00280 return FALSE;
00281 };
00282
00283
00284 void LLUICtrl::resetDirty()
00285 {
00286 }
00287
00288
00289 void LLUICtrl::onTabInto()
00290 {
00291 }
00292
00293
00294 void LLUICtrl::clear()
00295 {
00296 }
00297
00298
00299 void LLUICtrl::setIsChrome(BOOL is_chrome)
00300 {
00301 mIsChrome = is_chrome;
00302 }
00303
00304
00305 BOOL LLUICtrl::getIsChrome() const
00306 {
00307
00308 LLView* parent_ctrl = getParent();
00309 while(parent_ctrl)
00310 {
00311 if(parent_ctrl->isCtrl())
00312 {
00313 break;
00314 }
00315 parent_ctrl = parent_ctrl->getParent();
00316 }
00317
00318 if(parent_ctrl)
00319 {
00320 return mIsChrome || ((LLUICtrl*)parent_ctrl)->getIsChrome();
00321 }
00322 else
00323 {
00324 return mIsChrome ;
00325 }
00326 }
00327
00328
00329
00330
00331 class CompareByDefaultTabGroup: public LLCompareByTabOrder
00332 {
00333 public:
00334 CompareByDefaultTabGroup(LLView::child_tab_order_t order, S32 default_tab_group):
00335 LLCompareByTabOrder(order),
00336 mDefaultTabGroup(default_tab_group) {}
00337 private:
00338 bool compareTabOrders(const LLView::tab_order_t & a, const LLView::tab_order_t & b) const
00339 {
00340 S32 ag = a.first;
00341 S32 bg = b.first;
00342
00343
00344 if(ag < mDefaultTabGroup && bg >= mDefaultTabGroup) return false;
00345 if(bg < mDefaultTabGroup && ag >= mDefaultTabGroup) return true;
00346 return a < b;
00347 }
00348 S32 mDefaultTabGroup;
00349 };
00350
00351
00352
00353
00354 class LLUICtrl::DefaultTabGroupFirstSorter : public LLQuerySorter, public LLSingleton<DefaultTabGroupFirstSorter>
00355 {
00356 public:
00357 void operator() (LLView * parent, viewList_t &children) const
00358 {
00359 children.sort(CompareByDefaultTabGroup(parent->getCtrlOrder(), parent->getDefaultTabGroup()));
00360 }
00361 };
00362
00363 BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
00364 {
00365
00366 LLCtrlQuery query = getTabOrderQuery();
00367
00368 query.setSorter(DefaultTabGroupFirstSorter::getInstance());
00369 child_list_t result = query(this);
00370 if(result.size() > 0)
00371 {
00372 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
00373 if(!ctrl->hasFocus())
00374 {
00375 ctrl->setFocus(TRUE);
00376 ctrl->onTabInto();
00377 if(focus_flash)
00378 {
00379 gFocusMgr.triggerFocusFlash();
00380 }
00381 }
00382 return TRUE;
00383 }
00384
00385 if(prefer_text_fields)
00386 {
00387 LLCtrlQuery query = getTabOrderQuery();
00388 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00389 child_list_t result = query(this);
00390 if(result.size() > 0)
00391 {
00392 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
00393 if(!ctrl->hasFocus())
00394 {
00395 ctrl->setFocus(TRUE);
00396 ctrl->onTabInto();
00397 gFocusMgr.triggerFocusFlash();
00398 }
00399 return TRUE;
00400 }
00401 }
00402
00403 result = getTabOrderQuery().run(this);
00404 if(result.size() > 0)
00405 {
00406 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
00407 if(!ctrl->hasFocus())
00408 {
00409 ctrl->setFocus(TRUE);
00410 ctrl->onTabInto();
00411 gFocusMgr.triggerFocusFlash();
00412 }
00413 return TRUE;
00414 }
00415 return FALSE;
00416 }
00417
00418 BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields)
00419 {
00420
00421 if(prefer_text_fields)
00422 {
00423 LLCtrlQuery query = getTabOrderQuery();
00424 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00425 child_list_t result = query(this);
00426 if(result.size() > 0)
00427 {
00428 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
00429 if(!ctrl->hasFocus())
00430 {
00431 ctrl->setFocus(TRUE);
00432 ctrl->onTabInto();
00433 gFocusMgr.triggerFocusFlash();
00434 }
00435 return TRUE;
00436 }
00437 }
00438
00439 child_list_t result = getTabOrderQuery().run(this);
00440 if(result.size() > 0)
00441 {
00442 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
00443 if(!ctrl->hasFocus())
00444 {
00445 ctrl->setFocus(TRUE);
00446 ctrl->onTabInto();
00447 gFocusMgr.triggerFocusFlash();
00448 }
00449 return TRUE;
00450 }
00451 return FALSE;
00452 }
00453
00454 BOOL LLUICtrl::focusNextItem(BOOL text_fields_only)
00455 {
00456
00457 LLCtrlQuery query = getTabOrderQuery();
00458 if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly"))
00459 {
00460 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00461 }
00462 child_list_t result = query(this);
00463 return focusNext(result);
00464 }
00465
00466 BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only)
00467 {
00468
00469 LLCtrlQuery query = getTabOrderQuery();
00470 if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly"))
00471 {
00472 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00473 }
00474 child_list_t result = query(this);
00475 return focusPrev(result);
00476 }
00477
00478 LLUICtrl* LLUICtrl::findRootMostFocusRoot() const
00479 {
00480 const LLUICtrl* focus_root = NULL;
00481 const LLUICtrl* next_view = this;
00482 while(next_view)
00483 {
00484 if (next_view->isFocusRoot())
00485 {
00486 focus_root = next_view;
00487 }
00488 next_view = next_view->getParentUICtrl();
00489 }
00490
00491
00492 return const_cast<LLUICtrl*>(focus_root);
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent)
00528 {
00529 BOOL has_tab_stop = hasTabStop();
00530 node->getAttributeBOOL("tab_stop", has_tab_stop);
00531
00532 setTabStop(has_tab_stop);
00533
00534 LLView::initFromXML(node, parent);
00535 }
00536
00537 LLXMLNodePtr LLUICtrl::getXML(bool save_children) const
00538 {
00539 LLXMLNodePtr node = LLView::getXML(save_children);
00540 node->createChild("tab_stop", TRUE)->setBoolValue(hasTabStop());
00541
00542 return node;
00543 }
00544
00545
00546 LLView* LLUICtrl::fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory)
00547 {
00548 LLUICtrl* ctrl = new LLUICtrl();
00549 ctrl->initFromXML(node, parent);
00550 return ctrl;
00551 }
00552
00553
00554
00555
00556 LLPanel* LLUICtrl::getParentPanel() const
00557 {
00558 LLView* parent = getParent();
00559 LLPanel* parent_panel = dynamic_cast<LLPanel*>(parent);
00560 while (!parent_panel)
00561 {
00562 parent = parent->getParent();
00563 }
00564 return (LLPanel*)(parent);
00565 }
00566
00567
00568
00569 LLUICtrl* LLUICtrl::getParentUICtrl() const
00570 {
00571 LLView* parent = getParent();
00572 while (parent)
00573 {
00574 if (parent->isCtrl())
00575 {
00576 return (LLUICtrl*)(parent);
00577 }
00578 else
00579 {
00580 parent = parent->getParent();
00581 }
00582 }
00583 return NULL;
00584 }
00585
00586
00587 void LLUICtrl::setTentative(BOOL b)
00588 {
00589 mTentative = b;
00590 }
00591
00592
00593 BOOL LLUICtrl::getTentative() const
00594 {
00595 return mTentative;
00596 }
00597
00598
00599 void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) )
00600 {
00601 }
00602
00603
00604 void LLUICtrl::setColor(const LLColor4& color)
00605 { }
00606
00607
00608 void LLUICtrl::setMinValue(LLSD min_value)
00609 { }
00610
00611
00612 void LLUICtrl::setMaxValue(LLSD max_value)
00613 { }