123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237 |
- /**
- * @file llfloater.cpp
- * @brief LLFloater base class
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- // Floating "windows" within the GL display, like the inventory floater,
- // mini-map floater, etc.
- #include "linden_common.h"
- #include "llfloater.h"
- #include "llbutton.h"
- #include "llcheckboxctrl.h"
- #include "llcontrol.h"
- #include "lldraghandle.h"
- #include "llresizebar.h"
- #include "llresizehandle.h"
- #include "llkeyboard.h"
- #include "lltextbox.h"
- #include "llwindow.h"
- #include "lltabcontainer.h"
- #include "lltrans.h"
- #include "lluictrlfactory.h"
- S32 gMenuBarHeight = 18;
- static const std::string LL_FLOATER_TAG = "floater";
- static const std::string LL_MULTI_FLOATER_TAG = "multi_floater";
- constexpr S32 MINIMIZED_WIDTH = 160;
- constexpr S32 CLOSE_BOX_FROM_TOP = 1;
- // Use this to control "jumping" behavior when Ctrl-Tabbing
- constexpr S32 TABBED_FLOATER_OFFSET = 0;
- U32 LLFloater::sLastFloaterId = 0;
- bool LLFloaterView::sStackMinimizedTopToBottom = false;
- bool LLFloaterView::sStackMinimizedRightToLeft = false;
- U32 LLFloaterView::sStackScreenWidthFraction = 1;
- std::string LLFloater::sButtonActiveImageNames[BUTTON_COUNT] =
- {
- "UIImgBtnCloseActiveUUID", // BUTTON_CLOSE
- "UIImgBtnRestoreActiveUUID", // BUTTON_RESTORE
- "UIImgBtnMinimizeActiveUUID", // BUTTON_MINIMIZE
- "UIImgBtnTearOffActiveUUID", // BUTTON_TEAR_OFF
- };
- std::string LLFloater::sButtonInactiveImageNames[BUTTON_COUNT] =
- {
- "UIImgBtnCloseInactiveUUID", // BUTTON_CLOSE
- "UIImgBtnRestoreInactiveUUID", // BUTTON_RESTORE
- "UIImgBtnMinimizeInactiveUUID", // BUTTON_MINIMIZE
- "UIImgBtnTearOffInactiveUUID", // BUTTON_TEAR_OFF
- };
- std::string LLFloater::sButtonPressedImageNames[BUTTON_COUNT] =
- {
- "UIImgBtnClosePressedUUID", // BUTTON_CLOSE
- "UIImgBtnRestorePressedUUID", // BUTTON_RESTORE
- "UIImgBtnMinimizePressedUUID", // BUTTON_MINIMIZE
- "UIImgBtnTearOffPressedUUID", // BUTTON_TEAR_OFF
- };
- std::string LLFloater::sButtonNames[BUTTON_COUNT] =
- {
- "llfloater_close_btn", // BUTTON_CLOSE
- "llfloater_restore_btn", // BUTTON_RESTORE
- "llfloater_minimize_btn", // BUTTON_MINIMIZE
- "llfloater_tear_off_btn", // BUTTON_TEAR_OFF
- };
- std::string LLFloater::sButtonToolTipNames[BUTTON_COUNT] =
- {
- #ifdef LL_DARWIN
- "button-mac-close", // BUTTON_CLOSE
- #else
- "button-close", // BUTTON_CLOSE
- #endif
- "button-restore", // BUTTON_RESTORE
- "button-minimize", // BUTTON_MINIMIZE
- "button-tear-off", // BUTTON_TEAR_OFF
- };
- LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
- {
- LLFloater::onClickClose, // BUTTON_CLOSE
- LLFloater::onClickMinimize, // BUTTON_RESTORE
- LLFloater::onClickMinimize, // BUTTON_MINIMIZE
- LLFloater::onClickTearOff, // BUTTON_TEAR_OFF
- };
- LLMultiFloater* LLFloater::sHostp = NULL;
- static bool sResizing = false;
- static S32 sLastSizeX = 0;
- static S32 sLastSizeY = 0;
- //static
- bool LLFloater::resizing(S32& size_x, S32& size_y)
- {
- bool resizing = sResizing;
- if (resizing)
- {
- size_x = sLastSizeX;
- size_y = sLastSizeY;
- sResizing = false;
- }
- return resizing;
- }
- // Instance created in LLViewerWindow::initBase() and destroyed in
- // LLViewerWindow::shutdownViews()
- LLFloaterView* gFloaterViewp = NULL;
- LLFloater::LLFloater()
- : LLPanel(),
- mId(++sLastFloaterId),
- mTitleIsPristine(true),
- mAutoFocus(true),
- mResizable(false),
- mDragOnLeft(false),
- mMinWidth(0),
- mMinHeight(0),
- mDragHandle(NULL)
- {
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- mButtonsEnabled[i] = false;
- mButtons[i] = NULL;
- }
- for (S32 i = 0; i < 4; ++i)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
- mNotificationContext = new LLFloaterNotificationContext(getHandle());
- }
- LLFloater::LLFloater(const std::string& name)
- : LLPanel(name),
- mId(++sLastFloaterId),
- mTitleIsPristine(true),
- mAutoFocus(true) // Automatically take focus when opened
- {
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- mButtonsEnabled[i] = false;
- mButtons[i] = NULL;
- }
- for (S32 i = 0; i < 4; ++i)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
- initFloater(LLStringUtil::null, false,
- DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT,
- false, true, true); // defaults
- }
- LLFloater::LLFloater(const std::string& name, const LLRect& rect,
- const std::string& title, bool resizable,
- S32 min_width, S32 min_height, bool drag_on_left,
- bool minimizable, bool close_btn, bool bordered)
- : LLPanel(name, rect, bordered),
- mId(++sLastFloaterId),
- mTitleIsPristine(true),
- mAutoFocus(true) // Automatically take focus when opened
- {
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- mButtonsEnabled[i] = false;
- mButtons[i] = NULL;
- }
- for (S32 i = 0; i < 4; ++i)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
- initFloater(title, resizable, min_width, min_height, drag_on_left,
- minimizable, close_btn);
- }
- LLFloater::LLFloater(const std::string& name, const std::string& rect_control,
- const std::string& title, bool resizable,
- S32 min_width, S32 min_height, bool drag_on_left,
- bool minimizable, bool close_btn, bool bordered)
- : LLPanel(name, rect_control, bordered),
- mId(++sLastFloaterId),
- mTitleIsPristine(true),
- mAutoFocus(true) // Automatically take focus when opened
- {
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- mButtonsEnabled[i] = false;
- mButtons[i] = NULL;
- }
- for (S32 i = 0; i < 4; ++i)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
- initFloater(title, resizable, min_width, min_height, drag_on_left,
- minimizable, close_btn);
- }
- // NOTE: floaters constructed from XML call init() twice !
- void LLFloater::initFloater(const std::string& title, bool resizable,
- S32 min_width, S32 min_height,
- bool drag_on_left, bool minimizable,
- bool close_btn)
- {
- mNotificationContext = new LLFloaterNotificationContext(getHandle());
- // Init function can be called more than once, so clear out old data.
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- mButtonsEnabled[i] = false;
- if (mButtons[i])
- {
- removeChild(mButtons[i]);
- delete mButtons[i];
- mButtons[i] = NULL;
- }
- }
- mButtonScale = 1.f;
- // SJB: this is a bit of a hack:
- bool need_border = hasBorder();
- // Remove the border since deleteAllChildren() will also delete the border
- // (but not clear mBorder)
- removeBorder();
- // this will delete mBorder too
- deleteAllChildren();
- // add the border back if we want it
- if (need_border)
- {
- addBorder();
- }
- // Chrome floaters do not take focus at all
- setFocusRoot(!getIsChrome());
- // Reset cached pointers
- mDragHandle = NULL;
- for (S32 i = 0; i < 4; ++i)
- {
- mResizeBar[i] = NULL;
- mResizeHandle[i] = NULL;
- }
- mCanTearOff = true;
- // Clicks stop here.
- setMouseOpaque(true);
- mForeground = false;
- mDragOnLeft = drag_on_left == true;
- // Floaters always draw their background, unlike every other panel.
- setBackgroundVisible(true);
- // Floaters start not minimized. When minimized, they save their former
- // rectangle to be used on restore.
- mMinimized = false;
- mExpandedRect.set(0, 0, 0, 0);
- S32 close_box_size; // For layout purposes, how big is the close box ?
- if (close_btn)
- {
- close_box_size = LLFLOATER_CLOSE_BOX_SIZE;
- }
- else
- {
- close_box_size = 0;
- }
- // Drag handle; we add it first so that it is in the background.
- if (drag_on_left)
- {
- LLRect drag_handle_rect;
- drag_handle_rect.setOriginAndSize(0, 0, DRAG_HANDLE_WIDTH,
- getRect().getHeight() -
- LLPANEL_BORDER_WIDTH -
- close_box_size);
- mDragHandle = new LLDragHandleLeft("drag", drag_handle_rect, title);
- }
- else // Drag on top
- {
- LLRect drag_handle_rect(0, getRect().getHeight(),
- getRect().getWidth(), 0);
- mDragHandle = new LLDragHandleTop("Drag Handle", drag_handle_rect,
- title);
- }
- addChild(mDragHandle);
- // Resize Handle
- mResizable = resizable;
- mMinWidth = min_width;
- mMinHeight = min_height;
- if (mResizable)
- {
- // Resize bars (sides)
- constexpr S32 RESIZE_BAR_THICKNESS = 3;
- mResizeBar[LLResizeBar::LEFT] =
- new LLResizeBar("resizebar_left", this,
- LLRect(0, getRect().getHeight(),
- RESIZE_BAR_THICKNESS, 0),
- min_width, S32_MAX, LLResizeBar::LEFT);
- addChild(mResizeBar[0]);
- mResizeBar[LLResizeBar::TOP] =
- new LLResizeBar("resizebar_top", this,
- LLRect(0, getRect().getHeight(),
- getRect().getWidth(),
- getRect().getHeight() -
- RESIZE_BAR_THICKNESS),
- min_height, S32_MAX, LLResizeBar::TOP);
- addChild(mResizeBar[1]);
- mResizeBar[LLResizeBar::RIGHT] =
- new LLResizeBar("resizebar_right", this,
- LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS,
- getRect().getHeight(), getRect().getWidth(),
- 0),
- min_width, S32_MAX, LLResizeBar::RIGHT);
- addChild(mResizeBar[2]);
- mResizeBar[LLResizeBar::BOTTOM] =
- new LLResizeBar("resizebar_bottom", this,
- LLRect(0, RESIZE_BAR_THICKNESS,
- getRect().getWidth(), 0),
- min_height, S32_MAX, LLResizeBar::BOTTOM);
- addChild(mResizeBar[3]);
- // Resize handles (corners)
- mResizeHandle[0] =
- new LLResizeHandle("Resize Handle",
- LLRect(getRect().getWidth() -
- RESIZE_HANDLE_WIDTH,
- RESIZE_HANDLE_HEIGHT,
- getRect().getWidth(), 0),
- min_width, min_height,
- LLResizeHandle::RIGHT_BOTTOM);
- addChild(mResizeHandle[0]);
- mResizeHandle[1] =
- new LLResizeHandle("resize",
- LLRect(getRect().getWidth() -
- RESIZE_HANDLE_WIDTH,
- getRect().getHeight(),
- getRect().getWidth(),
- getRect().getHeight() -
- RESIZE_HANDLE_HEIGHT),
- min_width, min_height,
- LLResizeHandle::RIGHT_TOP, !close_btn);
- addChild(mResizeHandle[1]);
- mResizeHandle[2] =
- new LLResizeHandle("resize",
- LLRect(0, RESIZE_HANDLE_HEIGHT,
- RESIZE_HANDLE_WIDTH, 0),
- min_width, min_height,
- LLResizeHandle::LEFT_BOTTOM);
- addChild(mResizeHandle[2]);
- mResizeHandle[3] =
- new LLResizeHandle("resize",
- LLRect(0, getRect().getHeight(),
- RESIZE_HANDLE_WIDTH,
- getRect().getHeight() -
- RESIZE_HANDLE_HEIGHT),
- min_width, min_height,
- LLResizeHandle::LEFT_TOP);
- addChild(mResizeHandle[3]);
- }
- // Close button.
- if (close_btn)
- {
- mButtonsEnabled[BUTTON_CLOSE] = true;
- }
- // Minimize button only for top draggers
- if (!drag_on_left && minimizable)
- {
- mButtonsEnabled[BUTTON_MINIMIZE] = true;
- }
- // Keep track of whether this window has ever been dragged while it was
- // minimized. If it has, we will remember its position for the next time
- // it is minimized.
- mHasBeenDraggedWhileMinimized = false;
- mPreviousMinimizedLeft = 0;
- mPreviousMinimizedBottom = 0;
- buildButtons();
- #if 0 // JC: Do not do this here, because many floaters first construct
- // themselves, then show themselves. Put it in setVisibleAndFrontmost.
- make_ui_sound("UISndWindowOpen");
- #endif
- // RN: floaters are created in the invisible state
- setVisible(false);
- if (gFloaterViewp && !getParent())
- {
- gFloaterViewp->addChild(this);
- }
- }
- //virtual
- LLFloater::~LLFloater()
- {
- delete mNotificationContext;
- mNotificationContext = NULL;
- #if 0
- // Am I not hosted by another floater ?
- if (mHostHandle.isDead())
- {
- LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
- if (parent)
- {
- parent->removeChild(this);
- }
- }
- #endif
- // Just in case we might still have focus here, release it.
- releaseFocus();
- // This is important so that floaters with persistent rects (i.e., those
- // created with rect control rather than an LLRect) are restored in their
- // correct, non-minimized positions.
- setMinimized(false);
- delete mDragHandle;
- for (S32 i = 0; i < 4; ++i)
- {
- delete mResizeBar[i];
- delete mResizeHandle[i];
- }
- }
- void LLFloater::setVisible(bool visible)
- {
- LLPanel::setVisible(visible);
- if (!visible)
- {
- if (gFocusMgr.childIsTopCtrl(this))
- {
- gFocusMgr.setTopCtrl(NULL);
- }
- if (gFocusMgr.childHasMouseCapture(this))
- {
- gFocusMgr.setMouseCapture(NULL);
- }
- }
- for (handle_set_iter_t it = mDependents.begin(), end = mDependents.end();
- it != end; ++it)
- {
- LLFloater* floaterp = it->get();
- if (floaterp)
- {
- floaterp->setVisible(visible);
- }
- }
- }
- void LLFloater::open()
- {
- if (getSoundFlags() != SILENT && (!getVisible() || isMinimized()) &&
- // Do not play open sound for hosted (tabbed) windows
- !getHost() && !sHostp)
- {
- make_ui_sound("UISndWindowOpen");
- }
- // NOTE: do not allow rehosting from one multifloater to another
- if (getHost())
- {
- // Already hosted
- getHost()->showFloater(this);
- }
- else if (sHostp)
- {
- // Needs a host; only select tabs if window they are hosted in is
- // visible
- sHostp->addFloater(this, sHostp->getVisible());
- }
- else
- {
- setMinimized(false);
- setVisibleAndFrontmost(mAutoFocus);
- }
- onOpen();
- }
- void LLFloater::close(bool app_quitting)
- {
- // Always unminimize before trying to close. Most of the time the user will
- // never see this state.
- setMinimized(false);
- if (canClose())
- {
- if (getHost())
- {
- getHost()->removeFloater(this);
- if (gFloaterViewp) // Paranoia
- {
- gFloaterViewp->addChild(this);
- }
- }
- if (!app_quitting && getVisible() && !getHost() &&
- getSoundFlags() != SILENT)
- {
- make_ui_sound("UISndWindowClose");
- }
- // Now close dependent floater
- while (!mDependents.empty())
- {
- handle_set_iter_t it = mDependents.begin();
- LLFloater* floaterp = it->get();
- mDependents.erase(it);
- if (floaterp)
- {
- floaterp->mDependeeHandle = LLHandle<LLFloater>();
- floaterp->close();
- }
- }
- cleanupHandles();
- gFocusMgr.clearLastFocusForGroup(this);
- if (hasFocus())
- {
- // Do this early, so UI controls will commit before the window is
- // taken down.
- releaseFocus();
- // Give focus to dependee floater if it exists, and we had focus
- // first
- if (isDependent())
- {
- LLFloater* dependee = mDependeeHandle.get();
- if (dependee && !dependee->isDead())
- {
- dependee->setFocus(true);
- }
- }
- }
- // Let floater do cleanup.
- onClose(app_quitting);
- }
- }
- //virtual
- void LLFloater::reshape(S32 width, S32 height, bool called_from_parent)
- {
- LLPanel::reshape(width, height, called_from_parent);
- }
- void LLFloater::releaseFocus()
- {
- if (gFocusMgr.childIsTopCtrl(this))
- {
- gFocusMgr.setTopCtrl(NULL);
- }
- if (gFocusMgr.childHasKeyboardFocus(this))
- {
- gFocusMgr.setKeyboardFocus(NULL);
- }
- if (gFocusMgr.childHasMouseCapture(this))
- {
- gFocusMgr.setMouseCapture(NULL);
- }
- }
- void LLFloater::setResizeLimits(S32 min_width, S32 min_height)
- {
- mMinWidth = min_width;
- mMinHeight = min_height;
- for (S32 i = 0; i < 4; ++i)
- {
- if (mResizeBar[i])
- {
- if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
- {
- mResizeBar[i]->setResizeLimits(min_width, S32_MAX);
- }
- else
- {
- mResizeBar[i]->setResizeLimits(min_height, S32_MAX);
- }
- }
- if (mResizeHandle[i])
- {
- mResizeHandle[i]->setResizeLimits(min_width, min_height);
- }
- }
- }
- bool LLFloater::resizedFromHandles() const
- {
- for (S32 i = 0; i < 4; ++i)
- {
- if (mResizeBar[i] && mResizeBar[i]->resizing())
- {
- return true;
- }
- if (mResizeHandle[i] && mResizeHandle[i]->resizing())
- {
- return true;
- }
- }
- return false;
- }
- void LLFloater::center()
- {
- if (gFloaterViewp && !getHost()) // Hosted floaters cannot move
- {
- centerWithin(gFloaterViewp->getRect());
- }
- }
- void LLFloater::applyRectControl()
- {
- if (!getRectControl().empty())
- {
- const LLRect& rect =
- LLUI::sConfigGroup->getRect(getRectControl().c_str());
- translate(rect.mLeft - getRect().mLeft,
- rect.mBottom - getRect().mBottom);
- if (mResizable)
- {
- reshape(llmax(mMinWidth, rect.getWidth()),
- llmax(mMinHeight, rect.getHeight()));
- }
- }
- }
- void LLFloater::applyTitle()
- {
- if (mDragHandle)
- {
- mDragHandle->setTitle(mTitle);
- }
- }
- const std::string& LLFloater::getCurrentTitle() const
- {
- return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
- }
- void LLFloater::setTitle(const std::string& title)
- {
- mTitleIsPristine = false;
- mTitle = title;
- applyTitle();
- }
- std::string LLFloater::getTitle()
- {
- if (mTitle.empty() && mDragHandle)
- {
- return mDragHandle->getTitle();
- }
- return mTitle;
- }
- bool LLFloater::canSnapTo(LLView* other_view)
- {
- if (!other_view)
- {
- llwarns << "Cannot snap to a NULL view" << llendl;
- return false;
- }
- if (other_view != getParent())
- {
- LLFloater* floaterp = other_view->asFloater();
- if (floaterp && floaterp->getSnapTarget() == getHandle() &&
- mDependents.count(floaterp->getHandle()))
- {
- // This is a dependent that is already snapped to us, so do not
- // snap back to it
- return false;
- }
- }
- return LLPanel::canSnapTo(other_view);
- }
- void LLFloater::snappedTo(LLView* snap_view)
- {
- if (!snap_view || snap_view == getParent())
- {
- clearSnapTarget();
- }
- else
- {
- LLFloater* floaterp = snap_view->asFloater();
- if (floaterp)
- {
- setSnapTarget(floaterp->getHandle());
- }
- }
- }
- void LLFloater::userSetShape(const LLRect& new_rect)
- {
- const LLRect old_rect = getRect();
- LLView::userSetShape(new_rect);
- // If not minimized, adjust all snapped dependents to new shape
- if (!isMinimized())
- {
- // Gather all snapped dependents
- for (handle_set_iter_t it = mDependents.begin(),
- end = mDependents.end();
- it != end; ++it)
- {
- LLFloater* floaterp = it->get();
- // Is a dependent snapped to us ?
- if (floaterp && floaterp->getSnapTarget() == getHandle())
- {
- S32 delta_x = 0;
- S32 delta_y = 0;
- // Check to see if it snapped to right or top, and move if
- // dependee floater is resizing
- LLRect dependent_rect = floaterp->getRect();
- S32 old_width = old_rect.getWidth();
- // dependent on my right ?
- if (dependent_rect.mLeft - getRect().mLeft >= old_width ||
- // dependent aligned with my right ?
- dependent_rect.mRight == getRect().mLeft + old_width)
- {
- // Was snapped directly onto right side or aligned with it
- delta_x += new_rect.getWidth() - old_width;
- }
- S32 old_height = old_rect.getHeight();
- if (dependent_rect.mBottom - getRect().mBottom >= old_height ||
- dependent_rect.mTop == getRect().mBottom + old_height)
- {
- // Was snapped directly onto top side or aligned with it
- delta_y += new_rect.getHeight() - old_height;
- }
- // Take translation of dependee floater into account as well
- delta_x += new_rect.mLeft - old_rect.mLeft;
- delta_y += new_rect.mBottom - old_rect.mBottom;
- dependent_rect.translate(delta_x, delta_y);
- floaterp->userSetShape(dependent_rect);
- }
- }
- if (resizedFromHandles())
- {
- sResizing = true;
- sLastSizeX = getRect().getWidth();
- sLastSizeY = getRect().getHeight();
- }
- }
- else if (new_rect.mLeft != old_rect.mLeft ||
- new_rect.mBottom != old_rect.mBottom)
- {
- // If minimized, and origin has changed
- mHasBeenDraggedWhileMinimized = true;
- }
- }
- void LLFloater::setMinimized(bool minimize)
- {
- if (minimize == mMinimized) return;
- if (minimize)
- {
- mExpandedRect = getRect();
- // If the floater has been dragged while minimized in the past, then
- // locate it at its previous minimized location. Otherwise, ask the
- // view for a minimize position.
- if (mHasBeenDraggedWhileMinimized)
- {
- setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
- }
- else if (gFloaterViewp) // Paranoa
- {
- S32 left, bottom;
- gFloaterViewp->getMinimizePosition(&left, &bottom);
- setOrigin(left, bottom);
- }
- if (mButtonsEnabled[BUTTON_MINIMIZE])
- {
- mButtonsEnabled[BUTTON_MINIMIZE] = false;
- mButtonsEnabled[BUTTON_RESTORE] = true;
- }
- if (mDragHandle)
- {
- mDragHandle->setVisible(true);
- }
- setBorderVisible(true);
- for (handle_set_iter_t it = mDependents.begin(),
- end = mDependents.end();
- it != end; ++it)
- {
- LLFloater* floaterp = it->get();
- if (floaterp)
- {
- if (floaterp->isMinimizeable())
- {
- floaterp->setMinimized(true);
- }
- else if (!floaterp->isMinimized())
- {
- floaterp->setVisible(false);
- }
- }
- }
- // Lose keyboard focus when minimized
- releaseFocus();
- for (S32 i = 0; i < 4; ++i)
- {
- if (mResizeBar[i])
- {
- mResizeBar[i]->setEnabled(false);
- }
- if (mResizeHandle[i])
- {
- mResizeHandle[i]->setEnabled(false);
- }
- }
- mMinimized = true;
- // Reshape *after* setting mMinimized
- reshape(MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE);
- }
- else
- {
- // If this window has been dragged while minimized (at any time),
- // remember its position for the next time it's minimized.
- if (mHasBeenDraggedWhileMinimized)
- {
- const LLRect& currentRect = getRect();
- mPreviousMinimizedLeft = currentRect.mLeft;
- mPreviousMinimizedBottom = currentRect.mBottom;
- }
- setOrigin(mExpandedRect.mLeft, mExpandedRect.mBottom);
- if (mButtonsEnabled[BUTTON_RESTORE])
- {
- mButtonsEnabled[BUTTON_MINIMIZE] = true;
- mButtonsEnabled[BUTTON_RESTORE] = false;
- }
- // show dependent floater
- for (handle_set_iter_t it = mDependents.begin(),
- end = mDependents.end();
- it != end; ++it)
- {
- LLFloater* floaterp = it->get();
- if (floaterp)
- {
- floaterp->setMinimized(false);
- floaterp->setVisible(true);
- }
- }
- for (S32 i = 0; i < 4; ++i)
- {
- if (mResizeBar[i])
- {
- mResizeBar[i]->setEnabled(isResizable());
- }
- if (mResizeHandle[i])
- {
- mResizeHandle[i]->setEnabled(isResizable());
- }
- }
- mMinimized = false;
- // Reshape *after* setting mMinimized
- reshape(mExpandedRect.getWidth(), mExpandedRect.getHeight());
- }
- applyTitle ();
- make_ui_sound("UISndWindowClose");
- updateButtons();
- }
- void LLFloater::setFocus(bool b)
- {
- if (b && getIsChrome())
- {
- return;
- }
- LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this);
- // A descendent already has focus
- bool child_had_focus = gFocusMgr.childHasKeyboardFocus(this);
- // Give focus to first valid descendent
- LLPanel::setFocus(b);
- if (b)
- {
- LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
- // Only push focused floaters to front of stack if not in midst of
- // ctrl-tab cycle
- if (!getHost() && (!parent || !parent->getCycleMode()) &&
- !isFrontmost())
- {
- setFrontmost();
- }
- // When getting focus, delegate to last descendent which had focus
- if (last_focus && !child_had_focus &&
- last_focus->isInEnabledChain() &&
- last_focus->isInVisibleChain())
- {
- // *FIX: should handle case where focus doesn't stick
- last_focus->setFocus(true);
- }
- }
- }
- //virtual
- void LLFloater::setIsChrome(bool is_chrome)
- {
- // Chrome floaters do not take focus at all
- if (is_chrome)
- {
- // Remove focus if we are changing to chrome
- setFocus(false);
- // Cannot CTRL-TAB to "chrome" floaters
- setFocusRoot(false);
- }
- // No titles displayed on "chrome" floaters
- if (mDragHandle)
- {
- mDragHandle->setTitleVisible(!is_chrome);
- }
- LLPanel::setIsChrome(is_chrome);
- }
- void LLFloater::setTitleVisible(bool visible)
- {
- if (mDragHandle)
- {
- mDragHandle->setTitleVisible(visible);
- }
- }
- // Change the draw style to account for the foreground state.
- void LLFloater::setForeground(bool front)
- {
- if (front != mForeground)
- {
- mForeground = front;
- if (mDragHandle)
- mDragHandle->setForeground(front);
- if (!front)
- {
- releaseFocus();
- }
- setBackgroundOpaque(front);
- }
- }
- void LLFloater::cleanupHandles()
- {
- // Remove handles to non-existent dependents
- for (handle_set_iter_t it = mDependents.begin(); it != mDependents.end(); )
- {
- LLFloater* floaterp = it->get();
- if (!floaterp)
- {
- it = mDependents.erase(it);
- }
- else
- {
- ++it;
- }
- }
- }
- void LLFloater::setHost(LLMultiFloater* host)
- {
- if (mHostHandle.isDead() && host)
- {
- // Make buttons smaller for hosted windows to differentiate from parent
- mButtonScale = 0.9f;
- // Add tear off button
- if (mCanTearOff)
- {
- mButtonsEnabled[BUTTON_TEAR_OFF] = true;
- }
- }
- else if (!mHostHandle.isDead() && !host)
- {
- mButtonScale = 1.f;
- #if 0
- mButtonsEnabled[BUTTON_TEAR_OFF] = false;
- #endif
- }
- updateButtons();
- if (host)
- {
- mHostHandle = host->getHandle();
- mLastHostHandle = host->getHandle();
- }
- else
- {
- mHostHandle.markDead();
- }
- }
- void LLFloater::moveResizeHandlesToFront()
- {
- for (S32 i = 0; i < 4; ++i)
- {
- if (mResizeBar[i])
- {
- sendChildToFront(mResizeBar[i]);
- }
- }
- for (S32 i = 0; i < 4; ++i)
- {
- if (mResizeHandle[i])
- {
- sendChildToFront(mResizeHandle[i]);
- }
- }
- }
- bool LLFloater::isFrontmost()
- {
- return getVisible() &&
- gFloaterViewp && gFloaterViewp->getFrontmost() == this;
- }
- void LLFloater::addDependentFloater(LLFloater* floaterp, bool reposition)
- {
- if (!gFloaterViewp) return; // Paranoia
- mDependents.insert(floaterp->getHandle());
- floaterp->mDependeeHandle = getHandle();
- if (reposition)
- {
- floaterp->setRect(gFloaterViewp->findNeighboringPosition(this,
- floaterp));
- floaterp->setSnapTarget(getHandle());
- }
- gFloaterViewp->adjustToFitScreen(floaterp);
- if (floaterp->isFrontmost())
- {
- // Make sure to bring self and sibling floaters to front
- gFloaterViewp->bringToFront(floaterp);
- }
- }
- void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent,
- bool reposition)
- {
- LLFloater* dependent_floaterp = dependent.get();
- if (dependent_floaterp)
- {
- addDependentFloater(dependent_floaterp, reposition);
- }
- }
- void LLFloater::removeDependentFloater(LLFloater* floaterp)
- {
- mDependents.erase(floaterp->getHandle());
- floaterp->mDependeeHandle = LLHandle<LLFloater>();
- }
- bool LLFloater::offerClickToButton(S32 x, S32 y, MASK mask,
- EFloaterButtons index)
- {
- if (mButtonsEnabled[index])
- {
- LLButton* my_butt = mButtons[index];
- S32 local_x = x - my_butt->getRect().mLeft;
- S32 local_y = y - my_butt->getRect().mBottom;
- if (my_butt->pointInView(local_x, local_y) &&
- my_butt->handleMouseDown(local_x, local_y, mask))
- {
- // The button handled it
- return true;
- }
- }
- return false;
- }
- //virtual
- bool LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
- {
- if (mMinimized)
- {
- // Offer the click to titlebar buttons. Note: this block and the
- // offerClickToButton helper method could be removed because the parent
- // container will handle it for us but we will keep it here for safety
- // until after reworking the panel code to manage hidden children.
- if (offerClickToButton(x, y, mask, BUTTON_CLOSE) ||
- offerClickToButton(x, y, mask, BUTTON_RESTORE) ||
- offerClickToButton(x, y, mask, BUTTON_TEAR_OFF))
- {
- return true;
- }
- // Otherwise pass to drag handle for movement
- return mDragHandle->handleMouseDown(x, y, mask);
- }
- bringToFront(x, y);
- return LLPanel::handleMouseDown(x, y, mask);
- }
- //virtual
- bool LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask)
- {
- bool was_minimized = mMinimized;
- bringToFront(x, y);
- return was_minimized || LLPanel::handleRightMouseDown(x, y, mask);
- }
- bool LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
- {
- bringToFront(x, y);
- return LLPanel::handleMiddleMouseDown(x, y, mask);
- }
- //virtual
- bool LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
- {
- bool was_minimized = mMinimized;
- setMinimized(false);
- return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
- }
- void LLFloater::bringToFront(S32 x, S32 y)
- {
- if (getVisible() && pointInView(x, y))
- {
- LLMultiFloater* hostp = getHost();
- if (hostp)
- {
- hostp->showFloater(this);
- }
- else
- {
- LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
- if (parent)
- {
- parent->bringToFront(this);
- }
- }
- }
- }
- //virtual
- void LLFloater::setVisibleAndFrontmost(bool take_focus)
- {
- setVisible(true);
- setFrontmost(take_focus);
- }
- void LLFloater::setFrontmost(bool take_focus)
- {
- LLMultiFloater* hostp = getHost();
- if (hostp)
- {
- // This will bring the host floater to the front and select the
- // appropriate panel
- hostp->showFloater(this);
- }
- else
- {
- // There are more than one floater view so we need to query our parent
- // directly
- LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
- if (parent)
- {
- parent->bringToFront(this, take_focus);
- }
- }
- }
- //static
- void LLFloater::onClickMinimize(void* userdata)
- {
- LLFloater* self = (LLFloater*) userdata;
- if (self)
- {
- self->setMinimized(!self->isMinimized());
- }
- }
- void LLFloater::onClickTearOff(void* userdata)
- {
- LLFloater* self = (LLFloater*) userdata;
- if (!self || !gFloaterViewp) return;
- LLMultiFloater* host_floater = self->getHost();
- if (host_floater) //Tear off
- {
- LLRect new_rect;
- host_floater->removeFloater(self);
- // Re-parent to floater view
- gFloaterViewp->addChild(self);
- self->open();
- // Only force position for floaters that don't have that data saved
- if (self->getRectControl().empty())
- {
- new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5,
- host_floater->getRect().mTop -
- LLFLOATER_HEADER_SIZE - 5,
- self->getRect().getWidth(),
- self->getRect().getHeight());
- self->setRect(new_rect);
- }
- gFloaterViewp->adjustToFitScreen(self);
- // Give focus to new window to keep continuity for the user
- self->setFocus(true);
- }
- else //Attach to parent.
- {
- LLMultiFloater* new_host;
- new_host = (LLMultiFloater*)self->mLastHostHandle.get();
- if (new_host)
- {
- // To reenable minimize button if it was minimized
- self->setMinimized(false);
- new_host->showFloater(self);
- // Make sure host is visible
- new_host->open();
- }
- }
- }
- //static
- LLFloater* LLFloater::getClosableFloaterFromFocus()
- {
- if (!gFloaterViewp)
- {
- return NULL;
- }
- LLFloater* floaterp = NULL;
- for (child_list_const_iter_t it = gFloaterViewp->getChildList()->begin(),
- end = gFloaterViewp->getChildList()->end();
- it != end; ++it)
- {
- LLFloater* candidatep = (*it)->asFloater();
- if (candidatep && candidatep->hasFocus())
- {
- floaterp = candidatep;
- break;
- }
- }
- // The focused floater may not be closable: find and close a parental
- // floater that is closeable, if any.
- while (floaterp)
- {
- if (floaterp->isCloseable())
- {
- break;
- }
- floaterp = gFloaterViewp->getParentFloater(floaterp);
- }
- return floaterp;
- }
- //static
- void LLFloater::closeFocusedFloater()
- {
- LLFloater* floaterp = getClosableFloaterFromFocus();
- if (floaterp)
- {
- floaterp->close();
- }
- // If nothing took focus after closing focused floater give it to next
- // floater (to allow closing multiple windows via keyboard in rapid
- // succession)
- if (gFloaterViewp && !gFocusMgr.getKeyboardFocus())
- {
- // *HACK: use gFloaterViewp directly in case we are using CTRL-W to
- // close snapshot window which sits in gSnapshotFloaterViewp, and
- // needs to pass focus on to normal floater view
- gFloaterViewp->focusFrontFloater();
- }
- }
- //static
- void LLFloater::onClickClose(void* userdata)
- {
- LLFloater* self = (LLFloater*)userdata;
- if (self)
- {
- self->close();
- }
- }
- //virtual
- void LLFloater::draw()
- {
- // Draw background
- if (isBackgroundVisible())
- {
- S32 left = LLPANEL_BORDER_WIDTH;
- S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH;
- S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH;
- S32 bottom = LLPANEL_BORDER_WIDTH;
- LLColor4 shadow_color = LLUI::sColorDropShadow;
- F32 shadow_offset = (F32)LLUI::sDropShadowFloater;
- if (!isBackgroundOpaque())
- {
- shadow_offset *= 0.2f;
- shadow_color.mV[VALPHA] *= 0.5f;
- }
- gl_drop_shadow(left, top, right, bottom, shadow_color,
- ll_round(shadow_offset));
- // No transparent windows in simple UI
- if (isBackgroundOpaque())
- {
- gl_rect_2d(left, top, right, bottom, getBackgroundColor());
- }
- else
- {
- gl_rect_2d(left, top, right, bottom, getTransparentColor());
- }
- if (gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() &&
- !getCurrentTitle().empty())
- {
- // Draw highlight on title bar to indicate focus. RDW
- static S32 font_line_height = 0;
- if (!font_line_height)
- {
- static const LLFontGL* font = LLFontGL::getFontSansSerif();
- font_line_height = font->getLineHeight() - 1;
- }
- LLRect r = getRect();
- gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(),
- r.getHeight() - font_line_height,
- LLUI::sTitleBarFocusColor, 0, true);
- }
- }
- LLPanel::updateDefaultBtn();
- if (getDefaultButton())
- {
- if (hasFocus() && getDefaultButton()->getEnabled())
- {
- LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
- // Is this button a direct descendent and not a nested widget (e.g.
- // checkbox) ?
- LLButton* btn = dynamic_cast<LLButton*>(focus_ctrl);
- bool focus_is_child_button = btn && btn->getParent() == this;
- // only enable default button when current focus is not a button
- getDefaultButton()->setBorderEnabled(!focus_is_child_button);
- }
- else
- {
- getDefaultButton()->setBorderEnabled(false);
- }
- }
- if (isMinimized())
- {
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- drawChild(mButtons[i]);
- }
- drawChild(mDragHandle);
- }
- else
- {
- // Do not call LLPanel::draw() since we have implemented custom
- // background rendering
- LLView::draw();
- }
- if (isBackgroundVisible())
- {
- // Add in a border to improve spacialized visual clarity; use lines
- // instead of gl_rect_2d so we can round the edges as per James'
- // recommendation
- LLUI::setLineWidth(1.5f);
- LLColor4 outline_color =
- gFocusMgr.childHasKeyboardFocus(this) ? LLUI::sFloaterFocusBorderColor
- : LLUI::sFloaterUnfocusBorderColor;
- gl_rect_2d_offset_local(0, getRect().getHeight() + 1,
- getRect().getWidth() + 1, 0, outline_color,
- -LLPANEL_BORDER_WIDTH, false);
- LLUI::setLineWidth(1.f);
- }
- // Update tearoff button for torn off floaters when last host goes away
- if (mCanTearOff && !getHost())
- {
- LLFloater* old_host = mLastHostHandle.get();
- if (!old_host)
- {
- setCanTearOff(false);
- }
- }
- }
- void LLFloater::setCanMinimize(bool can_minimize)
- {
- // if removing minimize/restore button programmatically,
- // go ahead and unminimize floater
- if (!can_minimize)
- {
- setMinimized(false);
- }
- mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized();
- mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized();
- updateButtons();
- }
- void LLFloater::setCanClose(bool can_close)
- {
- mButtonsEnabled[BUTTON_CLOSE] = can_close;
- updateButtons();
- }
- void LLFloater::setCanTearOff(bool can_tear_off)
- {
- mCanTearOff = can_tear_off;
- mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead();
- updateButtons();
- }
- void LLFloater::setCanResize(bool can_resize)
- {
- if (mResizable && !can_resize)
- {
- for (S32 i = 0; i < 4; ++i)
- {
- removeChild(mResizeBar[i], true);
- mResizeBar[i] = NULL;
- removeChild(mResizeHandle[i], true);
- mResizeHandle[i] = NULL;
- }
- }
- else if (!mResizable && can_resize)
- {
- // Resize bars (sides)
- constexpr S32 RESIZE_BAR_THICKNESS = 3;
- mResizeBar[0] = new LLResizeBar("resizebar_left", this,
- LLRect(0, getRect().getHeight(),
- RESIZE_BAR_THICKNESS, 0),
- mMinWidth, S32_MAX, LLResizeBar::LEFT);
- addChild(mResizeBar[0]);
- mResizeBar[1] = new LLResizeBar("resizebar_top", this,
- LLRect(0, getRect().getHeight(),
- getRect().getWidth(),
- getRect().getHeight() -
- RESIZE_BAR_THICKNESS),
- mMinHeight, S32_MAX,
- LLResizeBar::TOP);
- addChild(mResizeBar[1]);
- mResizeBar[2] = new LLResizeBar("resizebar_right", this,
- LLRect(getRect().getWidth() -
- RESIZE_BAR_THICKNESS,
- getRect().getHeight(),
- getRect().getWidth(), 0),
- mMinWidth, S32_MAX,
- LLResizeBar::RIGHT);
- addChild(mResizeBar[2]);
- mResizeBar[3] = new LLResizeBar("resizebar_bottom", this,
- LLRect(0, RESIZE_BAR_THICKNESS,
- getRect().getWidth(), 0),
- mMinHeight, S32_MAX,
- LLResizeBar::BOTTOM);
- addChild(mResizeBar[3]);
- // Resize handles (corners)
- mResizeHandle[0] = new LLResizeHandle("Resize Handle",
- LLRect(getRect().getWidth() -
- RESIZE_HANDLE_WIDTH,
- RESIZE_HANDLE_HEIGHT,
- getRect().getWidth(), 0),
- mMinWidth, mMinHeight,
- LLResizeHandle::RIGHT_BOTTOM);
- addChild(mResizeHandle[0]);
- mResizeHandle[1] = new LLResizeHandle("resize",
- LLRect(getRect().getWidth() -
- RESIZE_HANDLE_WIDTH,
- getRect().getHeight(),
- getRect().getWidth(),
- getRect().getHeight() -
- RESIZE_HANDLE_HEIGHT),
- mMinWidth, mMinHeight,
- LLResizeHandle::RIGHT_TOP);
- addChild(mResizeHandle[1]);
- mResizeHandle[2] = new LLResizeHandle("resize",
- LLRect(0, RESIZE_HANDLE_HEIGHT,
- RESIZE_HANDLE_WIDTH, 0),
- mMinWidth, mMinHeight,
- LLResizeHandle::LEFT_BOTTOM);
- addChild(mResizeHandle[2]);
- mResizeHandle[3] = new LLResizeHandle("resize",
- LLRect(0, getRect().getHeight(),
- RESIZE_HANDLE_WIDTH,
- getRect().getHeight() -
- RESIZE_HANDLE_HEIGHT),
- mMinWidth, mMinHeight,
- LLResizeHandle::LEFT_TOP);
- addChild(mResizeHandle[3]);
- }
- mResizable = can_resize;
- }
- void LLFloater::setCanDrag(bool can_drag)
- {
- // If we delete drag handle, we no longer have access to the floater title
- // so just enable/disable it
- if (!can_drag && mDragHandle->getEnabled())
- {
- mDragHandle->setEnabled(false);
- }
- else if (can_drag && !mDragHandle->getEnabled())
- {
- mDragHandle->setEnabled(true);
- }
- }
- void LLFloater::updateButtons()
- {
- S32 close_box_size = ll_roundp((F32)LLFLOATER_CLOSE_BOX_SIZE *
- mButtonScale);
- S32 button_count = 0;
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- if (!mButtons[i]) continue;
- mButtons[i]->setEnabled(mButtonsEnabled[i]);
- if (mButtonsEnabled[i] ||
- // *HACK: always render close button for hosted floaters so that
- // users do not accidentally hit the button when closing multiple
- // windows in the chatterbox
- (i == BUTTON_CLOSE && mButtonScale != 1.f))
- {
- ++button_count;
- LLRect btn_rect;
- if (mDragOnLeft)
- {
- btn_rect.setLeftTopAndSize(LLPANEL_BORDER_WIDTH,
- getRect().getHeight() -
- CLOSE_BOX_FROM_TOP -
- (LLFLOATER_CLOSE_BOX_SIZE + 1) *
- button_count,
- close_box_size, close_box_size);
- }
- else
- {
- btn_rect.setLeftTopAndSize(getRect().getWidth() -
- LLPANEL_BORDER_WIDTH -
- (LLFLOATER_CLOSE_BOX_SIZE + 1) *
- button_count,
- getRect().getHeight() -
- CLOSE_BOX_FROM_TOP,
- close_box_size, close_box_size);
- }
- mButtons[i]->setRect(btn_rect);
- mButtons[i]->setVisible(true);
- // The restore button should have a tab stop so that it takes
- // action when you Ctrl-Tab to a minimized floater
- mButtons[i]->setTabStop(i == BUTTON_RESTORE);
- }
- else if (mButtons[i])
- {
- mButtons[i]->setVisible(false);
- }
- }
- if (mDragHandle)
- {
- mDragHandle->setMaxTitleWidth(getRect().getWidth() -
- button_count *
- (LLFLOATER_CLOSE_BOX_SIZE + 1));
- }
- }
- void LLFloater::buildButtons()
- {
- static std::vector<std::string> tooltips;
- if (tooltips.empty())
- {
- tooltips.reserve(BUTTON_COUNT);
- for (U32 i = 0; i < BUTTON_COUNT; ++i)
- {
- tooltips.emplace_back(LLTrans::getUIString(sButtonToolTipNames[i]));
- }
- }
- S32 close_box_size = ll_roundp((F32)LLFLOATER_CLOSE_BOX_SIZE *
- mButtonScale);
- for (S32 i = 0; i < BUTTON_COUNT; ++i)
- {
- LLRect btn_rect;
- if (mDragOnLeft)
- {
- btn_rect.setLeftTopAndSize(LLPANEL_BORDER_WIDTH,
- getRect().getHeight() -
- CLOSE_BOX_FROM_TOP -
- (LLFLOATER_CLOSE_BOX_SIZE + 1) *
- (i + 1),
- close_box_size, close_box_size);
- }
- else
- {
- btn_rect.setLeftTopAndSize(getRect().getWidth() -
- LLPANEL_BORDER_WIDTH -
- (LLFLOATER_CLOSE_BOX_SIZE + 1) *
- (i + 1),
- getRect().getHeight() -
- CLOSE_BOX_FROM_TOP,
- close_box_size, close_box_size);
- }
- LLButton* buttonp = new LLButton(sButtonNames[i], btn_rect,
- sButtonActiveImageNames[i],
- sButtonPressedImageNames[i],
- NULL, sButtonCallbacks[i], this,
- LLFontGL::getFontSansSerif());
- buttonp->setTabStop(false);
- buttonp->setFollowsTop();
- buttonp->setFollowsRight();
- buttonp->setToolTip(tooltips[i]);
- buttonp->setImageColor(LLUI::sFloaterButtonImageColor);
- buttonp->setHoverImages(sButtonPressedImageNames[i],
- sButtonPressedImageNames[i]);
- buttonp->setScaleImage(true);
- buttonp->setSaveToXML(false);
- addChild(buttonp);
- mButtons[i] = buttonp;
- }
- updateButtons();
- }
- /////////////////////////////////////////////////////
- // LLFloaterView
- LLFloaterView::LLFloaterView(const std::string& name, const LLRect& rect)
- : LLUICtrl(name, rect, false, NULL, NULL, FOLLOWS_ALL),
- mFocusCycleMode(false),
- mSnapOffsetBottom(0)
- {
- setTabStop(false);
- resetStartingFloaterPosition();
- }
- // By default, adjust vertical.
- void LLFloaterView::reshape(S32 width, S32 height, bool called_from_parent)
- {
- reshapeFloater(width, height, called_from_parent, ADJUST_VERTICAL_YES);
- }
- // When reshaping this view, make the floaters follow their closest edge.
- void LLFloaterView::reshapeFloater(S32 width, S32 height,
- bool called_from_parent,
- bool adjust_vertical)
- {
- S32 old_width = getRect().getWidth();
- S32 old_height = getRect().getHeight();
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (!floaterp || floaterp->isDependent())
- {
- // Dependents use same follow flags as their "dependee"
- continue;
- }
- LLRect r = floaterp->getRect();
- // Compute absolute distance from each edge of screen
- S32 left_offset = abs(r.mLeft);
- S32 right_offset = abs(old_width - r.mRight);
- S32 top_offset = abs(old_height - r.mTop);
- S32 bottom_offset = abs(r.mBottom);
- // Make if follow the edge it is closest to
- U32 follow_flags = 0x0;
- if (left_offset < right_offset)
- {
- follow_flags |= FOLLOWS_LEFT;
- }
- else
- {
- follow_flags |= FOLLOWS_RIGHT;
- }
- // "No vertical adjustment" usually means that the bottom of the view
- // has been pushed up or down. Hence we want the floaters to follow the
- // top.
- if (!adjust_vertical)
- {
- follow_flags |= FOLLOWS_TOP;
- }
- else if (top_offset < bottom_offset)
- {
- follow_flags |= FOLLOWS_TOP;
- }
- else
- {
- follow_flags |= FOLLOWS_BOTTOM;
- }
- floaterp->setFollows(follow_flags);
- // RN: all dependent floaters copy follow behavior of "parent"
- for (LLFloater::handle_set_iter_t
- dep_it = floaterp->mDependents.begin(),
- dep_end = floaterp->mDependents.end();
- dep_it != dep_end; ++dep_it)
- {
- LLFloater* dependent_floaterp = dep_it->get();
- if (dependent_floaterp)
- {
- dependent_floaterp->setFollows(follow_flags);
- }
- }
- }
- LLView::reshape(width, height, called_from_parent);
- }
- void LLFloaterView::restoreAll()
- {
- // Make sure all subwindows aren't minimized
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp)
- {
- floaterp->setMinimized(false);
- }
- }
- }
- void LLFloaterView::getNewFloaterPosition(S32* left, S32* top)
- {
- // Workaround: mRect may change between when this object is created and the
- // first time it is used.
- static bool first = true;
- if (first)
- {
- resetStartingFloaterPosition();
- first = false;
- }
- constexpr S32 FLOATER_PAD = 16;
- LLCoordWindow window_size;
- gWindowp->getSize(&window_size);
- LLRect full_window(0, window_size.mY, window_size.mX, 0);
- LLRect floater_creation_rect(160,
- full_window.getHeight() - 2 * gMenuBarHeight,
- full_window.getWidth() * 2 / 3, 130);
- floater_creation_rect.stretch(-FLOATER_PAD);
- *left = mNextLeft;
- *top = mNextTop;
- constexpr S32 STEP = 25;
- S32 bottom = floater_creation_rect.mBottom + 2 * STEP;
- S32 right = floater_creation_rect.mRight - 4 * STEP;
- mNextTop -= STEP;
- mNextLeft += STEP;
- if (mNextTop < bottom || mNextLeft > right)
- {
- ++mColumn;
- mNextTop = floater_creation_rect.mTop;
- mNextLeft = STEP * mColumn;
- if (mNextTop < bottom || mNextLeft > right)
- {
- // Advancing the column did not work, so start back at the
- // beginning
- resetStartingFloaterPosition();
- }
- }
- }
- void LLFloaterView::resetStartingFloaterPosition()
- {
- constexpr S32 FLOATER_PAD = 16;
- LLCoordWindow window_size;
- gWindowp->getSize(&window_size);
- LLRect full_window(0, window_size.mY, window_size.mX, 0);
- LLRect floater_creation_rect(
- 160,
- full_window.getHeight() - 2 * gMenuBarHeight,
- full_window.getWidth() * 2 / 3,
- 130);
- floater_creation_rect.stretch(-FLOATER_PAD);
- mNextLeft = floater_creation_rect.mLeft;
- mNextTop = floater_creation_rect.mTop;
- mColumn = 0;
- }
- LLRect LLFloaterView::findNeighboringPosition(LLFloater* reference_floater,
- LLFloater* neighbor)
- {
- LLRect base_rect = reference_floater->getRect();
- S32 width = neighbor->getRect().getWidth();
- S32 height = neighbor->getRect().getHeight();
- LLRect new_rect = neighbor->getRect();
- LLRect expanded_base_rect = base_rect;
- expanded_base_rect.stretch(10);
- for (LLFloater::handle_set_iter_t
- dep_it = reference_floater->mDependents.begin();
- dep_it != reference_floater->mDependents.end(); ++dep_it)
- {
- LLFloater* sibling = dep_it->get();
- // Check for dependents within 10 pixels of base floater
- if (sibling && sibling != neighbor && sibling->getVisible() &&
- expanded_base_rect.overlaps(sibling->getRect()))
- {
- base_rect.unionWith(sibling->getRect());
- }
- }
- S32 left_margin = llmax(0, base_rect.mLeft);
- S32 right_margin = llmax(0, getRect().getWidth() - base_rect.mRight);
- S32 top_margin = llmax(0, getRect().getHeight() - base_rect.mTop);
- S32 bottom_margin = llmax(0, base_rect.mBottom);
- // Find position for floater in following order right->left->bottom->top
- for (S32 i = 0; i < 5; ++i)
- {
- if (right_margin > width)
- {
- new_rect.translate(base_rect.mRight - neighbor->getRect().mLeft,
- base_rect.mTop - neighbor->getRect().mTop);
- return new_rect;
- }
- else if (left_margin > width)
- {
- new_rect.translate(base_rect.mLeft - neighbor->getRect().mRight,
- base_rect.mTop - neighbor->getRect().mTop);
- return new_rect;
- }
- else if (bottom_margin > height)
- {
- new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft,
- base_rect.mBottom - neighbor->getRect().mTop);
- return new_rect;
- }
- else if (top_margin > height)
- {
- new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft,
- base_rect.mTop - neighbor->getRect().mBottom);
- return new_rect;
- }
- // keep growing margins to find "best" fit
- left_margin += 20;
- right_margin += 20;
- top_margin += 20;
- bottom_margin += 20;
- }
- // didn't find anything, return initial rect
- return new_rect;
- }
- // *TODO: make this respect the floater mAutoFocus value, instead of using the
- // give_focus parameter.
- bool LLFloaterView::bringToFront(LLFloater* child, bool give_focus)
- {
- if (!child || !getChildList())
- {
- // NULL child or no children for us...
- return false;
- }
- if (child->getHost() ||
- std::find(getChildList()->begin(), getChildList()->end(), child) ==
- getChildList()->end())
- {
- // This floater is hosted elsewhere and hence not one of our children,
- // abort
- return false;
- }
- std::vector<LLView*> floaters_to_move;
- // Look at all floaters...tab
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (!floaterp || !floaterp->isDependent())
- {
- continue;
- }
- // If I am a dependent floater look for floaters that have me as a
- // dependent...
- if (floaterp->mDependents.find(child->getHandle()) !=
- floaterp->mDependents.end())
- {
- // ...and make sure all children of that floater (including me) are
- // brought to front...
- for (LLFloater::handle_set_iter_t
- dep_it = floaterp->mDependents.begin(),
- dep_end = floaterp->mDependents.end();
- dep_it != dep_end; ++dep_it)
- {
- LLFloater* sibling = dep_it->get();
- if (sibling)
- {
- floaters_to_move.push_back(sibling);
- }
- }
- // ...before bringing my parent to the front...
- floaters_to_move.push_back(floaterp);
- }
- }
- for (std::vector<LLView*>::iterator it = floaters_to_move.begin(),
- end = floaters_to_move.end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp)
- {
- sendChildToFront(floaterp);
- // Always unminimize dependee, but allow dependents to stay
- // minimized
- if (!floaterp->isDependent())
- {
- floaterp->setMinimized(false);
- }
- }
- }
- floaters_to_move.clear();
- // ...then bringing my own dependents to the front...
- for (LLFloater::handle_set_iter_t it = child->mDependents.begin(),
- end = child->mDependents.end();
- it != end; ++it)
- {
- LLFloater* dependent = it->get();
- if (dependent)
- {
- sendChildToFront(dependent);
- #if 0 // Do not un-minimize dependent windows automatically: respect the
- // user's wishes !
- dependent->setMinimized(false);
- #endif
- }
- }
- // ...and finally bringing myself to front (do this last, so that I am left
- // in front at end of this call)
- if (*getChildList()->begin() != child)
- {
- sendChildToFront(child);
- }
- child->setMinimized(false);
- if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
- {
- child->setFocus(true);
- }
- return true;
- }
- void LLFloaterView::highlightFocusedFloater()
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (!floaterp || floaterp->isDependent())
- {
- // Skip dependent floaters, as we will handle them in a batch along
- // with their dependee
- continue;
- }
- bool has_focus = gFocusMgr.childHasKeyboardFocus(floaterp);
- for (LLFloater::handle_set_iter_t
- dep_it = floaterp->mDependents.begin(),
- dep_end = floaterp->mDependents.end();
- dep_it != dep_end; ++dep_it)
- {
- LLFloater* dependent_floaterp = dep_it->get();
- if (dependent_floaterp &&
- gFocusMgr.childHasKeyboardFocus(dependent_floaterp))
- {
- has_focus = true;
- break;
- }
- }
- // Now set this floater and all its dependents
- floaterp->setForeground(has_focus);
- for (LLFloater::handle_set_iter_t
- dep_it = floaterp->mDependents.begin(),
- dep_end = floaterp->mDependents.end();
- dep_it != dep_end; ++dep_it)
- {
- LLFloater* dependent_floaterp = dep_it->get();
- if (dependent_floaterp)
- {
- dependent_floaterp->setForeground(has_focus);
- }
- }
- floaterp->cleanupHandles();
- }
- }
- void LLFloaterView::unhighlightFocusedFloater()
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp)
- {
- floaterp->setForeground(false);
- }
- }
- }
- void LLFloaterView::focusFrontFloater()
- {
- LLFloater* floaterp = getFrontmost();
- if (floaterp)
- {
- floaterp->setFocus(true);
- }
- }
- void LLFloaterView::getMinimizePosition(S32* left, S32* bottom)
- {
- S32 row, row_start, row_end, row_delta;
- S32 col, col_start, col_end, col_delta, width;
- LLRect snap_rect_local = getLocalSnapRect();
- if (sStackMinimizedTopToBottom)
- {
- row_start = snap_rect_local.getHeight(); // - LLFLOATER_HEADER_SIZE;
- row_end = snap_rect_local.mBottom;
- row_delta = -LLFLOATER_HEADER_SIZE;
- }
- else
- {
- row_start = snap_rect_local.mBottom;
- row_end = snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE;
- row_delta = LLFLOATER_HEADER_SIZE;
- }
- width = (snap_rect_local.getWidth() - MINIMIZED_WIDTH -
- snap_rect_local.mLeft) / sStackScreenWidthFraction;
- if (width < MINIMIZED_WIDTH)
- {
- width = MINIMIZED_WIDTH;
- }
- if (sStackMinimizedRightToLeft)
- {
- col_start = snap_rect_local.getWidth() - MINIMIZED_WIDTH;
- col_end = col_start - width;
- col_delta = -MINIMIZED_WIDTH;
- }
- else
- {
- col_start = snap_rect_local.mLeft;
- col_end = col_start + width;
- col_delta = MINIMIZED_WIDTH;
- }
- for (row = row_start; (row_delta > 0 ? row < row_end : row > row_end);
- row += row_delta)
- {
- for (col = col_start; (col_delta > 0 ? col < col_end : col > col_end);
- col += col_delta)
- {
- bool found_gap = true;
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (!floaterp || !floaterp->isMinimized())
- {
- continue;
- }
- // Examine minimized children.
- LLRect r = floaterp->getRect();
- if (r.mBottom < row + LLFLOATER_HEADER_SIZE &&
- r.mBottom > row - LLFLOATER_HEADER_SIZE &&
- r.mLeft < col + MINIMIZED_WIDTH &&
- r.mLeft > col - MINIMIZED_WIDTH)
- {
- // Needs the check for off grid; cannot drag, but window
- // resize makes them off
- found_gap = false;
- break;
- }
- }
- if (found_gap)
- {
- *left = col;
- *bottom = row;
- return; // Done
- }
- }
- }
- // Crude: stack them all there when screen is full of minimized floaters.
- *left = col_start;
- *bottom = row_start;
- }
- void LLFloaterView::destroyAllChildren()
- {
- LLView::deleteAllChildren();
- }
- void LLFloaterView::closeAllChildren(bool app_quitting)
- {
- // Iterate over a copy of the list, because closing windows will destroy
- // some windows on the list.
- child_list_t child_list = *getChildList();
- for (child_list_const_iter_t it = child_list.begin(),
- end = child_list.end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- child_list_const_iter_t exists = std::find(getChildList()->begin(),
- getChildList()->end(),
- viewp);
- if (exists == getChildList()->end())
- {
- // This floater has already been removed
- continue;
- }
- // Attempt to close floater. This will cause the "do you want to save"
- // dialogs to appear.
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && floaterp->canClose() && !floaterp->isDead())
- {
- floaterp->close(app_quitting);
- }
- }
- }
- bool LLFloaterView::allChildrenClosed()
- {
- // See if there are any visible floaters (some floaters "close" by setting
- // themselves invisible)
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && !floaterp->isDead() && floaterp->getVisible() &&
- floaterp->isCloseable())
- {
- return false;
- }
- }
- return true;
- }
- void LLFloaterView::refresh()
- {
- // Constrain children to be entirely on the screen
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && floaterp->getVisible())
- {
- // Minimized floaters are kept fully onscreen
- adjustToFitScreen(floaterp, !floaterp->isMinimized());
- }
- }
- }
- void LLFloaterView::adjustToFitScreen(LLFloater* floater,
- bool allow_partial_outside)
- {
- if (floater->getParent() != this)
- {
- // Floater is hosted elsewhere, so ignore
- return;
- }
- S32 screen_width = getSnapRect().getWidth();
- S32 screen_height = getSnapRect().getHeight();
- // Convert to local coordinate frame
- LLRect snap_rect_local = getLocalSnapRect();
- if (floater->isResizable())
- {
- LLRect view_rect = floater->getRect();
- S32 old_width = view_rect.getWidth();
- S32 old_height = view_rect.getHeight();
- S32 min_width;
- S32 min_height;
- floater->getResizeLimits(&min_width, &min_height);
- // Make sure floater is not already smaller than its min height/width
- S32 new_width = llmax(min_width, old_width);
- S32 new_height = llmax(min_height, old_height);
- if (new_width > screen_width || new_height > screen_height)
- {
- // We have to make this window able to fit on screen
- new_width = llmin(new_width, screen_width);
- new_height = llmin(new_height, screen_height);
- // ...while respecting minimum width/height
- new_width = llmax(new_width, min_width);
- new_height = llmax(new_height, min_height);
- floater->reshape(new_width, new_height);
- if (floater->followsRight())
- {
- floater->translate(old_width - new_width, 0);
- }
- if (floater->followsTop())
- {
- floater->translate(0, old_height - new_height);
- }
- }
- }
- // Move window fully onscreen
- if (floater->translateIntoRect(snap_rect_local, allow_partial_outside))
- {
- floater->clearSnapTarget();
- }
- }
- void LLFloaterView::draw()
- {
- refresh();
- // Hide focused floater if in cycle mode, so that it can be drawn on top
- LLFloater* floaterp = mFocusCycleMode ? getFocusedFloater() : NULL;
- if (floaterp)
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- if (*it != floaterp)
- {
- drawChild(*it);
- }
- }
- drawChild(floaterp, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET);
- }
- else
- {
- LLView::draw();
- }
- }
- LLRect LLFloaterView::getSnapRect() const
- {
- LLRect snap_rect = getRect();
- snap_rect.mBottom += mSnapOffsetBottom;
- return snap_rect;
- }
- LLFloater* LLFloaterView::getFocusedFloater()
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && floaterp->hasFocus())
- {
- return floaterp;
- }
- }
- return NULL;
- }
- LLFloater* LLFloaterView::getFrontmost()
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && floaterp->getVisible() && !floaterp->isDead())
- {
- return floaterp;
- }
- }
- return NULL;
- }
- LLFloater* LLFloaterView::getBackmost()
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && floaterp->getVisible())
- {
- return floaterp;
- }
- }
- return NULL;
- }
- void LLFloaterView::syncFloaterTabOrder()
- {
- // bring focused floater to front
- for (child_list_const_reverse_iter_t rit = getChildList()->rbegin(),
- rend = getChildList()->rend();
- rit != rend; ++rit)
- {
- LLView* viewp = *rit;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && gFocusMgr.childHasKeyboardFocus(floaterp))
- {
- bringToFront(floaterp, false);
- break;
- }
- }
- // Then sync draw order to tab order
- for (child_list_const_reverse_iter_t rit = getChildList()->rbegin(),
- rend = getChildList()->rend();
- rit != rend; ++rit)
- {
- LLView* viewp = *rit;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp)
- {
- moveChildToFrontOfTabGroup(floaterp);
- }
- }
- }
- LLFloater* LLFloaterView::getParentFloater(LLView* viewp)
- {
- LLView* parentp = viewp->getParent();
- while (parentp && parentp != this)
- {
- viewp = parentp;
- parentp = parentp->getParent();
- }
- if (parentp == this)
- {
- return viewp->asFloater();
- }
- return NULL;
- }
- S32 LLFloaterView::getZOrder(LLFloater* child)
- {
- S32 rv = 0;
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- if (*it == child)
- {
- break;
- }
- ++rv;
- }
- return rv;
- }
- void LLFloaterView::pushVisibleAll(bool visible, const skip_list_t& skip_list)
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* view = *it;
- if (skip_list.find(view) == skip_list.end())
- {
- view->pushVisible(visible);
- }
- }
- }
- void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* view = *it;
- if (skip_list.find(view) == skip_list.end())
- {
- view->popVisible();
- }
- }
- }
- void LLFloaterView::fitAllToScreen()
- {
- for (child_list_const_iter_t it = getChildList()->begin(),
- end = getChildList()->end();
- it != end; ++it)
- {
- LLView* viewp = *it;
- if (!viewp) continue;
- LLFloater* floaterp = viewp->asFloater();
- if (floaterp && floaterp->getVisible() && !floaterp->isDead())
- {
- adjustToFitScreen(floaterp);
- }
- }
- }
- //
- // LLMultiFloater
- //
- LLMultiFloater::LLMultiFloater()
- : mTabContainer(NULL),
- mTabPos(LLTabContainer::TOP),
- mAutoResize(true),
- mOrigMinWidth(0),
- mOrigMinHeight(0)
- {
- }
- LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos)
- : mTabContainer(NULL),
- mTabPos(tab_pos),
- mAutoResize(true),
- mOrigMinWidth(0),
- mOrigMinHeight(0)
- {
- }
- LLMultiFloater::LLMultiFloater(const std::string& name)
- : LLFloater(name),
- mTabContainer(NULL),
- mTabPos(LLTabContainer::TOP),
- mAutoResize(false),
- mOrigMinWidth(0),
- mOrigMinHeight(0)
- {
- }
- LLMultiFloater::LLMultiFloater(const std::string& name,
- const LLRect& rect,
- LLTabContainer::TabPosition tab_pos,
- bool auto_resize)
- : LLFloater(name, rect, name),
- mTabContainer(NULL),
- mTabPos(LLTabContainer::TOP),
- mAutoResize(auto_resize),
- mOrigMinWidth(0),
- mOrigMinHeight(0)
- {
- mTabContainer =
- new LLTabContainer("Preview Tabs",
- LLRect(LLPANEL_BORDER_WIDTH,
- getRect().getHeight() -
- LLFLOATER_HEADER_SIZE,
- getRect().getWidth() - LLPANEL_BORDER_WIDTH,
- 0),
- mTabPos, false, false);
- mTabContainer->setFollowsAll();
- if (isResizable())
- {
- mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
- }
- addChild(mTabContainer);
- }
- LLMultiFloater::LLMultiFloater(const std::string& name,
- const std::string& rect_control,
- LLTabContainer::TabPosition tab_pos,
- bool auto_resize)
- : LLFloater(name, rect_control, name),
- mTabContainer(NULL),
- mTabPos(tab_pos),
- mAutoResize(auto_resize),
- mOrigMinWidth(0),
- mOrigMinHeight(0)
- {
- mTabContainer =
- new LLTabContainer("Preview Tabs",
- LLRect(LLPANEL_BORDER_WIDTH,
- getRect().getHeight() -
- LLFLOATER_HEADER_SIZE,
- getRect().getWidth() - LLPANEL_BORDER_WIDTH,
- 0),
- mTabPos, false, false);
- mTabContainer->setFollowsAll();
- if (isResizable() && mTabPos == LLTabContainer::BOTTOM)
- {
- mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
- }
- addChild(mTabContainer);
- }
- //virtual
- const std::string& LLMultiFloater::getTag() const
- {
- return LL_MULTI_FLOATER_TAG;
- }
- //virtual
- LLXMLNodePtr LLMultiFloater::getXML(bool save_children) const
- {
- LLXMLNodePtr node = LLFloater::getXML();
- node->setName(LL_MULTI_FLOATER_TAG);
- return node;
- }
- //virtual
- void LLMultiFloater::open()
- {
- if (mTabContainer->getTabCount() > 0)
- {
- LLFloater::open();
- }
- else
- {
- // For now, do not allow multifloaters without any child floaters
- close();
- }
- }
- //virtual
- void LLMultiFloater::onClose(bool app_quitting)
- {
- if (closeAllFloaters())
- {
- LLFloater::onClose(app_quitting);
- }
- }
- //virtual
- void LLMultiFloater::draw()
- {
- if (mTabContainer->getTabCount() == 0)
- {
- // RN: could this potentially crash in draw hierarchy ?
- close();
- return;
- }
- for (S32 i = 0; i < mTabContainer->getTabCount(); ++i)
- {
- LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
- if (floaterp->getTitle() != mTabContainer->getPanelTitle(i))
- {
- mTabContainer->setPanelTitle(i, floaterp->getTitle());
- }
- }
- LLFloater::draw();
- }
- bool LLMultiFloater::closeAllFloaters()
- {
- S32 tab_to_close = 0;
- S32 lastTabCount = mTabContainer->getTabCount();
- while (tab_to_close < mTabContainer->getTabCount())
- {
- LLFloater* first_floater =
- (LLFloater*)mTabContainer->getPanelByIndex(tab_to_close);
- first_floater->close();
- if (lastTabCount == mTabContainer->getTabCount())
- {
- // Tab did not actually close, possibly due to a pending save
- // confirmation dialog, so try and close the next one in the list
- ++tab_to_close;
- }
- else
- {
- // Tab closed ok.
- lastTabCount = mTabContainer->getTabCount();
- }
- }
- if (mTabContainer->getTabCount() != 0)
- {
- // Could not close all the tabs (pending save dialog ?)
- return false;
- }
- return true; // else all tabs were successfully closed...
- }
- void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
- {
- S32 new_width = llmax(getRect().getWidth(),
- content_width + LLPANEL_BORDER_WIDTH * 2);
- S32 new_height = llmax(getRect().getHeight(),
- content_height + LLFLOATER_HEADER_SIZE +
- TABCNTR_HEADER_HEIGHT);
- if (isMinimized())
- {
- LLRect newrect;
- newrect.setLeftTopAndSize(getExpandedRect().mLeft,
- getExpandedRect().mTop,
- new_width, new_height);
- setExpandedRect(newrect);
- }
- else
- {
- S32 old_height = getRect().getHeight();
- reshape(new_width, new_height);
- // Keep top left corner in same position
- translate(0, old_height - new_height);
- }
- }
- // Adds the LLFloater pointed to by floaterp to this. If floaterp is already
- // hosted by this, then it is re-added to get new titles, etc.
- // If select_added_floater is true, the LLFloater pointed to by floaterp will
- // become the selected tab in this
- void LLMultiFloater::addFloater(LLFloater* floaterp, bool select_added_floater,
- LLTabContainer::eInsertionPoint insertion_pt)
- {
- if (!floaterp)
- {
- return;
- }
- if (!mTabContainer)
- {
- llerrs << "Tab Container used without having been initialized."
- << llendl;
- return;
- }
- if (floaterp->getHost() == this)
- {
- // Already hosted by me, remove do this so we get updated title, etc.
- mFloaterDataMap.erase(floaterp->getHandle());
- mTabContainer->removeTabPanel(floaterp);
- }
- else if (floaterp->getHost())
- {
- // floaterp is hosted by somebody else and this is adding it, so remove
- // it from its old host
- floaterp->getHost()->removeFloater(floaterp);
- }
- else if (gFloaterViewp && floaterp->getParent() == gFloaterViewp)
- {
- // Re-host preview floater as child panel
- gFloaterViewp->removeChild(floaterp);
- }
- // Store original configuration
- LLFloaterData floater_data;
- floater_data.mWidth = floaterp->getRect().getWidth();
- floater_data.mHeight = floaterp->getRect().getHeight();
- floater_data.mCanMinimize = floaterp->isMinimizeable();
- floater_data.mCanResize = floaterp->isResizable();
- // Remove minimize and close buttons
- floaterp->setCanMinimize(false);
- floaterp->setCanResize(false);
- floaterp->setCanDrag(false);
- floaterp->storeRectControl();
- // Avoid double rendering of floater background (makes it more opaque)
- floaterp->setBackgroundVisible(false);
- if (mAutoResize)
- {
- growToFit(floater_data.mWidth, floater_data.mHeight);
- }
- // Add the panel, add it to proper maps
- mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), false,
- onTabSelected, this, 0, false, insertion_pt);
- mFloaterDataMap[floaterp->getHandle()] = floater_data;
- updateResizeLimits();
- if (select_added_floater)
- {
- mTabContainer->selectTabPanel(floaterp);
- }
- else
- {
- // Reassert visible tab (hiding new floater if necessary)
- mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
- }
- floaterp->setHost(this);
- if (isMinimized())
- {
- floaterp->setVisible(false);
- }
- }
- // If the LLFloater pointed to by floaterp is hosted by this, then its tab is
- // selected and returns true. Otherwise returns false.
- bool LLMultiFloater::selectFloater(LLFloater* floaterp)
- {
- return mTabContainer->selectTabPanel(floaterp);
- }
- //virtual
- void LLMultiFloater::selectNextFloater()
- {
- mTabContainer->selectNextTab();
- }
- //virtual
- void LLMultiFloater::selectPrevFloater()
- {
- mTabContainer->selectPrevTab();
- }
- void LLMultiFloater::showFloater(LLFloater* floaterp)
- {
- // We won't select a panel that already is selected it is hard to do this
- // internally to tab container as tab selection is handled via index and
- // the tab at a given index might have changed
- if (floaterp != mTabContainer->getCurrentPanel() &&
- !mTabContainer->selectTabPanel(floaterp))
- {
- addFloater(floaterp, true);
- }
- }
- void LLMultiFloater::removeFloater(LLFloater* floaterp)
- {
- if (floaterp->getHost() != this)
- return;
- floater_data_map_t::iterator found_data_it =
- mFloaterDataMap.find(floaterp->getHandle());
- if (found_data_it != mFloaterDataMap.end())
- {
- LLFloaterData& floater_data = found_data_it->second;
- floaterp->setCanMinimize(floater_data.mCanMinimize);
- if (!floater_data.mCanResize)
- {
- // Restore original size
- floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
- }
- floaterp->setCanResize(floater_data.mCanResize);
- mFloaterDataMap.erase(found_data_it);
- }
- mTabContainer->removeTabPanel(floaterp);
- floaterp->setBackgroundVisible(true);
- floaterp->setCanDrag(true);
- floaterp->setHost(NULL);
- floaterp->applyRectControl();
- updateResizeLimits();
- tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
- }
- void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
- {
- // Default implementation does nothing
- }
- void LLMultiFloater::tabClose()
- {
- if (mTabContainer && mTabContainer->getTabCount() == 0)
- {
- // No more children, close myself
- close();
- }
- }
- void LLMultiFloater::setVisible(bool visible)
- {
- // *FIX: should not have to do this, fix adding to minimized multifloater
- LLFloater::setVisible(visible);
- if (mTabContainer)
- {
- LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
- if (cur_floaterp)
- {
- cur_floaterp->setVisible(visible);
- }
- // if no tab selected, and we're being shown,
- // select last tab to be added
- if (visible && !cur_floaterp)
- {
- mTabContainer->selectLastTab();
- }
- }
- }
- bool LLMultiFloater::handleKeyHere(KEY key, MASK mask)
- {
- if (key == 'W' && mask == MASK_CONTROL)
- {
- LLFloater* floaterp = getActiveFloater();
- // Is it user closeable and is system closeable ?
- if (floaterp && floaterp->canClose() && floaterp->isCloseable())
- {
- floaterp->close();
- }
- return true;
- }
- return LLFloater::handleKeyHere(key, mask);
- }
- LLFloater* LLMultiFloater::getActiveFloater()
- {
- LLView* viewp = mTabContainer->getCurrentPanel();
- if (viewp)
- {
- return viewp->asFloater();
- }
- return NULL;
- }
- S32 LLMultiFloater::getFloaterCount()
- {
- return mTabContainer->getTabCount();
- }
- // Returns true if the LLFloater pointed to by floaterp is currently in a
- // flashing state and is hosted by this.
- bool LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
- {
- if (floaterp && floaterp->getHost() == this)
- {
- return mTabContainer->getTabPanelFlashing(floaterp);
- }
- return false;
- }
- // Sets the current flashing state of the LLFloater pointed to by floaterp to
- // be the bool flashing if the LLFloater pointed to by floaterp is hosted by
- // this.
- void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, bool flashing)
- {
- if (floaterp && floaterp->getHost() == this)
- {
- mTabContainer->setTabPanelFlashing(floaterp, flashing);
- }
- }
- //static
- void LLMultiFloater::onTabSelected(void* userdata, bool from_click)
- {
- LLMultiFloater* floaterp = (LLMultiFloater*)userdata;
- floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(),
- from_click);
- }
- void LLMultiFloater::setCanResize(bool can_resize)
- {
- LLFloater::setCanResize(can_resize);
- if (isResizable() &&
- mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
- {
- mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
- }
- else
- {
- mTabContainer->setRightTabBtnOffset(0);
- }
- }
- bool LLMultiFloater::postBuild()
- {
- // Remember any original xml minimum size
- getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
- if (mTabContainer)
- {
- return true;
- }
- mTabContainer = getChild<LLTabContainer>("Preview Tabs");
- return true;
- }
- void LLMultiFloater::updateResizeLimits()
- {
- // Initialize minimum size constraint to the original xml values.
- S32 new_min_width = mOrigMinWidth;
- S32 new_min_height = mOrigMinHeight;
- // Possibly increase minimum size constraint due to children's minimums.
- for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
- {
- LLFloater* floaterp =
- (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
- if (floaterp)
- {
- new_min_width = llmax(new_min_width,
- floaterp->getMinWidth() +
- LLPANEL_BORDER_WIDTH * 2);
- new_min_height = llmax(new_min_height,
- floaterp->getMinHeight() +
- LLFLOATER_HEADER_SIZE +
- TABCNTR_HEADER_HEIGHT);
- }
- }
- setResizeLimits(new_min_width, new_min_height);
- S32 cur_height = getRect().getHeight();
- S32 new_width = llmax(getRect().getWidth(), new_min_width);
- S32 new_height = llmax(getRect().getHeight(), new_min_height);
- if (isMinimized())
- {
- const LLRect& expanded = getExpandedRect();
- LLRect newrect;
- newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop,
- llmax(expanded.getWidth(), new_width),
- llmax(expanded.getHeight(), new_height));
- setExpandedRect(newrect);
- }
- else
- {
- reshape(new_width, new_height);
- // Make sure upper left corner doesn't move
- translate(0, cur_height - getRect().getHeight());
- // Make sure this window is visible on screen when it has been modified
- // (tab added, etc)
- if (gFloaterViewp) // Paranoia
- {
- gFloaterViewp->adjustToFitScreen(this, true);
- }
- }
- }
- //virtual
- const std::string& LLFloater::getTag() const
- {
- return LL_FLOATER_TAG;
- }
- //virtual
- LLXMLNodePtr LLFloater::getXML(bool save_children) const
- {
- LLXMLNodePtr node = LLPanel::getXML();
- node->setName(LL_FLOATER_TAG);
- node->createChild("title", true)->setStringValue(getCurrentTitle());
- node->createChild("can_resize", true)->setBoolValue(isResizable());
- node->createChild("can_minimize", true)->setBoolValue(isMinimizeable());
- node->createChild("can_close", true)->setBoolValue(isCloseable());
- node->createChild("can_drag_on_left", true)->setBoolValue(isDragOnLeft());
- node->createChild("min_width", true)->setIntValue(getMinWidth());
- node->createChild("min_height", true)->setIntValue(getMinHeight());
- node->createChild("can_tear_off", true)->setBoolValue(mCanTearOff);
- return node;
- }
- //static
- LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView* parent,
- LLUICtrlFactory* factory)
- {
- std::string name = LL_FLOATER_TAG;
- node->getAttributeString("name", name);
- LLFloater* floaterp = new LLFloater(name);
- std::string filename;
- node->getAttributeString("filename", filename);
- if (filename.empty())
- {
- // Load from node
- floaterp->initFloaterXML(node, parent, factory);
- }
- else
- {
- // Load from file
- factory->buildFloater(floaterp, filename);
- }
- return floaterp;
- }
- void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView* parent,
- LLUICtrlFactory* factory, bool open_it)
- {
- std::string name = getName();
- node->getAttributeString("name", name);
- std::string title = getCurrentTitle();
- node->getAttributeString("title", title);
- std::string rect_control;
- node->getAttributeString("rect_control", rect_control);
- bool resizable = isResizable();
- node->getAttributeBool("can_resize", resizable);
- bool minimizable = isMinimizeable();
- node->getAttributeBool("can_minimize", minimizable);
- bool close_btn = isCloseable();
- node->getAttributeBool("can_close", close_btn);
- bool drag_on_left = isDragOnLeft();
- node->getAttributeBool("can_drag_on_left", drag_on_left);
- S32 min_width = getMinWidth();
- node->getAttributeS32("min_width", min_width);
- S32 min_height = getMinHeight();
- node->getAttributeS32("min_height", min_height);
- if (!rect_control.empty())
- {
- setRectControl(rect_control);
- }
- LLRect rect;
- createRect(node, rect, parent, LLRect());
- setRect(rect);
- setName(name);
- initFloater(title, resizable, min_width, min_height, drag_on_left,
- minimizable, close_btn);
- mTitle = title;
- applyTitle();
- bool can_tear_off;
- if (node->getAttributeBool("can_tear_off", can_tear_off))
- {
- setCanTearOff(can_tear_off);
- }
- initFromXML(node, parent);
- LLMultiFloater* last_host = sHostp;
- bool is_multi_floater = node->hasName("multi_floater");
- if (is_multi_floater)
- {
- sHostp = (LLMultiFloater*)this;
- }
- initChildrenXML(node, factory);
- if (is_multi_floater)
- {
- sHostp = last_host;
- }
- if (!postBuild())
- {
- llerrs << "Failed to construct floater " << name << llendl;
- }
- applyRectControl();
- if (open_it)
- {
- open();
- }
- moveResizeHandlesToFront();
- }
|