llfloater.cpp

Go to the documentation of this file.
00001 
00032 // Floating "windows" within the GL display, like the inventory floater,
00033 // mini-map floater, etc.
00034 
00035 #include "linden_common.h"
00036 
00037 #include "llfloater.h"
00038 
00039 #include "llfocusmgr.h"
00040 
00041 #include "lluictrlfactory.h"
00042 #include "llbutton.h"
00043 #include "llcheckboxctrl.h"
00044 #include "lldraghandle.h"
00045 #include "llfocusmgr.h"
00046 #include "llresizebar.h"
00047 #include "llresizehandle.h"
00048 #include "llkeyboard.h"
00049 #include "llmenugl.h"   // MENU_BAR_HEIGHT
00050 #include "lltextbox.h"
00051 #include "llresmgr.h"
00052 #include "llui.h"
00053 #include "llviewborder.h"
00054 #include "llwindow.h"
00055 #include "llstl.h"
00056 #include "llcontrol.h"
00057 #include "lltabcontainer.h"
00058 #include "v2math.h"
00059 
00060 extern BOOL gNoRender;
00061 
00062 const S32 MINIMIZED_WIDTH = 160;
00063 const S32 CLOSE_BOX_FROM_TOP = 1;
00064 // use this to control "jumping" behavior when Ctrl-Tabbing
00065 const S32 TABBED_FLOATER_OFFSET = 0;
00066 
00067 LLString        LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = 
00068 {
00069         "UIImgBtnCloseActiveUUID",              //BUTTON_CLOSE
00070         "UIImgBtnRestoreActiveUUID",    //BUTTON_RESTORE
00071         "UIImgBtnMinimizeActiveUUID",   //BUTTON_MINIMIZE
00072         "UIImgBtnTearOffActiveUUID",    //BUTTON_TEAR_OFF
00073         "UIImgBtnCloseActiveUUID",              //BUTTON_EDIT
00074 };
00075 
00076 LLString        LLFloater::sButtonInactiveImageNames[BUTTON_COUNT] = 
00077 {
00078         "UIImgBtnCloseInactiveUUID",    //BUTTON_CLOSE
00079         "UIImgBtnRestoreInactiveUUID",  //BUTTON_RESTORE
00080         "UIImgBtnMinimizeInactiveUUID", //BUTTON_MINIMIZE
00081         "UIImgBtnTearOffInactiveUUID",  //BUTTON_TEAR_OFF
00082         "UIImgBtnCloseInactiveUUID",    //BUTTON_EDIT
00083 };
00084 
00085 LLString        LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = 
00086 {
00087         "UIImgBtnClosePressedUUID",             //BUTTON_CLOSE
00088         "UIImgBtnRestorePressedUUID",   //BUTTON_RESTORE
00089         "UIImgBtnMinimizePressedUUID",  //BUTTON_MINIMIZE
00090         "UIImgBtnTearOffPressedUUID",   //BUTTON_TEAR_OFF
00091         "UIImgBtnClosePressedUUID",             //BUTTON_EDIT
00092 };
00093 
00094 LLString        LLFloater::sButtonNames[BUTTON_COUNT] = 
00095 {
00096         "llfloater_close_btn",  //BUTTON_CLOSE
00097         "llfloater_restore_btn",        //BUTTON_RESTORE
00098         "llfloater_minimize_btn",       //BUTTON_MINIMIZE
00099         "llfloater_tear_off_btn",       //BUTTON_TEAR_OFF
00100         "llfloater_edit_btn",           //BUTTON_EDIT
00101 };
00102 
00103 LLString        LLFloater::sButtonToolTips[BUTTON_COUNT] = 
00104 {
00105 #ifdef LL_DARWIN
00106         "Close (Cmd-W)",        //BUTTON_CLOSE
00107 #else
00108         "Close (Ctrl-W)",       //BUTTON_CLOSE
00109 #endif
00110         "Restore",      //BUTTON_RESTORE
00111         "Minimize",     //BUTTON_MINIMIZE
00112         "Tear Off",     //BUTTON_TEAR_OFF
00113         "Edit",         //BUTTON_EDIT
00114 };
00115 
00116 LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
00117 {
00118         LLFloater::onClickClose,        //BUTTON_CLOSE
00119         LLFloater::onClickMinimize, //BUTTON_RESTORE
00120         LLFloater::onClickMinimize, //BUTTON_MINIMIZE
00121         LLFloater::onClickTearOff,      //BUTTON_TEAR_OFF
00122         LLFloater::onClickEdit, //BUTTON_EDIT
00123 };
00124 
00125 LLMultiFloater* LLFloater::sHostp = NULL;
00126 BOOL                    LLFloater::sEditModeEnabled;
00127 LLFloater::handle_map_t LLFloater::sFloaterMap;
00128 
00129 LLFloaterView* gFloaterView = NULL;
00130 
00131 LLFloater::LLFloater() 
00132 {
00133         // automatically take focus when opened
00134         mAutoFocus = TRUE;
00135         for (S32 i = 0; i < BUTTON_COUNT; i++)
00136         {
00137                 mButtonsEnabled[i] = FALSE;
00138                 mButtons[i] = NULL;
00139         }
00140         mDragHandle = NULL;
00141 }
00142 
00143 LLFloater::LLFloater(const LLString& name)
00144 :       LLPanel(name)
00145 {
00146         for (S32 i = 0; i < BUTTON_COUNT; i++)
00147         {
00148                 mButtonsEnabled[i] = FALSE;
00149                 mButtons[i] = NULL;
00150         }
00151 
00152         LLString title; // null string
00153         // automatically take focus when opened
00154         mAutoFocus = TRUE;
00155         init(title, FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, TRUE, TRUE); // defaults
00156 }
00157 
00158 
00159 LLFloater::LLFloater(const LLString& name, const LLRect& rect, const LLString& title, 
00160         BOOL resizable, 
00161         S32 min_width, 
00162         S32 min_height,
00163         BOOL drag_on_left,
00164         BOOL minimizable,
00165         BOOL close_btn,
00166         BOOL bordered)
00167 :       LLPanel(name, rect, bordered)
00168 {
00169         for (S32 i = 0; i < BUTTON_COUNT; i++)
00170         {
00171                 mButtonsEnabled[i] = FALSE;
00172                 mButtons[i] = NULL;
00173         }
00174         // automatically take focus when opened
00175         mAutoFocus = TRUE;
00176         init( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn);
00177 }
00178 
00179 LLFloater::LLFloater(const LLString& name, const LLString& rect_control, const LLString& title, 
00180         BOOL resizable, 
00181         S32 min_width, 
00182         S32 min_height,
00183         BOOL drag_on_left,
00184         BOOL minimizable,
00185         BOOL close_btn,
00186         BOOL bordered)
00187 :       LLPanel(name, rect_control, bordered)
00188 {
00189         for (S32 i = 0; i < BUTTON_COUNT; i++)
00190         {
00191                 mButtonsEnabled[i] = FALSE;
00192                 mButtons[i] = NULL;
00193         }
00194         // automatically take focus when opened
00195         mAutoFocus = TRUE;
00196         init( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn);
00197 }
00198 
00199 
00200 // Note: Floaters constructed from XML call init() twice!
00201 void LLFloater::init(const LLString& title,
00202                                          BOOL resizable, S32 min_width, S32 min_height,
00203                                          BOOL drag_on_left, BOOL minimizable, BOOL close_btn)
00204 {
00205         // Init function can be called more than once, so clear out old data.
00206         for (S32 i = 0; i < BUTTON_COUNT; i++)
00207         {
00208                 mButtonsEnabled[i] = FALSE;
00209                 if (mButtons[i] != NULL)
00210                 {
00211                         removeChild(mButtons[i]);
00212                         delete mButtons[i];
00213                         mButtons[i] = NULL;
00214                 }
00215         }
00216         mButtonScale = 1.f;
00217 
00218         LLPanel::deleteAllChildren();
00219         //sjb: HACK! we had a border which was just deleted, so re-create it
00220         if (mBorder != NULL)
00221         {
00222                 addBorder();
00223         }
00224 
00225         // chrome floaters don't take focus at all
00226         mIsFocusRoot = !getIsChrome();
00227 
00228         // Reset cached pointers
00229         mDragHandle = NULL;
00230         for (S32 i = 0; i < 4; i++) 
00231         {
00232                 mResizeBar[i] = NULL;
00233                 mResizeHandle[i] = NULL;
00234         }
00235         mCanTearOff = TRUE;
00236         mEditing = FALSE;
00237 
00238         // Clicks stop here.
00239         setMouseOpaque(TRUE);
00240 
00241         mFirstLook = TRUE;
00242         mForeground = FALSE;
00243         mDragOnLeft = drag_on_left == TRUE;
00244 
00245         // Floaters always draw their background, unlike every other panel.
00246         setBackgroundVisible(TRUE);
00247 
00248         // Floaters start not minimized.  When minimized, they save their
00249         // prior rectangle to be used on restore.
00250         mMinimized = FALSE;
00251         mPreviousRect.set(0,0,0,0);
00252         
00253         S32 close_pad;                  // space to the right of close box
00254         S32 close_box_size;             // For layout purposes, how big is the close box?
00255         if (close_btn)
00256         {
00257                 close_box_size = LLFLOATER_CLOSE_BOX_SIZE;
00258                 close_pad = 0;
00259         }
00260         else
00261         {
00262                 close_box_size = 0;
00263                 close_pad = 0;
00264         }
00265 
00266         S32 minimize_box_size;
00267         S32 minimize_pad;
00268         if (minimizable && !drag_on_left)
00269         {
00270                 minimize_box_size = LLFLOATER_CLOSE_BOX_SIZE;
00271                 minimize_pad = 0;
00272         }
00273         else
00274         {
00275                 minimize_box_size = 0;
00276                 minimize_pad = 0;
00277         }
00278 
00279         // Drag Handle
00280         // Add first so it's in the background.
00281 //      const S32 drag_pad = 2;
00282         LLRect drag_handle_rect;
00283         if (!drag_on_left)
00284         {
00285                 drag_handle_rect.set( 0, mRect.getHeight(), mRect.getWidth(), 0 );
00286 
00287                 /*
00288                 drag_handle_rect.setLeftTopAndSize(
00289                         0, mRect.getHeight(),
00290                         mRect.getWidth() 
00291                                 - LLPANEL_BORDER_WIDTH 
00292                                 - drag_pad
00293                                 - minimize_box_size - minimize_pad 
00294                                 - close_box_size - close_pad,
00295                         DRAG_HANDLE_HEIGHT);
00296                         */
00297                 mDragHandle = new LLDragHandleTop( "Drag Handle", drag_handle_rect, title );
00298         }
00299         else
00300         {
00301                 drag_handle_rect.setOriginAndSize(
00302                         0, 0,
00303                         DRAG_HANDLE_WIDTH,
00304                         mRect.getHeight() - LLPANEL_BORDER_WIDTH - close_box_size);
00305                 mDragHandle = new LLDragHandleLeft("drag", drag_handle_rect, title );
00306         }
00307         addChild(mDragHandle);
00308 
00309         // Resize Handle
00310         mResizable = resizable;
00311         mMinWidth = min_width;
00312         mMinHeight = min_height;
00313 
00314         if( mResizable )
00315         {
00316                 // Resize bars (sides)
00317                 const S32 RESIZE_BAR_THICKNESS = 3;
00318                 mResizeBar[LLResizeBar::LEFT] = new LLResizeBar( 
00319                         "resizebar_left",
00320                         this,
00321                         LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0), 
00322                         min_width, S32_MAX, LLResizeBar::LEFT );
00323                 addChild( mResizeBar[0] );
00324 
00325                 mResizeBar[LLResizeBar::TOP] = new LLResizeBar( 
00326                         "resizebar_top",
00327                         this,
00328                         LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS), 
00329                         min_height, S32_MAX, LLResizeBar::TOP );
00330                 addChild( mResizeBar[1] );
00331 
00332                 mResizeBar[LLResizeBar::RIGHT] = new LLResizeBar( 
00333                         "resizebar_right",
00334                         this,
00335                         LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), 
00336                         min_width, S32_MAX, LLResizeBar::RIGHT );
00337                 addChild( mResizeBar[2] );
00338 
00339                 mResizeBar[LLResizeBar::BOTTOM] = new LLResizeBar( 
00340                         "resizebar_bottom",
00341                         this,
00342                         LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0), 
00343                         min_height, S32_MAX, LLResizeBar::BOTTOM );
00344                 addChild( mResizeBar[3] );
00345 
00346 
00347                 // Resize handles (corners)
00348                 mResizeHandle[0] = new LLResizeHandle( 
00349                         "Resize Handle",
00350                         LLRect( mRect.getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, mRect.getWidth(), 0),
00351                         min_width,
00352                         min_height,
00353                         LLResizeHandle::RIGHT_BOTTOM);
00354                 addChild(mResizeHandle[0]);
00355 
00356                 mResizeHandle[1] = new LLResizeHandle( "resize", 
00357                         LLRect( mRect.getWidth() - RESIZE_HANDLE_WIDTH, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_HANDLE_HEIGHT),
00358                         min_width,
00359                         min_height,
00360                         LLResizeHandle::RIGHT_TOP );
00361                 addChild(mResizeHandle[1]);
00362                 
00363                 mResizeHandle[2] = new LLResizeHandle( "resize", 
00364                         LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ),
00365                         min_width,
00366                         min_height,
00367                         LLResizeHandle::LEFT_BOTTOM );
00368                 addChild(mResizeHandle[2]);
00369 
00370                 mResizeHandle[3] = new LLResizeHandle( "resize", 
00371                         LLRect( 0, mRect.getHeight(), RESIZE_HANDLE_WIDTH, mRect.getHeight() - RESIZE_HANDLE_HEIGHT ),
00372                         min_width,
00373                         min_height,
00374                         LLResizeHandle::LEFT_TOP );
00375                 addChild(mResizeHandle[3]);
00376         }
00377 
00378         // Close button.
00379         if (close_btn)
00380         {
00381                 mButtonsEnabled[BUTTON_CLOSE] = TRUE;
00382         }
00383 
00384         // Minimize button only for top draggers
00385         if ( !drag_on_left && minimizable )
00386         {
00387                 mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
00388         }
00389 
00390         // Keep track of whether this window has ever been dragged while it
00391         // was minimized.  If it has, we'll remember its position for the
00392         // next time it's minimized.
00393         mHasBeenDraggedWhileMinimized = FALSE;
00394         mPreviousMinimizedLeft = 0;
00395         mPreviousMinimizedBottom = 0;
00396 
00397         buildButtons();
00398 
00399         // JC - Don't do this here, because many floaters first construct themselves,
00400         // then show themselves.  Put it in setVisibleAndFrontmost.
00401         // make_ui_sound("UISndWindowOpen");
00402 
00403         // RN: floaters are created in the invisible state      
00404         setVisible(FALSE);
00405 
00406         // add self to handle->floater map
00407         sFloaterMap[mViewHandle] = this;
00408 
00409         if (!getParent())
00410         {
00411                 gFloaterView->addChild(this);
00412         }
00413 }
00414 
00415 // virtual
00416 LLFloater::~LLFloater()
00417 {
00418         control_map_t::iterator itor;
00419         for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor)
00420         {
00421                 delete itor->second;
00422         }
00423         mFloaterControls.clear();
00424 
00426         //if (mHostHandle.isDead())
00427         //{
00428         //      LLFloaterView* parent = (LLFloaterView*) getParent();
00429 
00430         //      if( parent )
00431         //      {
00432         //              parent->removeChild( this );
00433         //      }
00434         //}
00435 
00436         // Just in case we might still have focus here, release it.
00437         releaseFocus();
00438 
00439         // This is important so that floaters with persistent rects (i.e., those
00440         // created with rect control rather than an LLRect) are restored in their
00441         // correct, non-minimized positions.
00442         setMinimized( FALSE );
00443 
00444         sFloaterMap.erase(mViewHandle);
00445 
00446         delete mDragHandle;
00447         for (S32 i = 0; i < 4; i++) 
00448         {
00449                 delete mResizeBar[i];
00450                 delete mResizeHandle[i];
00451         }
00452 }
00453 
00454 // virtual
00455 EWidgetType LLFloater::getWidgetType() const
00456 {
00457         return WIDGET_TYPE_FLOATER;
00458 }
00459 
00460 // virtual
00461 LLString LLFloater::getWidgetTag() const
00462 {
00463         return LL_FLOATER_TAG;
00464 }
00465 
00466 void LLFloater::destroy()
00467 {
00468         die();  
00469 }
00470 
00471 void LLFloater::setVisible( BOOL visible )
00472 {
00473         LLPanel::setVisible(visible);
00474         if( visible && mFirstLook )
00475         {
00476                 mFirstLook = FALSE;
00477         }
00478 
00479         if( !visible )
00480         {
00481                 if( gFocusMgr.childIsTopCtrl( this ) )
00482                 {
00483                         gFocusMgr.setTopCtrl(NULL);
00484                 }
00485 
00486                 if( gFocusMgr.childHasMouseCapture( this ) )
00487                 {
00488                         gFocusMgr.setMouseCapture(NULL);
00489                 }
00490         }
00491 
00492         for(handle_set_iter_t dependent_it = mDependents.begin();
00493                 dependent_it != mDependents.end(); )
00494         {
00495                 LLFloater* floaterp = LLFloater::getFloaterByHandle(*dependent_it);
00496 
00497                 if (floaterp)
00498                 {
00499                         floaterp->setVisible(visible);
00500                 }
00501                 ++dependent_it;
00502         }
00503 }
00504 
00505 void LLFloater::open()  /* Flawfinder: ignore */
00506 {
00507         if (mSoundFlags != SILENT 
00508         // don't play open sound for hosted (tabbed) windows
00509                 && !getHost() 
00510                 && !sHostp
00511                 && (!getVisible() || isMinimized()))
00512         {
00513                 make_ui_sound("UISndWindowOpen");
00514         }
00515 
00516         //RN: for now, we don't allow rehosting from one multifloater to another
00517         // just need to fix the bugs
00518         LLMultiFloater* hostp = getHost();
00519         if (sHostp != NULL && hostp == NULL)
00520         {
00521                 // needs a host
00522                 // only select tabs if window they are hosted in is visible
00523                 sHostp->addFloater(this, sHostp->getVisible());
00524         }
00525         else if (hostp != NULL)
00526         {
00527                 // already hosted
00528                 hostp->showFloater(this);
00529         }
00530         else
00531         {
00532                 setMinimized(FALSE);
00533                 setVisibleAndFrontmost(mAutoFocus);
00534         }
00535 
00536         onOpen();
00537 }
00538 
00539 void LLFloater::close(bool app_quitting)
00540 {
00541         // Always unminimize before trying to close.
00542         // Most of the time the user will never see this state.
00543         setMinimized(FALSE);
00544 
00545         if (canClose())
00546         {
00547                 if (getHost())
00548                 {
00549                         ((LLMultiFloater*)getHost())->removeFloater(this);
00550                 }
00551 
00552                 if (mSoundFlags != SILENT
00553                         && getVisible()
00554                         && !getHost()
00555                         && !app_quitting)
00556                 {
00557                         make_ui_sound("UISndWindowClose");
00558                 }
00559 
00560                 // now close dependent floater
00561                 for(handle_set_iter_t dependent_it = mDependents.begin();
00562                         dependent_it != mDependents.end(); )
00563                 {
00564                         
00565                         LLFloater* floaterp = LLFloater::getFloaterByHandle(*dependent_it);
00566                         if (floaterp)
00567                         {
00568                                 ++dependent_it;
00569                                 floaterp->close();
00570                         }
00571                         else
00572                         {
00573                                 mDependents.erase(dependent_it++);
00574                         }
00575                 }
00576                 
00577                 cleanupHandles();
00578                 gFocusMgr.clearLastFocusForGroup(this);
00579 
00580                 if (hasFocus())
00581                 {
00582                         // Do this early, so UI controls will commit before the
00583                         // window is taken down.
00584                         releaseFocus();
00585 
00586                         // give focus to dependee floater if it exists, and we had focus first
00587                         if (isDependent())
00588                         {
00589                                 LLFloater* dependee = LLFloater::getFloaterByHandle(mDependeeHandle);
00590                                 if (dependee && !dependee->isDead())
00591                                 {
00592                                         dependee->setFocus(TRUE);
00593                                 }
00594                         }
00595                 }
00596 
00597                 // Let floater do cleanup.
00598                 onClose(app_quitting);
00599         }
00600 }
00601 
00602 
00603 void LLFloater::releaseFocus()
00604 {
00605         if( gFocusMgr.childIsTopCtrl( this ) )
00606         {
00607                 gFocusMgr.setTopCtrl(NULL);
00608         }
00609 
00610         if( gFocusMgr.childHasKeyboardFocus( this ) )
00611         {
00612                 gFocusMgr.setKeyboardFocus(NULL, NULL);
00613         }
00614 
00615         if( gFocusMgr.childHasMouseCapture( this ) )
00616         {
00617                 gFocusMgr.setMouseCapture(NULL);
00618         }
00619 }
00620 
00621 
00622 void LLFloater::setResizeLimits( S32 min_width, S32 min_height )
00623 {
00624         mMinWidth = min_width;
00625         mMinHeight = min_height;
00626 
00627         for( S32 i = 0; i < 4; i++ )
00628         {
00629                 if( mResizeBar[i] )
00630                 {
00631                         if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
00632                         {
00633                                 mResizeBar[i]->setResizeLimits( min_width, S32_MAX );
00634                         }
00635                         else
00636                         {
00637                                 mResizeBar[i]->setResizeLimits( min_height, S32_MAX );
00638                         }
00639                 }
00640                 if( mResizeHandle[i] )
00641                 {
00642                         mResizeHandle[i]->setResizeLimits( min_width, min_height );
00643                 }
00644         }
00645 }
00646 
00647 
00648 void LLFloater::center()
00649 {
00650         if(getHost())
00651         {
00652                 // hosted floaters can't move
00653                 return;
00654         }
00655         const LLRect &window = gFloaterView->getRect();
00656 
00657         S32 left   = window.mLeft + (window.getWidth() - mRect.getWidth()) / 2;
00658         S32 bottom = window.mBottom + (window.getHeight() - mRect.getHeight()) / 2;
00659 
00660         translate( left - mRect.mLeft, bottom - mRect.mBottom );
00661 }
00662 
00663 void LLFloater::applyRectControl()
00664 {
00665         if (!mRectControl.empty())
00666         {
00667                 const LLRect& rect = LLUI::sConfigGroup->getRect(mRectControl);
00668                 translate( rect.mLeft - mRect.mLeft, rect.mBottom - mRect.mBottom);
00669                 if (mResizable)
00670                 {
00671                         reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight()));
00672                 }
00673         }
00674 }
00675 
00676 void LLFloater::setTitle( const LLString& title )
00677 {
00678         if (gNoRender)
00679         {
00680                 return;
00681         }
00682         mDragHandle->setTitle( title );
00683 }
00684 
00685 const LLString& LLFloater::getTitle() const
00686 {
00687         return mDragHandle ? mDragHandle->getTitle() : LLString::null;
00688 }
00689 
00690 void LLFloater::setShortTitle( const LLString& short_title )
00691 {
00692         mShortTitle = short_title;
00693 }
00694 
00695 LLString LLFloater::getShortTitle()
00696 {
00697         if (mShortTitle.empty())
00698         {
00699                 return mDragHandle ? mDragHandle->getTitle() : LLString::null;
00700         }
00701         else
00702         {
00703                 return mShortTitle;
00704         }
00705 }
00706 
00707 
00708 
00709 BOOL LLFloater::canSnapTo(LLView* other_view)
00710 {
00711         if (NULL == other_view)
00712         {
00713                 llwarns << "other_view is NULL" << llendl;
00714                 return FALSE;
00715         }
00716 
00717         if (other_view != getParent())
00718         {
00719                 LLFloater* other_floaterp = (LLFloater*)other_view;
00720                 
00721                 if (other_floaterp->getSnapTarget() == mViewHandle && mDependents.find(other_floaterp->getHandle()) != mDependents.end())
00722                 {
00723                         // this is a dependent that is already snapped to us, so don't snap back to it
00724                         return FALSE;
00725                 }
00726         }
00727 
00728         return LLPanel::canSnapTo(other_view);
00729 }
00730 
00731 void LLFloater::snappedTo(LLView* snap_view)
00732 {
00733         if (!snap_view || snap_view == getParent())
00734         {
00735                 clearSnapTarget();
00736         }
00737         else
00738         {
00739                 //RN: assume it's a floater as it must be a sibling to our parent floater
00740                 LLFloater* floaterp = (LLFloater*)snap_view;
00741                 
00742                 setSnapTarget(floaterp->getHandle());
00743         }
00744 }
00745 
00746 void LLFloater::userSetShape(const LLRect& new_rect)
00747 {
00748         LLRect old_rect = mRect;
00749         LLView::userSetShape(new_rect);
00750 
00751         // if not minimized, adjust all snapped dependents to new shape
00752         if (!isMinimized())
00753         {
00754                 // gather all snapped dependents
00755                 for(handle_set_iter_t dependent_it = mDependents.begin();
00756                         dependent_it != mDependents.end(); ++dependent_it)
00757                 {
00758                         LLFloater* floaterp = LLFloater::getFloaterByHandle(*dependent_it);
00759                         // is a dependent snapped to us?
00760                         if (floaterp && floaterp->getSnapTarget() == mViewHandle)
00761                         {
00762                                 S32 delta_x = 0;
00763                                 S32 delta_y = 0;
00764                                 // check to see if it snapped to right or top, and move if dependee floater is resizing
00765                                 LLRect dependent_rect = floaterp->getRect();
00766                                 if (dependent_rect.mLeft - mRect.mLeft >= old_rect.getWidth() || // dependent on my right?
00767                                         dependent_rect.mRight == mRect.mLeft + old_rect.getWidth()) // dependent aligned with my right
00768                                 {
00769                                         // was snapped directly onto right side or aligned with it
00770                                         delta_x += new_rect.getWidth() - old_rect.getWidth();
00771                                 }
00772                                 if (dependent_rect.mBottom - mRect.mBottom >= old_rect.getHeight() ||
00773                                         dependent_rect.mTop == mRect.mBottom + old_rect.getHeight())
00774                                 {
00775                                         // was snapped directly onto top side or aligned with it
00776                                         delta_y += new_rect.getHeight() - old_rect.getHeight();
00777                                 }
00778 
00779                                 // take translation of dependee floater into account as well
00780                                 delta_x += new_rect.mLeft - old_rect.mLeft;
00781                                 delta_y += new_rect.mBottom - old_rect.mBottom;
00782 
00783                                 dependent_rect.translate(delta_x, delta_y);
00784                                 floaterp->userSetShape(dependent_rect);
00785                         }
00786                 }
00787         }
00788         else
00789         {
00790                 // If minimized, and origin has changed, set
00791                 // mHasBeenDraggedWhileMinimized to TRUE
00792                 if ((new_rect.mLeft != old_rect.mLeft) ||
00793                         (new_rect.mBottom != old_rect.mBottom))
00794                 {
00795                         mHasBeenDraggedWhileMinimized = TRUE;
00796                 }
00797         }
00798 }
00799 
00800 void LLFloater::setMinimized(BOOL minimize)
00801 {
00802         if (minimize == mMinimized) return;
00803 
00804         if (minimize)
00805         {
00806                 mPreviousRect = mRect;
00807 
00808                 reshape( MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE, TRUE);
00809 
00810                 // If the floater has been dragged while minimized in the
00811                 // past, then locate it at its previous minimized location.
00812                 // Otherwise, ask the view for a minimize position.
00813                 if (mHasBeenDraggedWhileMinimized)
00814                 {
00815                         setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
00816                 }
00817                 else
00818                 {
00819                         S32 left, bottom;
00820                         gFloaterView->getMinimizePosition(&left, &bottom);
00821                         setOrigin( left, bottom );
00822                 }
00823 
00824                 if (mButtonsEnabled[BUTTON_MINIMIZE])
00825                 {
00826                         mButtonsEnabled[BUTTON_MINIMIZE] = FALSE;
00827                         mButtonsEnabled[BUTTON_RESTORE] = TRUE;
00828                 }
00829 
00830                 mMinimizedHiddenChildren.clear();
00831                 // hide all children
00832                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
00833                 {
00834                         LLView* viewp = *child_it;
00835                         if (!viewp->getVisible())
00836                         {
00837                                 mMinimizedHiddenChildren.push_back(viewp);
00838                         }
00839                         viewp->setVisible(FALSE);
00840                 }
00841 
00842                 // except the special controls
00843                 if (mDragHandle)
00844                 {
00845                         mDragHandle->setVisible(TRUE);
00846                 }
00847 
00848                 setBorderVisible(TRUE);
00849 
00850                 for(handle_set_iter_t dependent_it = mDependents.begin();
00851                         dependent_it != mDependents.end();
00852                         ++dependent_it)
00853                 {
00854                         LLFloater* floaterp = LLFloater::getFloaterByHandle(*dependent_it);
00855                         if (floaterp)
00856                         {
00857                                 if (floaterp->isMinimizeable())
00858                                 {
00859                                         floaterp->setMinimized(TRUE);
00860                                 }
00861                                 else if (!floaterp->isMinimized())
00862                                 {
00863                                         floaterp->setVisible(FALSE);
00864                                 }
00865                         }
00866                 }
00867 
00868                 // Lose keyboard focus when minimized
00869                 releaseFocus();
00870 
00871                 mMinimized = TRUE;
00872         }
00873         else
00874         {
00875                 // If this window has been dragged while minimized (at any time),
00876                 // remember its position for the next time it's minimized.
00877                 if (mHasBeenDraggedWhileMinimized)
00878                 {
00879                         const LLRect& currentRect = getRect();
00880                         mPreviousMinimizedLeft = currentRect.mLeft;
00881                         mPreviousMinimizedBottom = currentRect.mBottom;
00882                 }
00883 
00884                 reshape( mPreviousRect.getWidth(), mPreviousRect.getHeight(), TRUE );
00885                 setOrigin( mPreviousRect.mLeft, mPreviousRect.mBottom );
00886 
00887                 if (mButtonsEnabled[BUTTON_RESTORE])
00888                 {
00889                         mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
00890                         mButtonsEnabled[BUTTON_RESTORE] = FALSE;
00891                 }
00892 
00893                 // show all children
00894                 for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
00895                 {
00896                         LLView* viewp = *child_it;
00897                         viewp->setVisible(TRUE);
00898                 }
00899 
00900                 std::vector<LLView*>::iterator itor = mMinimizedHiddenChildren.begin();
00901                 while (itor != mMinimizedHiddenChildren.end())
00902                 {
00903                         (*itor)->setVisible(FALSE);
00904                         ++itor;
00905                 }
00906                 mMinimizedHiddenChildren.clear();
00907 
00908                 // show dependent floater
00909                 for(handle_set_iter_t dependent_it = mDependents.begin();
00910                         dependent_it != mDependents.end();
00911                         ++dependent_it)
00912                 {
00913                         LLFloater* floaterp = LLFloater::getFloaterByHandle(*dependent_it);
00914                         if (floaterp)
00915                         {
00916                                 floaterp->setMinimized(FALSE);
00917                                 floaterp->setVisible(TRUE);
00918                         }
00919                 }
00920 
00921                 mMinimized = FALSE;
00922         }
00923         make_ui_sound("UISndWindowClose");
00924         updateButtons();
00925 }
00926 
00927 void LLFloater::setFocus( BOOL b )
00928 {
00929         if (b && getIsChrome())
00930         {
00931                 return;
00932         }
00933         LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this);
00934         // a descendent already has focus
00935         BOOL child_had_focus = gFocusMgr.childHasKeyboardFocus(this);
00936 
00937         // give focus to first valid descendent
00938         LLPanel::setFocus(b);
00939 
00940         if (b)
00941         {
00942                 // only push focused floaters to front of stack if not in midst of ctrl-tab cycle
00943                 if (!getHost() && !((LLFloaterView*)getParent())->getCycleMode())
00944                 {
00945                         if (!isFrontmost())
00946                         {
00947                                 setFrontmost();
00948                         }
00949                 }
00950 
00951                 // when getting focus, delegate to last descendent which had focus
00952                 if (last_focus && !child_had_focus && 
00953                         last_focus->isInEnabledChain() &&
00954                         last_focus->isInVisibleChain())
00955                 {
00956                         // *FIX: should handle case where focus doesn't stick
00957                         last_focus->setFocus(TRUE);
00958                 }
00959         }
00960 }
00961 
00962 void LLFloater::setIsChrome(BOOL is_chrome)
00963 {
00964         // chrome floaters don't take focus at all
00965         if (is_chrome)
00966         {
00967                 // remove focus if we're changing to chrome
00968                 setFocus(FALSE);
00969                 // can't Ctrl-Tab to "chrome" floaters
00970                 mIsFocusRoot = FALSE;
00971         }
00972         
00973         // no titles displayed on "chrome" floaters
00974         mDragHandle->setTitleVisible(!is_chrome);
00975         
00976         LLPanel::setIsChrome(is_chrome);
00977 }
00978 
00979 // Change the draw style to account for the foreground state.
00980 void LLFloater::setForeground(BOOL front)
00981 {
00982         if (front != mForeground)
00983         {
00984                 mForeground = front;
00985                 mDragHandle->setForeground( front );
00986 
00987                 if (!front)
00988                 {
00989                         releaseFocus();
00990                 }
00991 
00992                 setBackgroundOpaque( front ); 
00993         }
00994 }
00995 
00996 void LLFloater::cleanupHandles()
00997 {
00998         // remove handles to non-existent dependents
00999         for(handle_set_iter_t dependent_it = mDependents.begin();
01000                 dependent_it != mDependents.end(); )
01001         {
01002                 LLFloater* floaterp = LLFloater::getFloaterByHandle(*dependent_it);
01003                 if (!floaterp)
01004                 {
01005                         mDependents.erase(dependent_it++);
01006                 }
01007                 else
01008                 {
01009                         ++dependent_it;
01010                 }
01011         }
01012 }
01013 
01014 void LLFloater::setHost(LLMultiFloater* host)
01015 {
01016         if (mHostHandle.isDead() && host)
01017         {
01018                 // make buttons smaller for hosted windows to differentiate from parent
01019                 mButtonScale = 0.9f;
01020 
01021                 // add tear off button
01022                 if (mCanTearOff)
01023                 {
01024                         mButtonsEnabled[BUTTON_TEAR_OFF] = TRUE;
01025                 }
01026 
01027                 mIsFocusRoot = FALSE;
01028         }
01029         else if (!mHostHandle.isDead() && !host)
01030         {
01031                 mButtonScale = 1.f;
01032                 mIsFocusRoot = TRUE;
01033                 //mButtonsEnabled[BUTTON_TEAR_OFF] = FALSE;
01034         }
01035         updateButtons();
01036         if (host)
01037         {
01038                 mHostHandle = host->getHandle();
01039                 mLastHostHandle = host->getHandle();
01040         }
01041         else
01042         {
01043                 mHostHandle.markDead();
01044         }
01045 }
01046 
01047 void LLFloater::moveResizeHandlesToFront()
01048 {
01049         for( S32 i = 0; i < 4; i++ )
01050         {
01051                 if( mResizeBar[i] )
01052                 {
01053                         sendChildToFront(mResizeBar[i]);
01054                 }
01055         }
01056 
01057         for( S32 i = 0; i < 4; i++ )
01058         {
01059                 if( mResizeHandle[i] )
01060                 {
01061                         sendChildToFront(mResizeHandle[i]);
01062                 }
01063         }
01064 }
01065 
01066 BOOL LLFloater::isFrontmost()
01067 {
01068         return gFloaterView && gFloaterView->getFrontmost() == this && getVisible();
01069 }
01070 
01071 void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)
01072 {
01073         mDependents.insert(floaterp->getHandle());
01074         floaterp->mDependeeHandle = getHandle();
01075 
01076         if (reposition)
01077         {
01078                 floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp));
01079                 floaterp->setSnapTarget(mViewHandle);
01080         }
01081         gFloaterView->adjustToFitScreen(floaterp, FALSE);
01082         if (floaterp->isFrontmost())
01083         {
01084                 // make sure to bring self and sibling floaters to front
01085                 gFloaterView->bringToFront(floaterp);
01086         }
01087 }
01088 
01089 void LLFloater::addDependentFloater(LLViewHandle dependent, BOOL reposition)
01090 {
01091         LLFloater* dependent_floaterp = LLFloater::getFloaterByHandle(dependent);
01092         if(dependent_floaterp)
01093         {
01094                 addDependentFloater(dependent_floaterp, reposition);
01095         }
01096 }
01097 
01098 void LLFloater::removeDependentFloater(LLFloater* floaterp)
01099 {
01100         mDependents.erase(floaterp->getHandle());
01101         floaterp->mDependeeHandle = LLViewHandle::sDeadHandle;
01102 }
01103 
01104 // virtual
01105 BOOL LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
01106 {
01107         if( mMinimized )
01108         {
01109                 // Offer the click to the close button.
01110                 if( mButtonsEnabled[BUTTON_CLOSE] )
01111                 {
01112                         S32 local_x = x - mButtons[BUTTON_CLOSE]->getRect().mLeft;
01113                         S32 local_y = y - mButtons[BUTTON_CLOSE]->getRect().mBottom;
01114 
01115                         if (mButtons[BUTTON_CLOSE]->pointInView(local_x, local_y)
01116                                 && mButtons[BUTTON_CLOSE]->handleMouseDown(local_x, local_y, mask))
01117                         {
01118                                 // close button handled it, return
01119                                 return TRUE;
01120                         }
01121                 }
01122 
01123                 // Offer the click to the restore button.
01124                 if( mButtonsEnabled[BUTTON_RESTORE] )
01125                 {
01126                         S32 local_x = x - mButtons[BUTTON_RESTORE]->getRect().mLeft;
01127                         S32 local_y = y - mButtons[BUTTON_RESTORE]->getRect().mBottom;
01128 
01129                         if (mButtons[BUTTON_RESTORE]->pointInView(local_x, local_y)
01130                                 && mButtons[BUTTON_RESTORE]->handleMouseDown(local_x, local_y, mask))
01131                         {
01132                                 // restore button handled it, return
01133                                 return TRUE;
01134                         }
01135                 }
01136 
01137                 // Otherwise pass to drag handle for movement
01138                 return mDragHandle->handleMouseDown(x, y, mask);
01139         }
01140         else
01141         {
01142                 bringToFront( x, y );
01143                 return LLPanel::handleMouseDown( x, y, mask );
01144         }
01145 }
01146 
01147 // virtual
01148 BOOL LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask)
01149 {
01150         BOOL was_minimized = mMinimized;
01151         bringToFront( x, y );
01152         return was_minimized || LLPanel::handleRightMouseDown( x, y, mask );
01153 }
01154 
01155 
01156 // virtual
01157 BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
01158 {
01159         BOOL was_minimized = mMinimized;
01160         setMinimized(FALSE);
01161         return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
01162 }
01163 
01164 void LLFloater::bringToFront( S32 x, S32 y )
01165 {
01166         if (getVisible() && pointInView(x, y))
01167         {
01168                 LLMultiFloater* hostp = getHost();
01169                 if (hostp)
01170                 {
01171                         hostp->showFloater(this);
01172                 }
01173                 else
01174                 {
01175                         LLFloaterView* parent = (LLFloaterView*) getParent();
01176                         if (parent)
01177                         {
01178                                 parent->bringToFront( this );
01179                         }
01180                 }
01181         }
01182 }
01183 
01184 
01185 // virtual
01186 void LLFloater::setVisibleAndFrontmost(BOOL take_focus)
01187 {
01188         setVisible(TRUE);
01189         setFrontmost(take_focus);
01190 }
01191 
01192 void LLFloater::setFrontmost(BOOL take_focus)
01193 {
01194         LLMultiFloater* hostp = getHost();
01195         if (hostp)
01196         {
01197                 // this will bring the host floater to the front and select
01198                 // the appropriate panel
01199                 hostp->showFloater(this);
01200         }
01201         else
01202         {
01203                 // there are more than one floater view
01204                 // so we need to query our parent directly
01205                 ((LLFloaterView*)getParent())->bringToFront(this, take_focus);
01206         }
01207 }
01208 
01209 // static
01210 LLFloater*      LLFloater::getFloaterByHandle(LLViewHandle handle)
01211 {
01212         LLFloater* floater = NULL;
01213         if (sFloaterMap.count(handle))
01214         {
01215                 floater = sFloaterMap[handle];
01216         }
01217         if (floater && !floater->isDead())
01218         {
01219                 return floater;
01220         }
01221         else
01222         {
01223                 return NULL;
01224         }
01225 }
01226 
01227 //static
01228 void LLFloater::setEditModeEnabled(BOOL enable)
01229 {
01230         if (enable != sEditModeEnabled)
01231         {
01232                 S32 count = 0;
01233                 std::map<LLViewHandle, LLFloater*>::iterator iter;
01234                 for(iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter)
01235                 {
01236                         LLFloater* floater = iter->second;
01237                         if (!floater->isDead())
01238                         {
01239                                 iter->second->mButtonsEnabled[BUTTON_EDIT] = enable;
01240                                 iter->second->updateButtons();
01241                         }
01242                         count++;
01243                 }
01244         }
01245 
01246         sEditModeEnabled = enable;
01247 }
01248 
01249 //static
01250 BOOL LLFloater::getEditModeEnabled()
01251 {
01252         return sEditModeEnabled;
01253 }
01254 
01255 //static 
01256 void LLFloater::show(LLFloater* floaterp)
01257 {
01258         if (floaterp) 
01259         {
01260                 floaterp->open();
01261                 if (floaterp->getHost())
01262                 {
01263                         floaterp->getHost()->open();
01264                 }
01265         }
01266 }
01267 
01268 //static 
01269 void LLFloater::hide(LLFloater* floaterp)
01270 {
01271         if (floaterp) floaterp->close();
01272 }
01273 
01274 //static
01275 BOOL LLFloater::visible(LLFloater* floaterp)
01276 {
01277         if (floaterp) 
01278         {
01279                 return !floaterp->isMinimized() && floaterp->isInVisibleChain();
01280         }
01281         return FALSE;
01282 }
01283 
01284 // static
01285 void LLFloater::onClickMinimize(void *userdata)
01286 {
01287         LLFloater* self = (LLFloater*) userdata;
01288         if (!self) return;
01289 
01290         self->setMinimized( !self->isMinimized() );
01291 }
01292 
01293 void LLFloater::onClickTearOff(void *userdata)
01294 {
01295         LLFloater* self = (LLFloater*) userdata;
01296         if (!self) return;
01297 
01298         LLMultiFloater* host_floater = self->getHost();
01299         if (host_floater) //Tear off
01300         {
01301                 LLRect new_rect;
01302                 host_floater->removeFloater(self);
01303                 // reparent to floater view
01304                 gFloaterView->addChild(self);
01305 
01306                 self->open();   /* Flawfinder: ignore */
01307                 
01308                 // only force position for floaters that don't have that data saved
01309                 if (self->mRectControl.empty())
01310                 {
01311                         new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->mRect.getWidth(), self->mRect.getHeight());
01312                         self->setRect(new_rect);
01313                 }
01314                 gFloaterView->adjustToFitScreen(self, FALSE);
01315                 // give focus to new window to keep continuity for the user
01316                 self->setFocus(TRUE);
01317         }
01318         else  //Attach to parent.
01319         {
01320                 LLMultiFloater* new_host = (LLMultiFloater*)LLFloater::getFloaterByHandle(self->mLastHostHandle);
01321                 if (new_host)
01322                 {
01323                         new_host->showFloater(self);
01324                         // make sure host is visible
01325                         new_host->open();
01326                 }
01327         }
01328 }
01329 
01330 // static
01331 void LLFloater::onClickEdit(void *userdata)
01332 {
01333         LLFloater* self = (LLFloater*) userdata;
01334         if (!self) return;
01335 
01336         self->mEditing = self->mEditing ? FALSE : TRUE;
01337 }
01338 
01339 // static
01340 void LLFloater::closeFocusedFloater()
01341 {
01342         LLFloater* focused_floater = NULL;
01343 
01344         std::map<LLViewHandle, LLFloater*>::iterator iter;
01345         for(iter = sFloaterMap.begin(); iter != sFloaterMap.end(); ++iter)
01346         {
01347                 focused_floater = iter->second;
01348                 if (focused_floater->hasFocus())
01349                 {
01350                         break;
01351                 }
01352         }
01353 
01354         if (iter == sFloaterMap.end())
01355         {
01356                 // nothing found, return
01357                 return;
01358         }
01359 
01360         focused_floater->close();
01361 
01362         // if nothing took focus after closing focused floater
01363         // give it to next floater (to allow closing multiple windows via keyboard in rapid succession)
01364         if (gFocusMgr.getKeyboardFocus() == NULL)
01365         {
01366                 // HACK: use gFloaterView directly in case we are using Ctrl-W to close snapshot window
01367                 // which sits in gSnapshotFloaterView, and needs to pass focus on to normal floater view
01368                 gFloaterView->focusFrontFloater();
01369         }
01370 }
01371 
01372 
01373 // static
01374 void LLFloater::onClickClose( void* userdata )
01375 {
01376         LLFloater* self = (LLFloater*) userdata;
01377         if (!self) return;
01378 
01379         self->close();
01380 }
01381 
01382 
01383 // virtual
01384 void LLFloater::draw()
01385 {
01386         if( getVisible() )
01387         {
01388                 // draw background
01389                 if( mBgVisible )
01390                 {
01391                         S32 left = LLPANEL_BORDER_WIDTH;
01392                         S32 top = mRect.getHeight() - LLPANEL_BORDER_WIDTH;
01393                         S32 right = mRect.getWidth() - LLPANEL_BORDER_WIDTH;
01394                         S32 bottom = LLPANEL_BORDER_WIDTH;
01395 
01396                         LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow");
01397                         F32 shadow_offset = (F32)LLUI::sConfigGroup->getS32("DropShadowFloater");
01398                         if (!mBgOpaque)
01399                         {
01400                                 shadow_offset *= 0.2f;
01401                                 shadow_color.mV[VALPHA] *= 0.5f;
01402                         }
01403                         gl_drop_shadow(left, top, right, bottom, 
01404                                 shadow_color, 
01405                                 llround(shadow_offset));
01406 
01407                         // No transparent windows in simple UI
01408                         if (mBgOpaque)
01409                         {
01410                                 gl_rect_2d( left, top, right, bottom, mBgColorOpaque );
01411                         }
01412                         else
01413                         {
01414                                 gl_rect_2d( left, top, right, bottom, mBgColorAlpha );
01415                         }
01416 
01417                         if(gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() && !getTitle().empty())
01418                         {
01419                                 // draw highlight on title bar to indicate focus.  RDW
01420                                 const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );
01421                                 LLRect r = getRect();
01422                                 gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1, 
01423                                         LLUI::sColorsGroup->getColor("TitleBarFocusColor"), 0, TRUE);
01424                         }
01425                 }
01426 
01427                 if( mDefaultBtn)
01428                 {
01429                         if (gFocusMgr.childHasKeyboardFocus( this ) && mDefaultBtn->getEnabled())
01430                         {
01431                                 LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
01432                                 // is this button a direct descendent and not a nested widget (e.g. checkbox)?
01433                                 BOOL focus_is_child_button = focus_ctrl->getWidgetType() == WIDGET_TYPE_BUTTON && focus_ctrl->getParent() == this;
01434                                 // only enable default button when current focus is not a button
01435                                 mDefaultBtn->setBorderEnabled(!focus_is_child_button);
01436                         }
01437                         else
01438                         {
01439                                 mDefaultBtn->setBorderEnabled(FALSE);
01440                         }
01441                 }
01442 
01443                 // draw children
01444                 LLView* focused_child = gFocusMgr.getKeyboardFocus();
01445                 BOOL focused_child_visible = FALSE;
01446                 if (focused_child && focused_child->getParent() == this)
01447                 {
01448                         focused_child_visible = focused_child->getVisible();
01449                         focused_child->setVisible(FALSE);
01450                 }
01451 
01452                 LLView::draw();
01453 
01454                 if( mBgVisible )
01455                 {
01456                         // add in a border to improve spacialized visual aclarity ;)
01457                         // use lines instead of gl_rect_2d so we can round the edges as per james' recommendation
01458                         LLUI::setLineWidth(1.5f);
01459                         LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? LLUI::sColorsGroup->getColor("FloaterFocusBorderColor") : LLUI::sColorsGroup->getColor("FloaterUnfocusBorderColor");
01460                         gl_rect_2d_offset_local(0, mRect.getHeight() + 1, mRect.getWidth() + 1, 0, outlineColor, -LLPANEL_BORDER_WIDTH, FALSE);
01461                         LLUI::setLineWidth(1.f);
01462                 }
01463         
01464                 if (focused_child_visible)
01465                 {
01466                         focused_child->setVisible(TRUE);
01467                 }
01468                 drawChild(focused_child);
01469 
01470                 // update tearoff button for torn off floaters
01471                 // when last host goes away
01472                 if (mCanTearOff && !getHost())
01473                 {
01474                         LLFloater* old_host = gFloaterView->getFloaterByHandle(mLastHostHandle);
01475                         if (!old_host)
01476                         {
01477                                 setCanTearOff(FALSE);
01478                         }
01479                 }
01480         }
01481 }
01482 
01483 // virtual
01484 void LLFloater::onOpen()
01485 {
01486 }
01487 
01488 // virtual
01489 void LLFloater::onClose(bool app_quitting)
01490 {
01491         destroy();
01492 }
01493 
01494 // virtual
01495 BOOL LLFloater::canClose()
01496 {
01497         return TRUE;
01498 }
01499 
01500 // virtual
01501 BOOL LLFloater::canSaveAs()
01502 {
01503         return FALSE;
01504 }
01505 
01506 // virtual
01507 void LLFloater::saveAs()
01508 {
01509 }
01510 
01511 void    LLFloater::setCanMinimize(BOOL can_minimize)
01512 {
01513         // removing minimize/restore button programmatically,
01514         // go ahead and uniminimize floater
01515         if (!can_minimize)
01516         {
01517                 setMinimized(FALSE);
01518         }
01519 
01520         if (can_minimize)
01521         {
01522                 if (isMinimized())
01523                 {
01524                         mButtonsEnabled[BUTTON_MINIMIZE] = FALSE;
01525                         mButtonsEnabled[BUTTON_RESTORE] = TRUE;
01526                 }
01527                 else
01528                 {
01529                         mButtonsEnabled[BUTTON_MINIMIZE] = TRUE;
01530                         mButtonsEnabled[BUTTON_RESTORE] = FALSE;
01531                 }
01532         }
01533         else
01534         {
01535                 mButtonsEnabled[BUTTON_MINIMIZE] = FALSE;
01536                 mButtonsEnabled[BUTTON_RESTORE] = FALSE;
01537         }
01538 
01539         updateButtons();
01540 }
01541 
01542 void    LLFloater::setCanClose(BOOL can_close)
01543 {
01544         mButtonsEnabled[BUTTON_CLOSE] = can_close;
01545 
01546         updateButtons();
01547 }
01548 
01549 void    LLFloater::setCanTearOff(BOOL can_tear_off)
01550 {
01551         mCanTearOff = can_tear_off;
01552         mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead();
01553 
01554         updateButtons();
01555 }
01556 
01557 
01558 void    LLFloater::setCanResize(BOOL can_resize)
01559 {
01560         if (mResizable && !can_resize)
01561         {
01562                 for (S32 i = 0; i < 4; i++) 
01563                 {
01564                         removeChild(mResizeBar[i], TRUE);
01565                         mResizeBar[i] = NULL; 
01566 
01567                         removeChild(mResizeHandle[i], TRUE);
01568                         mResizeHandle[i] = NULL;
01569                 }
01570         }
01571         else if (!mResizable && can_resize)
01572         {
01573                 // Resize bars (sides)
01574                 const S32 RESIZE_BAR_THICKNESS = 3;
01575                 mResizeBar[0] = new LLResizeBar( 
01576                         "resizebar_left",
01577                         this,
01578                         LLRect( 0, mRect.getHeight(), RESIZE_BAR_THICKNESS, 0), 
01579                         mMinWidth, S32_MAX, LLResizeBar::LEFT );
01580                 addChild( mResizeBar[0] );
01581 
01582                 mResizeBar[1] = new LLResizeBar( 
01583                         "resizebar_top",
01584                         this,
01585                         LLRect( 0, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_BAR_THICKNESS), 
01586                         mMinHeight, S32_MAX, LLResizeBar::TOP );
01587                 addChild( mResizeBar[1] );
01588 
01589                 mResizeBar[2] = new LLResizeBar( 
01590                         "resizebar_right",
01591                         this,
01592                         LLRect( mRect.getWidth() - RESIZE_BAR_THICKNESS, mRect.getHeight(), mRect.getWidth(), 0), 
01593                         mMinWidth, S32_MAX, LLResizeBar::RIGHT );
01594                 addChild( mResizeBar[2] );
01595 
01596                 mResizeBar[3] = new LLResizeBar( 
01597                         "resizebar_bottom",
01598                         this,
01599                         LLRect( 0, RESIZE_BAR_THICKNESS, mRect.getWidth(), 0), 
01600                         mMinHeight, S32_MAX, LLResizeBar::BOTTOM );
01601                 addChild( mResizeBar[3] );
01602 
01603 
01604                 // Resize handles (corners)
01605                 mResizeHandle[0] = new LLResizeHandle( 
01606                         "Resize Handle",
01607                         LLRect( mRect.getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, mRect.getWidth(), 0),
01608                         mMinWidth,
01609                         mMinHeight,
01610                         LLResizeHandle::RIGHT_BOTTOM);
01611                 addChild(mResizeHandle[0]);
01612 
01613                 mResizeHandle[1] = new LLResizeHandle( "resize", 
01614                         LLRect( mRect.getWidth() - RESIZE_HANDLE_WIDTH, mRect.getHeight(), mRect.getWidth(), mRect.getHeight() - RESIZE_HANDLE_HEIGHT),
01615                         mMinWidth,
01616                         mMinHeight,
01617                         LLResizeHandle::RIGHT_TOP );
01618                 addChild(mResizeHandle[1]);
01619                 
01620                 mResizeHandle[2] = new LLResizeHandle( "resize", 
01621                         LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ),
01622                         mMinWidth,
01623                         mMinHeight,
01624                         LLResizeHandle::LEFT_BOTTOM );
01625                 addChild(mResizeHandle[2]);
01626 
01627                 mResizeHandle[3] = new LLResizeHandle( "resize", 
01628                         LLRect( 0, mRect.getHeight(), RESIZE_HANDLE_WIDTH, mRect.getHeight() - RESIZE_HANDLE_HEIGHT ),
01629                         mMinWidth,
01630                         mMinHeight,
01631                         LLResizeHandle::LEFT_TOP );
01632                 addChild(mResizeHandle[3]);
01633         }
01634         mResizable = can_resize;
01635 }
01636 
01637 void LLFloater::setCanDrag(BOOL can_drag)
01638 {
01639         // if we delete drag handle, we no longer have access to the floater's title
01640         // so just enable/disable it
01641         if (!can_drag && mDragHandle->getEnabled())
01642         {
01643                 mDragHandle->setEnabled(FALSE);
01644         }
01645         else if (can_drag && !mDragHandle->getEnabled())
01646         {
01647                 mDragHandle->setEnabled(TRUE);
01648         }
01649 }
01650 
01651 void LLFloater::updateButtons()
01652 {
01653         S32 button_count = 0;
01654         for (S32 i = 0; i < BUTTON_COUNT; i++)
01655         {
01656                 if (mButtonsEnabled[i])
01657                 {
01658                         button_count++;
01659 
01660                         LLRect btn_rect;
01661                         if (mDragOnLeft)
01662                         {
01663                                 btn_rect.setLeftTopAndSize(
01664                                         LLPANEL_BORDER_WIDTH,
01665                                         mRect.getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count,
01666                                         llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
01667                                         llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
01668                         }
01669                         else
01670                         {
01671                                 btn_rect.setLeftTopAndSize(
01672                                         mRect.getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count,
01673                                         mRect.getHeight() - CLOSE_BOX_FROM_TOP,
01674                                         llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
01675                                         llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
01676                         }
01677 
01678                         mButtons[i]->setRect(btn_rect);
01679                         mButtons[i]->setVisible(TRUE);
01680                         mButtons[i]->setEnabled(TRUE);
01681                         // the restore button should have a tab stop so that it takes action when you Ctrl-Tab to a minimized floater
01682                         mButtons[i]->setTabStop(i == BUTTON_RESTORE);
01683                 }
01684                 else if (mButtons[i])
01685                 {
01686                         mButtons[i]->setVisible(FALSE);
01687                         mButtons[i]->setEnabled(FALSE);
01688                 }
01689         }
01690 
01691         mDragHandle->setMaxTitleWidth(mRect.getWidth() - (button_count * (LLFLOATER_CLOSE_BOX_SIZE + 1)));
01692 }
01693 
01694 void LLFloater::buildButtons()
01695 {
01696         for (S32 i = 0; i < BUTTON_COUNT; i++)
01697         {
01698                 LLRect btn_rect;
01699                 if (mDragOnLeft)
01700                 {
01701                         btn_rect.setLeftTopAndSize(
01702                                 LLPANEL_BORDER_WIDTH,
01703                                 mRect.getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1),
01704                                 llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
01705                                 llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
01706                 }
01707                 else
01708                 {
01709                         btn_rect.setLeftTopAndSize(
01710                                 mRect.getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1),
01711                                 mRect.getHeight() - CLOSE_BOX_FROM_TOP,
01712                                 llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale),
01713                                 llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale));
01714                 }
01715 
01716                 LLButton* buttonp = new LLButton(
01717                         sButtonNames[i],
01718                         btn_rect,
01719                         sButtonActiveImageNames[i],
01720                         sButtonPressedImageNames[i],
01721                         "",
01722                         sButtonCallbacks[i],
01723                         this,
01724                         LLFontGL::sSansSerif);
01725 
01726                 buttonp->setTabStop(FALSE);
01727                 buttonp->setFollowsTop();
01728                 buttonp->setFollowsRight();
01729                 buttonp->setToolTip( sButtonToolTips[i] );
01730                 buttonp->setImageColor(LLUI::sColorsGroup->getColor("FloaterButtonImageColor"));
01731                 buttonp->setHoverImages(sButtonPressedImageNames[i],
01732                                                                 sButtonPressedImageNames[i]);
01733                 buttonp->setScaleImage(TRUE);
01734                 buttonp->setSaveToXML(false);
01735                 addChild(buttonp);
01736                 mButtons[i] = buttonp;
01737         }
01738 
01739         updateButtons();
01740 }
01741 
01743 // LLFloaterView
01744 
01745 LLFloaterView::LLFloaterView( const LLString& name, const LLRect& rect )
01746 :       LLUICtrl( name, rect, FALSE, NULL, NULL, FOLLOWS_ALL ),
01747         mFocusCycleMode(FALSE),
01748         mSnapOffsetBottom(0)
01749 {
01750         setTabStop(FALSE);
01751         resetStartingFloaterPosition();
01752 }
01753 
01754 EWidgetType LLFloaterView::getWidgetType() const
01755 {
01756         return WIDGET_TYPE_FLOATER_VIEW;
01757 }
01758 
01759 LLString LLFloaterView::getWidgetTag() const
01760 {
01761         return LL_FLOATER_VIEW_TAG;
01762 }
01763 
01764 // By default, adjust vertical.
01765 void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent)
01766 {
01767         reshape(width, height, called_from_parent, ADJUST_VERTICAL_YES);
01768 }
01769 
01770 // When reshaping this view, make the floaters follow their closest edge.
01771 void LLFloaterView::reshape(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical)
01772 {
01773         S32 old_width = mRect.getWidth();
01774         S32 old_height = mRect.getHeight();
01775 
01776         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
01777         {
01778                 LLView* viewp = *child_it;
01779                 LLFloater* floaterp = (LLFloater*)viewp;
01780                 if (floaterp->isDependent())
01781                 {
01782                         // dependents use same follow flags as their "dependee"
01783                         continue;
01784                 }
01785                 LLRect r = floaterp->getRect();
01786 
01787                 // Compute absolute distance from each edge of screen
01788                 S32 left_offset = llabs(r.mLeft - 0);
01789                 S32 right_offset = llabs(old_width - r.mRight);
01790 
01791                 S32 top_offset = llabs(old_height - r.mTop);
01792                 S32 bottom_offset = llabs(r.mBottom - 0);
01793 
01794                 // Make if follow the edge it is closest to
01795                 U32 follow_flags = 0x0;
01796 
01797                 if (left_offset < right_offset)
01798                 {
01799                         follow_flags |= FOLLOWS_LEFT;
01800                 }
01801                 else
01802                 {
01803                         follow_flags |= FOLLOWS_RIGHT;
01804                 }
01805 
01806                 // "No vertical adjustment" usually means that the bottom of the view
01807                 // has been pushed up or down.  Hence we want the floaters to follow
01808                 // the top.
01809                 if (!adjust_vertical)
01810                 {
01811                         follow_flags |= FOLLOWS_TOP;
01812                 }
01813                 else if (top_offset < bottom_offset)
01814                 {
01815                         follow_flags |= FOLLOWS_TOP;
01816                 }
01817                 else
01818                 {
01819                         follow_flags |= FOLLOWS_BOTTOM;
01820                 }
01821 
01822                 floaterp->setFollows(follow_flags);
01823 
01824                 //RN: all dependent floaters copy follow behavior of "parent"
01825                 for(LLFloater::handle_set_iter_t dependent_it = floaterp->mDependents.begin();
01826                         dependent_it != floaterp->mDependents.end(); ++dependent_it)
01827                 {
01828                         LLFloater* dependent_floaterp = getFloaterByHandle(*dependent_it);
01829                         if (dependent_floaterp)
01830                         {
01831                                 dependent_floaterp->setFollows(follow_flags);
01832                         }
01833                 }
01834         }
01835 
01836         LLView::reshape(width, height, called_from_parent);
01837 }
01838 
01839 
01840 void LLFloaterView::restoreAll()
01841 {
01842         // make sure all subwindows aren't minimized
01843         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
01844         {
01845                 LLFloater* floaterp = (LLFloater*)*child_it;
01846                 floaterp->setMinimized(FALSE);
01847         }
01848 
01849         // *FIX: make sure dependents are restored
01850 
01851         // children then deleted by default view constructor
01852 }
01853 
01854 
01855 void LLFloaterView::getNewFloaterPosition(S32* left,S32* top)
01856 {
01857         // Workaround: mRect may change between when this object is created and the first time it is used.
01858         static BOOL first = TRUE;
01859         if( first )
01860         {
01861                 resetStartingFloaterPosition();
01862                 first = FALSE;
01863         }
01864         
01865         const S32 FLOATER_PAD = 16;
01866         LLCoordWindow window_size;
01867         getWindow()->getSize(&window_size);
01868         LLRect full_window(0, window_size.mY, window_size.mX, 0);
01869         LLRect floater_creation_rect(
01870                 160,
01871                 full_window.getHeight() - 2 * MENU_BAR_HEIGHT,
01872                 full_window.getWidth() * 2 / 3,
01873                 130 );
01874         floater_creation_rect.stretch( -FLOATER_PAD );
01875 
01876         *left = mNextLeft;
01877         *top = mNextTop;
01878 
01879         const S32 STEP = 25;
01880         S32 bottom = floater_creation_rect.mBottom + 2 * STEP;
01881         S32 right = floater_creation_rect.mRight - 4 * STEP;
01882 
01883         mNextTop -= STEP;
01884         mNextLeft += STEP;
01885 
01886         if( (mNextTop < bottom ) || (mNextLeft > right) )
01887         {
01888                 mColumn++;
01889                 mNextTop = floater_creation_rect.mTop;
01890                 mNextLeft = STEP * mColumn;
01891 
01892                 if( (mNextTop < bottom) || (mNextLeft > right) )
01893                 {
01894                         // Advancing the column didn't work, so start back at the beginning
01895                         resetStartingFloaterPosition();
01896                 }
01897         }
01898 }
01899 
01900 void LLFloaterView::resetStartingFloaterPosition()
01901 {
01902         const S32 FLOATER_PAD = 16;
01903         LLCoordWindow window_size;
01904         getWindow()->getSize(&window_size);
01905         LLRect full_window(0, window_size.mY, window_size.mX, 0);
01906         LLRect floater_creation_rect(
01907                 160,
01908                 full_window.getHeight() - 2 * MENU_BAR_HEIGHT,
01909                 full_window.getWidth() * 2 / 3,
01910                 130 );
01911         floater_creation_rect.stretch( -FLOATER_PAD );
01912 
01913         mNextLeft = floater_creation_rect.mLeft;
01914         mNextTop = floater_creation_rect.mTop;
01915         mColumn = 0;
01916 }
01917 
01918 LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor )
01919 {
01920         LLRect base_rect = reference_floater->getRect();
01921         S32 width = neighbor->getRect().getWidth();
01922         S32 height = neighbor->getRect().getHeight();
01923         LLRect new_rect = neighbor->getRect();
01924 
01925         LLRect expanded_base_rect = base_rect;
01926         expanded_base_rect.stretch(10);
01927         for(LLFloater::handle_set_iter_t dependent_it = reference_floater->mDependents.begin();
01928                 dependent_it != reference_floater->mDependents.end(); ++dependent_it)
01929         {
01930                 LLFloater* sibling = LLFloater::getFloaterByHandle(*dependent_it);
01931                 // check for dependents within 10 pixels of base floater
01932                 if (sibling && 
01933                         sibling != neighbor && 
01934                         sibling->getVisible() && 
01935                         expanded_base_rect.rectInRect(&sibling->getRect()))
01936                 {
01937                         base_rect.unionWith(sibling->getRect());
01938                 }
01939         }
01940 
01941         S32 left_margin = llmax(0, base_rect.mLeft);
01942         S32 right_margin = llmax(0, mRect.getWidth() - base_rect.mRight);
01943         S32 top_margin = llmax(0, mRect.getHeight() - base_rect.mTop);
01944         S32 bottom_margin = llmax(0, base_rect.mBottom);
01945 
01946         // find position for floater in following order
01947         // right->left->bottom->top
01948         for (S32 i = 0; i < 5; i++)
01949         {
01950                 if (right_margin > width)
01951                 {
01952                         new_rect.translate(base_rect.mRight - neighbor->mRect.mLeft, base_rect.mTop - neighbor->mRect.mTop);
01953                         return new_rect;
01954                 }
01955                 else if (left_margin > width)
01956                 {
01957                         new_rect.translate(base_rect.mLeft - neighbor->mRect.mRight, base_rect.mTop - neighbor->mRect.mTop);
01958                         return new_rect;
01959                 }
01960                 else if (bottom_margin > height)
01961                 {
01962                         new_rect.translate(base_rect.mLeft - neighbor->mRect.mLeft, base_rect.mBottom - neighbor->mRect.mTop);
01963                         return new_rect;
01964                 }
01965                 else if (top_margin > height)
01966                 {
01967                         new_rect.translate(base_rect.mLeft - neighbor->mRect.mLeft, base_rect.mTop - neighbor->mRect.mBottom);
01968                         return new_rect;
01969                 }
01970 
01971                 // keep growing margins to find "best" fit
01972                 left_margin += 20;
01973                 right_margin += 20;
01974                 top_margin += 20;
01975                 bottom_margin += 20;
01976         }
01977 
01978         // didn't find anything, return initial rect
01979         return new_rect;
01980 }
01981 
01982 void LLFloaterView::setCycleMode(BOOL mode)
01983 {
01984         mFocusCycleMode = mode;
01985 }
01986 
01987 BOOL LLFloaterView::getCycleMode()
01988 {
01989         return mFocusCycleMode;
01990 }
01991 
01992 void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus)
01993 {
01994         // *TODO: make this respect floater's mAutoFocus value, instead of
01995         // using parameter
01996         if (child->getHost())
01997         {
01998                 // this floater is hosted elsewhere and hence not one of our children, abort
01999                 return;
02000         }
02001         std::vector<LLView*> floaters_to_move;
02002         // Look at all floaters...tab
02003         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02004         {
02005                 LLView* viewp = *child_it;
02006                 LLFloater *floater = (LLFloater *)viewp;
02007 
02008                 // ...but if I'm a dependent floater...
02009                 if (child->isDependent())
02010                 {
02011                         // ...look for floaters that have me as a dependent...
02012                         LLFloater::handle_set_iter_t found_dependent = floater->mDependents.find(child->getHandle());
02013 
02014                         if (found_dependent != floater->mDependents.end())
02015                         {
02016                                 // ...and make sure all children of that floater (including me) are brought to front...
02017                                 for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
02018                                         dependent_it != floater->mDependents.end(); )
02019                                 {
02020                                         LLFloater* sibling = LLFloater::getFloaterByHandle(*dependent_it);
02021                                         if (sibling)
02022                                         {
02023                                                 floaters_to_move.push_back(sibling);
02024                                         }
02025                                         ++dependent_it;
02026                                 }
02027                                 //...before bringing my parent to the front...
02028                                 floaters_to_move.push_back(floater);
02029                         }
02030                 }
02031         }
02032 
02033         std::vector<LLView*>::iterator view_it;
02034         for(view_it = floaters_to_move.begin(); view_it != floaters_to_move.end(); ++view_it)
02035         {
02036                 LLFloater* floaterp = (LLFloater*)(*view_it);
02037                 sendChildToFront(floaterp);
02038 
02039                 // always unminimize dependee, but allow dependents to stay minimized
02040                 if (!floaterp->isDependent())
02041                 {
02042                         floaterp->setMinimized(FALSE);
02043                 }
02044         }
02045         floaters_to_move.clear();
02046 
02047         // ...then bringing my own dependents to the front...
02048         for(LLFloater::handle_set_iter_t dependent_it = child->mDependents.begin();
02049                 dependent_it != child->mDependents.end(); )
02050         {
02051                 LLFloater* dependent = getFloaterByHandle(*dependent_it);
02052                 if (dependent)
02053                 {
02054                         sendChildToFront(dependent);
02055                         //don't un-minimize dependent windows automatically
02056                         // respect user's wishes
02057                         //dependent->setMinimized(FALSE);
02058                 }
02059                 ++dependent_it;
02060         }
02061 
02062         // ...and finally bringing myself to front 
02063         // (do this last, so that I'm left in front at end of this call)
02064         if( *getChildList()->begin() != child ) 
02065         {
02066                 sendChildToFront(child);
02067         }
02068         child->setMinimized(FALSE);
02069         if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
02070         {
02071                 child->setFocus(TRUE);
02072         }
02073 }
02074 
02075 void LLFloaterView::highlightFocusedFloater()
02076 {
02077         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02078         {
02079                 LLFloater *floater = (LLFloater *)(*child_it);
02080 
02081                 // skip dependent floaters, as we'll handle them in a batch along with their dependee(?)
02082                 if (floater->isDependent())
02083                 {
02084                         continue;
02085                 }
02086 
02087                 BOOL floater_or_dependent_has_focus = gFocusMgr.childHasKeyboardFocus(floater);
02088                 for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
02089                         dependent_it != floater->mDependents.end(); 
02090                         ++dependent_it)
02091                 {
02092                         LLFloater* dependent_floaterp = getFloaterByHandle(*dependent_it);
02093                         if (dependent_floaterp && gFocusMgr.childHasKeyboardFocus(dependent_floaterp))
02094                         {
02095                                 floater_or_dependent_has_focus = TRUE;
02096                         }
02097                 }
02098 
02099                 // now set this floater and all its dependents
02100                 floater->setForeground(floater_or_dependent_has_focus);
02101 
02102                 for(LLFloater::handle_set_iter_t dependent_it = floater->mDependents.begin();
02103                         dependent_it != floater->mDependents.end(); )
02104                 {
02105                         LLFloater* dependent_floaterp = getFloaterByHandle(*dependent_it);
02106                         if (dependent_floaterp)
02107                         {
02108                                 dependent_floaterp->setForeground(floater_or_dependent_has_focus);
02109                         }
02110                         ++dependent_it;
02111                 }
02112                         
02113                 floater->cleanupHandles();
02114         }
02115 }
02116 
02117 void LLFloaterView::unhighlightFocusedFloater()
02118 {
02119         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02120         {
02121                 LLFloater *floater = (LLFloater *)(*child_it);
02122 
02123                 floater->setForeground(FALSE);
02124         }
02125 }
02126 
02127 void LLFloaterView::focusFrontFloater()
02128 {
02129         LLFloater* floaterp = getFrontmost();
02130         if (floaterp)
02131         {
02132                 floaterp->setFocus(TRUE);
02133         }
02134 }
02135 
02136 void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom)
02137 {
02138         S32 col = 0;
02139         LLRect snap_rect_local = getLocalSnapRect();
02140         for(S32 row = snap_rect_local.mBottom;
02141                 row < snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE;
02142                 row += LLFLOATER_HEADER_SIZE ) //loop rows
02143         {
02144                 for(col = snap_rect_local.mLeft;
02145                         col < snap_rect_local.getWidth() - MINIMIZED_WIDTH;
02146                         col += MINIMIZED_WIDTH)
02147                 {
02148                         bool foundGap = TRUE;
02149                         for(child_list_const_iter_t child_it = getChildList()->begin();
02150                                 child_it != getChildList()->end();
02151                                 ++child_it) //loop floaters
02152                         {
02153                                 // Examine minimized children.
02154                                 LLFloater* floater = (LLFloater*)((LLView*)*child_it);
02155                                 if(floater->isMinimized()) 
02156                                 {
02157                                         LLRect r = floater->getRect();
02158                                         if((r.mBottom < (row + LLFLOATER_HEADER_SIZE))
02159                                            && (r.mBottom > (row - LLFLOATER_HEADER_SIZE))
02160                                            && (r.mLeft < (col + MINIMIZED_WIDTH))
02161                                            && (r.mLeft > (col - MINIMIZED_WIDTH)))
02162                                         {
02163                                                 // needs the check for off grid. can't drag,
02164                                                 // but window resize makes them off
02165                                                 foundGap = FALSE;
02166                                                 break;
02167                                         }
02168                                 }
02169                         } //done floaters
02170                         if(foundGap)
02171                         {
02172                                 *left = col;
02173                                 *bottom = row;
02174                                 return; //done
02175                         }
02176                 } //done this col
02177         }
02178 
02179         // crude - stack'em all at 0,0 when screen is full of minimized
02180         // floaters.
02181         *left = snap_rect_local.mLeft;
02182         *bottom = snap_rect_local.mBottom;
02183 }
02184 
02185 
02186 void LLFloaterView::destroyAllChildren()
02187 {
02188         LLView::deleteAllChildren();
02189 }
02190 
02191 void LLFloaterView::closeAllChildren(bool app_quitting)
02192 {
02193         // iterate over a copy of the list, because closing windows will destroy
02194         // some windows on the list.
02195         child_list_t child_list = *(getChildList());
02196 
02197         for (child_list_const_iter_t it = child_list.begin(); it != child_list.end(); ++it)
02198         {
02199                 LLView* viewp = *it;
02200                 child_list_const_iter_t exists = std::find(getChildList()->begin(), getChildList()->end(), viewp);
02201                 if (exists == getChildList()->end())
02202                 {
02203                         // this floater has already been removed
02204                         continue;
02205                 }
02206 
02207                 LLFloater* floaterp = (LLFloater*)viewp;
02208 
02209                 // Attempt to close floater.  This will cause the "do you want to save"
02210                 // dialogs to appear.
02211                 if (floaterp->canClose())
02212                 {
02213                         floaterp->close(app_quitting);
02214                 }
02215         }
02216 }
02217 
02218 
02219 BOOL LLFloaterView::allChildrenClosed()
02220 {
02221         // see if there are any visible floaters (some floaters "close"
02222         // by setting themselves invisible)
02223         S32 visible_count = 0;
02224         for (child_list_const_iter_t it = getChildList()->begin(); it != getChildList()->end(); ++it)
02225         {
02226                 LLView* viewp = *it;
02227                 LLFloater* floaterp = (LLFloater*)viewp;
02228 
02229                 if (floaterp->getVisible() && floaterp->canClose())
02230                 {
02231                         visible_count++;
02232                 }
02233         }
02234 
02235         return (visible_count == 0);
02236 }
02237 
02238 
02239 void LLFloaterView::refresh()
02240 {
02241         // Constrain children to be entirely on the screen
02242         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02243         {
02244                 LLFloater* floaterp = (LLFloater*)*child_it;
02245                 if( floaterp->getVisible() )
02246                 {
02247                         adjustToFitScreen(floaterp, TRUE);
02248                 }
02249         }
02250 }
02251 
02252 void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_outside)
02253 {
02254         if (floater->getParent() != this)
02255         {
02256                 // floater is hosted elsewhere, so ignore
02257                 return;
02258         }
02259         S32 screen_width = getSnapRect().getWidth();
02260         S32 screen_height = getSnapRect().getHeight();
02261         // convert to local coordinate frame
02262         LLRect snap_rect_local = getLocalSnapRect();
02263 
02264         if( floater->isResizable() )
02265         {
02266                 LLRect view_rect = floater->getRect();
02267                 S32 view_width = view_rect.getWidth();
02268                 S32 view_height = view_rect.getHeight();
02269                 S32 min_width;
02270                 S32 min_height;
02271                 floater->getResizeLimits( &min_width, &min_height );
02272 
02273                 S32 new_width = llmax( min_width, view_width );
02274                 S32 new_height = llmax( min_height, view_height );
02275 
02276                 if( (new_width > screen_width) || (new_height > screen_height) )
02277                 {
02278                         new_width = llmin(new_width, screen_width);
02279                         new_height = llmin(new_height, screen_height);
02280 
02281                         floater->reshape( new_width, new_height, TRUE );
02282 
02283                         // Make sure the damn thing is actually onscreen.
02284                         if (floater->translateIntoRect(snap_rect_local, FALSE))
02285                         {
02286                                 floater->clearSnapTarget();
02287                         }
02288                 }
02289                 else if (!floater->isMinimized())
02290                 {
02291                         floater->reshape(new_width, new_height, TRUE);
02292                 }
02293         }
02294 
02295         if (floater->translateIntoRect( snap_rect_local, allow_partial_outside ))
02296         {
02297                 floater->clearSnapTarget();
02298         }
02299 }
02300 
02301 void LLFloaterView::draw()
02302 {
02303         refresh();
02304 
02305         // hide focused floater if in cycle mode, so that it can be drawn on top
02306         LLFloater* focused_floater = getFocusedFloater();
02307 
02308         if (mFocusCycleMode && focused_floater)
02309         {
02310                 child_list_const_iter_t child_it = getChildList()->begin();
02311                 for (;child_it != getChildList()->end(); ++child_it)
02312                 {
02313                         if ((*child_it) != focused_floater)
02314                         {
02315                                 drawChild(*child_it);
02316                         }
02317                 }
02318 
02319                 drawChild(focused_floater, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET);
02320         }
02321         else
02322         {
02323                 LLView::draw();
02324         }
02325 }
02326 
02327 const LLRect LLFloaterView::getSnapRect() const
02328 {
02329         LLRect snap_rect = mRect;
02330         snap_rect.mBottom += mSnapOffsetBottom;
02331 
02332         return snap_rect;
02333 }
02334 
02335 LLFloater *LLFloaterView::getFocusedFloater()
02336 {
02337         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02338         {
02339                 LLUICtrl* ctrlp = (*child_it)->isCtrl() ? static_cast<LLUICtrl*>(*child_it) : NULL;
02340                 if ( ctrlp && ctrlp->hasFocus() )
02341                 {
02342                         return static_cast<LLFloater *>(ctrlp);
02343                 }
02344         }
02345         return NULL;
02346 }
02347 
02348 LLFloater *LLFloaterView::getFrontmost()
02349 {
02350         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02351         {
02352                 LLView* viewp = *child_it;
02353                 if ( viewp->getVisible() && !viewp->isDead())
02354                 {
02355                         return (LLFloater *)viewp;
02356                 }
02357         }
02358         return NULL;
02359 }
02360 
02361 LLFloater *LLFloaterView::getBackmost()
02362 {
02363         LLFloater* back_most = NULL;
02364         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02365         {
02366                 LLView* viewp = *child_it;
02367                 if ( viewp->getVisible() )
02368                 {
02369                         back_most = (LLFloater *)viewp;
02370                 }
02371         }
02372         return back_most;
02373 }
02374 
02375 void LLFloaterView::syncFloaterTabOrder()
02376 {
02377         // bring focused floater to front
02378         for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it)
02379         {
02380                 LLFloater* floaterp = (LLFloater*)*child_it;
02381                 if (gFocusMgr.childHasKeyboardFocus(floaterp))
02382                 {
02383                         bringToFront(floaterp, FALSE);
02384                         break;
02385                 }
02386         }
02387 
02388         // then sync draw order to tab order
02389         for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it)
02390         {
02391                 LLFloater* floaterp = (LLFloater*)*child_it;
02392                 moveChildToFrontOfTabGroup(floaterp);
02393         }
02394 }
02395 
02396 LLFloater* LLFloaterView::getFloaterByHandle(LLViewHandle handle)
02397 {
02398         if (handle == LLViewHandle::sDeadHandle)
02399         {
02400                 return NULL;
02401         }
02402         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02403         {
02404                 LLView* viewp = *child_it;
02405                 if (((LLFloater*)viewp)->getHandle() == handle)
02406                 {
02407                         return (LLFloater*)viewp;
02408                 }
02409         }
02410         return NULL;
02411 }
02412 
02413 LLFloater*      LLFloaterView::getParentFloater(LLView* viewp)
02414 {
02415         LLView* parentp = viewp->getParent();
02416 
02417         while(parentp && parentp != this)
02418         {
02419                 viewp = parentp;
02420                 parentp = parentp->getParent();
02421         }
02422 
02423         if (parentp == this)
02424         {
02425                 return (LLFloater*)viewp;
02426         }
02427 
02428         return NULL;
02429 }
02430 
02431 S32 LLFloaterView::getZOrder(LLFloater* child)
02432 {
02433         S32 rv = 0;
02434         for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
02435         {
02436                 LLView* viewp = *child_it;
02437                 if(viewp == child)
02438                 {
02439                         break;
02440                 }
02441                 ++rv;
02442         }
02443         return rv;
02444 }
02445 
02446 void LLFloaterView::pushVisibleAll(BOOL visible, const skip_list_t& skip_list)
02447 {
02448         for (child_list_const_iter_t child_iter = getChildList()->begin();
02449                  child_iter != getChildList()->end(); ++child_iter)
02450         {
02451                 LLView *view = *child_iter;
02452                 if (skip_list.find(view) == skip_list.end())
02453                 {
02454                         view->pushVisible(visible);
02455                 }
02456         }
02457 }
02458 
02459 void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
02460 {
02461         for (child_list_const_iter_t child_iter = getChildList()->begin();
02462                  child_iter != getChildList()->end(); ++child_iter)
02463         {
02464                 LLView *view = *child_iter;
02465                 if (skip_list.find(view) == skip_list.end())
02466                 {
02467                         view->popVisible();
02468                 }
02469         }
02470 }
02471 
02472 //
02473 // LLMultiFloater
02474 //
02475 
02476 LLMultiFloater::LLMultiFloater() :
02477         mTabContainer(NULL),
02478         mTabPos(LLTabContainerCommon::TOP),
02479         mAutoResize(TRUE)
02480 {
02481 
02482 }
02483 
02484 LLMultiFloater::LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos) :
02485         mTabContainer(NULL),
02486         mTabPos(tab_pos),
02487         mAutoResize(TRUE)
02488 {
02489 
02490 }
02491 
02492 LLMultiFloater::LLMultiFloater(const LLString &name) :
02493         LLFloater(name),
02494         mTabContainer(NULL),
02495         mTabPos(LLTabContainerCommon::TOP),
02496         mAutoResize(FALSE)
02497 {
02498 }
02499 
02500 LLMultiFloater::LLMultiFloater(
02501         const LLString& name,
02502         const LLRect& rect,
02503         LLTabContainer::TabPosition tab_pos,
02504         BOOL auto_resize) : 
02505         LLFloater(name, rect, name),
02506         mTabContainer(NULL),
02507         mTabPos(LLTabContainerCommon::TOP),
02508         mAutoResize(auto_resize)
02509 {
02510         mTabContainer = new LLTabContainer("Preview Tabs", 
02511                 LLRect(LLPANEL_BORDER_WIDTH, mRect.getHeight() - LLFLOATER_HEADER_SIZE, mRect.getWidth() - LLPANEL_BORDER_WIDTH, 0), 
02512                 mTabPos, 
02513                 NULL, 
02514                 NULL);
02515         mTabContainer->setFollowsAll();
02516         if (mResizable)
02517         {
02518                 mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
02519         }
02520 
02521         addChild(mTabContainer);
02522 }
02523 
02524 LLMultiFloater::LLMultiFloater(
02525         const LLString& name,
02526         const LLString& rect_control,
02527         LLTabContainer::TabPosition tab_pos,
02528         BOOL auto_resize) : 
02529         LLFloater(name, rect_control, name),
02530         mTabContainer(NULL),
02531         mTabPos(tab_pos),
02532         mAutoResize(auto_resize)
02533 {
02534         mTabContainer = new LLTabContainer("Preview Tabs", 
02535         LLRect(LLPANEL_BORDER_WIDTH, mRect.getHeight() - LLFLOATER_HEADER_SIZE, mRect.getWidth() - LLPANEL_BORDER_WIDTH, 0), 
02536         mTabPos, 
02537         NULL, 
02538         NULL);
02539         mTabContainer->setFollowsAll();
02540         if (mResizable && mTabPos == LLTabContainerCommon::BOTTOM)
02541         {
02542                 mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
02543         }
02544 
02545         addChild(mTabContainer);
02546         
02547 }
02548 
02549 LLMultiFloater::~LLMultiFloater()
02550 {
02551 }
02552 
02553 // virtual
02554 EWidgetType LLMultiFloater::getWidgetType() const
02555 {
02556         return WIDGET_TYPE_MULTI_FLOATER;
02557 }
02558 
02559 // virtual
02560 LLString LLMultiFloater::getWidgetTag() const
02561 {
02562         return LL_MULTI_FLOATER_TAG;
02563 }
02564 
02565 void LLMultiFloater::open()     /* Flawfinder: ignore */
02566 {
02567         if (mTabContainer->getTabCount() > 0)
02568         {
02569                 LLFloater::open();      /* Flawfinder: ignore */
02570         }
02571         else
02572         {
02573                 // for now, don't allow multifloaters
02574                 // without any child floaters
02575                 close();
02576         }
02577 }
02578 
02579 void LLMultiFloater::onClose(bool app_quitting)
02580 {
02581         if(closeAllFloaters() == TRUE)
02582         {
02583                 LLFloater::onClose(app_quitting ? true : false);
02584         }//else not all tabs could be closed...
02585 }
02586 
02587 void LLMultiFloater::draw()
02588 {
02589         if (mTabContainer->getTabCount() == 0)
02590         {
02591                 //RN: could this potentially crash in draw hierarchy?
02592                 close();
02593         }
02594         else
02595         {
02596                 for (S32 i = 0; i < mTabContainer->getTabCount(); i++)
02597                 {
02598                         LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
02599                         if (floaterp->getTitle() != mTabContainer->getPanelTitle(i))
02600                         {
02601                                 mTabContainer->setPanelTitle(i, floaterp->getTitle());
02602                         }
02603                 }
02604                 LLFloater::draw();
02605         }
02606 }
02607 
02608 BOOL LLMultiFloater::closeAllFloaters()
02609 {
02610         S32     tabToClose = 0;
02611         S32     lastTabCount = mTabContainer->getTabCount();
02612         while (tabToClose < mTabContainer->getTabCount())
02613         {
02614                 LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose);
02615                 first_floater->close();
02616                 if(lastTabCount == mTabContainer->getTabCount())
02617                 {
02618                         //Tab did not actually close, possibly due to a pending Save Confirmation dialog..
02619                         //so try and close the next one in the list...
02620                         tabToClose++;
02621                 }else
02622                 {
02623                         //Tab closed ok.
02624                         lastTabCount = mTabContainer->getTabCount();
02625                 }
02626         }
02627         if( mTabContainer->getTabCount() != 0 )
02628                 return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE.
02629         return TRUE; //else all tabs were successfully closed...
02630 }
02631 
02632 void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
02633 {
02634         S32 new_width = llmax(mRect.getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2);
02635         S32 new_height = llmax(mRect.getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
02636 
02637         if (isMinimized())
02638         {
02639                 mPreviousRect.setLeftTopAndSize(mPreviousRect.mLeft, mPreviousRect.mTop, new_width, new_height);
02640         }
02641         else
02642         {
02643                 S32 old_height = mRect.getHeight();
02644                 reshape(new_width, new_height);
02645                 // keep top left corner in same position
02646                 translate(0, old_height - new_height);
02647         }
02648 }
02649 
02661 void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point)
02662 {
02663         if (!floaterp)
02664         {
02665                 return;
02666         }
02667 
02668         if (!mTabContainer)
02669         {
02670                 llerrs << "Tab Container used without having been initialized." << llendl;
02671                 return;
02672         }
02673 
02674         if (floaterp->getHost() == this)
02675         {
02676                 // already hosted by me, remove
02677                 // do this so we get updated title, etc.
02678                 mFloaterDataMap.erase(floaterp->getHandle());
02679                 mTabContainer->removeTabPanel(floaterp);
02680         }
02681         else if (floaterp->getHost())
02682         {
02683                 // floaterp is hosted by somebody else and
02684                 // this is adding it, so remove it from it's old host
02685                 floaterp->getHost()->removeFloater(floaterp);
02686         }
02687         else if (floaterp->getParent() == gFloaterView)
02688         {
02689                 // rehost preview floater as child panel
02690                 gFloaterView->removeChild(floaterp);
02691         }
02692 
02693         // store original configuration
02694         LLFloaterData floater_data;
02695         floater_data.mWidth = floaterp->getRect().getWidth();
02696         floater_data.mHeight = floaterp->getRect().getHeight();
02697         floater_data.mCanMinimize = floaterp->isMinimizeable();
02698         floater_data.mCanResize = floaterp->isResizable();
02699 
02700         // remove minimize and close buttons
02701         floaterp->setCanMinimize(FALSE);
02702         floaterp->setCanResize(FALSE);
02703         floaterp->setCanDrag(FALSE);
02704         floaterp->storeRectControl();
02705 
02706         if (mAutoResize)
02707         {
02708                 growToFit(floater_data.mWidth, floater_data.mHeight);
02709         }
02710 
02711         //add the panel, add it to proper maps
02712         mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point);
02713         mFloaterDataMap[floaterp->getHandle()] = floater_data;
02714 
02715         updateResizeLimits();
02716 
02717         if ( select_added_floater )
02718         {
02719                 mTabContainer->selectLastTab();
02720         }
02721 
02722         floaterp->setHost(this);
02723         if (mMinimized)
02724         {
02725                 floaterp->setVisible(FALSE);
02726         }
02727 }
02728 
02737 BOOL LLMultiFloater::selectFloater(LLFloater* floaterp)
02738 {
02739         return mTabContainer->selectTabPanel(floaterp);
02740 }
02741 
02742 // virtual
02743 void LLMultiFloater::selectNextFloater()
02744 {
02745         mTabContainer->selectNextTab();
02746 }
02747 
02748 // virtual
02749 void LLMultiFloater::selectPrevFloater()
02750 {
02751         mTabContainer->selectPrevTab();
02752 }
02753 
02754 void LLMultiFloater::showFloater(LLFloater* floaterp)
02755 {
02756         // we won't select a panel that already is selected
02757         // it is hard to do this internally to tab container
02758         // as tab selection is handled via index and the tab at a given
02759         // index might have changed
02760         if (floaterp != mTabContainer->getCurrentPanel() &&
02761                 !mTabContainer->selectTabPanel(floaterp))
02762         {
02763                 addFloater(floaterp, TRUE);
02764         }
02765 }
02766 
02767 void LLMultiFloater::removeFloater(LLFloater* floaterp)
02768 {
02769         if ( floaterp->getHost() != this )
02770                 return;
02771 
02772         floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle());
02773         if (found_data_it != mFloaterDataMap.end())
02774         {
02775                 LLFloaterData& floater_data = found_data_it->second;
02776                 floaterp->setCanMinimize(floater_data.mCanMinimize);
02777                 if (!floater_data.mCanResize)
02778                 {
02779                         // restore original size
02780                         floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
02781                 }
02782                 floaterp->setCanResize(floater_data.mCanResize);
02783                 mFloaterDataMap.erase(found_data_it);
02784         }
02785         mTabContainer->removeTabPanel(floaterp);
02786         floaterp->setBackgroundVisible(TRUE);
02787         floaterp->setCanDrag(TRUE);
02788         floaterp->setHost(NULL);
02789         floaterp->applyRectControl();
02790 
02791         updateResizeLimits();
02792 
02793         tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
02794 }
02795 
02796 void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
02797 {
02798         // default implementation does nothing
02799 }
02800 
02801 void LLMultiFloater::tabClose()
02802 {
02803         if (mTabContainer->getTabCount() == 0)
02804         {
02805                 // no more children, close myself
02806                 close();
02807         }
02808 }
02809 
02810 void LLMultiFloater::setVisible(BOOL visible)
02811 {
02812         // *FIX: shouldn't have to do this, fix adding to minimized multifloater
02813         LLFloater::setVisible(visible);
02814         
02815         if (mTabContainer)
02816         {
02817                 LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
02818 
02819                 if (cur_floaterp)
02820                 {
02821                         cur_floaterp->setVisible(visible);
02822                 }
02823 
02824                 // if no tab selected, and we're being shown,
02825                 // select last tab to be added
02826                 if (visible && !cur_floaterp)
02827                 {
02828                         mTabContainer->selectLastTab();
02829                 }
02830         }
02831 }
02832 
02833 BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
02834 {
02835         if (getEnabled()
02836                 && mask == MASK_CONTROL)
02837         {
02838                 if (key == 'W')
02839                 {
02840                         LLFloater* floater = getActiveFloater();
02841                         // is user closeable and is system closeable
02842                         if (floater && floater->canClose() && floater->isCloseable())
02843                         {
02844                                 floater->close();
02845                         }
02846                         return TRUE;
02847                 }
02848         }
02849 
02850         return LLFloater::handleKeyHere(key, mask, called_from_parent);
02851 }
02852 
02853 LLFloater* LLMultiFloater::getActiveFloater()
02854 {
02855         return (LLFloater*)mTabContainer->getCurrentPanel();
02856 }
02857 
02858 S32     LLMultiFloater::getFloaterCount()
02859 {
02860         return mTabContainer->getTabCount();
02861 }
02862 
02872 BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
02873 {
02874         if ( floaterp && floaterp->getHost() == this )
02875                 return mTabContainer->getTabPanelFlashing(floaterp);
02876 
02877         return FALSE;
02878 }
02879 
02889 void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
02890 {
02891         if ( floaterp && floaterp->getHost() == this )
02892                 mTabContainer->setTabPanelFlashing(floaterp, flashing);
02893 }
02894 
02895 //static
02896 void LLMultiFloater::onTabSelected(void* userdata, bool from_click)
02897 {
02898         LLMultiFloater* floaterp = (LLMultiFloater*)userdata;
02899 
02900         floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click);
02901 }
02902 
02903 void LLMultiFloater::setCanResize(BOOL can_resize)
02904 {
02905         LLFloater::setCanResize(can_resize);
02906         if (mResizable && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
02907         {
02908                 mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
02909         }
02910         else
02911         {
02912                 mTabContainer->setRightTabBtnOffset(0);
02913         }
02914 }
02915 
02916 BOOL LLMultiFloater::postBuild()
02917 {
02918         if (mTabContainer)
02919         {
02920                 return TRUE;
02921         }
02922 
02923         requires("Preview Tabs", WIDGET_TYPE_TAB_CONTAINER);
02924         if (checkRequirements())
02925         {
02926                 mTabContainer = LLUICtrlFactory::getTabContainerByName(this, "Preview Tabs");
02927                 return TRUE;
02928         }
02929 
02930         return FALSE;
02931 }
02932 
02933 void LLMultiFloater::updateResizeLimits()
02934 {
02935         S32 new_min_width = 0;
02936         S32 new_min_height = 0;
02937         S32 tab_idx;
02938         for (tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
02939         {
02940                 LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
02941                 if (floaterp)
02942                 {
02943                         new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
02944                         new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
02945                 }
02946         }
02947         setResizeLimits(new_min_width, new_min_height);
02948 
02949         S32 cur_height = mRect.getHeight();
02950         S32 new_width = llmax(mRect.getWidth(), new_min_width);
02951         S32 new_height = llmax(mRect.getHeight(), new_min_height);
02952 
02953         if (isMinimized())
02954         {
02955                 mPreviousRect.setLeftTopAndSize(mPreviousRect.mLeft, mPreviousRect.mTop, llmax(mPreviousRect.getWidth(), new_width), llmax(mPreviousRect.getHeight(), new_height));
02956         }
02957         else
02958         {
02959                 reshape(new_width, new_height);
02960 
02961                 // make sure upper left corner doesn't move
02962                 translate(0, cur_height - mRect.getHeight());
02963 
02964                 // Try to keep whole view onscreen, don't allow partial offscreen.
02965                 gFloaterView->adjustToFitScreen(this, FALSE);
02966         }
02967 }
02968 
02969 // virtual
02970 LLXMLNodePtr LLFloater::getXML(bool save_children) const
02971 {
02972         LLXMLNodePtr node = LLPanel::getXML();
02973 
02974         node->createChild("title", TRUE)->setStringValue(getTitle());
02975 
02976         node->createChild("can_resize", TRUE)->setBoolValue(isResizable());
02977 
02978         node->createChild("can_minimize", TRUE)->setBoolValue(isMinimizeable());
02979 
02980         node->createChild("can_close", TRUE)->setBoolValue(isCloseable());
02981 
02982         node->createChild("can_drag_on_left", TRUE)->setBoolValue(isDragOnLeft());
02983 
02984         node->createChild("min_width", TRUE)->setIntValue(getMinWidth());
02985 
02986         node->createChild("min_height", TRUE)->setIntValue(getMinHeight());
02987 
02988         node->createChild("can_tear_off", TRUE)->setBoolValue(mCanTearOff);
02989         
02990         return node;
02991 }
02992 
02993 // static
02994 LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
02995 {
02996         LLString name("floater");
02997         node->getAttributeString("name", name);
02998 
02999         LLFloater *floaterp = new LLFloater(name);
03000 
03001         LLString filename;
03002         node->getAttributeString("filename", filename);
03003 
03004         if (filename.empty())
03005         {
03006                 // Load from node
03007                 floaterp->initFloaterXML(node, parent, factory);
03008         }
03009         else
03010         {
03011                 // Load from file
03012                 factory->buildFloater(floaterp, filename);
03013         }
03014 
03015         return floaterp;
03016 }
03017 
03018 void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open)  /* Flawfinder: ignore */
03019 {
03020         LLString name(getName());
03021         LLString title(getTitle());
03022         LLString short_title(getShortTitle());
03023         LLString rect_control("");
03024         BOOL resizable = isResizable();
03025         S32 min_width = getMinWidth();
03026         S32 min_height = getMinHeight();
03027         BOOL drag_on_left = isDragOnLeft();
03028         BOOL minimizable = isMinimizeable();
03029         BOOL close_btn = isCloseable();
03030         LLRect rect;
03031 
03032         node->getAttributeString("name", name);
03033         node->getAttributeString("title", title);
03034         node->getAttributeString("short_title", short_title);
03035         node->getAttributeString("rect_control", rect_control);
03036         node->getAttributeBOOL("can_resize", resizable);
03037         node->getAttributeBOOL("can_minimize", minimizable);
03038         node->getAttributeBOOL("can_close", close_btn);
03039         node->getAttributeBOOL("can_drag_on_left", drag_on_left);
03040         node->getAttributeS32("min_width", min_width);
03041         node->getAttributeS32("min_height", min_height);
03042 
03043         if (! rect_control.empty())
03044         {
03045                 setRectControl(rect_control);
03046         }
03047 
03048         createRect(node, rect, parent, LLRect());
03049         
03050         setRect(rect);
03051         setName(name);
03052         
03053         init(title,
03054                         resizable,
03055                         min_width,
03056                         min_height,
03057                         drag_on_left,
03058                         minimizable,
03059                         close_btn);
03060 
03061         setShortTitle(short_title);
03062 
03063         BOOL can_tear_off;
03064         if (node->getAttributeBOOL("can_tear_off", can_tear_off))
03065         {
03066                 setCanTearOff(can_tear_off);
03067         }
03068         
03069         initFromXML(node, parent);
03070 
03071         LLMultiFloater* last_host = LLFloater::getFloaterHost();
03072         if (node->hasName("multi_floater"))
03073         {
03074                 LLFloater::setFloaterHost((LLMultiFloater*) this);
03075         }
03076 
03077         initChildrenXML(node, factory);
03078 
03079         if (node->hasName("multi_floater"))
03080         {
03081                 LLFloater::setFloaterHost(last_host);
03082         }
03083 
03084         BOOL result = postBuild();
03085 
03086         if (!result)
03087         {
03088                 llerrs << "Failed to construct floater " << name << llendl;
03089         }
03090 
03091         applyRectControl();
03092         if (open)       /* Flawfinder: ignore */
03093         {
03094                 this->open();   /* Flawfinder: ignore */
03095         }
03096 
03097         moveResizeHandlesToFront();
03098 }

Generated on Thu Jul 1 06:08:31 2010 for Second Life Viewer by  doxygen 1.4.7