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

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