llpanel.cpp

Go to the documentation of this file.
00001 
00032 // Opaque view with a background and a border.  Can contain LLUICtrls.
00033 
00034 #include "linden_common.h"
00035 
00036 #include "llpanel.h"
00037 
00038 #include "llalertdialog.h"
00039 #include "llfocusmgr.h"
00040 #include "llfontgl.h"
00041 #include "llrect.h"
00042 #include "llerror.h"
00043 #include "lltimer.h"
00044 
00045 #include "llmenugl.h"
00046 //#include "llstatusbar.h"
00047 #include "llui.h"
00048 #include "llkeyboard.h"
00049 #include "lllineeditor.h"
00050 #include "llcontrol.h"
00051 #include "lltextbox.h"
00052 #include "lluictrl.h"
00053 #include "lluictrlfactory.h"
00054 #include "llviewborder.h"
00055 #include "llbutton.h"
00056 
00057 // LLLayoutStack
00058 #include "llgl.h"
00059 #include "llglheaders.h"
00060 #include "llresizebar.h"
00061 #include "llcriticaldamp.h"
00062 
00063 LLPanel::alert_queue_t LLPanel::sAlertQueue;
00064 
00065 const S32 RESIZE_BAR_OVERLAP = 1;
00066 const S32 RESIZE_BAR_HEIGHT = 3;
00067 
00068 static LLRegisterWidget<LLPanel> r1("panel");
00069 
00070 void LLPanel::init()
00071 {
00072         // mRectControl
00073         mBgColorAlpha        = LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" );
00074         mBgColorOpaque       = LLUI::sColorsGroup->getColor( "FocusBackgroundColor" );
00075         mDefaultBtnHighlight = LLUI::sColorsGroup->getColor( "DefaultHighlightLight" );
00076         mBgVisible = FALSE;
00077         mBgOpaque = FALSE;
00078         mBorder = NULL;
00079         mDefaultBtn = NULL;
00080         setIsChrome(FALSE); //is this a decorator to a live window or a form?
00081         mLastTabGroup = 0;
00082 
00083         mPanelHandle.bind(this);
00084         setTabStop(FALSE);
00085 }
00086 
00087 LLPanel::LLPanel()
00088 : mRectControl()
00089 {
00090         init();
00091         setName("panel");
00092 }
00093 
00094 LLPanel::LLPanel(const LLString& name)
00095 :       LLUICtrl(name, LLRect(0, 0, 0, 0), TRUE, NULL, NULL),
00096         mRectControl()
00097 {
00098         init();
00099 }
00100 
00101 
00102 LLPanel::LLPanel(const LLString& name, const LLRect& rect, BOOL bordered)
00103 :       LLUICtrl(name, rect, TRUE, NULL, NULL),
00104         mRectControl()
00105 {
00106         init();
00107         if (bordered)
00108         {
00109                 addBorder();
00110         }
00111 }
00112 
00113 
00114 LLPanel::LLPanel(const LLString& name, const LLString& rect_control, BOOL bordered)
00115 :       LLUICtrl(name, LLUI::sConfigGroup->getRect(rect_control), TRUE, NULL, NULL),
00116         mRectControl( rect_control )
00117 {
00118         init();
00119         if (bordered)
00120         {
00121                 addBorder();
00122         }
00123 }
00124 
00125 LLPanel::~LLPanel()
00126 {
00127         storeRectControl();
00128 }
00129 
00130 // virtual
00131 BOOL LLPanel::isPanel() const
00132 {
00133         return TRUE;
00134 }
00135 
00136 // virtual
00137 BOOL LLPanel::postBuild()
00138 {
00139         return TRUE;
00140 }
00141 
00142 void LLPanel::addBorder(LLViewBorder::EBevel border_bevel,
00143                                                 LLViewBorder::EStyle border_style, S32 border_thickness)
00144 {
00145         removeBorder();
00146         mBorder = new LLViewBorder( "panel border", 
00147                                                                 LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), 
00148                                                                 border_bevel, border_style, border_thickness );
00149         mBorder->setSaveToXML(false);
00150         addChild( mBorder );
00151 }
00152 
00153 void LLPanel::removeBorder()
00154 {
00155         delete mBorder;
00156         mBorder = NULL;
00157 }
00158 
00159 
00160 // virtual
00161 void LLPanel::clearCtrls()
00162 {
00163         LLView::ctrl_list_t ctrls = getCtrlList();
00164         for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it)
00165         {
00166                 LLUICtrl* ctrl = *ctrl_it;
00167                 ctrl->setFocus( FALSE );
00168                 ctrl->setEnabled( FALSE );
00169                 ctrl->clear();
00170         }
00171 }
00172 
00173 void LLPanel::setCtrlsEnabled( BOOL b )
00174 {
00175         LLView::ctrl_list_t ctrls = getCtrlList();
00176         for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it)
00177         {
00178                 LLUICtrl* ctrl = *ctrl_it;
00179                 ctrl->setEnabled( b );
00180         }
00181 }
00182 
00183 void LLPanel::draw()
00184 {
00185         // draw background
00186         if( mBgVisible )
00187         {
00188                 //RN: I don't see the point of this
00189                 S32 left = 0;//LLPANEL_BORDER_WIDTH;
00190                 S32 top = getRect().getHeight();// - LLPANEL_BORDER_WIDTH;
00191                 S32 right = getRect().getWidth();// - LLPANEL_BORDER_WIDTH;
00192                 S32 bottom = 0;//LLPANEL_BORDER_WIDTH;
00193 
00194                 if (mBgOpaque )
00195                 {
00196                         gl_rect_2d( left, top, right, bottom, mBgColorOpaque );
00197                 }
00198                 else
00199                 {
00200                         gl_rect_2d( left, top, right, bottom, mBgColorAlpha );
00201                 }
00202         }
00203 
00204         updateDefaultBtn();
00205 
00206         LLView::draw();
00207 }
00208 
00209 void LLPanel::updateDefaultBtn()
00210 {
00211         // This method does not call LLView::draw() so callers will need
00212         // to take care of that themselves at the appropriate place in
00213         // their rendering sequence
00214 
00215         if( mDefaultBtn)
00216         {
00217                 if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled())
00218                 {
00219                         LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
00220                         LLButton* buttonp = dynamic_cast<LLButton*>(focus_ctrl);
00221                         BOOL focus_is_child_button = buttonp && buttonp->getCommitOnReturn();
00222                         // only enable default button when current focus is not a return-capturing button
00223                         mDefaultBtn->setBorderEnabled(!focus_is_child_button);
00224                 }
00225                 else
00226                 {
00227                         mDefaultBtn->setBorderEnabled(FALSE);
00228                 }
00229         }
00230 }
00231 
00232 void LLPanel::refresh()
00233 {
00234         // do nothing by default
00235         // but is automatically called in setFocus(TRUE)
00236 }
00237 
00238 void LLPanel::setDefaultBtn(LLButton* btn)
00239 {
00240         if (mDefaultBtn && mDefaultBtn->getEnabled())
00241         {
00242                 mDefaultBtn->setBorderEnabled(FALSE);
00243         }
00244         mDefaultBtn = btn; 
00245         if (mDefaultBtn)
00246         {
00247                 mDefaultBtn->setBorderEnabled(TRUE);
00248         }
00249 }
00250 
00251 void LLPanel::setDefaultBtn(const LLString& id)
00252 {
00253         LLButton *button = getChild<LLButton>(id);
00254         if (button)
00255         {
00256                 setDefaultBtn(button);
00257         }
00258         else
00259         {
00260                 setDefaultBtn(NULL);
00261         }
00262 }
00263 
00264 void LLPanel::addCtrl( LLUICtrl* ctrl, S32 tab_group)
00265 {
00266         mLastTabGroup = tab_group;
00267 
00268         LLView::addCtrl(ctrl, tab_group);
00269 }
00270 
00271 void LLPanel::addCtrlAtEnd( LLUICtrl* ctrl, S32 tab_group)
00272 {
00273         mLastTabGroup = tab_group;
00274 
00275         LLView::addCtrlAtEnd(ctrl, tab_group);
00276 }
00277 
00278 BOOL LLPanel::handleKeyHere( KEY key, MASK mask )
00279 {
00280         BOOL handled = FALSE;
00281 
00282         LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus();
00283 
00284         // handle user hitting ESC to defocus
00285         if (key == KEY_ESCAPE)
00286         {
00287                 gFocusMgr.setKeyboardFocus(NULL);
00288                 return TRUE;
00289         }
00290         else if( (mask == MASK_SHIFT) && (KEY_TAB == key))
00291         {
00292                 //SHIFT-TAB
00293                 if (cur_focus)
00294                 {
00295                         LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
00296                         if (focus_root)
00297                         {
00298                                 handled = focus_root->focusPrevItem(FALSE);
00299                         }
00300                 }
00301         }
00302         else if( (mask == MASK_NONE ) && (KEY_TAB == key))      
00303         {
00304                 //TAB
00305                 if (cur_focus)
00306                 {
00307                         LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
00308                         if (focus_root)
00309                         {
00310                                 handled = focus_root->focusNextItem(FALSE);
00311                         }
00312                 }
00313         }
00314 
00315         // If we have a default button, click it when
00316         // return is pressed, unless current focus is a return-capturing button
00317         // in which case *that* button will handle the return key
00318         LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
00319         if (cur_focus && !(focused_button && focused_button->getCommitOnReturn()))
00320         {
00321                 // RETURN key means hit default button in this case
00322                 if (key == KEY_RETURN && mask == MASK_NONE 
00323                         && mDefaultBtn != NULL 
00324                         && mDefaultBtn->getVisible()
00325                         && mDefaultBtn->getEnabled())
00326                 {
00327                         mDefaultBtn->onCommit();
00328                         handled = TRUE;
00329                 }
00330         }
00331 
00332         if (key == KEY_RETURN && mask == MASK_NONE)
00333         {
00334                 // set keyboard focus to self to trigger commitOnFocusLost behavior on current ctrl
00335                 if (cur_focus && cur_focus->acceptsTextInput())
00336                 {
00337                         cur_focus->onCommit();
00338                         handled = TRUE;
00339                 }
00340         }
00341 
00342         return handled;
00343 }
00344 
00345 BOOL LLPanel::checkRequirements()
00346 {
00347         if (!mRequirementsError.empty())
00348         {
00349                 LLString::format_map_t args;
00350                 args["[COMPONENTS]"] = mRequirementsError;
00351                 args["[FLOATER]"] = getName();
00352 
00353                 llwarns << getName() << " failed requirements check on: \n"  
00354                                 << mRequirementsError << llendl;
00355                         
00356                 alertXml("FailedRequirementsCheck", args);
00357                 mRequirementsError.clear();
00358                 return FALSE;
00359         }
00360 
00361         return TRUE;
00362 }
00363 
00364 //static
00365 void LLPanel::alertXml(LLString label, LLString::format_map_t args)
00366 {
00367         sAlertQueue.push(LLAlertInfo(label,args));
00368 }
00369 
00370 //static
00371 BOOL LLPanel::nextAlert(LLAlertInfo &alert)
00372 {
00373         if (!sAlertQueue.empty())
00374         {
00375                 alert = sAlertQueue.front();
00376                 sAlertQueue.pop();
00377                 return TRUE;
00378         }
00379 
00380         return FALSE;
00381 }
00382 
00383 void LLPanel::setFocus(BOOL b)
00384 {
00385         if( b )
00386         {
00387                 if (!gFocusMgr.childHasKeyboardFocus(this))
00388                 {
00389                         //refresh();
00390                         if (!focusFirstItem())
00391                         {
00392                                 LLUICtrl::setFocus(TRUE);
00393                         }
00394                         onFocusReceived();
00395                 }
00396         }
00397         else
00398         {
00399                 if( this == gFocusMgr.getKeyboardFocus() )
00400                 {
00401                         gFocusMgr.setKeyboardFocus( NULL );
00402                 }
00403                 else
00404                 {
00405                         //RN: why is this here?
00406                         LLView::ctrl_list_t ctrls = getCtrlList();
00407                         for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it)
00408                         {
00409                                 LLUICtrl* ctrl = *ctrl_it;
00410                                 ctrl->setFocus( FALSE );
00411                         }
00412                 }
00413         }
00414 }
00415 
00416 void LLPanel::setBorderVisible(BOOL b)
00417 {
00418         if (mBorder)
00419         {
00420                 mBorder->setVisible( b );
00421         }
00422 }
00423 
00424 // virtual
00425 LLXMLNodePtr LLPanel::getXML(bool save_children) const
00426 {
00427         LLXMLNodePtr node = LLView::getXML();
00428 
00429         if (mBorder && mBorder->getVisible())
00430         {
00431                 node->createChild("border", TRUE)->setBoolValue(TRUE);
00432         }
00433 
00434         if (!mRectControl.empty())
00435         {
00436                 node->createChild("rect_control", TRUE)->setStringValue(mRectControl);
00437         }
00438 
00439         if (!mLabel.empty())
00440         {
00441                 node->createChild("label", TRUE)->setStringValue(mLabel);
00442         }
00443 
00444         if (save_children)
00445         {
00446                 LLView::child_list_const_reverse_iter_t rit;
00447                 for (rit = getChildList()->rbegin(); rit != getChildList()->rend(); ++rit)
00448                 {
00449                         LLView* childp = *rit;
00450 
00451                         if (childp->getSaveToXML())
00452                         {
00453                                 LLXMLNodePtr xml_node = childp->getXML();
00454 
00455                                 node->addChild(xml_node);
00456                         }
00457                 }
00458         }
00459 
00460         return node;
00461 }
00462 
00463 LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *factory)
00464 {
00465         LLString name("panel");
00466         node->getAttributeString("name", name);
00467 
00468         LLPanel* panelp = factory->createFactoryPanel(name);
00469         // Fall back on a default panel, if there was no special factory.
00470         if (!panelp)
00471         {
00472                 LLRect rect;
00473                 createRect(node, rect, parent, LLRect());
00474                 // create a new panel without a border, by default
00475                 panelp = new LLPanel(name, rect, FALSE);
00476                 panelp->initPanelXML(node, parent, factory);
00477                 // preserve panel's width and height, but override the location
00478                 const LLRect& panelrect = panelp->getRect();
00479                 S32 w = panelrect.getWidth();
00480                 S32 h = panelrect.getHeight();
00481                 rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
00482                 panelp->setRect(rect);
00483         }
00484         else
00485         {
00486                 panelp->initPanelXML(node, parent, factory);
00487         }
00488 
00489         return panelp;
00490 }
00491 
00492 BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
00493 {
00494         LLString name = getName();
00495         node->getAttributeString("name", name);
00496         setName(name);
00497 
00498         setPanelParameters(node, parent);
00499 
00500         initChildrenXML(node, factory);
00501 
00502         LLString xml_filename;
00503         node->getAttributeString("filename", xml_filename);
00504 
00505         BOOL didPost;
00506 
00507         if (!xml_filename.empty())
00508         {
00509                 didPost = factory->buildPanel(this, xml_filename, NULL);
00510 
00511                 LLRect new_rect = getRect();
00512                 // override rectangle with embedding parameters as provided
00513                 createRect(node, new_rect, parent);
00514                 setOrigin(new_rect.mLeft, new_rect.mBottom);
00515                 reshape(new_rect.getWidth(), new_rect.getHeight());
00516                 // optionally override follows flags from including nodes
00517                 parseFollowsFlags(node);
00518         }
00519         else
00520         {
00521                 didPost = FALSE;
00522         }
00523         
00524         if (!didPost)
00525         {
00526                 postBuild();
00527                 didPost = TRUE;
00528         }
00529 
00530         return didPost;
00531 }
00532 
00533 void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory)
00534 {
00535         LLXMLNodePtr child;
00536         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
00537         {
00538                 // look for string declarations for programmatic text
00539                 if (child->hasName("string"))
00540                 {
00541                         LLString string_name;
00542                         child->getAttributeString("name", string_name);
00543                         if (!string_name.empty())
00544                         {
00545                                 mUIStrings[string_name] = LLUIString(child->getTextContents());
00546                         }
00547                 }
00548                 else
00549                 {
00550                         factory->createWidget(this, child);
00551                 }
00552         }
00553 }
00554 
00555 void LLPanel::setPanelParameters(LLXMLNodePtr node, LLView* parent)
00556 {
00558         initFromXML(node, parent);
00559 
00561         BOOL border = mBorder != NULL;
00562         node->getAttributeBOOL("border", border);
00563         if (border)
00564         {
00565                 LLViewBorder::EBevel bevel_style = LLViewBorder::BEVEL_OUT;
00566                 LLViewBorder::getBevelFromAttribute(node, bevel_style);
00567 
00568                 LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE;
00569                 LLString border_string;
00570                 node->getAttributeString("border_style", border_string);
00571                 LLString::toLower(border_string);
00572 
00573                 if (border_string == "texture")
00574                 {
00575                         border_style = LLViewBorder::STYLE_TEXTURE;
00576                 }
00577 
00578                 S32 border_thickness = LLPANEL_BORDER_WIDTH;
00579                 node->getAttributeS32("border_thickness", border_thickness);
00580 
00581                 addBorder(bevel_style, border_style, border_thickness);
00582         }
00583         else
00584         {
00585                 removeBorder();
00586         }
00587 
00589         BOOL background_visible = mBgVisible;
00590         node->getAttributeBOOL("background_visible", background_visible);
00591         setBackgroundVisible(background_visible);
00592         
00593         BOOL background_opaque = mBgOpaque;
00594         node->getAttributeBOOL("background_opaque", background_opaque);
00595         setBackgroundOpaque(background_opaque);
00596 
00597         LLColor4 color;
00598         color = mBgColorOpaque;
00599         LLUICtrlFactory::getAttributeColor(node,"bg_opaque_color", color);
00600         setBackgroundColor(color);
00601 
00602         color = mBgColorAlpha;
00603         LLUICtrlFactory::getAttributeColor(node,"bg_alpha_color", color);
00604         setTransparentColor(color);
00605 
00606         LLString label = getLabel();
00607         node->getAttributeString("label", label);
00608         setLabel(label);
00609 }
00610 
00611 LLString LLPanel::getString(const LLString& name, const LLString::format_map_t& args) const
00612 {
00613         ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
00614         if (found_it != mUIStrings.end())
00615         {
00616                 // make a copy as format works in place
00617                 LLUIString formatted_string = found_it->second;
00618                 formatted_string.setArgList(args);
00619                 return formatted_string.getString();
00620         }
00621         LLString err_str("Failed to find string " + name + " in panel " + getName());
00622         // *TODO: once the QAR-369 ui-cleanup work on settings is in we need to change the following line to be
00623         //if(LLUI::sConfigGroup->getBOOL("QAMode"))
00624         if(LLUI::sQAMode)
00625         {
00626                 llerrs << err_str << llendl;
00627         }
00628         else
00629         {
00630                 llwarns << err_str << llendl;
00631         }
00632         return LLString::null;
00633 }
00634 
00635 LLUIString LLPanel::getUIString(const LLString& name) const
00636 {
00637         ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
00638         if (found_it != mUIStrings.end())
00639         {
00640                 return found_it->second;
00641         }
00642         llerrs << "Failed to find string " << name << " in panel " << getName() << llendl;
00643         return LLUIString(LLString::null);
00644 }
00645 
00646 
00647 void LLPanel::childSetVisible(const LLString& id, bool visible)
00648 {
00649         LLView* child = getChild<LLView>(id);
00650         if (child)
00651         {
00652                 child->setVisible(visible);
00653         }
00654 }
00655 
00656 bool LLPanel::childIsVisible(const LLString& id) const
00657 {
00658         LLView* child = getChild<LLView>(id);
00659         if (child)
00660         {
00661                 return (bool)child->getVisible();
00662         }
00663         return false;
00664 }
00665 
00666 void LLPanel::childSetEnabled(const LLString& id, bool enabled)
00667 {
00668         LLView* child = getChild<LLView>(id);
00669         if (child)
00670         {
00671                 child->setEnabled(enabled);
00672         }
00673 }
00674 
00675 void LLPanel::childSetTentative(const LLString& id, bool tentative)
00676 {
00677         LLView* child = getChild<LLView>(id);
00678         if (child)
00679         {
00680                 child->setTentative(tentative);
00681         }
00682 }
00683 
00684 bool LLPanel::childIsEnabled(const LLString& id) const
00685 {
00686         LLView* child = getChild<LLView>(id);
00687         if (child)
00688         {
00689                 return (bool)child->getEnabled();
00690         }
00691         return false;
00692 }
00693 
00694 
00695 void LLPanel::childSetToolTip(const LLString& id, const LLString& msg)
00696 {
00697         LLView* child = getChild<LLView>(id);
00698         if (child)
00699         {
00700                 child->setToolTip(msg);
00701         }
00702 }
00703 
00704 void LLPanel::childSetRect(const LLString& id, const LLRect& rect)
00705 {
00706         LLView* child = getChild<LLView>(id);
00707         if (child)
00708         {
00709                 child->setRect(rect);
00710         }
00711 }
00712 
00713 bool LLPanel::childGetRect(const LLString& id, LLRect& rect) const
00714 {
00715         LLView* child = getChild<LLView>(id);
00716         if (child)
00717         {
00718                 rect = child->getRect();
00719                 return true;
00720         }
00721         return false;
00722 }
00723 
00724 void LLPanel::childSetFocus(const LLString& id, BOOL focus)
00725 {
00726         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00727         if (child)
00728         {
00729                 child->setFocus(focus);
00730         }
00731 }
00732 
00733 BOOL LLPanel::childHasFocus(const LLString& id)
00734 {
00735         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00736         if (child)
00737         {
00738                 return child->hasFocus();
00739         }
00740         else
00741         {
00742                 childNotFound(id);
00743                 return FALSE;
00744         }
00745 }
00746 
00747 
00748 void LLPanel::childSetFocusChangedCallback(const LLString& id, void (*cb)(LLFocusableElement*, void*), void* user_data)
00749 {
00750         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00751         if (child)
00752         {
00753                 child->setFocusChangedCallback(cb, user_data);
00754         }
00755 }
00756 
00757 void LLPanel::childSetCommitCallback(const LLString& id, void (*cb)(LLUICtrl*, void*), void *userdata )
00758 {
00759         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00760         if (child)
00761         {
00762                 child->setCommitCallback(cb);
00763                 child->setCallbackUserData(userdata);
00764         }
00765 }
00766 
00767 void LLPanel::childSetDoubleClickCallback(const LLString& id, void (*cb)(void*), void *userdata )
00768 {
00769         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00770         if (child)
00771         {
00772                 child->setDoubleClickCallback(cb);
00773                 if (userdata)
00774                 {
00775                         child->setCallbackUserData(userdata);
00776                 }
00777         }
00778 }
00779 
00780 void LLPanel::childSetValidate(const LLString& id, BOOL (*cb)(LLUICtrl*, void*))
00781 {
00782         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00783         if (child)
00784         {
00785                 child->setValidateBeforeCommit(cb);
00786         }
00787 }
00788 
00789 void LLPanel::childSetUserData(const LLString& id, void* userdata)
00790 {
00791         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00792         if (child)
00793         {
00794                 child->setCallbackUserData(userdata);
00795         }
00796 }
00797 
00798 void LLPanel::childSetColor(const LLString& id, const LLColor4& color)
00799 {
00800         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00801         if (child)
00802         {
00803                 child->setColor(color);
00804         }
00805 }
00806 
00807 LLCtrlSelectionInterface* LLPanel::childGetSelectionInterface(const LLString& id) const
00808 {
00809         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00810         if (child)
00811         {
00812                 return child->getSelectionInterface();
00813         }
00814         return NULL;
00815 }
00816 
00817 LLCtrlListInterface* LLPanel::childGetListInterface(const LLString& id) const
00818 {
00819         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00820         if (child)
00821         {
00822                 return child->getListInterface();
00823         }
00824         return NULL;
00825 }
00826 
00827 LLCtrlScrollInterface* LLPanel::childGetScrollInterface(const LLString& id) const
00828 {
00829         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00830         if (child)
00831         {
00832                 return child->getScrollInterface();
00833         }
00834         return NULL;
00835 }
00836 
00837 void LLPanel::childSetValue(const LLString& id, LLSD value)
00838 {
00839         LLView* child = getChild<LLView>(id, true);
00840         if (child)
00841         {
00842                 child->setValue(value);
00843         }
00844 }
00845 
00846 LLSD LLPanel::childGetValue(const LLString& id) const
00847 {
00848         LLView* child = getChild<LLView>(id, true);
00849         if (child)
00850         {
00851                 return child->getValue();
00852         }
00853         // Not found => return undefined
00854         return LLSD();
00855 }
00856 
00857 BOOL LLPanel::childSetTextArg(const LLString& id, const LLString& key, const LLStringExplicit& text)
00858 {
00859         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00860         if (child)
00861         {
00862                 return child->setTextArg(key, text);
00863         }
00864         return FALSE;
00865 }
00866 
00867 BOOL LLPanel::childSetLabelArg(const LLString& id, const LLString& key, const LLStringExplicit& text)
00868 {
00869         LLView* child = getChild<LLView>(id);
00870         if (child)
00871         {
00872                 return child->setLabelArg(key, text);
00873         }
00874         return FALSE;
00875 }
00876 
00877 BOOL LLPanel::childSetToolTipArg(const LLString& id, const LLString& key, const LLStringExplicit& text)
00878 {
00879         LLView* child = getChildView(id, true, FALSE);
00880         if (child)
00881         {
00882                 return child->setToolTipArg(key, text);
00883         }
00884         return FALSE;
00885 }
00886 
00887 void LLPanel::childSetMinValue(const LLString& id, LLSD min_value)
00888 {
00889         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00890         if (child)
00891         {
00892                 child->setMinValue(min_value);
00893         }
00894 }
00895 
00896 void LLPanel::childSetMaxValue(const LLString& id, LLSD max_value)
00897 {
00898         LLUICtrl* child = getChild<LLUICtrl>(id, true);
00899         if (child)
00900         {
00901                 child->setMaxValue(max_value);
00902         }
00903 }
00904 
00905 void LLPanel::childShowTab(const LLString& id, const LLString& tabname, bool visible)
00906 {
00907         LLTabContainer* child = getChild<LLTabContainer>(id);
00908         if (child)
00909         {
00910                 child->selectTabByName(tabname);
00911         }
00912 }
00913 
00914 LLPanel *LLPanel::childGetVisibleTab(const LLString& id) const
00915 {
00916         LLTabContainer* child = getChild<LLTabContainer>(id);
00917         if (child)
00918         {
00919                 return child->getCurrentPanel();
00920         }
00921         return NULL;
00922 }
00923 
00924 void LLPanel::childSetTabChangeCallback(const LLString& id, const LLString& tabname, void (*on_tab_clicked)(void*, bool), void *userdata)
00925 {
00926         LLTabContainer* child = getChild<LLTabContainer>(id);
00927         if (child)
00928         {
00929                 LLPanel *panel = child->getPanelByName(tabname);
00930                 if (panel)
00931                 {
00932                         child->setTabChangeCallback(panel, on_tab_clicked);
00933                         child->setTabUserData(panel, userdata);
00934                 }
00935         }
00936 }
00937 
00938 void LLPanel::childSetKeystrokeCallback(const LLString& id, void (*keystroke_callback)(LLLineEditor* caller, void* user_data), void *user_data)
00939 {
00940         LLLineEditor* child = getChild<LLLineEditor>(id);
00941         if (child)
00942         {
00943                 child->setKeystrokeCallback(keystroke_callback);
00944                 if (user_data)
00945                 {
00946                         child->setCallbackUserData(user_data);
00947                 }
00948         }
00949 }
00950 
00951 void LLPanel::childSetPrevalidate(const LLString& id, BOOL (*func)(const LLWString &) )
00952 {
00953         LLLineEditor* child = getChild<LLLineEditor>(id);
00954         if (child)
00955         {
00956                 child->setPrevalidate(func);
00957         }
00958 }
00959 
00960 void LLPanel::childSetWrappedText(const LLString& id, const LLString& text, bool visible)
00961 {
00962         LLTextBox* child = getChild<LLTextBox>(id);
00963         if (child)
00964         {
00965                 child->setVisible(visible);
00966                 child->setWrappedText(text);
00967         }
00968 }
00969 
00970 void LLPanel::childSetAction(const LLString& id, void(*function)(void*), void* value)
00971 {
00972         LLButton* button = getChild<LLButton>(id);
00973         if (button)
00974         {
00975                 button->setClickedCallback(function, value);
00976         }
00977 }
00978 
00979 void LLPanel::childSetActionTextbox(const LLString& id, void(*function)(void*))
00980 {
00981         LLTextBox* textbox = getChild<LLTextBox>(id);
00982         if (textbox)
00983         {
00984                 textbox->setClickedCallback(function);
00985         }
00986 }
00987 
00988 void LLPanel::childSetControlName(const LLString& id, const LLString& control_name)
00989 {
00990         LLView* view = getChild<LLView>(id);
00991         if (view)
00992         {
00993                 view->setControlName(control_name, NULL);
00994         }
00995 }
00996 
00997 //virtual
00998 LLView* LLPanel::getChildView(const LLString& name, BOOL recurse, BOOL create_if_missing) const
00999 {
01000         // just get child, don't try to create a dummy one
01001         LLView* view = LLUICtrl::getChildView(name, recurse, FALSE);
01002         if (!view && !recurse)
01003         {
01004                 childNotFound(name);
01005         }
01006         if (!view && create_if_missing)
01007         {
01008                 view = createDummyWidget<LLView>(name);
01009         }
01010         return view;
01011 }
01012 
01013 void LLPanel::childNotFound(const LLString& id) const
01014 {
01015         if (mExpectedMembers.find(id) == mExpectedMembers.end())
01016         {
01017                 mNewExpectedMembers.insert(id);
01018         }
01019 }
01020 
01021 void LLPanel::childDisplayNotFound()
01022 {
01023         if (mNewExpectedMembers.empty())
01024         {
01025                 return;
01026         }
01027         LLString msg;
01028         expected_members_list_t::iterator itor;
01029         for (itor=mNewExpectedMembers.begin(); itor!=mNewExpectedMembers.end(); ++itor)
01030         {
01031                 msg.append(*itor);
01032                 msg.append("\n");
01033                 mExpectedMembers.insert(*itor);
01034         }
01035         mNewExpectedMembers.clear();
01036         LLString::format_map_t args;
01037         args["[CONTROLS]"] = msg;
01038         LLAlertDialog::showXml("FloaterNotFound", args);
01039 }
01040 
01041 void LLPanel::storeRectControl()
01042 {
01043         if( !mRectControl.empty() )
01044         {
01045                 LLUI::sConfigGroup->setRect( mRectControl, getRect() );
01046         }
01047 }
01048 
01049 
01050 //
01051 // LLLayoutStack
01052 //
01053 struct LLLayoutStack::LLEmbeddedPanel
01054 {
01055         LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : 
01056                         mPanel(panelp), 
01057                         mMinWidth(min_width), 
01058                         mMinHeight(min_height),
01059                         mAutoResize(auto_resize),
01060                         mUserResize(user_resize),
01061                         mOrientation(orientation),
01062                         mVisibleAmt(1.f) // default to fully visible
01063         {
01064                 LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM;
01065                 LLRect resize_bar_rect = panelp->getRect();
01066 
01067                 S32 min_dim;
01068                 if (orientation == HORIZONTAL)
01069                 {
01070                         min_dim = mMinHeight;
01071                 }
01072                 else
01073                 {
01074                         min_dim = mMinWidth;
01075                 }
01076                 mResizeBar = new LLResizeBar("resizer", mPanel, LLRect(), min_dim, S32_MAX, side);
01077                 mResizeBar->setEnableSnapping(FALSE);
01078                 // panels initialized as hidden should not start out partially visible
01079                 if (!mPanel->getVisible())
01080                 {
01081                         mVisibleAmt = 0.f;
01082                 }
01083         }
01084 
01085         ~LLEmbeddedPanel()
01086         {
01087                 // probably not necessary, but...
01088                 delete mResizeBar;
01089                 mResizeBar = NULL;
01090         }
01091 
01092         LLPanel* mPanel;
01093         S32 mMinWidth;
01094         S32 mMinHeight;
01095         BOOL mAutoResize;
01096         BOOL mUserResize;
01097         LLResizeBar* mResizeBar;
01098         eLayoutOrientation mOrientation;
01099         F32 mVisibleAmt;
01100 };
01101 
01102 static LLRegisterWidget<LLLayoutStack> r2("layout_stack");
01103 
01104 LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation) : 
01105                 mOrientation(orientation),
01106                 mMinWidth(0),
01107                 mMinHeight(0),
01108                 mPanelSpacing(RESIZE_BAR_HEIGHT)
01109 {
01110 }
01111 
01112 LLLayoutStack::~LLLayoutStack()
01113 {
01114         std::for_each(mPanels.begin(), mPanels.end(), DeletePointer());
01115 }
01116 
01117 void LLLayoutStack::draw()
01118 {
01119         updateLayout();
01120         {
01121                 e_panel_list_t::iterator panel_it;
01122                 for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01123                 {
01124                         // clip to layout rectangle, not bounding rectangle
01125                         LLRect clip_rect = (*panel_it)->mPanel->getRect();
01126                         // scale clipping rectangle by visible amount
01127                         if (mOrientation == HORIZONTAL)
01128                         {
01129                                 clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->mVisibleAmt);
01130                         }
01131                         else
01132                         {
01133                                 clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->mVisibleAmt);
01134                         }
01135 
01136                         LLPanel* panelp = (*panel_it)->mPanel;
01137 
01138                         LLLocalClipRect clip(clip_rect);
01139                         // only force drawing invisible children if visible amount is non-zero
01140                         drawChild(panelp, 0, 0, !clip_rect.isNull());
01141                 }
01142         }
01143 }
01144 
01145 void LLLayoutStack::removeCtrl(LLUICtrl* ctrl)
01146 {
01147         LLEmbeddedPanel* embedded_panelp = findEmbeddedPanel((LLPanel*)ctrl);
01148 
01149         if (embedded_panelp)
01150         {
01151                 mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp));
01152                 delete embedded_panelp;
01153         }
01154 
01155         // need to update resizebars
01156 
01157         calcMinExtents();
01158 
01159         LLView::removeCtrl(ctrl);
01160 }
01161 
01162 LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
01163 {
01164         LLXMLNodePtr node = LLView::getXML();
01165         return node;
01166 }
01167 
01168 //static 
01169 LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
01170 {
01171         LLString orientation_string("vertical");
01172         node->getAttributeString("orientation", orientation_string);
01173 
01174         eLayoutOrientation orientation = VERTICAL;
01175 
01176         if (orientation_string == "horizontal")
01177         {
01178                 orientation = HORIZONTAL;
01179         }
01180         else if (orientation_string == "vertical")
01181         {
01182                 orientation = VERTICAL;
01183         }
01184         else
01185         {
01186                 llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl;
01187         }
01188 
01189         LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
01190 
01191         node->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
01192         // don't allow negative spacing values
01193         layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
01194 
01195         LLString name("stack");
01196         node->getAttributeString("name", name);
01197 
01198         layout_stackp->setName(name);
01199         layout_stackp->initFromXML(node, parent);
01200 
01201         LLXMLNodePtr child;
01202         for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
01203         {
01204                 S32 min_width = 0;
01205                 S32 min_height = 0;
01206                 BOOL auto_resize = TRUE;
01207 
01208                 child->getAttributeS32("min_width", min_width);
01209                 child->getAttributeS32("min_height", min_height);
01210                 child->getAttributeBOOL("auto_resize", auto_resize);
01211 
01212                 if (child->hasName("layout_panel"))
01213                 {
01214                         BOOL user_resize = TRUE;
01215                         child->getAttributeBOOL("user_resize", user_resize);
01216                         LLPanel* panelp = (LLPanel*)LLPanel::fromXML(child, layout_stackp, factory);
01217                         if (panelp)
01218                         {
01219                                 panelp->setFollowsNone();
01220                                 layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
01221                         }
01222                 }
01223                 else
01224                 {
01225                         BOOL user_resize = FALSE;
01226                         child->getAttributeBOOL("user_resize", user_resize);
01227 
01228                         LLPanel* panelp = new LLPanel("auto_panel");
01229                         LLView* new_child = factory->createWidget(panelp, child);
01230                         if (new_child)
01231                         {
01232                                 // put child in new embedded panel
01233                                 layout_stackp->addPanel(panelp, min_width, min_height, auto_resize, user_resize);
01234                                 // resize panel to contain widget and move widget to be contained in panel
01235                                 panelp->setRect(new_child->getRect());
01236                                 new_child->setOrigin(0, 0);
01237                         }
01238                         else
01239                         {
01240                                 panelp->die();
01241                         }
01242                 }
01243         }
01244         layout_stackp->updateLayout();
01245 
01246         return layout_stackp;
01247 }
01248 
01249 S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
01250 {
01251         // if we are spanning our children (crude upward propagation of size)
01252         // then don't enforce our size on our children
01253         if (mOrientation == HORIZONTAL)
01254         {
01255                 cur_height = llmax(mMinHeight, getRect().getHeight());
01256         }
01257 
01258         return cur_height;
01259 }
01260 
01261 S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
01262 {
01263         // if we are spanning our children (crude upward propagation of size)
01264         // then don't enforce our size on our children
01265         if (mOrientation == VERTICAL)
01266         {
01267                 cur_width = llmax(mMinWidth, getRect().getWidth());
01268         }
01269 
01270         return cur_width;
01271 }
01272 
01273 void LLLayoutStack::addPanel(LLPanel* panel, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize, S32 index)
01274 {
01275         LLEmbeddedPanel* embedded_panel = new LLEmbeddedPanel(panel, mOrientation, min_width, min_height, auto_resize, user_resize);
01276         
01277         mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()), embedded_panel);
01278         
01279         addChild(panel);
01280         addChild(embedded_panel->mResizeBar);
01281 
01282         // bring all resize bars to the front so that they are clickable even over the panels
01283         // with a bit of overlap
01284         for (e_panel_list_t::iterator panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01285         {
01286                 LLResizeBar* resize_barp = (*panel_it)->mResizeBar;
01287                 sendChildToFront(resize_barp);
01288         }
01289 
01290 }
01291 
01292 void LLLayoutStack::removePanel(LLPanel* panel)
01293 {
01294         removeChild(panel);
01295 }
01296 
01297 void LLLayoutStack::updateLayout(BOOL force_resize)
01298 {
01299         calcMinExtents();
01300 
01301         // calculate current extents
01302         S32 total_width = 0;
01303         S32 total_height = 0;
01304 
01305         const F32 ANIM_OPEN_TIME = 0.02f;
01306         const F32 ANIM_CLOSE_TIME = 0.03f;
01307 
01308         e_panel_list_t::iterator panel_it;
01309         for (panel_it = mPanels.begin(); panel_it != mPanels.end();     ++panel_it)
01310         {
01311                 LLPanel* panelp = (*panel_it)->mPanel;
01312                 if (panelp->getVisible()) 
01313                 {
01314                         (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME));
01315                         if ((*panel_it)->mVisibleAmt > 0.99f)
01316                         {
01317                                 (*panel_it)->mVisibleAmt = 1.f;
01318                         }
01319                 }
01320                 else // not visible
01321                 {
01322                         (*panel_it)->mVisibleAmt = lerp((*panel_it)->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME));
01323                         if ((*panel_it)->mVisibleAmt < 0.001f)
01324                         {
01325                                 (*panel_it)->mVisibleAmt = 0.f;
01326                         }
01327                 }
01328 
01329                 if (mOrientation == HORIZONTAL)
01330                 {
01331                         // enforce minimize size constraint by default
01332                         if (panelp->getRect().getWidth() < (*panel_it)->mMinWidth)
01333                         {
01334                                 panelp->reshape((*panel_it)->mMinWidth, panelp->getRect().getHeight());
01335                         }
01336                 total_width += llround(panelp->getRect().getWidth() * (*panel_it)->mVisibleAmt);
01337                 // want n-1 panel gaps for n panels
01338                         if (panel_it != mPanels.begin())
01339                         {
01340                                 total_width += mPanelSpacing;
01341                         }
01342                 }
01343                 else //VERTICAL
01344                 {
01345                         // enforce minimize size constraint by default
01346                         if (panelp->getRect().getHeight() < (*panel_it)->mMinHeight)
01347                         {
01348                                 panelp->reshape(panelp->getRect().getWidth(), (*panel_it)->mMinHeight);
01349                         }
01350                         total_height += llround(panelp->getRect().getHeight() * (*panel_it)->mVisibleAmt);
01351                         if (panel_it != mPanels.begin())
01352                         {
01353                                 total_height += mPanelSpacing;
01354                         }
01355                 }
01356         }
01357 
01358         S32 num_resizable_panels = 0;
01359         S32 shrink_headroom_available = 0;
01360         S32 shrink_headroom_total = 0;
01361         for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01362         {
01363                 // panels that are not fully visible do not count towards shrink headroom
01364                 if ((*panel_it)->mVisibleAmt < 1.f) 
01365                 {
01366                         continue;
01367                 }
01368 
01369                 // if currently resizing a panel or the panel is flagged as not automatically resizing
01370                 // only track total available headroom, but don't use it for automatic resize logic
01371                 if ((*panel_it)->mResizeBar->hasMouseCapture() 
01372                         || (!(*panel_it)->mAutoResize 
01373                                 && !force_resize))
01374                 {
01375                         if (mOrientation == HORIZONTAL)
01376                         {
01377                                 shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
01378                         }
01379                         else //VERTICAL
01380                         {
01381                                 shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
01382                         }
01383                 }
01384                 else
01385                 {
01386                         num_resizable_panels++;
01387                         if (mOrientation == HORIZONTAL)
01388                         {
01389                                 shrink_headroom_available += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
01390                                 shrink_headroom_total += (*panel_it)->mPanel->getRect().getWidth() - (*panel_it)->mMinWidth;
01391                         }
01392                         else //VERTICAL
01393                         {
01394                                 shrink_headroom_available += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
01395                                 shrink_headroom_total += (*panel_it)->mPanel->getRect().getHeight() - (*panel_it)->mMinHeight;
01396                         }
01397                 }
01398         }
01399 
01400         // calculate how many pixels need to be distributed among layout panels
01401         // positive means panels need to grow, negative means shrink
01402         S32 pixels_to_distribute;
01403         if (mOrientation == HORIZONTAL)
01404         {
01405                 pixels_to_distribute = getRect().getWidth() - total_width;
01406         }
01407         else //VERTICAL
01408         {
01409                 pixels_to_distribute = getRect().getHeight() - total_height;
01410         }
01411 
01412         // now we distribute the pixels...
01413         S32 cur_x = 0;
01414         S32 cur_y = getRect().getHeight();
01415 
01416         for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01417         {
01418                 LLPanel* panelp = (*panel_it)->mPanel;
01419 
01420                 S32 cur_width = panelp->getRect().getWidth();
01421                 S32 cur_height = panelp->getRect().getHeight();
01422                 S32 new_width = llmax((*panel_it)->mMinWidth, cur_width);
01423                 S32 new_height = llmax((*panel_it)->mMinHeight, cur_height); 
01424 
01425                 S32 delta_size = 0;
01426 
01427                 // if panel can automatically resize (not animating, and resize flag set)...
01428                 if ((*panel_it)->mVisibleAmt == 1.f 
01429                         && (force_resize || (*panel_it)->mAutoResize) 
01430                         && !(*panel_it)->mResizeBar->hasMouseCapture()) 
01431                 {
01432                         if (mOrientation == HORIZONTAL)
01433                         {
01434                                 // if we're shrinking
01435                                 if (pixels_to_distribute < 0)
01436                                 {
01437                                         // shrink proportionally to amount over minimum
01438                                         // so we can do this in one pass
01439                                         delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_width - (*panel_it)->mMinWidth) / (F32)shrink_headroom_available)) : 0;
01440                                         shrink_headroom_available -= (cur_width - (*panel_it)->mMinWidth);
01441                                 }
01442                                 else
01443                                 {
01444                                         // grow all elements equally
01445                                         delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
01446                                         num_resizable_panels--;
01447                                 }
01448                                 pixels_to_distribute -= delta_size;
01449                                 new_width = llmax((*panel_it)->mMinWidth, cur_width + delta_size);
01450                         }
01451                         else
01452                         {
01453                                 new_width = getDefaultWidth(new_width);
01454                         }
01455 
01456                         if (mOrientation == VERTICAL)
01457                         {
01458                                 if (pixels_to_distribute < 0)
01459                                 {
01460                                         // shrink proportionally to amount over minimum
01461                                         // so we can do this in one pass
01462                                         delta_size = (shrink_headroom_available > 0) ? llround((F32)pixels_to_distribute * ((F32)(cur_height - (*panel_it)->mMinHeight) / (F32)shrink_headroom_available)) : 0;
01463                                         shrink_headroom_available -= (cur_height - (*panel_it)->mMinHeight);
01464                                 }
01465                                 else
01466                                 {
01467                                         delta_size = llround((F32)pixels_to_distribute / (F32)num_resizable_panels);
01468                                         num_resizable_panels--;
01469                                 }
01470                                 pixels_to_distribute -= delta_size;
01471                                 new_height = llmax((*panel_it)->mMinHeight, cur_height + delta_size);
01472                         }
01473                         else
01474                         {
01475                                 new_height = getDefaultHeight(new_height);
01476                         }
01477                 }
01478                 else
01479                 {
01480                         if (mOrientation == HORIZONTAL)
01481                         {
01482                                 new_height = getDefaultHeight(new_height);
01483                         }
01484                         else // VERTICAL
01485                         {
01486                                 new_width = getDefaultWidth(new_width);
01487                         }
01488                 }
01489 
01490                 // adjust running headroom count based on new sizes
01491                 shrink_headroom_total += delta_size;
01492 
01493                 panelp->reshape(new_width, new_height);
01494                 panelp->setOrigin(cur_x, cur_y - new_height);
01495 
01496                 LLRect panel_rect = panelp->getRect();
01497                 LLRect resize_bar_rect = panel_rect;
01498                 if (mOrientation == HORIZONTAL)
01499                 {
01500                         resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
01501                         resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing + RESIZE_BAR_OVERLAP;
01502                 }
01503                 else
01504                 {
01505                         resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
01506                         resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing - RESIZE_BAR_OVERLAP;
01507                 }
01508                 (*panel_it)->mResizeBar->setRect(resize_bar_rect);
01509 
01510                 if (mOrientation == HORIZONTAL)
01511                 {
01512                         cur_x += llround(new_width * (*panel_it)->mVisibleAmt) + mPanelSpacing;
01513                 }
01514                 else //VERTICAL
01515                 {
01516                         cur_y -= llround(new_height * (*panel_it)->mVisibleAmt) + mPanelSpacing;
01517                 }
01518         }
01519 
01520         // update resize bars with new limits
01521         LLResizeBar* last_resize_bar = NULL;
01522         for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01523         {
01524                 LLPanel* panelp = (*panel_it)->mPanel;
01525 
01526                 if (mOrientation == HORIZONTAL)
01527                 {
01528                         (*panel_it)->mResizeBar->setResizeLimits(
01529                                 (*panel_it)->mMinWidth, 
01530                                 (*panel_it)->mMinWidth + shrink_headroom_total);
01531                 }
01532                 else //VERTICAL
01533                 {
01534                         (*panel_it)->mResizeBar->setResizeLimits(
01535                                 (*panel_it)->mMinHeight, 
01536                                 (*panel_it)->mMinHeight + shrink_headroom_total);
01537                 }
01538 
01539                 // toggle resize bars based on panel visibility, resizability, etc
01540                 BOOL resize_bar_enabled = panelp->getVisible() && (*panel_it)->mUserResize;
01541                 (*panel_it)->mResizeBar->setVisible(resize_bar_enabled);
01542 
01543                 if (resize_bar_enabled)
01544                 {
01545                         last_resize_bar = (*panel_it)->mResizeBar;
01546                 }
01547         }
01548 
01549         // hide last resize bar as there is nothing past it
01550         // resize bars need to be in between two resizable panels
01551         if (last_resize_bar)
01552         {
01553                 last_resize_bar->setVisible(FALSE);
01554         }
01555 
01556         // not enough room to fit existing contents
01557         if (force_resize == FALSE
01558                 // layout did not complete by reaching target position
01559                 && ((mOrientation == VERTICAL && cur_y != -mPanelSpacing)
01560                         || (mOrientation == HORIZONTAL && cur_x != getRect().getWidth() + mPanelSpacing)))
01561         {
01562                 // do another layout pass with all stacked elements contributing
01563                 // even those that don't usually resize
01564                 llassert_always(force_resize == FALSE);
01565                 updateLayout(TRUE);
01566         }
01567 } // end LLLayoutStack::updateLayout
01568 
01569 
01570 LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
01571 {
01572         e_panel_list_t::const_iterator panel_it;
01573         for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01574         {
01575                 if ((*panel_it)->mPanel == panelp)
01576                 {
01577                         return *panel_it;
01578                 }
01579         }
01580         return NULL;
01581 }
01582 
01583 void LLLayoutStack::calcMinExtents()
01584 {
01585         mMinWidth = 0;
01586         mMinHeight = 0;
01587 
01588         e_panel_list_t::iterator panel_it;
01589         for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it)
01590         {
01591                 if (mOrientation == HORIZONTAL)
01592                 {
01593                         mMinHeight = llmax(     mMinHeight, 
01594                                                                 (*panel_it)->mMinHeight);
01595             mMinWidth += (*panel_it)->mMinWidth;
01596                         if (panel_it != mPanels.begin())
01597                         {
01598                                 mMinWidth += mPanelSpacing;
01599                         }
01600                 }
01601                 else //VERTICAL
01602                 {
01603                 mMinWidth = llmax(      mMinWidth, 
01604                                                                 (*panel_it)->mMinWidth);
01605                         mMinHeight += (*panel_it)->mMinHeight;
01606                         if (panel_it != mPanels.begin())
01607                         {
01608                                 mMinHeight += mPanelSpacing;
01609                         }
01610                 }
01611         }
01612 }

Generated on Fri May 16 08:32:55 2008 for SecondLife by  doxygen 1.5.5