llview.cpp

Go to the documentation of this file.
00001 
00033 #include "linden_common.h"
00034 
00035 #include "llview.h"
00036 
00037 #include <cassert>
00038 #include <boost/tokenizer.hpp>
00039 
00040 #include "llevent.h"
00041 #include "llfontgl.h"
00042 #include "llfocusmgr.h"
00043 #include "llgl.h"
00044 #include "llglheaders.h"
00045 #include "llrect.h"
00046 #include "llstl.h"
00047 #include "llui.h"       // colors saved settings
00048 #include "lluictrl.h"
00049 #include "llwindow.h"
00050 #include "v3color.h"
00051 
00052 
00053 BOOL    LLView::sDebugRects = FALSE;
00054 BOOL    LLView::sDebugKeys = FALSE;
00055 S32             LLView::sDepth = 0;
00056 BOOL    LLView::sDebugMouseHandling = FALSE;
00057 LLString LLView::sMouseHandlerMessage;
00058 S32     LLView::sSelectID = GL_NAME_UI_RESERVED;
00059 BOOL    LLView::sEditingUI = FALSE;
00060 BOOL    LLView::sForceReshape = FALSE;
00061 LLView* LLView::sEditingUIView = NULL;
00062 S32             LLView::sLastLeftXML = S32_MIN;
00063 S32             LLView::sLastBottomXML = S32_MIN;
00064 std::map<LLViewHandle,LLView*> LLView::sViewHandleMap;
00065 
00066 S32             LLViewHandle::sNextID = 0;
00067 LLViewHandle LLViewHandle::sDeadHandle;
00068 
00069 #if LL_DEBUG
00070 BOOL LLView::sIsDrawing = FALSE;
00071 #endif
00072 
00073 //static
00074 LLView* LLView::getViewByHandle(LLViewHandle handle)
00075 {
00076         if (handle == LLViewHandle::sDeadHandle)
00077         {
00078                 return NULL;
00079         }
00080         std::map<LLViewHandle,LLView*>::iterator iter = sViewHandleMap.find(handle);
00081         if (iter != sViewHandleMap.end())
00082         {
00083                 return iter->second;
00084         }
00085         else
00086         {
00087                 return NULL;
00088         }
00089 }
00090 
00091 //static
00092 BOOL LLView::deleteViewByHandle(LLViewHandle handle)
00093 {
00094         std::map<LLViewHandle,LLView*>::iterator iter = sViewHandleMap.find(handle);
00095         if (iter != sViewHandleMap.end())
00096         {
00097                 delete iter->second; // will remove from map
00098                 return TRUE;
00099         }
00100         else
00101         {
00102                 return FALSE;
00103         }
00104 }
00105 
00106 LLView::LLView() :
00107         mParentView(NULL),
00108         mReshapeFlags(FOLLOWS_NONE),
00109         mDefaultTabGroup(0),
00110         mEnabled(TRUE),
00111         mMouseOpaque(TRUE),
00112         mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
00113         mSaveToXML(TRUE),
00114         mIsFocusRoot(FALSE),
00115         mLastVisible(TRUE),
00116         mSpanChildren(FALSE),
00117         mVisible(TRUE),
00118         mHidden(FALSE),
00119         mNextInsertionOrdinal(0)
00120 {
00121         mViewHandle.init();
00122         sViewHandleMap[mViewHandle] = this;
00123 }
00124 
00125 LLView::LLView(const LLString& name, BOOL mouse_opaque) :
00126         mParentView(NULL),
00127         mName(name),
00128         mReshapeFlags(FOLLOWS_NONE),
00129         mDefaultTabGroup(0),
00130         mEnabled(TRUE),
00131         mMouseOpaque(mouse_opaque),
00132         mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
00133         mSaveToXML(TRUE),
00134         mIsFocusRoot(FALSE),
00135         mLastVisible(TRUE),
00136         mSpanChildren(FALSE),
00137         mVisible(TRUE),
00138         mHidden(FALSE),
00139         mNextInsertionOrdinal(0)
00140 {
00141         mViewHandle.init();
00142         sViewHandleMap[mViewHandle] = this;
00143 }
00144 
00145 
00146 LLView::LLView(
00147         const LLString& name, const LLRect& rect, BOOL mouse_opaque, U32 reshape) :
00148         mParentView(NULL),
00149         mName(name),
00150         mRect(rect),
00151         mReshapeFlags(reshape),
00152         mDefaultTabGroup(0),
00153         mEnabled(TRUE),
00154         mMouseOpaque(mouse_opaque),
00155         mSoundFlags(MOUSE_UP), // default to only make sound on mouse up
00156         mSaveToXML(TRUE),
00157         mIsFocusRoot(FALSE),
00158         mLastVisible(TRUE),
00159         mSpanChildren(FALSE),
00160         mVisible(TRUE),
00161         mHidden(FALSE),
00162         mNextInsertionOrdinal(0)
00163 {
00164         mViewHandle.init();
00165         sViewHandleMap[mViewHandle] = this;
00166 }
00167 
00168 
00169 LLView::~LLView()
00170 {
00171         //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl;
00172 //      llassert(LLView::sIsDrawing == FALSE);
00173         if( gFocusMgr.getKeyboardFocus() == this )
00174         {
00175                 llwarns << "View holding keyboard focus deleted: " << getName() << ".  Keyboard focus removed." << llendl;
00176                 gFocusMgr.removeKeyboardFocusWithoutCallback( this );
00177         }
00178 
00179         if( hasMouseCapture() )
00180         {
00181                 llwarns << "View holding mouse capture deleted: " << getName() << ".  Mouse capture removed." << llendl;
00182                 gFocusMgr.removeMouseCaptureWithoutCallback( this );
00183         }
00184 
00185         sViewHandleMap.erase(mViewHandle);
00186 
00187         deleteAllChildren();
00188 
00189         if (mParentView != NULL)
00190         {
00191                 mParentView->removeChild(this);
00192         }
00193 
00194         dispatch_list_t::iterator itor;
00195         for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
00196         {
00197                 (*itor).second->clearDispatchers();
00198         }
00199 
00200         std::for_each(mFloaterControls.begin(), mFloaterControls.end(),
00201                                   DeletePairedPointer());
00202 }
00203 
00204 // virtual
00205 BOOL LLView::isView()
00206 {
00207         return TRUE;
00208 }
00209 
00210 // virtual
00211 BOOL LLView::isCtrl() const
00212 {
00213         return FALSE;
00214 }
00215 
00216 // virtual
00217 BOOL LLView::isPanel()
00218 {
00219         return FALSE;
00220 }
00221 
00222 void LLView::setMouseOpaque(BOOL b)
00223 {
00224         mMouseOpaque = b;
00225 }
00226 
00227 void LLView::setToolTip(const LLString& msg)
00228 {
00229         mToolTipMsg = msg;
00230 }
00231 
00232 // virtual
00233 void LLView::setRect(const LLRect& rect)
00234 {
00235         mRect = rect;
00236 }
00237 
00238 
00239 void LLView::setFollows(U32 flags)                      
00240 {
00241         mReshapeFlags = flags;
00242 }
00243 
00244 void LLView::setFollowsNone()                           
00245 {
00246         mReshapeFlags = FOLLOWS_NONE; 
00247 }
00248 
00249 void LLView::setFollowsLeft()                           
00250 {
00251         mReshapeFlags |= FOLLOWS_LEFT; 
00252 }
00253 
00254 void LLView::setFollowsTop()                                    
00255 {
00256         mReshapeFlags |= FOLLOWS_TOP; 
00257 }
00258 
00259 void LLView::setFollowsRight()                          
00260 {
00261         mReshapeFlags |= FOLLOWS_RIGHT;
00262 }
00263 
00264 void LLView::setFollowsBottom()                         
00265 {
00266         mReshapeFlags |= FOLLOWS_BOTTOM;
00267 }
00268 
00269 void LLView::setFollowsAll()                                    
00270 {
00271         mReshapeFlags |= FOLLOWS_ALL;
00272 }
00273 
00274 void LLView::setSoundFlags(U8 flags)         
00275 {
00276         mSoundFlags = flags;
00277 }
00278 
00279 void LLView::setName(LLString name)                     
00280 {
00281         mName = name;
00282 }
00283 
00284 void LLView::setSpanChildren( BOOL span_children ) 
00285 {
00286         mSpanChildren = span_children; updateRect();
00287 }
00288 
00289 const LLString& LLView::getToolTip()
00290 {
00291         return mToolTipMsg;
00292 }
00293 
00294 // virtual
00295 const LLString& LLView::getName() const
00296 {
00297         static const LLString unnamed("(no name)");
00298         return mName.empty() ? unnamed : mName;
00299 }
00300 
00301 void LLView::sendChildToFront(LLView* child)
00302 {
00303         if (child->mParentView == this) 
00304         {
00305                 mChildList.remove( child );
00306                 mChildList.push_front(child);
00307         }
00308 }
00309 
00310 void LLView::sendChildToBack(LLView* child)
00311 {
00312         if (child->mParentView == this) 
00313         {
00314                 mChildList.remove( child );
00315                 mChildList.push_back(child);
00316         }
00317 }
00318 
00319 void LLView::moveChildToFrontOfTabGroup(LLUICtrl* child)
00320 {
00321         if(mCtrlOrder.find(child) != mCtrlOrder.end())
00322         {
00323                 mCtrlOrder[child].second = -1 * mNextInsertionOrdinal++;
00324         }
00325 }
00326 
00327 void LLView::addChild(LLView* child, S32 tab_group)
00328 {
00329         if (mParentView == child) 
00330         {
00331                 llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
00332         }
00333         // remove from current parent
00334         if (child->mParentView) 
00335         {
00336                 child->mParentView->removeChild(child);
00337         }
00338 
00339         // add to front of child list, as normal
00340         mChildList.push_front(child);
00341 
00342         // add to ctrl list if is LLUICtrl
00343         if (child->isCtrl())
00344         {
00345                 // controls are stored in reverse order from render order
00346                 addCtrlAtEnd((LLUICtrl*) child, tab_group);
00347         }
00348 
00349         child->mParentView = this;
00350         updateRect();
00351 }
00352 
00353 
00354 void LLView::addChildAtEnd(LLView* child, S32 tab_group)
00355 {
00356         if (mParentView == child) 
00357         {
00358                 llerrs << "Adding view " << child->getName() << " as child of itself" << llendl;
00359         }
00360         // remove from current parent
00361         if (child->mParentView) 
00362         {
00363                 child->mParentView->removeChild(child);
00364         }
00365 
00366         // add to back of child list
00367         mChildList.push_back(child);
00368 
00369         // add to ctrl list if is LLUICtrl
00370         if (child->isCtrl())
00371         {
00372                 // controls are stored in reverse order from render order
00373                 addCtrl((LLUICtrl*) child, tab_group);
00374         }
00375         
00376         child->mParentView = this;
00377         updateRect();
00378 }
00379 
00380 // remove the specified child from the view, and set it's parent to NULL.
00381 void LLView::removeChild(LLView* child, BOOL deleteIt)
00382 {
00383         if (child->mParentView == this) 
00384         {
00385                 mChildList.remove( child );
00386                 child->mParentView = NULL;
00387                 if (child->isCtrl())
00388                 {
00389                         removeCtrl((LLUICtrl*)child);
00390                 }
00391                 if (deleteIt)
00392                 {
00393                         delete child;
00394                 }
00395         }
00396         else
00397         {
00398                 llerrs << "LLView::removeChild called with non-child" << llendl;
00399         }
00400 }
00401 
00402 void LLView::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
00403 {
00404         mCtrlOrder.insert(tab_order_pair_t(ctrl,
00405                                                                 tab_order_t(tab_group, mNextInsertionOrdinal++)));
00406 }
00407 
00408 void LLView::addCtrl( LLUICtrl* ctrl, S32 tab_group)
00409 {
00410         // add to front of list by using negative ordinal, which monotonically increases
00411         mCtrlOrder.insert(tab_order_pair_t(ctrl,
00412                                                                 tab_order_t(tab_group, -1 * mNextInsertionOrdinal++)));
00413 }
00414 
00415 void LLView::removeCtrl(LLUICtrl* ctrl)
00416 {
00417         child_tab_order_t::iterator found = mCtrlOrder.find(ctrl);
00418         if(found != mCtrlOrder.end())
00419         {
00420                 mCtrlOrder.erase(found);
00421         }
00422 }
00423 
00424 S32 LLView::getDefaultTabGroup() const { return mDefaultTabGroup; }
00425 
00426 LLView::ctrl_list_t LLView::getCtrlList() const
00427 {
00428         ctrl_list_t controls;
00429         for(child_list_const_iter_t iter = mChildList.begin();
00430                 iter != mChildList.end();
00431                 iter++)
00432         {
00433                 if((*iter)->isCtrl())
00434                 {
00435                         controls.push_back(static_cast<LLUICtrl*>(*iter));
00436                 }
00437         }
00438         return controls;
00439 }
00440 
00441 LLView::ctrl_list_t LLView::getCtrlListSorted() const
00442 {
00443         ctrl_list_t controls = getCtrlList();
00444         std::sort(controls.begin(), controls.end(), LLCompareByTabOrder(mCtrlOrder));
00445         return controls;
00446 }
00447 
00448 LLCompareByTabOrder::LLCompareByTabOrder(LLView::child_tab_order_t order): mTabOrder(order) {}
00449 
00450 bool LLCompareByTabOrder::compareTabOrders(const LLView::tab_order_t & a, const LLView::tab_order_t & b) const
00451 {
00452         return a < b;
00453 }
00454 
00455 // This method compares two LLViews by the tab order specified in the comparator object.  The
00456 // code for this is a little convoluted because each argument can have four states:
00457 // 1) not a control, 2) a control but not in the tab order, 3) a control in the tab order, 4) null
00458 bool LLCompareByTabOrder::operator() (const LLView* const a, const LLView* const b) const
00459 {
00460         S32 a_score = 0, b_score = 0;
00461         if(a) a_score--;
00462         if(b) b_score--;
00463         if(a && a->isCtrl()) a_score--;
00464         if(b && b->isCtrl()) b_score--;
00465         if(a_score == -2 && b_score == -2)
00466         {
00467                 const LLUICtrl * const a_ctrl = static_cast<const LLUICtrl*>(a);
00468                 const LLUICtrl * const b_ctrl = static_cast<const LLUICtrl*>(b);
00469                 LLView::child_tab_order_const_iter_t a_found = mTabOrder.find(a_ctrl), b_found = mTabOrder.find(b_ctrl);
00470                 if(a_found != mTabOrder.end()) a_score--;
00471                 if(b_found != mTabOrder.end()) b_score--;
00472                 if(a_score == -3 && b_score == -3)
00473                 {
00474                         // whew!  Once we're in here, they're both in the tab order, and we can compare based on that
00475                         return compareTabOrders(a_found->second, b_found->second);
00476                 }
00477         }
00478         return (a_score == b_score) ? a < b : a_score < b_score;
00479 }
00480 
00481 BOOL LLView::isInVisibleChain() const
00482 {
00483         const LLView* cur_view = this;
00484         while(cur_view)
00485         {
00486                 if (!cur_view->getVisible())
00487                 {
00488                         return FALSE;
00489                 }
00490                 cur_view = cur_view->getParent();
00491         }
00492         return TRUE;
00493 }
00494 
00495 BOOL LLView::isInEnabledChain() const
00496 {
00497         const LLView* cur_view = this;
00498         while(cur_view)
00499         {
00500                 if (!cur_view->getEnabled())
00501                 {
00502                         return FALSE;
00503                 }
00504                 cur_view = cur_view->getParent();
00505         }
00506         return TRUE;
00507 }
00508 
00509 BOOL LLView::isFocusRoot() const
00510 {
00511         return mIsFocusRoot;
00512 }
00513 
00514 LLView* LLView::findRootMostFocusRoot() 
00515 {
00516         LLView* focus_root = NULL;
00517         LLView* next_view = this;
00518         while(next_view)
00519         {
00520                 if (next_view->isFocusRoot())
00521                 {
00522                         focus_root = next_view;
00523                 }
00524                 next_view = next_view->getParent();
00525         }
00526         return focus_root;
00527 }
00528 
00529 BOOL LLView::canFocusChildren() const
00530 {
00531         return TRUE;
00532 }
00533 
00534 BOOL LLView::focusNextRoot()
00535 {
00536         LLView::child_list_t result = LLView::getFocusRootsQuery().run(this);
00537         return LLView::focusNext(result);
00538 }
00539 
00540 BOOL LLView::focusPrevRoot()
00541 {
00542         LLView::child_list_t result = LLView::getFocusRootsQuery().run(this);
00543         return LLView::focusPrev(result);
00544 }
00545 
00546 BOOL LLView::focusNextItem(BOOL text_fields_only)
00547 {
00548         // this assumes that this method is called on the focus root.
00549         LLCtrlQuery query = LLView::getTabOrderQuery();
00550         if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly"))
00551         {
00552                 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00553         }
00554         LLView::child_list_t result = query(this);
00555         return LLView::focusNext(result);
00556 }
00557 
00558 BOOL LLView::focusPrevItem(BOOL text_fields_only)
00559 {
00560         // this assumes that this method is called on the focus root.
00561         LLCtrlQuery query = LLView::getTabOrderQuery();
00562         if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly"))
00563         {
00564                 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00565         }
00566         LLView::child_list_t result = query(this);
00567         return LLView::focusPrev(result);
00568 }
00569 
00570 
00571 // static
00572 BOOL LLView::focusNext(LLView::child_list_t & result)
00573 {
00574         LLView::child_list_iter_t focused = result.end();
00575         for(LLView::child_list_iter_t iter = result.begin();
00576                 iter != result.end();
00577                 ++iter)
00578         {
00579                 if(gFocusMgr.childHasKeyboardFocus(*iter))
00580                 {
00581                         focused = iter;
00582                         break;
00583                 }
00584         }
00585         LLView::child_list_iter_t next = focused;
00586         next = (next == result.end()) ? result.begin() : ++next;
00587         while(next != focused)
00588         {
00589                 // wrap around to beginning if necessary
00590                 if(next == result.end())
00591                 {
00592                         next = result.begin();
00593                 }
00594                 if((*next)->isCtrl())
00595                 {
00596                         LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next);
00597                         ctrl->setFocus(TRUE);
00598                         ctrl->onTabInto();  
00599                         gFocusMgr.triggerFocusFlash();
00600                         return TRUE;
00601                 }
00602                 ++next;
00603         }
00604         return FALSE;
00605 }
00606 
00607 // static
00608 BOOL LLView::focusPrev(LLView::child_list_t & result)
00609 {
00610         LLView::child_list_reverse_iter_t focused = result.rend();
00611         for(LLView::child_list_reverse_iter_t iter = result.rbegin();
00612                 iter != result.rend();
00613                 ++iter)
00614         {
00615                 if(gFocusMgr.childHasKeyboardFocus(*iter))
00616                 {
00617                         focused = iter;
00618                         break;
00619                 }
00620         }
00621         LLView::child_list_reverse_iter_t next = focused;
00622         next = (next == result.rend()) ? result.rbegin() : ++next;
00623         while(next != focused)
00624         {
00625                 // wrap around to beginning if necessary
00626                 if(next == result.rend())
00627                 {
00628                         next = result.rbegin();
00629                 }
00630                 if((*next)->isCtrl())
00631                 {
00632                         LLUICtrl * ctrl = static_cast<LLUICtrl*>(*next);
00633                         if (!ctrl->hasFocus())
00634                         {
00635                                 ctrl->setFocus(TRUE);
00636                                 ctrl->onTabInto();  
00637                                 gFocusMgr.triggerFocusFlash();
00638                         }
00639                         return TRUE;
00640                 }
00641                 ++next;
00642         }
00643         return FALSE;
00644 }
00645 
00646 BOOL LLView::focusFirstItem(BOOL prefer_text_fields)
00647 {
00648         // search for text field first
00649         if(prefer_text_fields)
00650         {
00651                 LLCtrlQuery query = LLView::getTabOrderQuery();
00652                 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00653                 LLView::child_list_t result = query(this);
00654                 if(result.size() > 0)
00655                 {
00656                         LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
00657                         if(!ctrl->hasFocus())
00658                         {
00659                                 ctrl->setFocus(TRUE);
00660                                 ctrl->onTabInto();  
00661                                 gFocusMgr.triggerFocusFlash();
00662                         }
00663                         return TRUE;
00664                 }
00665         }
00666         // no text field found, or we don't care about text fields
00667         LLView::child_list_t result = LLView::getTabOrderQuery().run(this);
00668         if(result.size() > 0)
00669         {
00670                 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
00671                 if(!ctrl->hasFocus())
00672                 {
00673                         ctrl->setFocus(TRUE);
00674                         ctrl->onTabInto();  
00675                         gFocusMgr.triggerFocusFlash();
00676                 }
00677                 return TRUE;
00678         }       
00679         return FALSE;
00680 }
00681 
00682 BOOL LLView::focusLastItem(BOOL prefer_text_fields)
00683 {
00684         // search for text field first
00685         if(prefer_text_fields)
00686         {
00687                 LLCtrlQuery query = LLView::getTabOrderQuery();
00688                 query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
00689                 LLView::child_list_t result = query(this);
00690                 if(result.size() > 0)
00691                 {
00692                         LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
00693                         if(!ctrl->hasFocus())
00694                         {
00695                                 ctrl->setFocus(TRUE);
00696                                 ctrl->onTabInto();  
00697                                 gFocusMgr.triggerFocusFlash();
00698                         }
00699                         return TRUE;
00700                 }
00701         }
00702         // no text field found, or we don't care about text fields
00703         LLView::child_list_t result = LLView::getTabOrderQuery().run(this);
00704         if(result.size() > 0)
00705         {
00706                 LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
00707                 if(!ctrl->hasFocus())
00708                 {
00709                         ctrl->setFocus(TRUE);
00710                         ctrl->onTabInto();  
00711                         gFocusMgr.triggerFocusFlash();
00712                 }
00713                 return TRUE;
00714         }       
00715         return FALSE;
00716 }
00717 
00718 
00719 
00720 // delete all children. Override this function if you need to
00721 // perform any extra clean up such as cached pointers to selected
00722 // children, etc.
00723 void LLView::deleteAllChildren()
00724 {
00725         // clear out the control ordering
00726         mCtrlOrder.clear();
00727 
00728         while (!mChildList.empty())
00729         {
00730                 LLView* viewp = mChildList.front();
00731                 delete viewp; // will remove the child from mChildList
00732         }
00733 }
00734 
00735 void LLView::setAllChildrenEnabled(BOOL b)
00736 {
00737         for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
00738         {
00739                 LLView* viewp = *child_it;
00740                 viewp->setEnabled(b);
00741         }
00742 }
00743 
00744 // virtual
00745 void LLView::setTentative(BOOL b)
00746 {
00747 }
00748 
00749 // virtual
00750 BOOL LLView::getTentative() const
00751 {
00752         return FALSE;
00753 }
00754 
00755 // virtual
00756 void LLView::setEnabled(BOOL enabled)
00757 {
00758         mEnabled = enabled;
00759 }
00760 
00761 // virtual
00762 void LLView::setVisible(BOOL visible)
00763 {
00764         if ( mVisible != visible )
00765         {
00766                 if( !visible && (gFocusMgr.getTopCtrl() == this) )
00767                 {
00768                         gFocusMgr.setTopCtrl( NULL );
00769                 }
00770 
00771                 mVisible = visible;
00772 
00773                 // notify children of visibility change if root, or part of visible hierarchy
00774                 if (!getParent() || getParent()->isInVisibleChain())
00775                 {
00776                         // tell all children of this view that the visibility may have changed
00777                         onVisibilityChange( visible );
00778                 }
00779         }
00780 }
00781 
00782 // virtual
00783 void LLView::setHidden(BOOL hidden)
00784 {
00785         mHidden = hidden;
00786 }
00787 
00788 // virtual
00789 BOOL LLView::setLabelArg(const LLString& key, const LLStringExplicit& text)
00790 {
00791         return FALSE;
00792 }
00793 
00794 // virtual
00795 void LLView::onVisibilityChange ( BOOL new_visibility )
00796 {
00797         for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
00798         {
00799                 LLView* viewp = *child_it;
00800                 // only views that are themselves visible will have their overall visibility affected by their ancestors
00801                 if (viewp->getVisible())
00802                 {
00803                         viewp->onVisibilityChange ( new_visibility );
00804                 }
00805         }
00806 }
00807 
00808 // virtual
00809 void LLView::translate(S32 x, S32 y)
00810 {
00811         mRect.translate(x, y);
00812 }
00813 
00814 // virtual
00815 BOOL LLView::canSnapTo(LLView* other_view)
00816 {
00817         return other_view->getVisible();
00818 }
00819 
00820 // virtual
00821 void LLView::snappedTo(LLView* snap_view)
00822 {
00823 }
00824 
00825 BOOL LLView::handleHover(S32 x, S32 y, MASK mask)
00826 {
00827         BOOL handled = childrenHandleHover( x, y, mask ) != NULL;
00828         if( !handled && mMouseOpaque && pointInView( x, y ) )
00829         {
00830                 LLUI::sWindow->setCursor(UI_CURSOR_ARROW);
00831                 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl;
00832                 handled = TRUE;
00833         }
00834 
00835         return handled;
00836 }
00837 
00838 LLString LLView::getShowNamesToolTip()
00839 {
00840         LLView* view = getParent();
00841         LLString name;
00842         LLString tool_tip = mName;
00843 
00844         while (view)
00845         {
00846                 name = view->getName();
00847 
00848                 if (name == "root") break;
00849 
00850                 if (view->getToolTip().find(".xml") != LLString::npos)
00851                 {
00852                         tool_tip = view->getToolTip() + "/" +  tool_tip;
00853                         break;
00854                 }
00855                 else
00856                 {
00857                         tool_tip = view->getName() + "/" +  tool_tip;
00858                 }
00859 
00860                 view = view->getParent();
00861         }
00862 
00863         return "/" + tool_tip;
00864 }
00865 
00866 
00867 BOOL LLView::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
00868 {
00869         BOOL handled = FALSE;
00870 
00871     LLString tool_tip;
00872 
00873         if ( getVisible() && getEnabled())
00874         {
00875                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
00876                 {
00877                         LLView* viewp = *child_it;
00878                         S32 local_x = x - viewp->mRect.mLeft;
00879                         S32 local_y = y - viewp->mRect.mBottom;
00880                         if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
00881                         {
00882                                 handled = TRUE;
00883                                 break;
00884                         }
00885                 }
00886 
00887                 if (LLUI::sShowXUINames && (mToolTipMsg.find(".xml", 0) == LLString::npos) && 
00888                         (mName.find("Drag", 0) == LLString::npos))
00889                 {
00890                         tool_tip = getShowNamesToolTip();
00891                 }
00892                 else
00893                 {
00894                         tool_tip = mToolTipMsg;
00895                 }
00896                 
00897 
00898 
00899                 BOOL showNamesTextBox = LLUI::sShowXUINames && (getWidgetType() == WIDGET_TYPE_TEXT_BOX);
00900 
00901                 if( !handled && (mMouseOpaque || showNamesTextBox) && pointInView( x, y ) && !tool_tip.empty())
00902                 {
00903 
00904                         msg = tool_tip;
00905 
00906                         // Convert rect local to screen coordinates
00907                         localPointToScreen(
00908                                 0, 0,
00909                                 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
00910                         localPointToScreen(
00911                                 mRect.getWidth(), mRect.getHeight(),
00912                                 &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
00913                         
00914                         handled = TRUE;
00915                 }
00916         }
00917 
00918         return handled;
00919 }
00920 
00921 BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
00922 {
00923         BOOL handled = FALSE;
00924 
00925         if( called_from_parent )
00926         {
00927                 // Downward traversal
00928                 if (getVisible() && mEnabled)
00929                 {
00930                         handled = childrenHandleKey( key, mask ) != NULL;
00931                 }
00932         }
00933 
00934         // JC: Must pass to disabled views, since they could have
00935         // keyboard focus, which requires the escape key to exit.
00936         if (!handled && getVisible())
00937         {
00938                 handled = handleKeyHere( key, mask, called_from_parent );
00939                 if (handled && LLView::sDebugKeys)
00940                 {
00941                         llinfos << "Key handled by " << getName() << llendl;
00942                 }
00943         }
00944 
00945         if( !handled && !called_from_parent)
00946         {
00947                 if (mIsFocusRoot)
00948                 {
00949                         // stop processing at focus root
00950                         handled = FALSE;
00951                 }
00952                 else if (mParentView)
00953                 {
00954                         // Upward traversal
00955                         handled = mParentView->handleKey( key, mask, FALSE );
00956                 }
00957         }
00958         return handled;
00959 }
00960 
00961 // Called from handleKey()
00962 // Handles key in this object.  Checking parents and children happens in handleKey()
00963 BOOL LLView::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
00964 {
00965         return FALSE;
00966 }
00967 
00968 BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
00969 {
00970         BOOL handled = FALSE;
00971 
00972         if( called_from_parent )
00973         {
00974                 // Downward traversal
00975                 if (getVisible() && mEnabled)
00976                 {
00977                         handled = childrenHandleUnicodeChar( uni_char ) != NULL;
00978                 }
00979         }
00980 
00981         if (!handled && getVisible())
00982         {
00983                 handled = handleUnicodeCharHere(uni_char, called_from_parent);
00984                 if (handled && LLView::sDebugKeys)
00985                 {
00986                         llinfos << "Unicode key handled by " << getName() << llendl;
00987                 }
00988         }
00989 
00990 
00991         if (!handled && !called_from_parent)
00992         {
00993                 if (mIsFocusRoot)
00994                 {
00995                         // stop processing at focus root
00996                         handled = FALSE;
00997                 }
00998                 else if(mParentView)
00999                 {
01000                         // Upward traversal
01001                         handled = mParentView->handleUnicodeChar(uni_char, FALSE);
01002                 }
01003         }
01004 
01005         return handled;
01006 }
01007 
01008 
01009 BOOL LLView::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent )
01010 {
01011         return FALSE;
01012 }
01013 
01014 
01015 BOOL LLView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
01016                                                            EDragAndDropType cargo_type, void* cargo_data,
01017                                                            EAcceptance* accept,
01018                                                            LLString& tooltip_msg)
01019 {
01020         // CRO this is an experiment to allow drag and drop into object inventory based on the DragAndDrop tool's permissions rather than the parent
01021         BOOL handled = childrenHandleDragAndDrop( x, y, mask, drop,
01022                                                                                         cargo_type,
01023                                                                                         cargo_data,
01024                                                                                         accept,
01025                                                                                         tooltip_msg) != NULL;
01026         if( !handled && mMouseOpaque )
01027         {
01028                 *accept = ACCEPT_NO;
01029                 handled = TRUE;
01030                 lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLView " << getName() << llendl;
01031         }
01032 
01033         return handled;
01034 }
01035 
01036 LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask,
01037                                                                            BOOL drop,
01038                                                                            EDragAndDropType cargo_type,
01039                                                                            void* cargo_data,
01040                                                                            EAcceptance* accept,
01041                                                                            LLString& tooltip_msg)
01042 {
01043         LLView* handled_view = FALSE;
01044         // CRO this is an experiment to allow drag and drop into object inventory based on the DragAndDrop tool's permissions rather than the parent
01045         if( getVisible() )
01046 //      if( getVisible() && mEnabled )
01047         {
01048                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01049                 {
01050                         LLView* viewp = *child_it;
01051                         S32 local_x = x - viewp->mRect.mLeft;
01052                         S32 local_y = y - viewp->mRect.mBottom;
01053                         if( viewp->pointInView(local_x, local_y) && 
01054                                 viewp->getVisible() &&
01055                                 viewp->mEnabled &&
01056                                 viewp->handleDragAndDrop(local_x, local_y, mask, drop,
01057                                                                                  cargo_type,
01058                                                                                  cargo_data,
01059                                                                                  accept,
01060                                                                                  tooltip_msg))
01061                         {
01062                                 handled_view = viewp;
01063                                 break;
01064                         }
01065                 }
01066         }
01067         return handled_view;
01068 }
01069 
01070 void LLView::onMouseCaptureLost()
01071 {
01072 }
01073 
01074 BOOL LLView::hasMouseCapture()
01075 { 
01076         return gFocusMgr.getMouseCapture() == this; 
01077 }
01078 
01079 BOOL LLView::handleMouseUp(S32 x, S32 y, MASK mask)
01080 {
01081         BOOL handled = childrenHandleMouseUp( x, y, mask ) != NULL;
01082         if( !handled && mMouseOpaque )
01083         {
01084                 handled = TRUE;
01085         }
01086         return handled;
01087 }
01088 
01089 BOOL LLView::handleMouseDown(S32 x, S32 y, MASK mask)
01090 {
01091         LLView* handled_view = childrenHandleMouseDown( x, y, mask );
01092         BOOL handled = (handled_view != NULL);
01093         if( !handled && mMouseOpaque )
01094         {
01095                 handled = TRUE;
01096                 handled_view = this;
01097         }
01098 
01099         // HACK If we're editing UI, select the leaf view that ate the click.
01100         if (sEditingUI && handled_view)
01101         {
01102                 // need to find leaf views, big hack
01103                 EWidgetType type = handled_view->getWidgetType();
01104                 if (type == WIDGET_TYPE_BUTTON
01105                         || type == WIDGET_TYPE_LINE_EDITOR
01106                         || type == WIDGET_TYPE_TEXT_EDITOR
01107                         || type == WIDGET_TYPE_TEXT_BOX)
01108                 {
01109                         sEditingUIView = handled_view;
01110                 }
01111         }
01112 
01113         return handled;
01114 }
01115 
01116 BOOL LLView::handleDoubleClick(S32 x, S32 y, MASK mask)
01117 {
01118         BOOL handled = childrenHandleDoubleClick( x, y, mask ) != NULL;
01119         if( !handled && mMouseOpaque )
01120         {
01121                 handleMouseDown(x, y, mask);
01122                 handled = TRUE;
01123         }
01124         return handled;
01125 }
01126 
01127 BOOL LLView::handleScrollWheel(S32 x, S32 y, S32 clicks)
01128 {
01129         BOOL handled = FALSE;
01130         if( getVisible() && mEnabled )
01131         {
01132                 handled = childrenHandleScrollWheel( x, y, clicks ) != NULL;
01133                 if( !handled && mMouseOpaque )
01134                 {
01135                         handled = TRUE;
01136                 }
01137         }
01138         return handled;
01139 }
01140 
01141 BOOL LLView::handleRightMouseDown(S32 x, S32 y, MASK mask)
01142 {
01143         BOOL handled = childrenHandleRightMouseDown( x, y, mask ) != NULL;
01144         if( !handled && mMouseOpaque )
01145         {
01146                 handled = TRUE;
01147         }
01148         return handled;
01149 }
01150 
01151 BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask)
01152 {
01153         BOOL handled = childrenHandleRightMouseUp( x, y, mask ) != NULL;
01154         if( !handled && mMouseOpaque )
01155         {
01156                 handled = TRUE;
01157         }
01158         return handled;
01159 }
01160 
01161 LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks)
01162 {
01163         LLView* handled_view = NULL;
01164         if (getVisible() && mEnabled )
01165         {
01166                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01167                 {
01168                         LLView* viewp = *child_it;
01169                         S32 local_x = x - viewp->mRect.mLeft;
01170                         S32 local_y = y - viewp->mRect.mBottom;
01171                         if (viewp->pointInView(local_x, local_y) && 
01172                                 viewp->handleScrollWheel( local_x, local_y, clicks ))
01173                         {
01174                                 if (sDebugMouseHandling)
01175                                 {
01176                                         sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01177                                 }
01178 
01179                                 handled_view = viewp;
01180                                 break;
01181                         }
01182                 }
01183         }
01184         return handled_view;
01185 }
01186 
01187 LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask)
01188 {
01189         LLView* handled_view = NULL;
01190         if (getVisible() && mEnabled )
01191         {
01192                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01193                 {
01194                         LLView* viewp = *child_it;
01195                         S32 local_x = x - viewp->mRect.mLeft;
01196                         S32 local_y = y - viewp->mRect.mBottom;
01197                         if(viewp->pointInView(local_x, local_y) &&
01198                                 viewp->getVisible() &&
01199                                 viewp->getEnabled() &&
01200                                 viewp->handleHover(local_x, local_y, mask) )
01201                         {
01202                                 if (sDebugMouseHandling)
01203                                 {
01204                                         sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01205                                 }
01206 
01207                                 handled_view = viewp;
01208                                 break;
01209                         }
01210                 }
01211         }
01212         return handled_view;
01213 }
01214 
01215 // Called during downward traversal
01216 LLView* LLView::childrenHandleKey(KEY key, MASK mask)
01217 {
01218         LLView* handled_view = NULL;
01219 
01220         if ( getVisible() && mEnabled )
01221         {
01222                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01223                 {
01224                         LLView* viewp = *child_it;
01225                         if (viewp->handleKey(key, mask, TRUE))
01226                         {
01227                                 if (LLView::sDebugKeys)
01228                                 {
01229                                         llinfos << "Key handled by " << viewp->getName() << llendl;
01230                                 }
01231                                 handled_view = viewp;
01232                                 break;
01233                         }
01234                 }
01235         }
01236 
01237         return handled_view;
01238 }
01239 
01240 // Called during downward traversal
01241 LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char)
01242 {
01243         LLView* handled_view = NULL;
01244 
01245         if ( getVisible() && mEnabled )
01246         {
01247                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01248                 {
01249                         LLView* viewp = *child_it;
01250                         if (viewp->handleUnicodeChar(uni_char, TRUE))
01251                         {
01252                                 if (LLView::sDebugKeys)
01253                                 {
01254                                         llinfos << "Unicode character handled by " << viewp->getName() << llendl;
01255                                 }
01256                                 handled_view = viewp;
01257                                 break;
01258                         }
01259                 }
01260         }
01261 
01262         return handled_view;
01263 }
01264 
01265 LLView* LLView::childrenHandleMouseDown(S32 x, S32 y, MASK mask)
01266 {
01267         LLView* handled_view = NULL;
01268 
01269         for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01270         {
01271                 LLView* viewp = *child_it;
01272                 S32 local_x = x - viewp->mRect.mLeft;
01273                 S32 local_y = y - viewp->mRect.mBottom;
01274 
01275                 if (viewp->pointInView(local_x, local_y) && 
01276                         viewp->getVisible() && 
01277                         viewp->mEnabled && 
01278                         viewp->handleMouseDown( local_x, local_y, mask ))
01279                 {
01280                         if (sDebugMouseHandling)
01281                         {
01282                                 sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01283                         }
01284                         handled_view = viewp;
01285                         break;
01286                 }
01287         }
01288         return handled_view;
01289 }
01290 
01291 LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask)
01292 {
01293         LLView* handled_view = NULL;
01294 
01295         if (getVisible() && mEnabled )
01296         {
01297                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01298                 {
01299                         LLView* viewp = *child_it;
01300                         S32 local_x = x - viewp->mRect.mLeft;
01301                         S32 local_y = y - viewp->mRect.mBottom;
01302                         if (viewp->pointInView(local_x, local_y) &&
01303                                 viewp->getVisible() &&
01304                                 viewp->mEnabled &&
01305                                 viewp->handleRightMouseDown( local_x, local_y, mask ))
01306                         {
01307                                 if (sDebugMouseHandling)
01308                                 {
01309                                         sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01310                                 }
01311                                 handled_view = viewp;
01312                                 break;
01313                         }
01314                 }
01315         }
01316         return handled_view;
01317 }
01318 
01319 LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask)
01320 {
01321         LLView* handled_view = NULL;
01322 
01323         if (getVisible() && mEnabled )
01324         {
01325                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01326                 {
01327                         LLView* viewp = *child_it;
01328                         S32 local_x = x - viewp->mRect.mLeft;
01329                         S32 local_y = y - viewp->mRect.mBottom;
01330                         if (viewp->pointInView(local_x, local_y) &&
01331                                 viewp->getVisible() &&
01332                                 viewp->mEnabled &&
01333                                 viewp->handleDoubleClick( local_x, local_y, mask ))
01334                         {
01335                                 if (sDebugMouseHandling)
01336                                 {
01337                                         sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01338                                 }
01339                                 handled_view = viewp;
01340                                 break;
01341                         }
01342                 }
01343         }
01344         return handled_view;
01345 }
01346 
01347 LLView* LLView::childrenHandleMouseUp(S32 x, S32 y, MASK mask)
01348 {
01349         LLView* handled_view = NULL;
01350         if( getVisible() && mEnabled )
01351         {
01352                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01353                 {
01354                         LLView* viewp = *child_it;
01355                         S32 local_x = x - viewp->mRect.mLeft;
01356                         S32 local_y = y - viewp->mRect.mBottom;
01357                         if (!viewp->pointInView(local_x, local_y))
01358                                 continue;
01359                         if (!viewp->getVisible())
01360                                 continue;
01361                         if (!viewp->mEnabled)
01362                                 continue;
01363                         if (viewp->handleMouseUp( local_x, local_y, mask ))
01364                         {
01365                                 if (sDebugMouseHandling)
01366                                 {
01367                                         sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01368                                 }
01369                                 handled_view = viewp;
01370                                 break;
01371                         }
01372                 }
01373         }
01374         return handled_view;
01375 }
01376 
01377 LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask)
01378 {
01379         LLView* handled_view = NULL;
01380         if( getVisible() && mEnabled )
01381         {
01382                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01383                 {
01384                         LLView* viewp = *child_it;
01385                         S32 local_x = x - viewp->mRect.mLeft;
01386                         S32 local_y = y - viewp->mRect.mBottom;
01387                         if (viewp->pointInView(local_x, local_y) &&
01388                                 viewp->getVisible() &&
01389                                 viewp->mEnabled &&
01390                                 viewp->handleRightMouseUp( local_x, local_y, mask ))
01391                         {
01392                                 if (sDebugMouseHandling)
01393                                 {
01394                                         sMouseHandlerMessage = LLString("->") + viewp->mName.c_str() + sMouseHandlerMessage;
01395                                 }
01396                                 handled_view = viewp;
01397                                 break;
01398                         }
01399                 }
01400         }
01401         return handled_view;
01402 }
01403 
01404 
01405 void LLView::draw()
01406 {
01407         if (sDebugRects)
01408         {
01409                 drawDebugRect();
01410 
01411                 // Check for bogus rectangle
01412                 if (mRect.mRight <= mRect.mLeft
01413                         || mRect.mTop <= mRect.mBottom)
01414                 {
01415                         llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl;
01416                 }
01417         }
01418 
01419         LLRect rootRect = getRootView()->getRect();
01420         LLRect screenRect;
01421 
01422         // draw focused control on top of everything else
01423         LLView* focus_view = gFocusMgr.getKeyboardFocus();
01424         if (focus_view && focus_view->getParent() != this)
01425         {
01426                 focus_view = NULL;
01427         }
01428 
01429         for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
01430         {
01431                 LLView *viewp = *child_iter;
01432                 ++sDepth;
01433 
01434                 if (viewp->getVisible() && viewp != focus_view)
01435                 {
01436                         // Only draw views that are within the root view
01437                         localRectToScreen(viewp->getRect(),&screenRect);
01438                         if ( rootRect.rectInRect(&screenRect) )
01439                         {
01440                                 glMatrixMode(GL_MODELVIEW);
01441                                 LLUI::pushMatrix();
01442                                 {
01443                                         LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f);
01444                                         viewp->draw();
01445                                 }
01446                                 LLUI::popMatrix();
01447                         }
01448                 }
01449 
01450                 --sDepth;
01451         }
01452 
01453         if (focus_view && focus_view->getVisible())
01454         {
01455                 drawChild(focus_view);
01456         }
01457 
01458         // HACK
01459         if (sEditingUI && this == sEditingUIView)
01460         {
01461                 drawDebugRect();
01462         }
01463 }
01464 
01465 //Draw a box for debugging.
01466 void LLView::drawDebugRect()
01467 {
01468         // drawing solids requires texturing be disabled
01469         LLGLSNoTexture no_texture;
01470 
01471         // draw red rectangle for the border
01472         LLColor4 border_color(0.f, 0.f, 0.f, 1.f);
01473         if (sEditingUI)
01474         {
01475                 border_color.mV[0] = 1.f;
01476         }
01477         else
01478         {
01479                 border_color.mV[sDepth%3] = 1.f;
01480         }
01481 
01482         glColor4fv( border_color.mV );
01483 
01484         glBegin(GL_LINES);
01485                 glVertex2i(0, mRect.getHeight() - 1);
01486                 glVertex2i(0, 0);
01487 
01488                 glVertex2i(0, 0);
01489                 glVertex2i(mRect.getWidth() - 1, 0);
01490 
01491                 glVertex2i(mRect.getWidth() - 1, 0);
01492                 glVertex2i(mRect.getWidth() - 1, mRect.getHeight() - 1);
01493 
01494                 glVertex2i(mRect.getWidth() - 1, mRect.getHeight() - 1);
01495                 glVertex2i(0, mRect.getHeight() - 1);
01496         glEnd();
01497 
01498         // Draw the name if it's not a leaf node
01499         if (mChildList.size() && !sEditingUI)
01500         {
01501                 //char temp[256];
01502                 S32 x, y;
01503                 glColor4fv( border_color.mV );
01504                 x = mRect.getWidth()/2;
01505                 y = mRect.getHeight()/2;
01506                 LLString debug_text = llformat("%s (%d x %d)", getName().c_str(),
01507                                                                            mRect.getWidth(), mRect.getHeight());
01508                 LLFontGL::sSansSerifSmall->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
01509                                                                                           LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL,
01510                                                                                           S32_MAX, S32_MAX, NULL, FALSE);
01511         }
01512 }
01513 
01514 void LLView::drawChild(LLView* childp, S32 x_offset, S32 y_offset, BOOL force_draw)
01515 {
01516         if (childp && childp->getParent() == this)
01517         {
01518                 ++sDepth;
01519 
01520                 if (childp->getVisible() || force_draw)
01521                 {
01522                         glMatrixMode(GL_MODELVIEW);
01523                         LLUI::pushMatrix();
01524                         {
01525                                 LLUI::translate((F32)childp->getRect().mLeft + x_offset, (F32)childp->getRect().mBottom + y_offset, 0.f);
01526                                 childp->draw();
01527                         }
01528                         LLUI::popMatrix();
01529                 }
01530 
01531                 --sDepth;
01532         }
01533 }
01534 
01535 
01536 void LLView::reshape(S32 width, S32 height, BOOL called_from_parent)
01537 {
01538         // make sure this view contains all its children
01539         updateRect();
01540 
01541         // compute how much things changed and apply reshape logic to children
01542         S32 delta_width = width - mRect.getWidth();
01543         S32 delta_height = height - mRect.getHeight();
01544 
01545         if (delta_width || delta_height || sForceReshape)
01546         {
01547                 // adjust our rectangle
01548                 mRect.mRight = mRect.mLeft + width;
01549                 mRect.mTop = mRect.mBottom + height;
01550 
01551                 // move child views according to reshape flags
01552                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01553                 {
01554                         LLView* viewp = *child_it;
01555                         LLRect child_rect( viewp->mRect );
01556 
01557                         if (viewp->followsRight() && viewp->followsLeft())
01558                         {
01559                                 child_rect.mRight += delta_width;
01560                         }
01561                         else if (viewp->followsRight())
01562                         {
01563                                 child_rect.mLeft += delta_width;
01564                                 child_rect.mRight += delta_width;
01565                         }
01566                         else if (viewp->followsLeft())
01567                         {
01568                                 // left is 0, don't need to adjust coords
01569                         }
01570                         else
01571                         {
01572                                 // BUG what to do when we don't follow anyone?
01573                                 // for now, same as followsLeft
01574                         }
01575 
01576                         if (viewp->followsTop() && viewp->followsBottom())
01577                         {
01578                                 child_rect.mTop += delta_height;
01579                         }
01580                         else if (viewp->followsTop())
01581                         {
01582                                 child_rect.mTop += delta_height;
01583                                 child_rect.mBottom += delta_height;
01584                         }
01585                         else if (viewp->followsBottom())
01586                         {
01587                                 // bottom is 0, so don't need to adjust coords
01588                         }
01589                         else
01590                         {
01591                                 // BUG what to do when we don't follow?
01592                                 // for now, same as bottom
01593                         }
01594 
01595                         S32 delta_x = child_rect.mLeft - viewp->mRect.mLeft;
01596                         S32 delta_y = child_rect.mBottom - viewp->mRect.mBottom;
01597                         viewp->translate( delta_x, delta_y );
01598                         viewp->reshape(child_rect.getWidth(), child_rect.getHeight());
01599                 }
01600         }
01601 
01602         if (!called_from_parent)
01603         {
01604                 if (mParentView)
01605                 {
01606                         mParentView->reshape(mParentView->getRect().getWidth(), mParentView->getRect().getHeight(), FALSE);
01607                 }
01608         }
01609 }
01610 
01611 LLRect LLView::getRequiredRect()
01612 {
01613         return mRect;
01614 }
01615 
01616 const LLRect LLView::getScreenRect() const
01617 {
01618         // *FIX: check for one-off error
01619         LLRect screen_rect;
01620         localPointToScreen(0, 0, &screen_rect.mLeft, &screen_rect.mBottom);
01621         localPointToScreen(mRect.getWidth(), mRect.getHeight(), &screen_rect.mRight, &screen_rect.mTop);
01622         return screen_rect;
01623 }
01624 
01625 const LLRect LLView::getLocalRect() const
01626 {
01627         LLRect local_rect(0, mRect.getHeight(), mRect.getWidth(), 0);
01628         return local_rect;
01629 }
01630 
01631 const LLRect LLView::getLocalSnapRect() const
01632 {
01633         LLRect local_snap_rect = getSnapRect();
01634         local_snap_rect.translate(-mRect.mLeft, -mRect.mBottom);
01635         return local_snap_rect;
01636 }
01637 
01638 void LLView::updateRect()
01639 {
01640         if (mSpanChildren && mChildList.size())
01641         {
01642                 LLView* first_child = (*mChildList.begin());
01643                 LLRect child_spanning_rect = first_child->mRect;
01644 
01645                 for ( child_list_iter_t child_it = ++mChildList.begin(); child_it != mChildList.end(); ++child_it)
01646                 {
01647                         LLView* viewp = *child_it;
01648                         if (viewp->getVisible())
01649                         {
01650                                 child_spanning_rect.unionWith(viewp->mRect);
01651                         }
01652                 }
01653 
01654                 S32 translate_x = llmin(0, child_spanning_rect.mLeft);
01655                 S32 translate_y = llmin(0, child_spanning_rect.mBottom);
01656                 S32 new_width   = llmax(mRect.getWidth() + translate_x, child_spanning_rect.getWidth());
01657                 S32 new_height  = llmax(mRect.getHeight() + translate_y, child_spanning_rect.getHeight());
01658 
01659                 mRect.setOriginAndSize(mRect.mLeft + translate_x, mRect.mBottom + translate_y, new_width, new_height);
01660 
01661                 for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01662                 {
01663                         LLView* viewp = *child_it;
01664                         viewp->mRect.translate(-translate_x, -translate_y);
01665                 }
01666         }
01667 }
01668 
01669 BOOL LLView::hasAncestor(LLView* parentp)
01670 {
01671         if (!parentp)
01672         {
01673                 return FALSE;
01674         }
01675 
01676         LLView* viewp = getParent();
01677         while(viewp)
01678         {
01679                 if (viewp == parentp)
01680                 {
01681                         return TRUE;
01682                 }
01683                 viewp = viewp->getParent();
01684         }
01685 
01686         return FALSE;
01687 }
01688 
01689 //-----------------------------------------------------------------------------
01690 
01691 BOOL LLView::childHasKeyboardFocus( const LLString& childname ) const
01692 {
01693         LLView *child = getChildByName(childname);
01694         if (child)
01695         {
01696                 return gFocusMgr.childHasKeyboardFocus(child);
01697         }
01698         else
01699         {
01700                 return FALSE;
01701         }
01702 }
01703 
01704 //-----------------------------------------------------------------------------
01705 
01706 BOOL LLView::hasChild(const LLString& childname, BOOL recurse) const
01707 {
01708         return getChildByName(childname, recurse) ? TRUE : FALSE;
01709 }
01710 
01711 //-----------------------------------------------------------------------------
01712 // getChildByName()
01713 //-----------------------------------------------------------------------------
01714 LLView* LLView::getChildByName(const LLString& name, BOOL recurse) const
01715 {
01716         if(name.empty())
01717                 return NULL;
01718         child_list_const_iter_t child_it;
01719         // Look for direct children *first*
01720         for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01721         {
01722                 LLView* childp = *child_it;
01723                 if (childp->getName() == name)
01724                 {
01725                         return childp;
01726                 }
01727         }
01728         if (recurse)
01729         {
01730                 // Look inside each child as well.
01731                 for ( child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it)
01732                 {
01733                         LLView* childp = *child_it;
01734                         LLView* viewp = childp->getChildByName(name, recurse);
01735                         if ( viewp )
01736                         {
01737                                 return viewp;
01738                         }
01739                 }
01740         }
01741         return NULL;
01742 }
01743 
01744 // virtual
01745 void LLView::onFocusLost()
01746 {
01747 }
01748 
01749 // virtual
01750 void LLView::onFocusReceived()
01751 {
01752 }
01753 
01754 // virtual
01755 void LLView::screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const
01756 {
01757         *local_x = screen_x - mRect.mLeft;
01758         *local_y = screen_y - mRect.mBottom;
01759 
01760         const LLView* cur = this;
01761         while( cur->mParentView )
01762         {
01763                 cur = cur->mParentView;
01764                 *local_x -= cur->mRect.mLeft;
01765                 *local_y -= cur->mRect.mBottom;
01766         }
01767 }
01768 
01769 void LLView::localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const
01770 {
01771         *screen_x = local_x + mRect.mLeft;
01772         *screen_y = local_y + mRect.mBottom;
01773 
01774         const LLView* cur = this;
01775         while( cur->mParentView )
01776         {
01777                 cur = cur->mParentView;
01778                 *screen_x += cur->mRect.mLeft;
01779                 *screen_y += cur->mRect.mBottom;
01780         }
01781 }
01782 
01783 void LLView::screenRectToLocal(const LLRect& screen, LLRect* local) const
01784 {
01785         *local = screen;
01786         local->translate( -mRect.mLeft, -mRect.mBottom );
01787 
01788         const LLView* cur = this;
01789         while( cur->mParentView )
01790         {
01791                 cur = cur->mParentView;
01792                 local->translate( -cur->mRect.mLeft, -cur->mRect.mBottom );
01793         }
01794 }
01795 
01796 void LLView::localRectToScreen(const LLRect& local, LLRect* screen) const
01797 {
01798         *screen = local;
01799         screen->translate( mRect.mLeft, mRect.mBottom );
01800 
01801         const LLView* cur = this;
01802         while( cur->mParentView )
01803         {
01804                 cur = cur->mParentView;
01805                 screen->translate( cur->mRect.mLeft, cur->mRect.mBottom );
01806         }
01807 }
01808 
01809 LLView* LLView::getRootView()
01810 {
01811         LLView* view = this;
01812         while( view->mParentView )
01813         {
01814                 view = view->mParentView;
01815         }
01816         return view;
01817 }
01818 
01819 //static 
01820 LLWindow* LLView::getWindow(void)
01821 {
01822         return LLUI::sWindow;
01823 }
01824 
01825 // Moves the view so that it is entirely inside of constraint.
01826 // If the view will not fit because it's too big, aligns with the top and left.
01827 // (Why top and left?  That's where the drag bars are for floaters.)
01828 BOOL LLView::translateIntoRect(const LLRect& constraint, BOOL allow_partial_outside )
01829 {
01830         S32 delta_x = 0;
01831         S32 delta_y = 0;
01832 
01833         if (allow_partial_outside)
01834         {
01835                 const S32 KEEP_ONSCREEN_PIXELS = 16;
01836 
01837                 if( mRect.mRight - KEEP_ONSCREEN_PIXELS < constraint.mLeft )
01838                 {
01839                         delta_x = constraint.mLeft - (mRect.mRight - KEEP_ONSCREEN_PIXELS);
01840                 }
01841                 else
01842                 if( mRect.mLeft + KEEP_ONSCREEN_PIXELS > constraint.mRight )
01843                 {
01844                         delta_x = constraint.mRight - (mRect.mLeft + KEEP_ONSCREEN_PIXELS);
01845                         delta_x += llmax( 0, mRect.getWidth() - constraint.getWidth() );
01846                 }
01847 
01848                 if( mRect.mTop > constraint.mTop )
01849                 {
01850                         delta_y = constraint.mTop - mRect.mTop;
01851                 }
01852                 else
01853                 if( mRect.mTop - KEEP_ONSCREEN_PIXELS < constraint.mBottom )
01854                 {
01855                         delta_y = constraint.mBottom - (mRect.mTop - KEEP_ONSCREEN_PIXELS);
01856                         delta_y -= llmax( 0, mRect.getHeight() - constraint.getHeight() );
01857                 }
01858         }
01859         else
01860         {
01861                 if( mRect.mLeft < constraint.mLeft )
01862                 {
01863                         delta_x = constraint.mLeft - mRect.mLeft;
01864                 }
01865                 else
01866                 if( mRect.mRight > constraint.mRight )
01867                 {
01868                         delta_x = constraint.mRight - mRect.mRight;
01869                         delta_x += llmax( 0, mRect.getWidth() - constraint.getWidth() );
01870                 }
01871 
01872                 if( mRect.mTop > constraint.mTop )
01873                 {
01874                         delta_y = constraint.mTop - mRect.mTop;
01875                 }
01876                 else
01877                 if( mRect.mBottom < constraint.mBottom )
01878                 {
01879                         delta_y = constraint.mBottom - mRect.mBottom;
01880                         delta_y -= llmax( 0, mRect.getHeight() - constraint.getHeight() );
01881                 }
01882         }
01883 
01884         if (delta_x != 0 || delta_y != 0)
01885         {
01886                 translate(delta_x, delta_y);
01887                 return TRUE;
01888         }
01889         return FALSE;
01890 }
01891 
01892 BOOL LLView::localPointToOtherView( S32 x, S32 y, S32 *other_x, S32 *other_y, LLView* other_view)
01893 {
01894         LLView* cur_view = this;
01895         LLView* root_view = NULL;
01896 
01897         while (cur_view)
01898         {
01899                 if (cur_view == other_view)
01900                 {
01901                         *other_x = x;
01902                         *other_y = y;
01903                         return TRUE;
01904                 }
01905 
01906                 x += cur_view->getRect().mLeft;
01907                 y += cur_view->getRect().mBottom;
01908 
01909                 cur_view = cur_view->getParent();
01910                 root_view = cur_view;
01911         }
01912 
01913         // assuming common root between two views, chase other_view's parents up to root
01914         cur_view = other_view;
01915         while (cur_view)
01916         {
01917                 x -= cur_view->getRect().mLeft;
01918                 y -= cur_view->getRect().mBottom;
01919 
01920                 cur_view = cur_view->getParent();
01921 
01922                 if (cur_view == root_view)
01923                 {
01924                         *other_x = x;
01925                         *other_y = y;
01926                         return TRUE;
01927                 }
01928         }
01929 
01930         *other_x = x;
01931         *other_y = y;
01932         return FALSE;
01933 }
01934 
01935 BOOL LLView::localRectToOtherView( const LLRect& local, LLRect* other, LLView* other_view ) const
01936 {
01937         LLRect cur_rect = local;
01938         const LLView* cur_view = this;
01939         const LLView* root_view = NULL;
01940 
01941         while (cur_view)
01942         {
01943                 if (cur_view == other_view)
01944                 {
01945                         *other = cur_rect;
01946                         return TRUE;
01947                 }
01948 
01949                 cur_rect.translate(cur_view->getRect().mLeft, cur_view->getRect().mBottom);
01950 
01951                 cur_view = cur_view->getParent();
01952                 root_view = cur_view;
01953         }
01954 
01955         // assuming common root between two views, chase other_view's parents up to root
01956         cur_view = other_view;
01957         while (cur_view)
01958         {
01959                 cur_rect.translate(-cur_view->getRect().mLeft, -cur_view->getRect().mBottom);
01960 
01961                 cur_view = cur_view->getParent();
01962 
01963                 if (cur_view == root_view)
01964                 {
01965                         *other = cur_rect;
01966                         return TRUE;
01967                 }
01968         }
01969 
01970         *other = cur_rect;
01971         return FALSE;
01972 }
01973 
01974 // virtual
01975 LLXMLNodePtr LLView::getXML(bool save_children) const
01976 {
01977         const LLString& type_name = getWidgetTag();
01978 
01979         LLXMLNodePtr node = new LLXMLNode(type_name, FALSE);
01980 
01981         node->createChild("name", TRUE)->setStringValue(getName());
01982         node->createChild("width", TRUE)->setIntValue(getRect().getWidth());
01983         node->createChild("height", TRUE)->setIntValue(getRect().getHeight());
01984 
01985         LLView* parent = getParent();
01986         S32 left = mRect.mLeft;
01987         S32 bottom = mRect.mBottom;
01988         if (parent) bottom -= parent->getRect().getHeight();
01989 
01990         node->createChild("left", TRUE)->setIntValue(left);
01991         node->createChild("bottom", TRUE)->setIntValue(bottom);
01992 
01993         U32 follows_flags = getFollows();
01994         if (follows_flags)
01995         {
01996                 std::stringstream buffer;
01997                 bool pipe = false;
01998                 if (followsLeft())
01999                 {
02000                         buffer << "left";
02001                         pipe = true;
02002                 }
02003                 if (followsTop())
02004                 {
02005                         if (pipe) buffer << "|";
02006                         buffer << "top";
02007                         pipe = true;
02008                 }
02009                 if (followsRight())
02010                 {
02011                         if (pipe) buffer << "|";
02012                         buffer << "right";
02013                         pipe = true;
02014                 }
02015                 if (followsBottom())
02016                 {
02017                         if (pipe) buffer << "|";
02018                         buffer << "bottom";
02019                 }
02020                 node->createChild("follows", TRUE)->setStringValue(buffer.str());
02021         }
02022         // Export all widgets as enabled and visible - code must disable.
02023         node->createChild("hidden", TRUE)->setBoolValue(mHidden);
02024         node->createChild("mouse_opaque", TRUE)->setBoolValue(mMouseOpaque );
02025         if (!mToolTipMsg.empty())
02026         {
02027                 node->createChild("tool_tip", TRUE)->setStringValue(mToolTipMsg);
02028         }
02029         if (mSoundFlags != MOUSE_UP)
02030         {
02031                 node->createChild("sound_flags", TRUE)->setIntValue((S32)mSoundFlags);
02032         }
02033 
02034         node->createChild("enabled", TRUE)->setBoolValue(mEnabled);
02035 
02036         if (!mControlName.empty())
02037         {
02038                 node->createChild("control_name", TRUE)->setStringValue(mControlName);
02039         }
02040         return node;
02041 }
02042 
02043 // static
02044 void LLView::addColorXML(LLXMLNodePtr node, const LLColor4& color,
02045                                                         const LLString& xml_name, const LLString& control_name)
02046 {
02047         if (color != LLUI::sColorsGroup->getColor(control_name))
02048         {
02049                 node->createChild(xml_name, TRUE)->setFloatValue(4, color.mV);
02050         }
02051 }
02052 
02053 // static
02054 void LLView::saveColorToXML(std::ostream& out, const LLColor4& color,
02055                                                         const LLString& xml_name, const LLString& control_name,
02056                                                         const LLString& indent)
02057 {
02058         if (color != LLUI::sColorsGroup->getColor(control_name))
02059         {
02060                 out << indent << xml_name << "=\"" 
02061                         << color.mV[VRED] << ", " 
02062                         << color.mV[VGREEN] << ", " 
02063                         << color.mV[VBLUE] << ", " 
02064                         << color.mV[VALPHA] << "\"\n";
02065         }
02066 }
02067 
02068 //static 
02069 LLString LLView::escapeXML(const LLString& xml, LLString& indent)
02070 {
02071         LLString ret = indent + "\"" + LLXMLNode::escapeXML(xml);
02072 
02073         //replace every newline with a close quote, new line, indent, open quote
02074         size_t index = ret.size()-1;
02075         size_t fnd;
02076         
02077         while ((fnd = ret.rfind("\n", index)) != std::string::npos)
02078         {
02079                 ret.replace(fnd, 1, "\"\n" + indent + "\"");
02080                 index = fnd-1;
02081         }
02082 
02083         //append close quote
02084         ret.append("\"");
02085         
02086         return ret;     
02087 }
02088 
02089 // static
02090 LLWString LLView::escapeXML(const LLWString& xml)
02091 {
02092         LLWString out;
02093         for (LLWString::size_type i = 0; i < xml.size(); ++i)
02094         {
02095                 llwchar c = xml[i];
02096                 switch(c)
02097                 {
02098                 case '"':       out.append(utf8string_to_wstring("&quot;"));    break;
02099                 case '\'':      out.append(utf8string_to_wstring("&apos;"));    break;
02100                 case '&':       out.append(utf8string_to_wstring("&amp;"));             break;
02101                 case '<':       out.append(utf8string_to_wstring("&lt;"));              break;
02102                 case '>':       out.append(utf8string_to_wstring("&gt;"));              break;
02103                 default:        out.push_back(c); break;
02104                 }
02105         }
02106         return out;
02107 }
02108 
02109 // static
02110 const LLCtrlQuery & LLView::getTabOrderQuery()
02111 {
02112         static LLCtrlQuery query;
02113         if(query.getPreFilters().size() == 0) {
02114                 query.addPreFilter(LLVisibleFilter::getInstance());
02115                 query.addPreFilter(LLEnabledFilter::getInstance());
02116                 query.addPreFilter(LLTabStopFilter::getInstance());
02117                 query.addPostFilter(LLUICtrl::LLTabStopPostFilter::getInstance());
02118         }
02119         return query;
02120 }
02121 
02122 // static
02123 const LLCtrlQuery & LLView::getFocusRootsQuery()
02124 {
02125         static LLCtrlQuery query;
02126         if(query.getPreFilters().size() == 0) {
02127                 query.addPreFilter(LLVisibleFilter::getInstance());
02128                 query.addPreFilter(LLEnabledFilter::getInstance());
02129                 query.addPreFilter(LLView::LLFocusRootsFilter::getInstance());
02130         }
02131         return query;
02132 }
02133 
02134 
02135 void    LLView::userSetShape(const LLRect& new_rect)
02136 {
02137         reshape(new_rect.getWidth(), new_rect.getHeight());
02138         translate(new_rect.mLeft - mRect.mLeft, new_rect.mBottom - mRect.mBottom);
02139 }
02140 
02141 LLView* LLView::findSnapRect(LLRect& new_rect, const LLCoordGL& mouse_dir,
02142                                                          LLView::ESnapType snap_type, S32 threshold, S32 padding)
02143 {
02144         LLView* snap_view = NULL;
02145 
02146         if (!mParentView)
02147         {
02148                 new_rect = mRect;
02149                 return snap_view;
02150         }
02151 
02152         // If the view is near the edge of its parent, snap it to
02153         // the edge.
02154         LLRect test_rect = getSnapRect();
02155         LLRect view_rect = getSnapRect();
02156         test_rect.stretch(padding);
02157         view_rect.stretch(padding);
02158 
02159         BOOL snapped_x = FALSE;
02160         BOOL snapped_y = FALSE;
02161 
02162         LLRect parent_local_snap_rect = mParentView->getLocalSnapRect();
02163 
02164         if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS)
02165         {
02166                 if (llabs(parent_local_snap_rect.mRight - test_rect.mRight) <= threshold && (parent_local_snap_rect.mRight - test_rect.mRight) * mouse_dir.mX >= 0)
02167                 {
02168                         view_rect.translate(parent_local_snap_rect.mRight - view_rect.mRight, 0);
02169                         snap_view = mParentView;
02170                         snapped_x = TRUE;
02171                 }
02172 
02173                 if (llabs(test_rect.mLeft - parent_local_snap_rect.mLeft) <= threshold && test_rect.mLeft * mouse_dir.mX <= 0)
02174                 {
02175                         view_rect.translate(parent_local_snap_rect.mLeft - view_rect.mLeft, 0);
02176                         snap_view = mParentView;
02177                         snapped_x = TRUE;
02178                 }
02179 
02180                 if (llabs(test_rect.mBottom - parent_local_snap_rect.mBottom) <= threshold && test_rect.mBottom * mouse_dir.mY <= 0)
02181                 {
02182                         view_rect.translate(0, parent_local_snap_rect.mBottom - view_rect.mBottom);
02183                         snap_view = mParentView;
02184                         snapped_y = TRUE;
02185                 }
02186 
02187                 if (llabs(parent_local_snap_rect.mTop - test_rect.mTop) <= threshold && (parent_local_snap_rect.mTop - test_rect.mTop) * mouse_dir.mY >= 0)
02188                 {
02189                         view_rect.translate(0, parent_local_snap_rect.mTop - view_rect.mTop);
02190                         snap_view = mParentView;
02191                         snapped_y = TRUE;
02192                 }
02193         }
02194         if (snap_type == SNAP_SIBLINGS || snap_type == SNAP_PARENT_AND_SIBLINGS)
02195         {
02196                 for ( child_list_const_iter_t child_it = mParentView->getChildList()->begin();
02197                           child_it != mParentView->getChildList()->end(); ++child_it)
02198                 {
02199                         LLView* siblingp = *child_it;
02200                         // skip self
02201                         if (siblingp == this || !siblingp->getVisible() || !canSnapTo(siblingp))
02202                         {
02203                                 continue;
02204                         }
02205 
02206                         LLRect sibling_rect = siblingp->getSnapRect();
02207 
02208                         if (!snapped_x && llabs(test_rect.mRight - sibling_rect.mLeft) <= threshold && (test_rect.mRight - sibling_rect.mLeft) * mouse_dir.mX <= 0)
02209                         {
02210                                 view_rect.translate(sibling_rect.mLeft - view_rect.mRight, 0);
02211                                 if (!snapped_y)
02212                                 {
02213                                         if (llabs(test_rect.mTop - sibling_rect.mTop) <= threshold && (test_rect.mTop - sibling_rect.mTop) * mouse_dir.mY <= 0)
02214                                         {
02215                                                 view_rect.translate(0, sibling_rect.mTop - test_rect.mTop);
02216                                                 snapped_y = TRUE;
02217                                         }
02218                                         else if (llabs(test_rect.mBottom - sibling_rect.mBottom) <= threshold && (test_rect.mBottom - sibling_rect.mBottom) * mouse_dir.mY <= 0)
02219                                         {
02220                                                 view_rect.translate(0, sibling_rect.mBottom - test_rect.mBottom);
02221                                                 snapped_y = TRUE;
02222                                         }
02223                                 }
02224                                 snap_view = siblingp;
02225                                 snapped_x = TRUE;
02226                         }
02227 
02228                         if (!snapped_x && llabs(test_rect.mLeft - sibling_rect.mRight) <= threshold && (test_rect.mLeft - sibling_rect.mRight) * mouse_dir.mX <= 0)
02229                         {
02230                                 view_rect.translate(sibling_rect.mRight - view_rect.mLeft, 0);
02231                                 if (!snapped_y)
02232                                 {
02233                                         if (llabs(test_rect.mTop - sibling_rect.mTop) <= threshold && (test_rect.mTop - sibling_rect.mTop) * mouse_dir.mY <= 0)
02234                                         {
02235                                                 view_rect.translate(0, sibling_rect.mTop - test_rect.mTop);
02236                                                 snapped_y = TRUE;
02237                                         }
02238                                         else if (llabs(test_rect.mBottom - sibling_rect.mBottom) <= threshold && (test_rect.mBottom - sibling_rect.mBottom) * mouse_dir.mY <= 0)
02239                                         {
02240                                                 view_rect.translate(0, sibling_rect.mBottom - test_rect.mBottom);
02241                                                 snapped_y = TRUE;
02242                                         }
02243                                 }
02244                                 snap_view = siblingp;
02245                                 snapped_x = TRUE;
02246                         }
02247 
02248                         if (!snapped_y && llabs(test_rect.mBottom - sibling_rect.mTop) <= threshold && (test_rect.mBottom - sibling_rect.mTop) * mouse_dir.mY <= 0)
02249                         {
02250                                 view_rect.translate(0, sibling_rect.mTop - view_rect.mBottom);
02251                                 if (!snapped_x)
02252                                 {
02253                                         if (llabs(test_rect.mLeft - sibling_rect.mLeft) <= threshold && (test_rect.mLeft - sibling_rect.mLeft) * mouse_dir.mX <= 0)
02254                                         {
02255                                                 view_rect.translate(sibling_rect.mLeft - test_rect.mLeft, 0);
02256                                                 snapped_x = TRUE;
02257                                         }
02258                                         else if (llabs(test_rect.mRight - sibling_rect.mRight) <= threshold && (test_rect.mRight - sibling_rect.mRight) * mouse_dir.mX <= 0)
02259                                         {
02260                                                 view_rect.translate(sibling_rect.mRight - test_rect.mRight, 0);
02261                                                 snapped_x = TRUE;
02262                                         }
02263                                 }
02264                                 snap_view = siblingp;
02265                                 snapped_y = TRUE;
02266                         }
02267 
02268                         if (!snapped_y && llabs(test_rect.mTop - sibling_rect.mBottom) <= threshold && (test_rect.mTop - sibling_rect.mBottom) * mouse_dir.mY <= 0)
02269                         {
02270                                 view_rect.translate(0, sibling_rect.mBottom - view_rect.mTop);
02271                                 if (!snapped_x)
02272                                 {
02273                                         if (llabs(test_rect.mLeft - sibling_rect.mLeft) <= threshold && (test_rect.mLeft - sibling_rect.mLeft) * mouse_dir.mX <= 0)
02274                                         {
02275                                                 view_rect.translate(sibling_rect.mLeft - test_rect.mLeft, 0);
02276                                                 snapped_x = TRUE;
02277                                         }
02278                                         else if (llabs(test_rect.mRight - sibling_rect.mRight) <= threshold && (test_rect.mRight - sibling_rect.mRight) * mouse_dir.mX <= 0)
02279                                         {
02280                                                 view_rect.translate(sibling_rect.mRight - test_rect.mRight, 0);
02281                                                 snapped_x = TRUE;
02282                                         }
02283                                 }
02284                                 snap_view = siblingp;
02285                                 snapped_y = TRUE;
02286                         }
02287                         
02288                         if (snapped_x && snapped_y)
02289                         {
02290                                 break;
02291                         }
02292                 }
02293         }
02294 
02295         // shrink actual view rect back down
02296         view_rect.stretch(-padding);
02297         new_rect = view_rect;
02298         return snap_view;
02299 }
02300 
02301 LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESnapEdge snap_edge, ESnapType snap_type, S32 threshold, S32 padding)
02302 {
02303         LLRect snap_rect = getSnapRect();
02304         S32 snap_pos = 0;
02305         switch(snap_edge)
02306         {
02307         case SNAP_LEFT:
02308                 snap_pos = snap_rect.mLeft;
02309                 break;
02310         case SNAP_RIGHT:
02311                 snap_pos = snap_rect.mRight;
02312                 break;
02313         case SNAP_TOP:
02314                 snap_pos = snap_rect.mTop;
02315                 break;
02316         case SNAP_BOTTOM:
02317                 snap_pos = snap_rect.mBottom;
02318                 break;
02319         }
02320 
02321         if (!mParentView)
02322         {
02323                 new_edge_val = snap_pos;
02324                 return NULL;
02325         }
02326 
02327         LLView* snap_view = NULL;
02328 
02329         // If the view is near the edge of its parent, snap it to
02330         // the edge.
02331         LLRect test_rect = snap_rect;
02332         test_rect.stretch(padding);
02333 
02334         BOOL snapped_x = FALSE;
02335         BOOL snapped_y = FALSE;
02336 
02337         LLRect parent_local_snap_rect = mParentView->getLocalSnapRect();
02338 
02339         if (snap_type == SNAP_PARENT || snap_type == SNAP_PARENT_AND_SIBLINGS)
02340         {
02341                 switch(snap_edge)
02342                 {
02343                 case SNAP_RIGHT:
02344                         if (llabs(parent_local_snap_rect.mRight - test_rect.mRight) <= threshold && (parent_local_snap_rect.mRight - test_rect.mRight) * mouse_dir.mX >= 0)
02345                         {
02346                                 snap_pos = parent_local_snap_rect.mRight - padding;
02347                                 snap_view = mParentView;
02348                                 snapped_x = TRUE;
02349                         }
02350                         break;
02351                 case SNAP_LEFT:
02352                         if (llabs(test_rect.mLeft - parent_local_snap_rect.mLeft) <= threshold && test_rect.mLeft * mouse_dir.mX <= 0)
02353                         {
02354                                 snap_pos = parent_local_snap_rect.mLeft + padding;
02355                                 snap_view = mParentView;
02356                                 snapped_x = TRUE;
02357                         }
02358                         break;
02359                 case SNAP_BOTTOM:
02360                         if (llabs(test_rect.mBottom - parent_local_snap_rect.mBottom) <= threshold && test_rect.mBottom * mouse_dir.mY <= 0)
02361                         {
02362                                 snap_pos = parent_local_snap_rect.mBottom + padding;
02363                                 snap_view = mParentView;
02364                                 snapped_y = TRUE;
02365                         }
02366                         break;
02367                 case SNAP_TOP:
02368                         if (llabs(parent_local_snap_rect.mTop - test_rect.mTop) <= threshold && (parent_local_snap_rect.mTop - test_rect.mTop) * mouse_dir.mY >= 0)
02369                         {
02370                                 snap_pos = parent_local_snap_rect.mTop - padding;
02371                                 snap_view = mParentView;
02372                                 snapped_y = TRUE;
02373                         }
02374                         break;
02375                 default:
02376                         llerrs << "Invalid snap edge" << llendl;
02377                 }
02378         }
02379 
02380         if (snap_type == SNAP_SIBLINGS || snap_type == SNAP_PARENT_AND_SIBLINGS)
02381         {
02382                 for ( child_list_const_iter_t child_it = mParentView->getChildList()->begin();
02383                           child_it != mParentView->getChildList()->end(); ++child_it)
02384                 {
02385                         LLView* siblingp = *child_it;
02386                         // skip self
02387                         if (siblingp == this || !siblingp->getVisible() || !canSnapTo(siblingp))
02388                         {
02389                                 continue;
02390                         }
02391 
02392                         LLRect sibling_rect = siblingp->getSnapRect();
02393 
02394                         switch(snap_edge)
02395                         {
02396                         case SNAP_RIGHT:
02397                                 if (!snapped_x)
02398                                 {
02399                                         if (llabs(test_rect.mRight - sibling_rect.mLeft) <= threshold && (test_rect.mRight - sibling_rect.mLeft) * mouse_dir.mX <= 0)
02400                                         {
02401                                                 snap_pos = sibling_rect.mLeft - padding;
02402                                                 snap_view = siblingp;
02403                                                 snapped_x = TRUE;
02404                                         }
02405                                         // if snapped with sibling along other axis, check for shared edge
02406                                         else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= threshold ||
02407                                                 llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= threshold)
02408                                         {
02409                                                 if (llabs(test_rect.mRight - sibling_rect.mRight) <= threshold && (test_rect.mRight - sibling_rect.mRight) * mouse_dir.mX <= 0)
02410                                                 {
02411                                                         snap_pos = sibling_rect.mRight;
02412                                                         snap_view = siblingp;
02413                                                         snapped_x = TRUE;
02414                                                 }
02415                                         }
02416                                 }
02417                                 break;
02418                         case SNAP_LEFT:
02419                                 if (!snapped_x)
02420                                 {
02421                                         if (llabs(test_rect.mLeft - sibling_rect.mRight) <= threshold && (test_rect.mLeft - sibling_rect.mRight) * mouse_dir.mX <= 0)
02422                                         {
02423                                                 snap_pos = sibling_rect.mRight + padding;
02424                                                 snap_view = siblingp;
02425                                                 snapped_x = TRUE;
02426                                         }
02427                                         // if snapped with sibling along other axis, check for shared edge
02428                                         else if (llabs(sibling_rect.mTop - (test_rect.mBottom - padding)) <= threshold ||
02429                                                 llabs(sibling_rect.mBottom - (test_rect.mTop + padding)) <= threshold)
02430                                         {
02431                                                 if (llabs(test_rect.mLeft - sibling_rect.mLeft) <= threshold && (test_rect.mLeft - sibling_rect.mLeft) * mouse_dir.mX <= 0)
02432                                                 {
02433                                                         snap_pos = sibling_rect.mLeft;
02434                                                         snap_view = siblingp;
02435                                                         snapped_x = TRUE;
02436                                                 }
02437                                         }
02438                                 }
02439                                 break;
02440                         case SNAP_BOTTOM:
02441                                 if (!snapped_y)
02442                                 {
02443                                         if (llabs(test_rect.mBottom - sibling_rect.mTop) <= threshold && (test_rect.mBottom - sibling_rect.mTop) * mouse_dir.mY <= 0)
02444                                         {
02445                                                 snap_pos = sibling_rect.mTop + padding;
02446                                                 snap_view = siblingp;
02447                                                 snapped_y = TRUE;
02448                                         }
02449                                         // if snapped with sibling along other axis, check for shared edge
02450                                         else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= threshold ||
02451                                                 llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= threshold)
02452                                         {
02453                                                 if (llabs(test_rect.mBottom - sibling_rect.mBottom) <= threshold && (test_rect.mBottom - sibling_rect.mBottom) * mouse_dir.mY <= 0)
02454                                                 {
02455                                                         snap_pos = sibling_rect.mBottom;
02456                                                         snap_view = siblingp;
02457                                                         snapped_y = TRUE;
02458                                                 }
02459                                         }
02460                                 }
02461                                 break;
02462                         case SNAP_TOP:
02463                                 if (!snapped_y)
02464                                 {
02465                                         if (llabs(test_rect.mTop - sibling_rect.mBottom) <= threshold && (test_rect.mTop - sibling_rect.mBottom) * mouse_dir.mY <= 0)
02466                                         {
02467                                                 snap_pos = sibling_rect.mBottom - padding;
02468                                                 snap_view = siblingp;
02469                                                 snapped_y = TRUE;
02470                                         }
02471                                         // if snapped with sibling along other axis, check for shared edge
02472                                         else if (llabs(sibling_rect.mRight - (test_rect.mLeft - padding)) <= threshold ||
02473                                                 llabs(sibling_rect.mLeft - (test_rect.mRight + padding)) <= threshold)
02474                                         {
02475                                                 if (llabs(test_rect.mTop - sibling_rect.mTop) <= threshold && (test_rect.mTop - sibling_rect.mTop) * mouse_dir.mY <= 0)
02476                                                 {
02477                                                         snap_pos = sibling_rect.mTop;
02478                                                         snap_view = siblingp;
02479                                                         snapped_y = TRUE;
02480                                                 }
02481                                         }
02482                                 }
02483                                 break;
02484                         default:
02485                                 llerrs << "Invalid snap edge" << llendl;
02486                         }
02487                         if (snapped_x && snapped_y)
02488                         {
02489                                 break;
02490                         }
02491                 }
02492         }
02493 
02494         new_edge_val = snap_pos;
02495         return snap_view;
02496 }
02497 
02498 bool operator==(const LLViewHandle& lhs, const LLViewHandle& rhs)
02499 {
02500         return lhs.mID == rhs.mID;
02501 }
02502 
02503 bool operator!=(const LLViewHandle& lhs, const LLViewHandle& rhs)
02504 {
02505         return lhs.mID != rhs.mID;
02506 }
02507 
02508 bool operator<(const LLViewHandle &lhs, const LLViewHandle &rhs)
02509 {
02510         return lhs.mID < rhs.mID;
02511 }
02512 
02513 //-----------------------------------------------------------------------------
02514 // Listener dispatch functions
02515 //-----------------------------------------------------------------------------
02516 
02517 void LLView::registerEventListener(LLString name, LLSimpleListener* function)
02518 {
02519         mDispatchList.insert(std::pair<LLString, LLSimpleListener*>(name, function));
02520 }
02521 
02522 void LLView::deregisterEventListener(LLString name)
02523 {
02524         dispatch_list_t::iterator itor = mDispatchList.find(name);
02525         if (itor != mDispatchList.end())
02526         {
02527                 mDispatchList.erase(itor);
02528         }
02529 }
02530 
02531 LLString LLView::findEventListener(LLSimpleListener *listener) const
02532 {
02533         dispatch_list_t::const_iterator itor;
02534         for (itor = mDispatchList.begin(); itor != mDispatchList.end(); ++itor)
02535         {
02536                 if (itor->second == listener)
02537                 {
02538                         return itor->first;
02539                 }
02540         }
02541         if (mParentView)
02542         {
02543                 return mParentView->findEventListener(listener);
02544         }
02545         return LLString::null;
02546 }
02547 
02548 LLSimpleListener* LLView::getListenerByName(const LLString& callback_name)
02549 {
02550         LLSimpleListener* callback = NULL;
02551         dispatch_list_t::iterator itor = mDispatchList.find(callback_name);
02552         if (itor != mDispatchList.end())
02553         {
02554                 callback = itor->second;
02555         }
02556         else if (mParentView)
02557         {
02558                 callback = mParentView->getListenerByName(callback_name);
02559         }
02560         return callback;
02561 }
02562 
02563 void LLView::addListenerToControl(LLEventDispatcher *dispatcher, const LLString& name, LLSD filter, LLSD userdata)
02564 {
02565         LLSimpleListener* listener = getListenerByName(name);
02566         if (listener)
02567         {
02568                 dispatcher->addListener(listener, filter, userdata);
02569         }
02570 }
02571 
02572 LLControlBase *LLView::findControl(LLString name)
02573 {
02574         control_map_t::iterator itor = mFloaterControls.find(name);
02575         if (itor != mFloaterControls.end())
02576         {
02577                 return itor->second;
02578         }
02579         if (mParentView)
02580         {
02581                 return mParentView->findControl(name);
02582         }
02583         return LLUI::sConfigGroup->getControl(name);
02584 }
02585 
02586 const S32 FLOATER_H_MARGIN = 15;
02587 const S32 MIN_WIDGET_HEIGHT = 10;
02588 const S32 VPAD = 4;
02589 
02590 // static
02591 U32 LLView::createRect(LLXMLNodePtr node, LLRect &rect, LLView* parent_view, const LLRect &required_rect)
02592 {
02593         U32 follows = 0;
02594         S32 x = FLOATER_H_MARGIN;
02595         S32 y = 0;
02596         S32 w = 0;
02597         S32 h = 0;
02598 
02599         U32 last_x = 0;
02600         U32 last_y = 0;
02601         if (parent_view)
02602         {
02603                 last_y = parent_view->getRect().getHeight();
02604                 child_list_t::const_iterator itor = parent_view->getChildList()->begin();
02605                 if (itor != parent_view->getChildList()->end())
02606                 {
02607                         LLView *last_view = (*itor);
02608                         if (last_view->getSaveToXML())
02609                         {
02610                                 last_x = last_view->getRect().mLeft;
02611                                 last_y = last_view->getRect().mBottom;
02612                         }
02613                 }
02614         }
02615 
02616         LLString rect_control;
02617         node->getAttributeString("rect_control", rect_control);
02618         if (! rect_control.empty())
02619         {
02620                 LLRect rect = LLUI::sConfigGroup->getRect(rect_control);
02621                 x = rect.mLeft;
02622                 y = rect.mBottom;
02623                 w = rect.getWidth();
02624                 h = rect.getHeight();
02625         }
02626         
02627         if (node->hasAttribute("left"))
02628         {
02629                 node->getAttributeS32("left", x);
02630         }
02631         if (node->hasAttribute("bottom"))
02632         {
02633                 node->getAttributeS32("bottom", y);
02634         }
02635 
02636         // Make your width the width of the containing
02637         // view if you don't specify a width.
02638         if (parent_view)
02639         {
02640                 w = llmax(required_rect.getWidth(), parent_view->getRect().getWidth() - (FLOATER_H_MARGIN) - x);
02641                 h = llmax(MIN_WIDGET_HEIGHT, required_rect.getHeight());
02642         }
02643 
02644         if (node->hasAttribute("width"))
02645         {
02646                 node->getAttributeS32("width", w);
02647         }
02648         if (node->hasAttribute("height"))
02649         {
02650                 node->getAttributeS32("height", h);
02651         }
02652 
02653         if (parent_view)
02654         {
02655                 if (node->hasAttribute("left_delta"))
02656                 {
02657                         S32 left_delta = 0;
02658                         node->getAttributeS32("left_delta", left_delta);
02659                         x = last_x + left_delta;
02660                 }
02661                 else if (node->hasAttribute("left") && node->hasAttribute("right"))
02662                 {
02663                         // compute width based on left and right
02664                         S32 right = 0;
02665                         node->getAttributeS32("right", right);
02666                         if (right < 0)
02667                         {
02668                                 right = parent_view->getRect().getWidth() + right;
02669                         }
02670                         w = right - x;
02671                 }
02672                 else if (node->hasAttribute("left"))
02673                 {
02674                         if (x < 0)
02675                         {
02676                                 x = parent_view->getRect().getWidth() + x;
02677                                 follows |= FOLLOWS_RIGHT;
02678                         }
02679                         else
02680                         {
02681                                 follows |= FOLLOWS_LEFT;
02682                         }
02683                 }
02684                 else if (node->hasAttribute("width") && node->hasAttribute("right"))
02685                 {
02686                         S32 right = 0;
02687                         node->getAttributeS32("right", right);
02688                         if (right < 0)
02689                         {
02690                                 right = parent_view->getRect().getWidth() + right;
02691                         }
02692                         x = right - w;
02693                 }
02694                 else
02695                 {
02696                         // left not specified, same as last
02697                         x = last_x;
02698                 }
02699 
02700                 if (node->hasAttribute("bottom_delta"))
02701                 {
02702                         S32 bottom_delta = 0;
02703                         node->getAttributeS32("bottom_delta", bottom_delta);
02704                         y = last_y + bottom_delta;
02705                 }
02706                 else if (node->hasAttribute("top"))
02707                 {
02708                         // compute height based on top
02709                         S32 top = 0;
02710                         node->getAttributeS32("top", top);
02711                         if (top < 0)
02712                         {
02713                                 top = parent_view->getRect().getHeight() + top;
02714                         }
02715                         h = top - y;
02716                 }
02717                 else if (node->hasAttribute("bottom"))
02718                 {
02719                         if (y < 0)
02720                         {
02721                                 y = parent_view->getRect().getHeight() + y;
02722                                 follows |= FOLLOWS_TOP;
02723                         }
02724                         else
02725                         {
02726                                 follows |= FOLLOWS_BOTTOM;
02727                         }
02728                 }
02729                 else
02730                 {
02731                         // if bottom not specified, generate automatically
02732                         if (last_y == 0)
02733                         {
02734                                 // treat first child as "bottom"
02735                                 y = parent_view->getRect().getHeight() - (h + VPAD);
02736                                 follows |= FOLLOWS_TOP;
02737                         }
02738                         else
02739                         {
02740                                 // treat subsequent children as "bottom_delta"
02741                                 y = last_y - (h + VPAD);
02742                         }
02743                 }
02744         }
02745         else
02746         {
02747                 x = llmax(x, 0);
02748                 y = llmax(y, 0);
02749                 follows = FOLLOWS_LEFT | FOLLOWS_TOP;
02750         }
02751         rect.setOriginAndSize(x, y, w, h);
02752 
02753         return follows;
02754 }
02755 
02756 void LLView::initFromXML(LLXMLNodePtr node, LLView* parent)
02757 {
02758         // create rect first, as this will supply initial follows flags
02759         LLRect view_rect;
02760         U32 follows_flags = createRect(node, view_rect, parent, getRequiredRect());
02761         // call reshape in case there are any child elements that need to be layed out
02762         reshape(view_rect.getWidth(), view_rect.getHeight());
02763         setRect(view_rect);
02764         setFollows(follows_flags);
02765 
02766         if (node->hasAttribute("follows"))
02767         {
02768                 setFollowsNone();
02769 
02770                 LLString follows;
02771                 node->getAttributeString("follows", follows);
02772 
02773                 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
02774                 boost::char_separator<char> sep("|");
02775                 tokenizer tokens(follows, sep);
02776                 tokenizer::iterator token_iter = tokens.begin();
02777 
02778                 while(token_iter != tokens.end())
02779                 {
02780                         const std::string& token_str = *token_iter;
02781                         if (token_str == "left")
02782                         {
02783                                 setFollowsLeft();
02784                         }
02785                         else if (token_str == "right")
02786                         {
02787                                 setFollowsRight();
02788                         }
02789                         else if (token_str == "top")
02790                         {
02791                                 setFollowsTop();
02792                         }
02793                         else if (token_str == "bottom")
02794                         {
02795                                 setFollowsBottom();
02796                         }
02797                         else if (token_str == "all")
02798                         {
02799                                 setFollowsAll();
02800                         }
02801                         ++token_iter;
02802                 }
02803         }
02804 
02805         if (node->hasAttribute("control_name"))
02806         {
02807                 LLString control_name;
02808                 node->getAttributeString("control_name", control_name);
02809                 setControlName(control_name, NULL);
02810         }
02811 
02812         if (node->hasAttribute("tool_tip"))
02813         {
02814                 LLString tool_tip_msg("");
02815                 node->getAttributeString("tool_tip", tool_tip_msg);
02816                 setToolTip(tool_tip_msg);
02817         }
02818 
02819         if (node->hasAttribute("enabled"))
02820         {
02821                 BOOL enabled;
02822                 node->getAttributeBOOL("enabled", enabled);
02823                 setEnabled(enabled);
02824         }
02825         
02826         if (node->hasAttribute("visible"))
02827         {
02828                 BOOL visible;
02829                 node->getAttributeBOOL("visible", visible);
02830                 setVisible(visible);
02831         }
02832         
02833         if (node->hasAttribute("hidden"))
02834         {
02835                 BOOL hidden;
02836                 node->getAttributeBOOL("hidden", hidden);
02837                 setHidden(hidden);
02838         }
02839 
02840         node->getAttributeS32("default_tab_group", mDefaultTabGroup);
02841         
02842         reshape(view_rect.getWidth(), view_rect.getHeight());
02843 }
02844 
02845 // static
02846 LLFontGL* LLView::selectFont(LLXMLNodePtr node)
02847 {
02848         LLFontGL* gl_font = NULL;
02849 
02850         if (node->hasAttribute("font"))
02851         {
02852                 LLString font_name;
02853                 node->getAttributeString("font", font_name);
02854 
02855                 gl_font = LLFontGL::fontFromName(font_name.c_str());
02856         }
02857         return gl_font;
02858 }
02859 
02860 // static
02861 LLFontGL::HAlign LLView::selectFontHAlign(LLXMLNodePtr node)
02862 {
02863         LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
02864 
02865         if (node->hasAttribute("halign"))
02866         {
02867                 LLString horizontal_align_name;
02868                 node->getAttributeString("halign", horizontal_align_name);
02869                 gl_hfont_align = LLFontGL::hAlignFromName(horizontal_align_name);
02870         }
02871         return gl_hfont_align;
02872 }
02873 
02874 // static
02875 LLFontGL::VAlign LLView::selectFontVAlign(LLXMLNodePtr node)
02876 {
02877         LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
02878 
02879         if (node->hasAttribute("valign"))
02880         {
02881                 LLString vert_align_name;
02882                 node->getAttributeString("valign", vert_align_name);
02883                 gl_vfont_align = LLFontGL::vAlignFromName(vert_align_name);
02884         }
02885         return gl_vfont_align;
02886 }
02887 
02888 // static
02889 LLFontGL::StyleFlags LLView::selectFontStyle(LLXMLNodePtr node)
02890 {
02891         LLFontGL::StyleFlags gl_font_style = LLFontGL::NORMAL;
02892 
02893         if (node->hasAttribute("style"))
02894         {
02895                 LLString style_flags_name;
02896                 node->getAttributeString("style", style_flags_name);
02897 
02898                 if (style_flags_name == "normal")
02899                 {
02900                         gl_font_style = LLFontGL::NORMAL;
02901                 }
02902                 else if (style_flags_name == "bold")
02903                 {
02904                         gl_font_style = LLFontGL::BOLD;
02905                 }
02906                 else if (style_flags_name == "italic")
02907                 {
02908                         gl_font_style = LLFontGL::ITALIC;
02909                 }
02910                 else if (style_flags_name == "underline")
02911                 {
02912                         gl_font_style = LLFontGL::UNDERLINE;
02913                 }
02914                 //else leave left
02915         }
02916         return gl_font_style;
02917 }
02918 
02919 void LLView::setControlValue(const LLSD& value)
02920 {
02921         LLUI::sConfigGroup->setValue(getControlName(), value);
02922 }
02923 
02924 //virtual
02925 LLString LLView::getControlName() const
02926 {
02927         return mControlName;
02928 }
02929 
02930 //virtual
02931 void LLView::setControlName(const LLString& control_name, LLView *context)
02932 {
02933         if (context == NULL)
02934         {
02935                 context = this;
02936         }
02937 
02938         // Unregister from existing listeners
02939         if (!mControlName.empty())
02940         {
02941                 clearDispatchers();
02942         }
02943 
02944         // Register new listener
02945         if (!control_name.empty())
02946         {
02947                 LLControlBase *control = context->findControl(control_name);
02948                 if (control)
02949                 {
02950                         mControlName = control_name;
02951                         LLSD state = control->registerListener(this, "DEFAULT");
02952                         setValue(state);
02953                 }
02954         }
02955 }
02956 
02957 // virtual
02958 bool LLView::handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
02959 {
02960         if (userdata.asString() == "DEFAULT" && event->desc() == "value_changed")
02961         {
02962                 LLSD state = event->getValue();
02963                 setValue(state);
02964                 return TRUE;
02965         }
02966         return FALSE;
02967 }
02968 
02969 void LLView::setValue(const LLSD& value)
02970 {
02971 }
02972 
02973 
02974 void LLView::addBoolControl(LLString name, bool initial_value)
02975 {
02976         mFloaterControls[name] = new LLControl(name, TYPE_BOOLEAN, initial_value, "Internal floater control");
02977 }
02978 
02979 LLControlBase *LLView::getControl(LLString name)
02980 {
02981         control_map_t::iterator itor = mFloaterControls.find(name);
02982         if (itor != mFloaterControls.end())
02983         {
02984                 return itor->second;
02985         }
02986         return NULL;
02987 }

Generated on Thu Jul 1 06:09:26 2010 for Second Life Viewer by  doxygen 1.4.7