lluictrl.cpp

Go to the documentation of this file.
00001 
00033 //#include "llviewerprecompiledheaders.h"
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 //virtual
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 :       // can't make this automatically follow top and left, breaks lots
00106         // of buttons in the UI. JC 7/20/2002
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 ); // calls onCommit()
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 //virtual
00138 BOOL LLUICtrl::isCtrl() const
00139 {
00140         return TRUE;
00141 }
00142 
00143 //virtual
00144 LLSD LLUICtrl::getValue() const
00145 {
00146         return LLSD();
00147 }
00148 
00149 // virtual
00150 BOOL LLUICtrl::setTextArg( const LLString& key, const LLStringExplicit& text ) 
00151 { 
00152         return FALSE; 
00153 }
00154 
00155 // virtual
00156 BOOL LLUICtrl::setLabelArg( const LLString& key, const LLStringExplicit& text ) 
00157 { 
00158         return FALSE; 
00159 }
00160 
00161 // virtual
00162 LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface()     
00163 { 
00164         return NULL; 
00165 }
00166 
00167 // virtual
00168 LLCtrlListInterface* LLUICtrl::getListInterface()                               
00169 { 
00170         return NULL; 
00171 }
00172 
00173 // virtual
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         // focus NEVER goes to ui ctrls that are disabled!
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         // trigger callbacks
00210         LLFocusableElement::onFocusReceived();
00211 
00212         // find first view in hierarchy above new focus that is a LLUICtrl
00213         LLView* viewp = getParent();
00214         LLUICtrl* last_focus = gFocusMgr.getLastKeyboardFocus();
00215 
00216         while (viewp && !viewp->isCtrl()) 
00217         {
00218                 viewp = viewp->getParent();
00219         }
00220 
00221         // and if it has newly gained focus, call onFocusReceived()
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         // trigger callbacks
00232         LLFocusableElement::onFocusLost();
00233 
00234         // find first view in hierarchy above old focus that is a LLUICtrl
00235         LLView* viewp = getParent();
00236         while (viewp && !viewp->isCtrl()) 
00237         {
00238                 viewp = viewp->getParent();
00239         }
00240 
00241         // and if it has just lost focus, call onFocusReceived()
00242         LLUICtrl* ctrlp = static_cast<LLUICtrl*>(viewp);
00243         // hasFocus() includes any descendants
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 // virtual
00260 void LLUICtrl::setTabStop( BOOL b )     
00261 { 
00262         mTabStop = b;
00263 }
00264 
00265 // virtual
00266 BOOL LLUICtrl::hasTabStop() const               
00267 { 
00268         return mTabStop;
00269 }
00270 
00271 // virtual
00272 BOOL LLUICtrl::acceptsTextInput() const
00273 { 
00274         return FALSE; 
00275 }
00276 
00277 //virtual
00278 BOOL LLUICtrl::isDirty() const
00279 {
00280         return FALSE;
00281 };
00282 
00283 //virtual
00284 void LLUICtrl::resetDirty()
00285 {
00286 }
00287 
00288 // virtual
00289 void LLUICtrl::onTabInto()                              
00290 {
00291 }
00292 
00293 // virtual
00294 void LLUICtrl::clear()                                  
00295 {
00296 }
00297 
00298 // virtual
00299 void LLUICtrl::setIsChrome(BOOL is_chrome)
00300 {
00301         mIsChrome = is_chrome; 
00302 }
00303 
00304 // virtual
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 // this comparator uses the crazy disambiguating logic of LLCompareByTabOrder,
00329 // but to switch up the order so that children that have the default tab group come first
00330 // and those that are prior to the default tab group come last
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         /*virtual*/ bool compareTabOrders(const LLView::tab_order_t & a, const LLView::tab_order_t & b) const
00339         {
00340                 S32 ag = a.first; // tab group for a
00341                 S32 bg = b.first; // tab group for b
00342                 // these two ifs have the effect of moving elements prior to the default tab group to the end of the list 
00343                 // (still sorted relative to each other, though)
00344                 if(ag < mDefaultTabGroup && bg >= mDefaultTabGroup) return false;
00345                 if(bg < mDefaultTabGroup && ag >= mDefaultTabGroup) return true;
00346                 return a < b;  // sort correctly if they're both on the same side of the default tab group
00347         }
00348         S32 mDefaultTabGroup;
00349 };
00350 
00351 
00352 // Sorter for plugging into the query.
00353 // I'd have defined it local to the one method that uses it but that broke the VS 05 compiler. -MG
00354 class LLUICtrl::DefaultTabGroupFirstSorter : public LLQuerySorter, public LLSingleton<DefaultTabGroupFirstSorter>
00355 {
00356 public:
00357         /*virtual*/ 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         // try to select default tab group child
00366         LLCtrlQuery query = getTabOrderQuery();
00367         // sort things such that the default tab group is at the front
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         // search for text field first
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         // no text field found, or we don't care about text fields
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         // search for text field first
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         // no text field found, or we don't care about text fields
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         // this assumes that this method is called on the focus root.
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         // this assumes that this method is called on the focus root.
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         // since focus_root could be this, need to cast away const to return
00491         // a non-const result
00492         return const_cast<LLUICtrl*>(focus_root);
00493 }
00494 
00495 
00496 /*
00497 // Don't let the children handle the tool tip.  Handle it here instead.
00498 BOOL LLUICtrl::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
00499 {
00500         BOOL handled = FALSE;
00501         if (getVisible() && pointInView( x, y ) ) 
00502         {
00503                 if( !mToolTipMsg.empty() )
00504                 {
00505                         msg = mToolTipMsg;
00506 
00507                         // Convert rect local to screen coordinates
00508                         localPointToScreen( 
00509                                 0, 0, 
00510                                 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
00511                         localPointToScreen(
00512                                 getRect().getWidth(), getRect().getHeight(),
00513                                 &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
00514 
00515                         handled = TRUE;
00516                 }
00517         }
00518 
00519         if (!handled)
00520         {
00521                 return LLView::handleToolTip(x, y, msg, sticky_rect_screen);
00522         }
00523 
00524         return handled;
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 //static 
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 // *NOTE: If other classes derive from LLPanel, they will need to be
00555 // added to this function.
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 // Skip over any parents that are not LLUICtrl's
00568 //  Used in focus logic since only LLUICtrl elements can have focus
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 // virtual
00587 void LLUICtrl::setTentative(BOOL b)                                                                     
00588 { 
00589         mTentative = b; 
00590 }
00591 
00592 // virtual
00593 BOOL LLUICtrl::getTentative() const                                                                     
00594 { 
00595         return mTentative; 
00596 }
00597 
00598 // virtual
00599 void LLUICtrl::setDoubleClickCallback( void (*cb)(void*) )                              
00600 { 
00601 }
00602 
00603 // virtual
00604 void LLUICtrl::setColor(const LLColor4& color)                                                  
00605 { }
00606 
00607 // virtual
00608 void LLUICtrl::setMinValue(LLSD min_value)                                                              
00609 { }
00610 
00611 // virtual
00612 void LLUICtrl::setMaxValue(LLSD max_value)                                                              
00613 { }

Generated on Fri May 16 08:33:00 2008 for SecondLife by  doxygen 1.5.5