llfloater.cpp 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237
  1. /**
  2. * @file llfloater.cpp
  3. * @brief LLFloater base class
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. // Floating "windows" within the GL display, like the inventory floater,
  33. // mini-map floater, etc.
  34. #include "linden_common.h"
  35. #include "llfloater.h"
  36. #include "llbutton.h"
  37. #include "llcheckboxctrl.h"
  38. #include "llcontrol.h"
  39. #include "lldraghandle.h"
  40. #include "llresizebar.h"
  41. #include "llresizehandle.h"
  42. #include "llkeyboard.h"
  43. #include "lltextbox.h"
  44. #include "llwindow.h"
  45. #include "lltabcontainer.h"
  46. #include "lltrans.h"
  47. #include "lluictrlfactory.h"
  48. S32 gMenuBarHeight = 18;
  49. static const std::string LL_FLOATER_TAG = "floater";
  50. static const std::string LL_MULTI_FLOATER_TAG = "multi_floater";
  51. constexpr S32 MINIMIZED_WIDTH = 160;
  52. constexpr S32 CLOSE_BOX_FROM_TOP = 1;
  53. // Use this to control "jumping" behavior when Ctrl-Tabbing
  54. constexpr S32 TABBED_FLOATER_OFFSET = 0;
  55. U32 LLFloater::sLastFloaterId = 0;
  56. bool LLFloaterView::sStackMinimizedTopToBottom = false;
  57. bool LLFloaterView::sStackMinimizedRightToLeft = false;
  58. U32 LLFloaterView::sStackScreenWidthFraction = 1;
  59. std::string LLFloater::sButtonActiveImageNames[BUTTON_COUNT] =
  60. {
  61. "UIImgBtnCloseActiveUUID", // BUTTON_CLOSE
  62. "UIImgBtnRestoreActiveUUID", // BUTTON_RESTORE
  63. "UIImgBtnMinimizeActiveUUID", // BUTTON_MINIMIZE
  64. "UIImgBtnTearOffActiveUUID", // BUTTON_TEAR_OFF
  65. };
  66. std::string LLFloater::sButtonInactiveImageNames[BUTTON_COUNT] =
  67. {
  68. "UIImgBtnCloseInactiveUUID", // BUTTON_CLOSE
  69. "UIImgBtnRestoreInactiveUUID", // BUTTON_RESTORE
  70. "UIImgBtnMinimizeInactiveUUID", // BUTTON_MINIMIZE
  71. "UIImgBtnTearOffInactiveUUID", // BUTTON_TEAR_OFF
  72. };
  73. std::string LLFloater::sButtonPressedImageNames[BUTTON_COUNT] =
  74. {
  75. "UIImgBtnClosePressedUUID", // BUTTON_CLOSE
  76. "UIImgBtnRestorePressedUUID", // BUTTON_RESTORE
  77. "UIImgBtnMinimizePressedUUID", // BUTTON_MINIMIZE
  78. "UIImgBtnTearOffPressedUUID", // BUTTON_TEAR_OFF
  79. };
  80. std::string LLFloater::sButtonNames[BUTTON_COUNT] =
  81. {
  82. "llfloater_close_btn", // BUTTON_CLOSE
  83. "llfloater_restore_btn", // BUTTON_RESTORE
  84. "llfloater_minimize_btn", // BUTTON_MINIMIZE
  85. "llfloater_tear_off_btn", // BUTTON_TEAR_OFF
  86. };
  87. std::string LLFloater::sButtonToolTipNames[BUTTON_COUNT] =
  88. {
  89. #ifdef LL_DARWIN
  90. "button-mac-close", // BUTTON_CLOSE
  91. #else
  92. "button-close", // BUTTON_CLOSE
  93. #endif
  94. "button-restore", // BUTTON_RESTORE
  95. "button-minimize", // BUTTON_MINIMIZE
  96. "button-tear-off", // BUTTON_TEAR_OFF
  97. };
  98. LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] =
  99. {
  100. LLFloater::onClickClose, // BUTTON_CLOSE
  101. LLFloater::onClickMinimize, // BUTTON_RESTORE
  102. LLFloater::onClickMinimize, // BUTTON_MINIMIZE
  103. LLFloater::onClickTearOff, // BUTTON_TEAR_OFF
  104. };
  105. LLMultiFloater* LLFloater::sHostp = NULL;
  106. static bool sResizing = false;
  107. static S32 sLastSizeX = 0;
  108. static S32 sLastSizeY = 0;
  109. //static
  110. bool LLFloater::resizing(S32& size_x, S32& size_y)
  111. {
  112. bool resizing = sResizing;
  113. if (resizing)
  114. {
  115. size_x = sLastSizeX;
  116. size_y = sLastSizeY;
  117. sResizing = false;
  118. }
  119. return resizing;
  120. }
  121. // Instance created in LLViewerWindow::initBase() and destroyed in
  122. // LLViewerWindow::shutdownViews()
  123. LLFloaterView* gFloaterViewp = NULL;
  124. LLFloater::LLFloater()
  125. : LLPanel(),
  126. mId(++sLastFloaterId),
  127. mTitleIsPristine(true),
  128. mAutoFocus(true),
  129. mResizable(false),
  130. mDragOnLeft(false),
  131. mMinWidth(0),
  132. mMinHeight(0),
  133. mDragHandle(NULL)
  134. {
  135. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  136. {
  137. mButtonsEnabled[i] = false;
  138. mButtons[i] = NULL;
  139. }
  140. for (S32 i = 0; i < 4; ++i)
  141. {
  142. mResizeBar[i] = NULL;
  143. mResizeHandle[i] = NULL;
  144. }
  145. mNotificationContext = new LLFloaterNotificationContext(getHandle());
  146. }
  147. LLFloater::LLFloater(const std::string& name)
  148. : LLPanel(name),
  149. mId(++sLastFloaterId),
  150. mTitleIsPristine(true),
  151. mAutoFocus(true) // Automatically take focus when opened
  152. {
  153. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  154. {
  155. mButtonsEnabled[i] = false;
  156. mButtons[i] = NULL;
  157. }
  158. for (S32 i = 0; i < 4; ++i)
  159. {
  160. mResizeBar[i] = NULL;
  161. mResizeHandle[i] = NULL;
  162. }
  163. initFloater(LLStringUtil::null, false,
  164. DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT,
  165. false, true, true); // defaults
  166. }
  167. LLFloater::LLFloater(const std::string& name, const LLRect& rect,
  168. const std::string& title, bool resizable,
  169. S32 min_width, S32 min_height, bool drag_on_left,
  170. bool minimizable, bool close_btn, bool bordered)
  171. : LLPanel(name, rect, bordered),
  172. mId(++sLastFloaterId),
  173. mTitleIsPristine(true),
  174. mAutoFocus(true) // Automatically take focus when opened
  175. {
  176. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  177. {
  178. mButtonsEnabled[i] = false;
  179. mButtons[i] = NULL;
  180. }
  181. for (S32 i = 0; i < 4; ++i)
  182. {
  183. mResizeBar[i] = NULL;
  184. mResizeHandle[i] = NULL;
  185. }
  186. initFloater(title, resizable, min_width, min_height, drag_on_left,
  187. minimizable, close_btn);
  188. }
  189. LLFloater::LLFloater(const std::string& name, const std::string& rect_control,
  190. const std::string& title, bool resizable,
  191. S32 min_width, S32 min_height, bool drag_on_left,
  192. bool minimizable, bool close_btn, bool bordered)
  193. : LLPanel(name, rect_control, bordered),
  194. mId(++sLastFloaterId),
  195. mTitleIsPristine(true),
  196. mAutoFocus(true) // Automatically take focus when opened
  197. {
  198. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  199. {
  200. mButtonsEnabled[i] = false;
  201. mButtons[i] = NULL;
  202. }
  203. for (S32 i = 0; i < 4; ++i)
  204. {
  205. mResizeBar[i] = NULL;
  206. mResizeHandle[i] = NULL;
  207. }
  208. initFloater(title, resizable, min_width, min_height, drag_on_left,
  209. minimizable, close_btn);
  210. }
  211. // NOTE: floaters constructed from XML call init() twice !
  212. void LLFloater::initFloater(const std::string& title, bool resizable,
  213. S32 min_width, S32 min_height,
  214. bool drag_on_left, bool minimizable,
  215. bool close_btn)
  216. {
  217. mNotificationContext = new LLFloaterNotificationContext(getHandle());
  218. // Init function can be called more than once, so clear out old data.
  219. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  220. {
  221. mButtonsEnabled[i] = false;
  222. if (mButtons[i])
  223. {
  224. removeChild(mButtons[i]);
  225. delete mButtons[i];
  226. mButtons[i] = NULL;
  227. }
  228. }
  229. mButtonScale = 1.f;
  230. // SJB: this is a bit of a hack:
  231. bool need_border = hasBorder();
  232. // Remove the border since deleteAllChildren() will also delete the border
  233. // (but not clear mBorder)
  234. removeBorder();
  235. // this will delete mBorder too
  236. deleteAllChildren();
  237. // add the border back if we want it
  238. if (need_border)
  239. {
  240. addBorder();
  241. }
  242. // Chrome floaters do not take focus at all
  243. setFocusRoot(!getIsChrome());
  244. // Reset cached pointers
  245. mDragHandle = NULL;
  246. for (S32 i = 0; i < 4; ++i)
  247. {
  248. mResizeBar[i] = NULL;
  249. mResizeHandle[i] = NULL;
  250. }
  251. mCanTearOff = true;
  252. // Clicks stop here.
  253. setMouseOpaque(true);
  254. mForeground = false;
  255. mDragOnLeft = drag_on_left == true;
  256. // Floaters always draw their background, unlike every other panel.
  257. setBackgroundVisible(true);
  258. // Floaters start not minimized. When minimized, they save their former
  259. // rectangle to be used on restore.
  260. mMinimized = false;
  261. mExpandedRect.set(0, 0, 0, 0);
  262. S32 close_box_size; // For layout purposes, how big is the close box ?
  263. if (close_btn)
  264. {
  265. close_box_size = LLFLOATER_CLOSE_BOX_SIZE;
  266. }
  267. else
  268. {
  269. close_box_size = 0;
  270. }
  271. // Drag handle; we add it first so that it is in the background.
  272. if (drag_on_left)
  273. {
  274. LLRect drag_handle_rect;
  275. drag_handle_rect.setOriginAndSize(0, 0, DRAG_HANDLE_WIDTH,
  276. getRect().getHeight() -
  277. LLPANEL_BORDER_WIDTH -
  278. close_box_size);
  279. mDragHandle = new LLDragHandleLeft("drag", drag_handle_rect, title);
  280. }
  281. else // Drag on top
  282. {
  283. LLRect drag_handle_rect(0, getRect().getHeight(),
  284. getRect().getWidth(), 0);
  285. mDragHandle = new LLDragHandleTop("Drag Handle", drag_handle_rect,
  286. title);
  287. }
  288. addChild(mDragHandle);
  289. // Resize Handle
  290. mResizable = resizable;
  291. mMinWidth = min_width;
  292. mMinHeight = min_height;
  293. if (mResizable)
  294. {
  295. // Resize bars (sides)
  296. constexpr S32 RESIZE_BAR_THICKNESS = 3;
  297. mResizeBar[LLResizeBar::LEFT] =
  298. new LLResizeBar("resizebar_left", this,
  299. LLRect(0, getRect().getHeight(),
  300. RESIZE_BAR_THICKNESS, 0),
  301. min_width, S32_MAX, LLResizeBar::LEFT);
  302. addChild(mResizeBar[0]);
  303. mResizeBar[LLResizeBar::TOP] =
  304. new LLResizeBar("resizebar_top", this,
  305. LLRect(0, getRect().getHeight(),
  306. getRect().getWidth(),
  307. getRect().getHeight() -
  308. RESIZE_BAR_THICKNESS),
  309. min_height, S32_MAX, LLResizeBar::TOP);
  310. addChild(mResizeBar[1]);
  311. mResizeBar[LLResizeBar::RIGHT] =
  312. new LLResizeBar("resizebar_right", this,
  313. LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS,
  314. getRect().getHeight(), getRect().getWidth(),
  315. 0),
  316. min_width, S32_MAX, LLResizeBar::RIGHT);
  317. addChild(mResizeBar[2]);
  318. mResizeBar[LLResizeBar::BOTTOM] =
  319. new LLResizeBar("resizebar_bottom", this,
  320. LLRect(0, RESIZE_BAR_THICKNESS,
  321. getRect().getWidth(), 0),
  322. min_height, S32_MAX, LLResizeBar::BOTTOM);
  323. addChild(mResizeBar[3]);
  324. // Resize handles (corners)
  325. mResizeHandle[0] =
  326. new LLResizeHandle("Resize Handle",
  327. LLRect(getRect().getWidth() -
  328. RESIZE_HANDLE_WIDTH,
  329. RESIZE_HANDLE_HEIGHT,
  330. getRect().getWidth(), 0),
  331. min_width, min_height,
  332. LLResizeHandle::RIGHT_BOTTOM);
  333. addChild(mResizeHandle[0]);
  334. mResizeHandle[1] =
  335. new LLResizeHandle("resize",
  336. LLRect(getRect().getWidth() -
  337. RESIZE_HANDLE_WIDTH,
  338. getRect().getHeight(),
  339. getRect().getWidth(),
  340. getRect().getHeight() -
  341. RESIZE_HANDLE_HEIGHT),
  342. min_width, min_height,
  343. LLResizeHandle::RIGHT_TOP, !close_btn);
  344. addChild(mResizeHandle[1]);
  345. mResizeHandle[2] =
  346. new LLResizeHandle("resize",
  347. LLRect(0, RESIZE_HANDLE_HEIGHT,
  348. RESIZE_HANDLE_WIDTH, 0),
  349. min_width, min_height,
  350. LLResizeHandle::LEFT_BOTTOM);
  351. addChild(mResizeHandle[2]);
  352. mResizeHandle[3] =
  353. new LLResizeHandle("resize",
  354. LLRect(0, getRect().getHeight(),
  355. RESIZE_HANDLE_WIDTH,
  356. getRect().getHeight() -
  357. RESIZE_HANDLE_HEIGHT),
  358. min_width, min_height,
  359. LLResizeHandle::LEFT_TOP);
  360. addChild(mResizeHandle[3]);
  361. }
  362. // Close button.
  363. if (close_btn)
  364. {
  365. mButtonsEnabled[BUTTON_CLOSE] = true;
  366. }
  367. // Minimize button only for top draggers
  368. if (!drag_on_left && minimizable)
  369. {
  370. mButtonsEnabled[BUTTON_MINIMIZE] = true;
  371. }
  372. // Keep track of whether this window has ever been dragged while it was
  373. // minimized. If it has, we will remember its position for the next time
  374. // it is minimized.
  375. mHasBeenDraggedWhileMinimized = false;
  376. mPreviousMinimizedLeft = 0;
  377. mPreviousMinimizedBottom = 0;
  378. buildButtons();
  379. #if 0 // JC: Do not do this here, because many floaters first construct
  380. // themselves, then show themselves. Put it in setVisibleAndFrontmost.
  381. make_ui_sound("UISndWindowOpen");
  382. #endif
  383. // RN: floaters are created in the invisible state
  384. setVisible(false);
  385. if (gFloaterViewp && !getParent())
  386. {
  387. gFloaterViewp->addChild(this);
  388. }
  389. }
  390. //virtual
  391. LLFloater::~LLFloater()
  392. {
  393. delete mNotificationContext;
  394. mNotificationContext = NULL;
  395. #if 0
  396. // Am I not hosted by another floater ?
  397. if (mHostHandle.isDead())
  398. {
  399. LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
  400. if (parent)
  401. {
  402. parent->removeChild(this);
  403. }
  404. }
  405. #endif
  406. // Just in case we might still have focus here, release it.
  407. releaseFocus();
  408. // This is important so that floaters with persistent rects (i.e., those
  409. // created with rect control rather than an LLRect) are restored in their
  410. // correct, non-minimized positions.
  411. setMinimized(false);
  412. delete mDragHandle;
  413. for (S32 i = 0; i < 4; ++i)
  414. {
  415. delete mResizeBar[i];
  416. delete mResizeHandle[i];
  417. }
  418. }
  419. void LLFloater::setVisible(bool visible)
  420. {
  421. LLPanel::setVisible(visible);
  422. if (!visible)
  423. {
  424. if (gFocusMgr.childIsTopCtrl(this))
  425. {
  426. gFocusMgr.setTopCtrl(NULL);
  427. }
  428. if (gFocusMgr.childHasMouseCapture(this))
  429. {
  430. gFocusMgr.setMouseCapture(NULL);
  431. }
  432. }
  433. for (handle_set_iter_t it = mDependents.begin(), end = mDependents.end();
  434. it != end; ++it)
  435. {
  436. LLFloater* floaterp = it->get();
  437. if (floaterp)
  438. {
  439. floaterp->setVisible(visible);
  440. }
  441. }
  442. }
  443. void LLFloater::open()
  444. {
  445. if (getSoundFlags() != SILENT && (!getVisible() || isMinimized()) &&
  446. // Do not play open sound for hosted (tabbed) windows
  447. !getHost() && !sHostp)
  448. {
  449. make_ui_sound("UISndWindowOpen");
  450. }
  451. // NOTE: do not allow rehosting from one multifloater to another
  452. if (getHost())
  453. {
  454. // Already hosted
  455. getHost()->showFloater(this);
  456. }
  457. else if (sHostp)
  458. {
  459. // Needs a host; only select tabs if window they are hosted in is
  460. // visible
  461. sHostp->addFloater(this, sHostp->getVisible());
  462. }
  463. else
  464. {
  465. setMinimized(false);
  466. setVisibleAndFrontmost(mAutoFocus);
  467. }
  468. onOpen();
  469. }
  470. void LLFloater::close(bool app_quitting)
  471. {
  472. // Always unminimize before trying to close. Most of the time the user will
  473. // never see this state.
  474. setMinimized(false);
  475. if (canClose())
  476. {
  477. if (getHost())
  478. {
  479. getHost()->removeFloater(this);
  480. if (gFloaterViewp) // Paranoia
  481. {
  482. gFloaterViewp->addChild(this);
  483. }
  484. }
  485. if (!app_quitting && getVisible() && !getHost() &&
  486. getSoundFlags() != SILENT)
  487. {
  488. make_ui_sound("UISndWindowClose");
  489. }
  490. // Now close dependent floater
  491. while (!mDependents.empty())
  492. {
  493. handle_set_iter_t it = mDependents.begin();
  494. LLFloater* floaterp = it->get();
  495. mDependents.erase(it);
  496. if (floaterp)
  497. {
  498. floaterp->mDependeeHandle = LLHandle<LLFloater>();
  499. floaterp->close();
  500. }
  501. }
  502. cleanupHandles();
  503. gFocusMgr.clearLastFocusForGroup(this);
  504. if (hasFocus())
  505. {
  506. // Do this early, so UI controls will commit before the window is
  507. // taken down.
  508. releaseFocus();
  509. // Give focus to dependee floater if it exists, and we had focus
  510. // first
  511. if (isDependent())
  512. {
  513. LLFloater* dependee = mDependeeHandle.get();
  514. if (dependee && !dependee->isDead())
  515. {
  516. dependee->setFocus(true);
  517. }
  518. }
  519. }
  520. // Let floater do cleanup.
  521. onClose(app_quitting);
  522. }
  523. }
  524. //virtual
  525. void LLFloater::reshape(S32 width, S32 height, bool called_from_parent)
  526. {
  527. LLPanel::reshape(width, height, called_from_parent);
  528. }
  529. void LLFloater::releaseFocus()
  530. {
  531. if (gFocusMgr.childIsTopCtrl(this))
  532. {
  533. gFocusMgr.setTopCtrl(NULL);
  534. }
  535. if (gFocusMgr.childHasKeyboardFocus(this))
  536. {
  537. gFocusMgr.setKeyboardFocus(NULL);
  538. }
  539. if (gFocusMgr.childHasMouseCapture(this))
  540. {
  541. gFocusMgr.setMouseCapture(NULL);
  542. }
  543. }
  544. void LLFloater::setResizeLimits(S32 min_width, S32 min_height)
  545. {
  546. mMinWidth = min_width;
  547. mMinHeight = min_height;
  548. for (S32 i = 0; i < 4; ++i)
  549. {
  550. if (mResizeBar[i])
  551. {
  552. if (i == LLResizeBar::LEFT || i == LLResizeBar::RIGHT)
  553. {
  554. mResizeBar[i]->setResizeLimits(min_width, S32_MAX);
  555. }
  556. else
  557. {
  558. mResizeBar[i]->setResizeLimits(min_height, S32_MAX);
  559. }
  560. }
  561. if (mResizeHandle[i])
  562. {
  563. mResizeHandle[i]->setResizeLimits(min_width, min_height);
  564. }
  565. }
  566. }
  567. bool LLFloater::resizedFromHandles() const
  568. {
  569. for (S32 i = 0; i < 4; ++i)
  570. {
  571. if (mResizeBar[i] && mResizeBar[i]->resizing())
  572. {
  573. return true;
  574. }
  575. if (mResizeHandle[i] && mResizeHandle[i]->resizing())
  576. {
  577. return true;
  578. }
  579. }
  580. return false;
  581. }
  582. void LLFloater::center()
  583. {
  584. if (gFloaterViewp && !getHost()) // Hosted floaters cannot move
  585. {
  586. centerWithin(gFloaterViewp->getRect());
  587. }
  588. }
  589. void LLFloater::applyRectControl()
  590. {
  591. if (!getRectControl().empty())
  592. {
  593. const LLRect& rect =
  594. LLUI::sConfigGroup->getRect(getRectControl().c_str());
  595. translate(rect.mLeft - getRect().mLeft,
  596. rect.mBottom - getRect().mBottom);
  597. if (mResizable)
  598. {
  599. reshape(llmax(mMinWidth, rect.getWidth()),
  600. llmax(mMinHeight, rect.getHeight()));
  601. }
  602. }
  603. }
  604. void LLFloater::applyTitle()
  605. {
  606. if (mDragHandle)
  607. {
  608. mDragHandle->setTitle(mTitle);
  609. }
  610. }
  611. const std::string& LLFloater::getCurrentTitle() const
  612. {
  613. return mDragHandle ? mDragHandle->getTitle() : LLStringUtil::null;
  614. }
  615. void LLFloater::setTitle(const std::string& title)
  616. {
  617. mTitleIsPristine = false;
  618. mTitle = title;
  619. applyTitle();
  620. }
  621. std::string LLFloater::getTitle()
  622. {
  623. if (mTitle.empty() && mDragHandle)
  624. {
  625. return mDragHandle->getTitle();
  626. }
  627. return mTitle;
  628. }
  629. bool LLFloater::canSnapTo(LLView* other_view)
  630. {
  631. if (!other_view)
  632. {
  633. llwarns << "Cannot snap to a NULL view" << llendl;
  634. return false;
  635. }
  636. if (other_view != getParent())
  637. {
  638. LLFloater* floaterp = other_view->asFloater();
  639. if (floaterp && floaterp->getSnapTarget() == getHandle() &&
  640. mDependents.count(floaterp->getHandle()))
  641. {
  642. // This is a dependent that is already snapped to us, so do not
  643. // snap back to it
  644. return false;
  645. }
  646. }
  647. return LLPanel::canSnapTo(other_view);
  648. }
  649. void LLFloater::snappedTo(LLView* snap_view)
  650. {
  651. if (!snap_view || snap_view == getParent())
  652. {
  653. clearSnapTarget();
  654. }
  655. else
  656. {
  657. LLFloater* floaterp = snap_view->asFloater();
  658. if (floaterp)
  659. {
  660. setSnapTarget(floaterp->getHandle());
  661. }
  662. }
  663. }
  664. void LLFloater::userSetShape(const LLRect& new_rect)
  665. {
  666. const LLRect old_rect = getRect();
  667. LLView::userSetShape(new_rect);
  668. // If not minimized, adjust all snapped dependents to new shape
  669. if (!isMinimized())
  670. {
  671. // Gather all snapped dependents
  672. for (handle_set_iter_t it = mDependents.begin(),
  673. end = mDependents.end();
  674. it != end; ++it)
  675. {
  676. LLFloater* floaterp = it->get();
  677. // Is a dependent snapped to us ?
  678. if (floaterp && floaterp->getSnapTarget() == getHandle())
  679. {
  680. S32 delta_x = 0;
  681. S32 delta_y = 0;
  682. // Check to see if it snapped to right or top, and move if
  683. // dependee floater is resizing
  684. LLRect dependent_rect = floaterp->getRect();
  685. S32 old_width = old_rect.getWidth();
  686. // dependent on my right ?
  687. if (dependent_rect.mLeft - getRect().mLeft >= old_width ||
  688. // dependent aligned with my right ?
  689. dependent_rect.mRight == getRect().mLeft + old_width)
  690. {
  691. // Was snapped directly onto right side or aligned with it
  692. delta_x += new_rect.getWidth() - old_width;
  693. }
  694. S32 old_height = old_rect.getHeight();
  695. if (dependent_rect.mBottom - getRect().mBottom >= old_height ||
  696. dependent_rect.mTop == getRect().mBottom + old_height)
  697. {
  698. // Was snapped directly onto top side or aligned with it
  699. delta_y += new_rect.getHeight() - old_height;
  700. }
  701. // Take translation of dependee floater into account as well
  702. delta_x += new_rect.mLeft - old_rect.mLeft;
  703. delta_y += new_rect.mBottom - old_rect.mBottom;
  704. dependent_rect.translate(delta_x, delta_y);
  705. floaterp->userSetShape(dependent_rect);
  706. }
  707. }
  708. if (resizedFromHandles())
  709. {
  710. sResizing = true;
  711. sLastSizeX = getRect().getWidth();
  712. sLastSizeY = getRect().getHeight();
  713. }
  714. }
  715. else if (new_rect.mLeft != old_rect.mLeft ||
  716. new_rect.mBottom != old_rect.mBottom)
  717. {
  718. // If minimized, and origin has changed
  719. mHasBeenDraggedWhileMinimized = true;
  720. }
  721. }
  722. void LLFloater::setMinimized(bool minimize)
  723. {
  724. if (minimize == mMinimized) return;
  725. if (minimize)
  726. {
  727. mExpandedRect = getRect();
  728. // If the floater has been dragged while minimized in the past, then
  729. // locate it at its previous minimized location. Otherwise, ask the
  730. // view for a minimize position.
  731. if (mHasBeenDraggedWhileMinimized)
  732. {
  733. setOrigin(mPreviousMinimizedLeft, mPreviousMinimizedBottom);
  734. }
  735. else if (gFloaterViewp) // Paranoa
  736. {
  737. S32 left, bottom;
  738. gFloaterViewp->getMinimizePosition(&left, &bottom);
  739. setOrigin(left, bottom);
  740. }
  741. if (mButtonsEnabled[BUTTON_MINIMIZE])
  742. {
  743. mButtonsEnabled[BUTTON_MINIMIZE] = false;
  744. mButtonsEnabled[BUTTON_RESTORE] = true;
  745. }
  746. if (mDragHandle)
  747. {
  748. mDragHandle->setVisible(true);
  749. }
  750. setBorderVisible(true);
  751. for (handle_set_iter_t it = mDependents.begin(),
  752. end = mDependents.end();
  753. it != end; ++it)
  754. {
  755. LLFloater* floaterp = it->get();
  756. if (floaterp)
  757. {
  758. if (floaterp->isMinimizeable())
  759. {
  760. floaterp->setMinimized(true);
  761. }
  762. else if (!floaterp->isMinimized())
  763. {
  764. floaterp->setVisible(false);
  765. }
  766. }
  767. }
  768. // Lose keyboard focus when minimized
  769. releaseFocus();
  770. for (S32 i = 0; i < 4; ++i)
  771. {
  772. if (mResizeBar[i])
  773. {
  774. mResizeBar[i]->setEnabled(false);
  775. }
  776. if (mResizeHandle[i])
  777. {
  778. mResizeHandle[i]->setEnabled(false);
  779. }
  780. }
  781. mMinimized = true;
  782. // Reshape *after* setting mMinimized
  783. reshape(MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE);
  784. }
  785. else
  786. {
  787. // If this window has been dragged while minimized (at any time),
  788. // remember its position for the next time it's minimized.
  789. if (mHasBeenDraggedWhileMinimized)
  790. {
  791. const LLRect& currentRect = getRect();
  792. mPreviousMinimizedLeft = currentRect.mLeft;
  793. mPreviousMinimizedBottom = currentRect.mBottom;
  794. }
  795. setOrigin(mExpandedRect.mLeft, mExpandedRect.mBottom);
  796. if (mButtonsEnabled[BUTTON_RESTORE])
  797. {
  798. mButtonsEnabled[BUTTON_MINIMIZE] = true;
  799. mButtonsEnabled[BUTTON_RESTORE] = false;
  800. }
  801. // show dependent floater
  802. for (handle_set_iter_t it = mDependents.begin(),
  803. end = mDependents.end();
  804. it != end; ++it)
  805. {
  806. LLFloater* floaterp = it->get();
  807. if (floaterp)
  808. {
  809. floaterp->setMinimized(false);
  810. floaterp->setVisible(true);
  811. }
  812. }
  813. for (S32 i = 0; i < 4; ++i)
  814. {
  815. if (mResizeBar[i])
  816. {
  817. mResizeBar[i]->setEnabled(isResizable());
  818. }
  819. if (mResizeHandle[i])
  820. {
  821. mResizeHandle[i]->setEnabled(isResizable());
  822. }
  823. }
  824. mMinimized = false;
  825. // Reshape *after* setting mMinimized
  826. reshape(mExpandedRect.getWidth(), mExpandedRect.getHeight());
  827. }
  828. applyTitle ();
  829. make_ui_sound("UISndWindowClose");
  830. updateButtons();
  831. }
  832. void LLFloater::setFocus(bool b)
  833. {
  834. if (b && getIsChrome())
  835. {
  836. return;
  837. }
  838. LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this);
  839. // A descendent already has focus
  840. bool child_had_focus = gFocusMgr.childHasKeyboardFocus(this);
  841. // Give focus to first valid descendent
  842. LLPanel::setFocus(b);
  843. if (b)
  844. {
  845. LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
  846. // Only push focused floaters to front of stack if not in midst of
  847. // ctrl-tab cycle
  848. if (!getHost() && (!parent || !parent->getCycleMode()) &&
  849. !isFrontmost())
  850. {
  851. setFrontmost();
  852. }
  853. // When getting focus, delegate to last descendent which had focus
  854. if (last_focus && !child_had_focus &&
  855. last_focus->isInEnabledChain() &&
  856. last_focus->isInVisibleChain())
  857. {
  858. // *FIX: should handle case where focus doesn't stick
  859. last_focus->setFocus(true);
  860. }
  861. }
  862. }
  863. //virtual
  864. void LLFloater::setIsChrome(bool is_chrome)
  865. {
  866. // Chrome floaters do not take focus at all
  867. if (is_chrome)
  868. {
  869. // Remove focus if we are changing to chrome
  870. setFocus(false);
  871. // Cannot CTRL-TAB to "chrome" floaters
  872. setFocusRoot(false);
  873. }
  874. // No titles displayed on "chrome" floaters
  875. if (mDragHandle)
  876. {
  877. mDragHandle->setTitleVisible(!is_chrome);
  878. }
  879. LLPanel::setIsChrome(is_chrome);
  880. }
  881. void LLFloater::setTitleVisible(bool visible)
  882. {
  883. if (mDragHandle)
  884. {
  885. mDragHandle->setTitleVisible(visible);
  886. }
  887. }
  888. // Change the draw style to account for the foreground state.
  889. void LLFloater::setForeground(bool front)
  890. {
  891. if (front != mForeground)
  892. {
  893. mForeground = front;
  894. if (mDragHandle)
  895. mDragHandle->setForeground(front);
  896. if (!front)
  897. {
  898. releaseFocus();
  899. }
  900. setBackgroundOpaque(front);
  901. }
  902. }
  903. void LLFloater::cleanupHandles()
  904. {
  905. // Remove handles to non-existent dependents
  906. for (handle_set_iter_t it = mDependents.begin(); it != mDependents.end(); )
  907. {
  908. LLFloater* floaterp = it->get();
  909. if (!floaterp)
  910. {
  911. it = mDependents.erase(it);
  912. }
  913. else
  914. {
  915. ++it;
  916. }
  917. }
  918. }
  919. void LLFloater::setHost(LLMultiFloater* host)
  920. {
  921. if (mHostHandle.isDead() && host)
  922. {
  923. // Make buttons smaller for hosted windows to differentiate from parent
  924. mButtonScale = 0.9f;
  925. // Add tear off button
  926. if (mCanTearOff)
  927. {
  928. mButtonsEnabled[BUTTON_TEAR_OFF] = true;
  929. }
  930. }
  931. else if (!mHostHandle.isDead() && !host)
  932. {
  933. mButtonScale = 1.f;
  934. #if 0
  935. mButtonsEnabled[BUTTON_TEAR_OFF] = false;
  936. #endif
  937. }
  938. updateButtons();
  939. if (host)
  940. {
  941. mHostHandle = host->getHandle();
  942. mLastHostHandle = host->getHandle();
  943. }
  944. else
  945. {
  946. mHostHandle.markDead();
  947. }
  948. }
  949. void LLFloater::moveResizeHandlesToFront()
  950. {
  951. for (S32 i = 0; i < 4; ++i)
  952. {
  953. if (mResizeBar[i])
  954. {
  955. sendChildToFront(mResizeBar[i]);
  956. }
  957. }
  958. for (S32 i = 0; i < 4; ++i)
  959. {
  960. if (mResizeHandle[i])
  961. {
  962. sendChildToFront(mResizeHandle[i]);
  963. }
  964. }
  965. }
  966. bool LLFloater::isFrontmost()
  967. {
  968. return getVisible() &&
  969. gFloaterViewp && gFloaterViewp->getFrontmost() == this;
  970. }
  971. void LLFloater::addDependentFloater(LLFloater* floaterp, bool reposition)
  972. {
  973. if (!gFloaterViewp) return; // Paranoia
  974. mDependents.insert(floaterp->getHandle());
  975. floaterp->mDependeeHandle = getHandle();
  976. if (reposition)
  977. {
  978. floaterp->setRect(gFloaterViewp->findNeighboringPosition(this,
  979. floaterp));
  980. floaterp->setSnapTarget(getHandle());
  981. }
  982. gFloaterViewp->adjustToFitScreen(floaterp);
  983. if (floaterp->isFrontmost())
  984. {
  985. // Make sure to bring self and sibling floaters to front
  986. gFloaterViewp->bringToFront(floaterp);
  987. }
  988. }
  989. void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent,
  990. bool reposition)
  991. {
  992. LLFloater* dependent_floaterp = dependent.get();
  993. if (dependent_floaterp)
  994. {
  995. addDependentFloater(dependent_floaterp, reposition);
  996. }
  997. }
  998. void LLFloater::removeDependentFloater(LLFloater* floaterp)
  999. {
  1000. mDependents.erase(floaterp->getHandle());
  1001. floaterp->mDependeeHandle = LLHandle<LLFloater>();
  1002. }
  1003. bool LLFloater::offerClickToButton(S32 x, S32 y, MASK mask,
  1004. EFloaterButtons index)
  1005. {
  1006. if (mButtonsEnabled[index])
  1007. {
  1008. LLButton* my_butt = mButtons[index];
  1009. S32 local_x = x - my_butt->getRect().mLeft;
  1010. S32 local_y = y - my_butt->getRect().mBottom;
  1011. if (my_butt->pointInView(local_x, local_y) &&
  1012. my_butt->handleMouseDown(local_x, local_y, mask))
  1013. {
  1014. // The button handled it
  1015. return true;
  1016. }
  1017. }
  1018. return false;
  1019. }
  1020. //virtual
  1021. bool LLFloater::handleMouseDown(S32 x, S32 y, MASK mask)
  1022. {
  1023. if (mMinimized)
  1024. {
  1025. // Offer the click to titlebar buttons. Note: this block and the
  1026. // offerClickToButton helper method could be removed because the parent
  1027. // container will handle it for us but we will keep it here for safety
  1028. // until after reworking the panel code to manage hidden children.
  1029. if (offerClickToButton(x, y, mask, BUTTON_CLOSE) ||
  1030. offerClickToButton(x, y, mask, BUTTON_RESTORE) ||
  1031. offerClickToButton(x, y, mask, BUTTON_TEAR_OFF))
  1032. {
  1033. return true;
  1034. }
  1035. // Otherwise pass to drag handle for movement
  1036. return mDragHandle->handleMouseDown(x, y, mask);
  1037. }
  1038. bringToFront(x, y);
  1039. return LLPanel::handleMouseDown(x, y, mask);
  1040. }
  1041. //virtual
  1042. bool LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask)
  1043. {
  1044. bool was_minimized = mMinimized;
  1045. bringToFront(x, y);
  1046. return was_minimized || LLPanel::handleRightMouseDown(x, y, mask);
  1047. }
  1048. bool LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
  1049. {
  1050. bringToFront(x, y);
  1051. return LLPanel::handleMiddleMouseDown(x, y, mask);
  1052. }
  1053. //virtual
  1054. bool LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
  1055. {
  1056. bool was_minimized = mMinimized;
  1057. setMinimized(false);
  1058. return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
  1059. }
  1060. void LLFloater::bringToFront(S32 x, S32 y)
  1061. {
  1062. if (getVisible() && pointInView(x, y))
  1063. {
  1064. LLMultiFloater* hostp = getHost();
  1065. if (hostp)
  1066. {
  1067. hostp->showFloater(this);
  1068. }
  1069. else
  1070. {
  1071. LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
  1072. if (parent)
  1073. {
  1074. parent->bringToFront(this);
  1075. }
  1076. }
  1077. }
  1078. }
  1079. //virtual
  1080. void LLFloater::setVisibleAndFrontmost(bool take_focus)
  1081. {
  1082. setVisible(true);
  1083. setFrontmost(take_focus);
  1084. }
  1085. void LLFloater::setFrontmost(bool take_focus)
  1086. {
  1087. LLMultiFloater* hostp = getHost();
  1088. if (hostp)
  1089. {
  1090. // This will bring the host floater to the front and select the
  1091. // appropriate panel
  1092. hostp->showFloater(this);
  1093. }
  1094. else
  1095. {
  1096. // There are more than one floater view so we need to query our parent
  1097. // directly
  1098. LLFloaterView* parent = dynamic_cast<LLFloaterView*>(getParent());
  1099. if (parent)
  1100. {
  1101. parent->bringToFront(this, take_focus);
  1102. }
  1103. }
  1104. }
  1105. //static
  1106. void LLFloater::onClickMinimize(void* userdata)
  1107. {
  1108. LLFloater* self = (LLFloater*) userdata;
  1109. if (self)
  1110. {
  1111. self->setMinimized(!self->isMinimized());
  1112. }
  1113. }
  1114. void LLFloater::onClickTearOff(void* userdata)
  1115. {
  1116. LLFloater* self = (LLFloater*) userdata;
  1117. if (!self || !gFloaterViewp) return;
  1118. LLMultiFloater* host_floater = self->getHost();
  1119. if (host_floater) //Tear off
  1120. {
  1121. LLRect new_rect;
  1122. host_floater->removeFloater(self);
  1123. // Re-parent to floater view
  1124. gFloaterViewp->addChild(self);
  1125. self->open();
  1126. // Only force position for floaters that don't have that data saved
  1127. if (self->getRectControl().empty())
  1128. {
  1129. new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5,
  1130. host_floater->getRect().mTop -
  1131. LLFLOATER_HEADER_SIZE - 5,
  1132. self->getRect().getWidth(),
  1133. self->getRect().getHeight());
  1134. self->setRect(new_rect);
  1135. }
  1136. gFloaterViewp->adjustToFitScreen(self);
  1137. // Give focus to new window to keep continuity for the user
  1138. self->setFocus(true);
  1139. }
  1140. else //Attach to parent.
  1141. {
  1142. LLMultiFloater* new_host;
  1143. new_host = (LLMultiFloater*)self->mLastHostHandle.get();
  1144. if (new_host)
  1145. {
  1146. // To reenable minimize button if it was minimized
  1147. self->setMinimized(false);
  1148. new_host->showFloater(self);
  1149. // Make sure host is visible
  1150. new_host->open();
  1151. }
  1152. }
  1153. }
  1154. //static
  1155. LLFloater* LLFloater::getClosableFloaterFromFocus()
  1156. {
  1157. if (!gFloaterViewp)
  1158. {
  1159. return NULL;
  1160. }
  1161. LLFloater* floaterp = NULL;
  1162. for (child_list_const_iter_t it = gFloaterViewp->getChildList()->begin(),
  1163. end = gFloaterViewp->getChildList()->end();
  1164. it != end; ++it)
  1165. {
  1166. LLFloater* candidatep = (*it)->asFloater();
  1167. if (candidatep && candidatep->hasFocus())
  1168. {
  1169. floaterp = candidatep;
  1170. break;
  1171. }
  1172. }
  1173. // The focused floater may not be closable: find and close a parental
  1174. // floater that is closeable, if any.
  1175. while (floaterp)
  1176. {
  1177. if (floaterp->isCloseable())
  1178. {
  1179. break;
  1180. }
  1181. floaterp = gFloaterViewp->getParentFloater(floaterp);
  1182. }
  1183. return floaterp;
  1184. }
  1185. //static
  1186. void LLFloater::closeFocusedFloater()
  1187. {
  1188. LLFloater* floaterp = getClosableFloaterFromFocus();
  1189. if (floaterp)
  1190. {
  1191. floaterp->close();
  1192. }
  1193. // If nothing took focus after closing focused floater give it to next
  1194. // floater (to allow closing multiple windows via keyboard in rapid
  1195. // succession)
  1196. if (gFloaterViewp && !gFocusMgr.getKeyboardFocus())
  1197. {
  1198. // *HACK: use gFloaterViewp directly in case we are using CTRL-W to
  1199. // close snapshot window which sits in gSnapshotFloaterViewp, and
  1200. // needs to pass focus on to normal floater view
  1201. gFloaterViewp->focusFrontFloater();
  1202. }
  1203. }
  1204. //static
  1205. void LLFloater::onClickClose(void* userdata)
  1206. {
  1207. LLFloater* self = (LLFloater*)userdata;
  1208. if (self)
  1209. {
  1210. self->close();
  1211. }
  1212. }
  1213. //virtual
  1214. void LLFloater::draw()
  1215. {
  1216. // Draw background
  1217. if (isBackgroundVisible())
  1218. {
  1219. S32 left = LLPANEL_BORDER_WIDTH;
  1220. S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH;
  1221. S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH;
  1222. S32 bottom = LLPANEL_BORDER_WIDTH;
  1223. LLColor4 shadow_color = LLUI::sColorDropShadow;
  1224. F32 shadow_offset = (F32)LLUI::sDropShadowFloater;
  1225. if (!isBackgroundOpaque())
  1226. {
  1227. shadow_offset *= 0.2f;
  1228. shadow_color.mV[VALPHA] *= 0.5f;
  1229. }
  1230. gl_drop_shadow(left, top, right, bottom, shadow_color,
  1231. ll_round(shadow_offset));
  1232. // No transparent windows in simple UI
  1233. if (isBackgroundOpaque())
  1234. {
  1235. gl_rect_2d(left, top, right, bottom, getBackgroundColor());
  1236. }
  1237. else
  1238. {
  1239. gl_rect_2d(left, top, right, bottom, getTransparentColor());
  1240. }
  1241. if (gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() &&
  1242. !getCurrentTitle().empty())
  1243. {
  1244. // Draw highlight on title bar to indicate focus. RDW
  1245. static S32 font_line_height = 0;
  1246. if (!font_line_height)
  1247. {
  1248. static const LLFontGL* font = LLFontGL::getFontSansSerif();
  1249. font_line_height = font->getLineHeight() - 1;
  1250. }
  1251. LLRect r = getRect();
  1252. gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(),
  1253. r.getHeight() - font_line_height,
  1254. LLUI::sTitleBarFocusColor, 0, true);
  1255. }
  1256. }
  1257. LLPanel::updateDefaultBtn();
  1258. if (getDefaultButton())
  1259. {
  1260. if (hasFocus() && getDefaultButton()->getEnabled())
  1261. {
  1262. LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
  1263. // Is this button a direct descendent and not a nested widget (e.g.
  1264. // checkbox) ?
  1265. LLButton* btn = dynamic_cast<LLButton*>(focus_ctrl);
  1266. bool focus_is_child_button = btn && btn->getParent() == this;
  1267. // only enable default button when current focus is not a button
  1268. getDefaultButton()->setBorderEnabled(!focus_is_child_button);
  1269. }
  1270. else
  1271. {
  1272. getDefaultButton()->setBorderEnabled(false);
  1273. }
  1274. }
  1275. if (isMinimized())
  1276. {
  1277. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  1278. {
  1279. drawChild(mButtons[i]);
  1280. }
  1281. drawChild(mDragHandle);
  1282. }
  1283. else
  1284. {
  1285. // Do not call LLPanel::draw() since we have implemented custom
  1286. // background rendering
  1287. LLView::draw();
  1288. }
  1289. if (isBackgroundVisible())
  1290. {
  1291. // Add in a border to improve spacialized visual clarity; use lines
  1292. // instead of gl_rect_2d so we can round the edges as per James'
  1293. // recommendation
  1294. LLUI::setLineWidth(1.5f);
  1295. LLColor4 outline_color =
  1296. gFocusMgr.childHasKeyboardFocus(this) ? LLUI::sFloaterFocusBorderColor
  1297. : LLUI::sFloaterUnfocusBorderColor;
  1298. gl_rect_2d_offset_local(0, getRect().getHeight() + 1,
  1299. getRect().getWidth() + 1, 0, outline_color,
  1300. -LLPANEL_BORDER_WIDTH, false);
  1301. LLUI::setLineWidth(1.f);
  1302. }
  1303. // Update tearoff button for torn off floaters when last host goes away
  1304. if (mCanTearOff && !getHost())
  1305. {
  1306. LLFloater* old_host = mLastHostHandle.get();
  1307. if (!old_host)
  1308. {
  1309. setCanTearOff(false);
  1310. }
  1311. }
  1312. }
  1313. void LLFloater::setCanMinimize(bool can_minimize)
  1314. {
  1315. // if removing minimize/restore button programmatically,
  1316. // go ahead and unminimize floater
  1317. if (!can_minimize)
  1318. {
  1319. setMinimized(false);
  1320. }
  1321. mButtonsEnabled[BUTTON_MINIMIZE] = can_minimize && !isMinimized();
  1322. mButtonsEnabled[BUTTON_RESTORE] = can_minimize && isMinimized();
  1323. updateButtons();
  1324. }
  1325. void LLFloater::setCanClose(bool can_close)
  1326. {
  1327. mButtonsEnabled[BUTTON_CLOSE] = can_close;
  1328. updateButtons();
  1329. }
  1330. void LLFloater::setCanTearOff(bool can_tear_off)
  1331. {
  1332. mCanTearOff = can_tear_off;
  1333. mButtonsEnabled[BUTTON_TEAR_OFF] = mCanTearOff && !mHostHandle.isDead();
  1334. updateButtons();
  1335. }
  1336. void LLFloater::setCanResize(bool can_resize)
  1337. {
  1338. if (mResizable && !can_resize)
  1339. {
  1340. for (S32 i = 0; i < 4; ++i)
  1341. {
  1342. removeChild(mResizeBar[i], true);
  1343. mResizeBar[i] = NULL;
  1344. removeChild(mResizeHandle[i], true);
  1345. mResizeHandle[i] = NULL;
  1346. }
  1347. }
  1348. else if (!mResizable && can_resize)
  1349. {
  1350. // Resize bars (sides)
  1351. constexpr S32 RESIZE_BAR_THICKNESS = 3;
  1352. mResizeBar[0] = new LLResizeBar("resizebar_left", this,
  1353. LLRect(0, getRect().getHeight(),
  1354. RESIZE_BAR_THICKNESS, 0),
  1355. mMinWidth, S32_MAX, LLResizeBar::LEFT);
  1356. addChild(mResizeBar[0]);
  1357. mResizeBar[1] = new LLResizeBar("resizebar_top", this,
  1358. LLRect(0, getRect().getHeight(),
  1359. getRect().getWidth(),
  1360. getRect().getHeight() -
  1361. RESIZE_BAR_THICKNESS),
  1362. mMinHeight, S32_MAX,
  1363. LLResizeBar::TOP);
  1364. addChild(mResizeBar[1]);
  1365. mResizeBar[2] = new LLResizeBar("resizebar_right", this,
  1366. LLRect(getRect().getWidth() -
  1367. RESIZE_BAR_THICKNESS,
  1368. getRect().getHeight(),
  1369. getRect().getWidth(), 0),
  1370. mMinWidth, S32_MAX,
  1371. LLResizeBar::RIGHT);
  1372. addChild(mResizeBar[2]);
  1373. mResizeBar[3] = new LLResizeBar("resizebar_bottom", this,
  1374. LLRect(0, RESIZE_BAR_THICKNESS,
  1375. getRect().getWidth(), 0),
  1376. mMinHeight, S32_MAX,
  1377. LLResizeBar::BOTTOM);
  1378. addChild(mResizeBar[3]);
  1379. // Resize handles (corners)
  1380. mResizeHandle[0] = new LLResizeHandle("Resize Handle",
  1381. LLRect(getRect().getWidth() -
  1382. RESIZE_HANDLE_WIDTH,
  1383. RESIZE_HANDLE_HEIGHT,
  1384. getRect().getWidth(), 0),
  1385. mMinWidth, mMinHeight,
  1386. LLResizeHandle::RIGHT_BOTTOM);
  1387. addChild(mResizeHandle[0]);
  1388. mResizeHandle[1] = new LLResizeHandle("resize",
  1389. LLRect(getRect().getWidth() -
  1390. RESIZE_HANDLE_WIDTH,
  1391. getRect().getHeight(),
  1392. getRect().getWidth(),
  1393. getRect().getHeight() -
  1394. RESIZE_HANDLE_HEIGHT),
  1395. mMinWidth, mMinHeight,
  1396. LLResizeHandle::RIGHT_TOP);
  1397. addChild(mResizeHandle[1]);
  1398. mResizeHandle[2] = new LLResizeHandle("resize",
  1399. LLRect(0, RESIZE_HANDLE_HEIGHT,
  1400. RESIZE_HANDLE_WIDTH, 0),
  1401. mMinWidth, mMinHeight,
  1402. LLResizeHandle::LEFT_BOTTOM);
  1403. addChild(mResizeHandle[2]);
  1404. mResizeHandle[3] = new LLResizeHandle("resize",
  1405. LLRect(0, getRect().getHeight(),
  1406. RESIZE_HANDLE_WIDTH,
  1407. getRect().getHeight() -
  1408. RESIZE_HANDLE_HEIGHT),
  1409. mMinWidth, mMinHeight,
  1410. LLResizeHandle::LEFT_TOP);
  1411. addChild(mResizeHandle[3]);
  1412. }
  1413. mResizable = can_resize;
  1414. }
  1415. void LLFloater::setCanDrag(bool can_drag)
  1416. {
  1417. // If we delete drag handle, we no longer have access to the floater title
  1418. // so just enable/disable it
  1419. if (!can_drag && mDragHandle->getEnabled())
  1420. {
  1421. mDragHandle->setEnabled(false);
  1422. }
  1423. else if (can_drag && !mDragHandle->getEnabled())
  1424. {
  1425. mDragHandle->setEnabled(true);
  1426. }
  1427. }
  1428. void LLFloater::updateButtons()
  1429. {
  1430. S32 close_box_size = ll_roundp((F32)LLFLOATER_CLOSE_BOX_SIZE *
  1431. mButtonScale);
  1432. S32 button_count = 0;
  1433. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  1434. {
  1435. if (!mButtons[i]) continue;
  1436. mButtons[i]->setEnabled(mButtonsEnabled[i]);
  1437. if (mButtonsEnabled[i] ||
  1438. // *HACK: always render close button for hosted floaters so that
  1439. // users do not accidentally hit the button when closing multiple
  1440. // windows in the chatterbox
  1441. (i == BUTTON_CLOSE && mButtonScale != 1.f))
  1442. {
  1443. ++button_count;
  1444. LLRect btn_rect;
  1445. if (mDragOnLeft)
  1446. {
  1447. btn_rect.setLeftTopAndSize(LLPANEL_BORDER_WIDTH,
  1448. getRect().getHeight() -
  1449. CLOSE_BOX_FROM_TOP -
  1450. (LLFLOATER_CLOSE_BOX_SIZE + 1) *
  1451. button_count,
  1452. close_box_size, close_box_size);
  1453. }
  1454. else
  1455. {
  1456. btn_rect.setLeftTopAndSize(getRect().getWidth() -
  1457. LLPANEL_BORDER_WIDTH -
  1458. (LLFLOATER_CLOSE_BOX_SIZE + 1) *
  1459. button_count,
  1460. getRect().getHeight() -
  1461. CLOSE_BOX_FROM_TOP,
  1462. close_box_size, close_box_size);
  1463. }
  1464. mButtons[i]->setRect(btn_rect);
  1465. mButtons[i]->setVisible(true);
  1466. // The restore button should have a tab stop so that it takes
  1467. // action when you Ctrl-Tab to a minimized floater
  1468. mButtons[i]->setTabStop(i == BUTTON_RESTORE);
  1469. }
  1470. else if (mButtons[i])
  1471. {
  1472. mButtons[i]->setVisible(false);
  1473. }
  1474. }
  1475. if (mDragHandle)
  1476. {
  1477. mDragHandle->setMaxTitleWidth(getRect().getWidth() -
  1478. button_count *
  1479. (LLFLOATER_CLOSE_BOX_SIZE + 1));
  1480. }
  1481. }
  1482. void LLFloater::buildButtons()
  1483. {
  1484. static std::vector<std::string> tooltips;
  1485. if (tooltips.empty())
  1486. {
  1487. tooltips.reserve(BUTTON_COUNT);
  1488. for (U32 i = 0; i < BUTTON_COUNT; ++i)
  1489. {
  1490. tooltips.emplace_back(LLTrans::getUIString(sButtonToolTipNames[i]));
  1491. }
  1492. }
  1493. S32 close_box_size = ll_roundp((F32)LLFLOATER_CLOSE_BOX_SIZE *
  1494. mButtonScale);
  1495. for (S32 i = 0; i < BUTTON_COUNT; ++i)
  1496. {
  1497. LLRect btn_rect;
  1498. if (mDragOnLeft)
  1499. {
  1500. btn_rect.setLeftTopAndSize(LLPANEL_BORDER_WIDTH,
  1501. getRect().getHeight() -
  1502. CLOSE_BOX_FROM_TOP -
  1503. (LLFLOATER_CLOSE_BOX_SIZE + 1) *
  1504. (i + 1),
  1505. close_box_size, close_box_size);
  1506. }
  1507. else
  1508. {
  1509. btn_rect.setLeftTopAndSize(getRect().getWidth() -
  1510. LLPANEL_BORDER_WIDTH -
  1511. (LLFLOATER_CLOSE_BOX_SIZE + 1) *
  1512. (i + 1),
  1513. getRect().getHeight() -
  1514. CLOSE_BOX_FROM_TOP,
  1515. close_box_size, close_box_size);
  1516. }
  1517. LLButton* buttonp = new LLButton(sButtonNames[i], btn_rect,
  1518. sButtonActiveImageNames[i],
  1519. sButtonPressedImageNames[i],
  1520. NULL, sButtonCallbacks[i], this,
  1521. LLFontGL::getFontSansSerif());
  1522. buttonp->setTabStop(false);
  1523. buttonp->setFollowsTop();
  1524. buttonp->setFollowsRight();
  1525. buttonp->setToolTip(tooltips[i]);
  1526. buttonp->setImageColor(LLUI::sFloaterButtonImageColor);
  1527. buttonp->setHoverImages(sButtonPressedImageNames[i],
  1528. sButtonPressedImageNames[i]);
  1529. buttonp->setScaleImage(true);
  1530. buttonp->setSaveToXML(false);
  1531. addChild(buttonp);
  1532. mButtons[i] = buttonp;
  1533. }
  1534. updateButtons();
  1535. }
  1536. /////////////////////////////////////////////////////
  1537. // LLFloaterView
  1538. LLFloaterView::LLFloaterView(const std::string& name, const LLRect& rect)
  1539. : LLUICtrl(name, rect, false, NULL, NULL, FOLLOWS_ALL),
  1540. mFocusCycleMode(false),
  1541. mSnapOffsetBottom(0)
  1542. {
  1543. setTabStop(false);
  1544. resetStartingFloaterPosition();
  1545. }
  1546. // By default, adjust vertical.
  1547. void LLFloaterView::reshape(S32 width, S32 height, bool called_from_parent)
  1548. {
  1549. reshapeFloater(width, height, called_from_parent, ADJUST_VERTICAL_YES);
  1550. }
  1551. // When reshaping this view, make the floaters follow their closest edge.
  1552. void LLFloaterView::reshapeFloater(S32 width, S32 height,
  1553. bool called_from_parent,
  1554. bool adjust_vertical)
  1555. {
  1556. S32 old_width = getRect().getWidth();
  1557. S32 old_height = getRect().getHeight();
  1558. for (child_list_const_iter_t it = getChildList()->begin(),
  1559. end = getChildList()->end();
  1560. it != end; ++it)
  1561. {
  1562. LLView* viewp = *it;
  1563. if (!viewp) continue;
  1564. LLFloater* floaterp = viewp->asFloater();
  1565. if (!floaterp || floaterp->isDependent())
  1566. {
  1567. // Dependents use same follow flags as their "dependee"
  1568. continue;
  1569. }
  1570. LLRect r = floaterp->getRect();
  1571. // Compute absolute distance from each edge of screen
  1572. S32 left_offset = abs(r.mLeft);
  1573. S32 right_offset = abs(old_width - r.mRight);
  1574. S32 top_offset = abs(old_height - r.mTop);
  1575. S32 bottom_offset = abs(r.mBottom);
  1576. // Make if follow the edge it is closest to
  1577. U32 follow_flags = 0x0;
  1578. if (left_offset < right_offset)
  1579. {
  1580. follow_flags |= FOLLOWS_LEFT;
  1581. }
  1582. else
  1583. {
  1584. follow_flags |= FOLLOWS_RIGHT;
  1585. }
  1586. // "No vertical adjustment" usually means that the bottom of the view
  1587. // has been pushed up or down. Hence we want the floaters to follow the
  1588. // top.
  1589. if (!adjust_vertical)
  1590. {
  1591. follow_flags |= FOLLOWS_TOP;
  1592. }
  1593. else if (top_offset < bottom_offset)
  1594. {
  1595. follow_flags |= FOLLOWS_TOP;
  1596. }
  1597. else
  1598. {
  1599. follow_flags |= FOLLOWS_BOTTOM;
  1600. }
  1601. floaterp->setFollows(follow_flags);
  1602. // RN: all dependent floaters copy follow behavior of "parent"
  1603. for (LLFloater::handle_set_iter_t
  1604. dep_it = floaterp->mDependents.begin(),
  1605. dep_end = floaterp->mDependents.end();
  1606. dep_it != dep_end; ++dep_it)
  1607. {
  1608. LLFloater* dependent_floaterp = dep_it->get();
  1609. if (dependent_floaterp)
  1610. {
  1611. dependent_floaterp->setFollows(follow_flags);
  1612. }
  1613. }
  1614. }
  1615. LLView::reshape(width, height, called_from_parent);
  1616. }
  1617. void LLFloaterView::restoreAll()
  1618. {
  1619. // Make sure all subwindows aren't minimized
  1620. for (child_list_const_iter_t it = getChildList()->begin(),
  1621. end = getChildList()->end();
  1622. it != end; ++it)
  1623. {
  1624. LLView* viewp = *it;
  1625. if (!viewp) continue;
  1626. LLFloater* floaterp = viewp->asFloater();
  1627. if (floaterp)
  1628. {
  1629. floaterp->setMinimized(false);
  1630. }
  1631. }
  1632. }
  1633. void LLFloaterView::getNewFloaterPosition(S32* left, S32* top)
  1634. {
  1635. // Workaround: mRect may change between when this object is created and the
  1636. // first time it is used.
  1637. static bool first = true;
  1638. if (first)
  1639. {
  1640. resetStartingFloaterPosition();
  1641. first = false;
  1642. }
  1643. constexpr S32 FLOATER_PAD = 16;
  1644. LLCoordWindow window_size;
  1645. gWindowp->getSize(&window_size);
  1646. LLRect full_window(0, window_size.mY, window_size.mX, 0);
  1647. LLRect floater_creation_rect(160,
  1648. full_window.getHeight() - 2 * gMenuBarHeight,
  1649. full_window.getWidth() * 2 / 3, 130);
  1650. floater_creation_rect.stretch(-FLOATER_PAD);
  1651. *left = mNextLeft;
  1652. *top = mNextTop;
  1653. constexpr S32 STEP = 25;
  1654. S32 bottom = floater_creation_rect.mBottom + 2 * STEP;
  1655. S32 right = floater_creation_rect.mRight - 4 * STEP;
  1656. mNextTop -= STEP;
  1657. mNextLeft += STEP;
  1658. if (mNextTop < bottom || mNextLeft > right)
  1659. {
  1660. ++mColumn;
  1661. mNextTop = floater_creation_rect.mTop;
  1662. mNextLeft = STEP * mColumn;
  1663. if (mNextTop < bottom || mNextLeft > right)
  1664. {
  1665. // Advancing the column did not work, so start back at the
  1666. // beginning
  1667. resetStartingFloaterPosition();
  1668. }
  1669. }
  1670. }
  1671. void LLFloaterView::resetStartingFloaterPosition()
  1672. {
  1673. constexpr S32 FLOATER_PAD = 16;
  1674. LLCoordWindow window_size;
  1675. gWindowp->getSize(&window_size);
  1676. LLRect full_window(0, window_size.mY, window_size.mX, 0);
  1677. LLRect floater_creation_rect(
  1678. 160,
  1679. full_window.getHeight() - 2 * gMenuBarHeight,
  1680. full_window.getWidth() * 2 / 3,
  1681. 130);
  1682. floater_creation_rect.stretch(-FLOATER_PAD);
  1683. mNextLeft = floater_creation_rect.mLeft;
  1684. mNextTop = floater_creation_rect.mTop;
  1685. mColumn = 0;
  1686. }
  1687. LLRect LLFloaterView::findNeighboringPosition(LLFloater* reference_floater,
  1688. LLFloater* neighbor)
  1689. {
  1690. LLRect base_rect = reference_floater->getRect();
  1691. S32 width = neighbor->getRect().getWidth();
  1692. S32 height = neighbor->getRect().getHeight();
  1693. LLRect new_rect = neighbor->getRect();
  1694. LLRect expanded_base_rect = base_rect;
  1695. expanded_base_rect.stretch(10);
  1696. for (LLFloater::handle_set_iter_t
  1697. dep_it = reference_floater->mDependents.begin();
  1698. dep_it != reference_floater->mDependents.end(); ++dep_it)
  1699. {
  1700. LLFloater* sibling = dep_it->get();
  1701. // Check for dependents within 10 pixels of base floater
  1702. if (sibling && sibling != neighbor && sibling->getVisible() &&
  1703. expanded_base_rect.overlaps(sibling->getRect()))
  1704. {
  1705. base_rect.unionWith(sibling->getRect());
  1706. }
  1707. }
  1708. S32 left_margin = llmax(0, base_rect.mLeft);
  1709. S32 right_margin = llmax(0, getRect().getWidth() - base_rect.mRight);
  1710. S32 top_margin = llmax(0, getRect().getHeight() - base_rect.mTop);
  1711. S32 bottom_margin = llmax(0, base_rect.mBottom);
  1712. // Find position for floater in following order right->left->bottom->top
  1713. for (S32 i = 0; i < 5; ++i)
  1714. {
  1715. if (right_margin > width)
  1716. {
  1717. new_rect.translate(base_rect.mRight - neighbor->getRect().mLeft,
  1718. base_rect.mTop - neighbor->getRect().mTop);
  1719. return new_rect;
  1720. }
  1721. else if (left_margin > width)
  1722. {
  1723. new_rect.translate(base_rect.mLeft - neighbor->getRect().mRight,
  1724. base_rect.mTop - neighbor->getRect().mTop);
  1725. return new_rect;
  1726. }
  1727. else if (bottom_margin > height)
  1728. {
  1729. new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft,
  1730. base_rect.mBottom - neighbor->getRect().mTop);
  1731. return new_rect;
  1732. }
  1733. else if (top_margin > height)
  1734. {
  1735. new_rect.translate(base_rect.mLeft - neighbor->getRect().mLeft,
  1736. base_rect.mTop - neighbor->getRect().mBottom);
  1737. return new_rect;
  1738. }
  1739. // keep growing margins to find "best" fit
  1740. left_margin += 20;
  1741. right_margin += 20;
  1742. top_margin += 20;
  1743. bottom_margin += 20;
  1744. }
  1745. // didn't find anything, return initial rect
  1746. return new_rect;
  1747. }
  1748. // *TODO: make this respect the floater mAutoFocus value, instead of using the
  1749. // give_focus parameter.
  1750. bool LLFloaterView::bringToFront(LLFloater* child, bool give_focus)
  1751. {
  1752. if (!child || !getChildList())
  1753. {
  1754. // NULL child or no children for us...
  1755. return false;
  1756. }
  1757. if (child->getHost() ||
  1758. std::find(getChildList()->begin(), getChildList()->end(), child) ==
  1759. getChildList()->end())
  1760. {
  1761. // This floater is hosted elsewhere and hence not one of our children,
  1762. // abort
  1763. return false;
  1764. }
  1765. std::vector<LLView*> floaters_to_move;
  1766. // Look at all floaters...tab
  1767. for (child_list_const_iter_t it = getChildList()->begin(),
  1768. end = getChildList()->end();
  1769. it != end; ++it)
  1770. {
  1771. LLView* viewp = *it;
  1772. if (!viewp) continue;
  1773. LLFloater* floaterp = viewp->asFloater();
  1774. if (!floaterp || !floaterp->isDependent())
  1775. {
  1776. continue;
  1777. }
  1778. // If I am a dependent floater look for floaters that have me as a
  1779. // dependent...
  1780. if (floaterp->mDependents.find(child->getHandle()) !=
  1781. floaterp->mDependents.end())
  1782. {
  1783. // ...and make sure all children of that floater (including me) are
  1784. // brought to front...
  1785. for (LLFloater::handle_set_iter_t
  1786. dep_it = floaterp->mDependents.begin(),
  1787. dep_end = floaterp->mDependents.end();
  1788. dep_it != dep_end; ++dep_it)
  1789. {
  1790. LLFloater* sibling = dep_it->get();
  1791. if (sibling)
  1792. {
  1793. floaters_to_move.push_back(sibling);
  1794. }
  1795. }
  1796. // ...before bringing my parent to the front...
  1797. floaters_to_move.push_back(floaterp);
  1798. }
  1799. }
  1800. for (std::vector<LLView*>::iterator it = floaters_to_move.begin(),
  1801. end = floaters_to_move.end();
  1802. it != end; ++it)
  1803. {
  1804. LLView* viewp = *it;
  1805. if (!viewp) continue;
  1806. LLFloater* floaterp = viewp->asFloater();
  1807. if (floaterp)
  1808. {
  1809. sendChildToFront(floaterp);
  1810. // Always unminimize dependee, but allow dependents to stay
  1811. // minimized
  1812. if (!floaterp->isDependent())
  1813. {
  1814. floaterp->setMinimized(false);
  1815. }
  1816. }
  1817. }
  1818. floaters_to_move.clear();
  1819. // ...then bringing my own dependents to the front...
  1820. for (LLFloater::handle_set_iter_t it = child->mDependents.begin(),
  1821. end = child->mDependents.end();
  1822. it != end; ++it)
  1823. {
  1824. LLFloater* dependent = it->get();
  1825. if (dependent)
  1826. {
  1827. sendChildToFront(dependent);
  1828. #if 0 // Do not un-minimize dependent windows automatically: respect the
  1829. // user's wishes !
  1830. dependent->setMinimized(false);
  1831. #endif
  1832. }
  1833. }
  1834. // ...and finally bringing myself to front (do this last, so that I am left
  1835. // in front at end of this call)
  1836. if (*getChildList()->begin() != child)
  1837. {
  1838. sendChildToFront(child);
  1839. }
  1840. child->setMinimized(false);
  1841. if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
  1842. {
  1843. child->setFocus(true);
  1844. }
  1845. return true;
  1846. }
  1847. void LLFloaterView::highlightFocusedFloater()
  1848. {
  1849. for (child_list_const_iter_t it = getChildList()->begin(),
  1850. end = getChildList()->end();
  1851. it != end; ++it)
  1852. {
  1853. LLView* viewp = *it;
  1854. if (!viewp) continue;
  1855. LLFloater* floaterp = viewp->asFloater();
  1856. if (!floaterp || floaterp->isDependent())
  1857. {
  1858. // Skip dependent floaters, as we will handle them in a batch along
  1859. // with their dependee
  1860. continue;
  1861. }
  1862. bool has_focus = gFocusMgr.childHasKeyboardFocus(floaterp);
  1863. for (LLFloater::handle_set_iter_t
  1864. dep_it = floaterp->mDependents.begin(),
  1865. dep_end = floaterp->mDependents.end();
  1866. dep_it != dep_end; ++dep_it)
  1867. {
  1868. LLFloater* dependent_floaterp = dep_it->get();
  1869. if (dependent_floaterp &&
  1870. gFocusMgr.childHasKeyboardFocus(dependent_floaterp))
  1871. {
  1872. has_focus = true;
  1873. break;
  1874. }
  1875. }
  1876. // Now set this floater and all its dependents
  1877. floaterp->setForeground(has_focus);
  1878. for (LLFloater::handle_set_iter_t
  1879. dep_it = floaterp->mDependents.begin(),
  1880. dep_end = floaterp->mDependents.end();
  1881. dep_it != dep_end; ++dep_it)
  1882. {
  1883. LLFloater* dependent_floaterp = dep_it->get();
  1884. if (dependent_floaterp)
  1885. {
  1886. dependent_floaterp->setForeground(has_focus);
  1887. }
  1888. }
  1889. floaterp->cleanupHandles();
  1890. }
  1891. }
  1892. void LLFloaterView::unhighlightFocusedFloater()
  1893. {
  1894. for (child_list_const_iter_t it = getChildList()->begin(),
  1895. end = getChildList()->end();
  1896. it != end; ++it)
  1897. {
  1898. LLView* viewp = *it;
  1899. if (!viewp) continue;
  1900. LLFloater* floaterp = viewp->asFloater();
  1901. if (floaterp)
  1902. {
  1903. floaterp->setForeground(false);
  1904. }
  1905. }
  1906. }
  1907. void LLFloaterView::focusFrontFloater()
  1908. {
  1909. LLFloater* floaterp = getFrontmost();
  1910. if (floaterp)
  1911. {
  1912. floaterp->setFocus(true);
  1913. }
  1914. }
  1915. void LLFloaterView::getMinimizePosition(S32* left, S32* bottom)
  1916. {
  1917. S32 row, row_start, row_end, row_delta;
  1918. S32 col, col_start, col_end, col_delta, width;
  1919. LLRect snap_rect_local = getLocalSnapRect();
  1920. if (sStackMinimizedTopToBottom)
  1921. {
  1922. row_start = snap_rect_local.getHeight(); // - LLFLOATER_HEADER_SIZE;
  1923. row_end = snap_rect_local.mBottom;
  1924. row_delta = -LLFLOATER_HEADER_SIZE;
  1925. }
  1926. else
  1927. {
  1928. row_start = snap_rect_local.mBottom;
  1929. row_end = snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE;
  1930. row_delta = LLFLOATER_HEADER_SIZE;
  1931. }
  1932. width = (snap_rect_local.getWidth() - MINIMIZED_WIDTH -
  1933. snap_rect_local.mLeft) / sStackScreenWidthFraction;
  1934. if (width < MINIMIZED_WIDTH)
  1935. {
  1936. width = MINIMIZED_WIDTH;
  1937. }
  1938. if (sStackMinimizedRightToLeft)
  1939. {
  1940. col_start = snap_rect_local.getWidth() - MINIMIZED_WIDTH;
  1941. col_end = col_start - width;
  1942. col_delta = -MINIMIZED_WIDTH;
  1943. }
  1944. else
  1945. {
  1946. col_start = snap_rect_local.mLeft;
  1947. col_end = col_start + width;
  1948. col_delta = MINIMIZED_WIDTH;
  1949. }
  1950. for (row = row_start; (row_delta > 0 ? row < row_end : row > row_end);
  1951. row += row_delta)
  1952. {
  1953. for (col = col_start; (col_delta > 0 ? col < col_end : col > col_end);
  1954. col += col_delta)
  1955. {
  1956. bool found_gap = true;
  1957. for (child_list_const_iter_t it = getChildList()->begin(),
  1958. end = getChildList()->end();
  1959. it != end; ++it)
  1960. {
  1961. LLView* viewp = *it;
  1962. if (!viewp) continue;
  1963. LLFloater* floaterp = viewp->asFloater();
  1964. if (!floaterp || !floaterp->isMinimized())
  1965. {
  1966. continue;
  1967. }
  1968. // Examine minimized children.
  1969. LLRect r = floaterp->getRect();
  1970. if (r.mBottom < row + LLFLOATER_HEADER_SIZE &&
  1971. r.mBottom > row - LLFLOATER_HEADER_SIZE &&
  1972. r.mLeft < col + MINIMIZED_WIDTH &&
  1973. r.mLeft > col - MINIMIZED_WIDTH)
  1974. {
  1975. // Needs the check for off grid; cannot drag, but window
  1976. // resize makes them off
  1977. found_gap = false;
  1978. break;
  1979. }
  1980. }
  1981. if (found_gap)
  1982. {
  1983. *left = col;
  1984. *bottom = row;
  1985. return; // Done
  1986. }
  1987. }
  1988. }
  1989. // Crude: stack them all there when screen is full of minimized floaters.
  1990. *left = col_start;
  1991. *bottom = row_start;
  1992. }
  1993. void LLFloaterView::destroyAllChildren()
  1994. {
  1995. LLView::deleteAllChildren();
  1996. }
  1997. void LLFloaterView::closeAllChildren(bool app_quitting)
  1998. {
  1999. // Iterate over a copy of the list, because closing windows will destroy
  2000. // some windows on the list.
  2001. child_list_t child_list = *getChildList();
  2002. for (child_list_const_iter_t it = child_list.begin(),
  2003. end = child_list.end();
  2004. it != end; ++it)
  2005. {
  2006. LLView* viewp = *it;
  2007. child_list_const_iter_t exists = std::find(getChildList()->begin(),
  2008. getChildList()->end(),
  2009. viewp);
  2010. if (exists == getChildList()->end())
  2011. {
  2012. // This floater has already been removed
  2013. continue;
  2014. }
  2015. // Attempt to close floater. This will cause the "do you want to save"
  2016. // dialogs to appear.
  2017. LLFloater* floaterp = viewp->asFloater();
  2018. if (floaterp && floaterp->canClose() && !floaterp->isDead())
  2019. {
  2020. floaterp->close(app_quitting);
  2021. }
  2022. }
  2023. }
  2024. bool LLFloaterView::allChildrenClosed()
  2025. {
  2026. // See if there are any visible floaters (some floaters "close" by setting
  2027. // themselves invisible)
  2028. for (child_list_const_iter_t it = getChildList()->begin(),
  2029. end = getChildList()->end();
  2030. it != end; ++it)
  2031. {
  2032. LLView* viewp = *it;
  2033. if (!viewp) continue;
  2034. LLFloater* floaterp = viewp->asFloater();
  2035. if (floaterp && !floaterp->isDead() && floaterp->getVisible() &&
  2036. floaterp->isCloseable())
  2037. {
  2038. return false;
  2039. }
  2040. }
  2041. return true;
  2042. }
  2043. void LLFloaterView::refresh()
  2044. {
  2045. // Constrain children to be entirely on the screen
  2046. for (child_list_const_iter_t it = getChildList()->begin(),
  2047. end = getChildList()->end();
  2048. it != end; ++it)
  2049. {
  2050. LLView* viewp = *it;
  2051. if (!viewp) continue;
  2052. LLFloater* floaterp = viewp->asFloater();
  2053. if (floaterp && floaterp->getVisible())
  2054. {
  2055. // Minimized floaters are kept fully onscreen
  2056. adjustToFitScreen(floaterp, !floaterp->isMinimized());
  2057. }
  2058. }
  2059. }
  2060. void LLFloaterView::adjustToFitScreen(LLFloater* floater,
  2061. bool allow_partial_outside)
  2062. {
  2063. if (floater->getParent() != this)
  2064. {
  2065. // Floater is hosted elsewhere, so ignore
  2066. return;
  2067. }
  2068. S32 screen_width = getSnapRect().getWidth();
  2069. S32 screen_height = getSnapRect().getHeight();
  2070. // Convert to local coordinate frame
  2071. LLRect snap_rect_local = getLocalSnapRect();
  2072. if (floater->isResizable())
  2073. {
  2074. LLRect view_rect = floater->getRect();
  2075. S32 old_width = view_rect.getWidth();
  2076. S32 old_height = view_rect.getHeight();
  2077. S32 min_width;
  2078. S32 min_height;
  2079. floater->getResizeLimits(&min_width, &min_height);
  2080. // Make sure floater is not already smaller than its min height/width
  2081. S32 new_width = llmax(min_width, old_width);
  2082. S32 new_height = llmax(min_height, old_height);
  2083. if (new_width > screen_width || new_height > screen_height)
  2084. {
  2085. // We have to make this window able to fit on screen
  2086. new_width = llmin(new_width, screen_width);
  2087. new_height = llmin(new_height, screen_height);
  2088. // ...while respecting minimum width/height
  2089. new_width = llmax(new_width, min_width);
  2090. new_height = llmax(new_height, min_height);
  2091. floater->reshape(new_width, new_height);
  2092. if (floater->followsRight())
  2093. {
  2094. floater->translate(old_width - new_width, 0);
  2095. }
  2096. if (floater->followsTop())
  2097. {
  2098. floater->translate(0, old_height - new_height);
  2099. }
  2100. }
  2101. }
  2102. // Move window fully onscreen
  2103. if (floater->translateIntoRect(snap_rect_local, allow_partial_outside))
  2104. {
  2105. floater->clearSnapTarget();
  2106. }
  2107. }
  2108. void LLFloaterView::draw()
  2109. {
  2110. refresh();
  2111. // Hide focused floater if in cycle mode, so that it can be drawn on top
  2112. LLFloater* floaterp = mFocusCycleMode ? getFocusedFloater() : NULL;
  2113. if (floaterp)
  2114. {
  2115. for (child_list_const_iter_t it = getChildList()->begin(),
  2116. end = getChildList()->end();
  2117. it != end; ++it)
  2118. {
  2119. if (*it != floaterp)
  2120. {
  2121. drawChild(*it);
  2122. }
  2123. }
  2124. drawChild(floaterp, -TABBED_FLOATER_OFFSET, TABBED_FLOATER_OFFSET);
  2125. }
  2126. else
  2127. {
  2128. LLView::draw();
  2129. }
  2130. }
  2131. LLRect LLFloaterView::getSnapRect() const
  2132. {
  2133. LLRect snap_rect = getRect();
  2134. snap_rect.mBottom += mSnapOffsetBottom;
  2135. return snap_rect;
  2136. }
  2137. LLFloater* LLFloaterView::getFocusedFloater()
  2138. {
  2139. for (child_list_const_iter_t it = getChildList()->begin(),
  2140. end = getChildList()->end();
  2141. it != end; ++it)
  2142. {
  2143. LLView* viewp = *it;
  2144. if (!viewp) continue;
  2145. LLFloater* floaterp = viewp->asFloater();
  2146. if (floaterp && floaterp->hasFocus())
  2147. {
  2148. return floaterp;
  2149. }
  2150. }
  2151. return NULL;
  2152. }
  2153. LLFloater* LLFloaterView::getFrontmost()
  2154. {
  2155. for (child_list_const_iter_t it = getChildList()->begin(),
  2156. end = getChildList()->end();
  2157. it != end; ++it)
  2158. {
  2159. LLView* viewp = *it;
  2160. if (!viewp) continue;
  2161. LLFloater* floaterp = viewp->asFloater();
  2162. if (floaterp && floaterp->getVisible() && !floaterp->isDead())
  2163. {
  2164. return floaterp;
  2165. }
  2166. }
  2167. return NULL;
  2168. }
  2169. LLFloater* LLFloaterView::getBackmost()
  2170. {
  2171. for (child_list_const_iter_t it = getChildList()->begin(),
  2172. end = getChildList()->end();
  2173. it != end; ++it)
  2174. {
  2175. LLView* viewp = *it;
  2176. if (!viewp) continue;
  2177. LLFloater* floaterp = viewp->asFloater();
  2178. if (floaterp && floaterp->getVisible())
  2179. {
  2180. return floaterp;
  2181. }
  2182. }
  2183. return NULL;
  2184. }
  2185. void LLFloaterView::syncFloaterTabOrder()
  2186. {
  2187. // bring focused floater to front
  2188. for (child_list_const_reverse_iter_t rit = getChildList()->rbegin(),
  2189. rend = getChildList()->rend();
  2190. rit != rend; ++rit)
  2191. {
  2192. LLView* viewp = *rit;
  2193. if (!viewp) continue;
  2194. LLFloater* floaterp = viewp->asFloater();
  2195. if (floaterp && gFocusMgr.childHasKeyboardFocus(floaterp))
  2196. {
  2197. bringToFront(floaterp, false);
  2198. break;
  2199. }
  2200. }
  2201. // Then sync draw order to tab order
  2202. for (child_list_const_reverse_iter_t rit = getChildList()->rbegin(),
  2203. rend = getChildList()->rend();
  2204. rit != rend; ++rit)
  2205. {
  2206. LLView* viewp = *rit;
  2207. if (!viewp) continue;
  2208. LLFloater* floaterp = viewp->asFloater();
  2209. if (floaterp)
  2210. {
  2211. moveChildToFrontOfTabGroup(floaterp);
  2212. }
  2213. }
  2214. }
  2215. LLFloater* LLFloaterView::getParentFloater(LLView* viewp)
  2216. {
  2217. LLView* parentp = viewp->getParent();
  2218. while (parentp && parentp != this)
  2219. {
  2220. viewp = parentp;
  2221. parentp = parentp->getParent();
  2222. }
  2223. if (parentp == this)
  2224. {
  2225. return viewp->asFloater();
  2226. }
  2227. return NULL;
  2228. }
  2229. S32 LLFloaterView::getZOrder(LLFloater* child)
  2230. {
  2231. S32 rv = 0;
  2232. for (child_list_const_iter_t it = getChildList()->begin(),
  2233. end = getChildList()->end();
  2234. it != end; ++it)
  2235. {
  2236. if (*it == child)
  2237. {
  2238. break;
  2239. }
  2240. ++rv;
  2241. }
  2242. return rv;
  2243. }
  2244. void LLFloaterView::pushVisibleAll(bool visible, const skip_list_t& skip_list)
  2245. {
  2246. for (child_list_const_iter_t it = getChildList()->begin(),
  2247. end = getChildList()->end();
  2248. it != end; ++it)
  2249. {
  2250. LLView* view = *it;
  2251. if (skip_list.find(view) == skip_list.end())
  2252. {
  2253. view->pushVisible(visible);
  2254. }
  2255. }
  2256. }
  2257. void LLFloaterView::popVisibleAll(const skip_list_t& skip_list)
  2258. {
  2259. for (child_list_const_iter_t it = getChildList()->begin(),
  2260. end = getChildList()->end();
  2261. it != end; ++it)
  2262. {
  2263. LLView* view = *it;
  2264. if (skip_list.find(view) == skip_list.end())
  2265. {
  2266. view->popVisible();
  2267. }
  2268. }
  2269. }
  2270. void LLFloaterView::fitAllToScreen()
  2271. {
  2272. for (child_list_const_iter_t it = getChildList()->begin(),
  2273. end = getChildList()->end();
  2274. it != end; ++it)
  2275. {
  2276. LLView* viewp = *it;
  2277. if (!viewp) continue;
  2278. LLFloater* floaterp = viewp->asFloater();
  2279. if (floaterp && floaterp->getVisible() && !floaterp->isDead())
  2280. {
  2281. adjustToFitScreen(floaterp);
  2282. }
  2283. }
  2284. }
  2285. //
  2286. // LLMultiFloater
  2287. //
  2288. LLMultiFloater::LLMultiFloater()
  2289. : mTabContainer(NULL),
  2290. mTabPos(LLTabContainer::TOP),
  2291. mAutoResize(true),
  2292. mOrigMinWidth(0),
  2293. mOrigMinHeight(0)
  2294. {
  2295. }
  2296. LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos)
  2297. : mTabContainer(NULL),
  2298. mTabPos(tab_pos),
  2299. mAutoResize(true),
  2300. mOrigMinWidth(0),
  2301. mOrigMinHeight(0)
  2302. {
  2303. }
  2304. LLMultiFloater::LLMultiFloater(const std::string& name)
  2305. : LLFloater(name),
  2306. mTabContainer(NULL),
  2307. mTabPos(LLTabContainer::TOP),
  2308. mAutoResize(false),
  2309. mOrigMinWidth(0),
  2310. mOrigMinHeight(0)
  2311. {
  2312. }
  2313. LLMultiFloater::LLMultiFloater(const std::string& name,
  2314. const LLRect& rect,
  2315. LLTabContainer::TabPosition tab_pos,
  2316. bool auto_resize)
  2317. : LLFloater(name, rect, name),
  2318. mTabContainer(NULL),
  2319. mTabPos(LLTabContainer::TOP),
  2320. mAutoResize(auto_resize),
  2321. mOrigMinWidth(0),
  2322. mOrigMinHeight(0)
  2323. {
  2324. mTabContainer =
  2325. new LLTabContainer("Preview Tabs",
  2326. LLRect(LLPANEL_BORDER_WIDTH,
  2327. getRect().getHeight() -
  2328. LLFLOATER_HEADER_SIZE,
  2329. getRect().getWidth() - LLPANEL_BORDER_WIDTH,
  2330. 0),
  2331. mTabPos, false, false);
  2332. mTabContainer->setFollowsAll();
  2333. if (isResizable())
  2334. {
  2335. mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
  2336. }
  2337. addChild(mTabContainer);
  2338. }
  2339. LLMultiFloater::LLMultiFloater(const std::string& name,
  2340. const std::string& rect_control,
  2341. LLTabContainer::TabPosition tab_pos,
  2342. bool auto_resize)
  2343. : LLFloater(name, rect_control, name),
  2344. mTabContainer(NULL),
  2345. mTabPos(tab_pos),
  2346. mAutoResize(auto_resize),
  2347. mOrigMinWidth(0),
  2348. mOrigMinHeight(0)
  2349. {
  2350. mTabContainer =
  2351. new LLTabContainer("Preview Tabs",
  2352. LLRect(LLPANEL_BORDER_WIDTH,
  2353. getRect().getHeight() -
  2354. LLFLOATER_HEADER_SIZE,
  2355. getRect().getWidth() - LLPANEL_BORDER_WIDTH,
  2356. 0),
  2357. mTabPos, false, false);
  2358. mTabContainer->setFollowsAll();
  2359. if (isResizable() && mTabPos == LLTabContainer::BOTTOM)
  2360. {
  2361. mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
  2362. }
  2363. addChild(mTabContainer);
  2364. }
  2365. //virtual
  2366. const std::string& LLMultiFloater::getTag() const
  2367. {
  2368. return LL_MULTI_FLOATER_TAG;
  2369. }
  2370. //virtual
  2371. LLXMLNodePtr LLMultiFloater::getXML(bool save_children) const
  2372. {
  2373. LLXMLNodePtr node = LLFloater::getXML();
  2374. node->setName(LL_MULTI_FLOATER_TAG);
  2375. return node;
  2376. }
  2377. //virtual
  2378. void LLMultiFloater::open()
  2379. {
  2380. if (mTabContainer->getTabCount() > 0)
  2381. {
  2382. LLFloater::open();
  2383. }
  2384. else
  2385. {
  2386. // For now, do not allow multifloaters without any child floaters
  2387. close();
  2388. }
  2389. }
  2390. //virtual
  2391. void LLMultiFloater::onClose(bool app_quitting)
  2392. {
  2393. if (closeAllFloaters())
  2394. {
  2395. LLFloater::onClose(app_quitting);
  2396. }
  2397. }
  2398. //virtual
  2399. void LLMultiFloater::draw()
  2400. {
  2401. if (mTabContainer->getTabCount() == 0)
  2402. {
  2403. // RN: could this potentially crash in draw hierarchy ?
  2404. close();
  2405. return;
  2406. }
  2407. for (S32 i = 0; i < mTabContainer->getTabCount(); ++i)
  2408. {
  2409. LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i);
  2410. if (floaterp->getTitle() != mTabContainer->getPanelTitle(i))
  2411. {
  2412. mTabContainer->setPanelTitle(i, floaterp->getTitle());
  2413. }
  2414. }
  2415. LLFloater::draw();
  2416. }
  2417. bool LLMultiFloater::closeAllFloaters()
  2418. {
  2419. S32 tab_to_close = 0;
  2420. S32 lastTabCount = mTabContainer->getTabCount();
  2421. while (tab_to_close < mTabContainer->getTabCount())
  2422. {
  2423. LLFloater* first_floater =
  2424. (LLFloater*)mTabContainer->getPanelByIndex(tab_to_close);
  2425. first_floater->close();
  2426. if (lastTabCount == mTabContainer->getTabCount())
  2427. {
  2428. // Tab did not actually close, possibly due to a pending save
  2429. // confirmation dialog, so try and close the next one in the list
  2430. ++tab_to_close;
  2431. }
  2432. else
  2433. {
  2434. // Tab closed ok.
  2435. lastTabCount = mTabContainer->getTabCount();
  2436. }
  2437. }
  2438. if (mTabContainer->getTabCount() != 0)
  2439. {
  2440. // Could not close all the tabs (pending save dialog ?)
  2441. return false;
  2442. }
  2443. return true; // else all tabs were successfully closed...
  2444. }
  2445. void LLMultiFloater::growToFit(S32 content_width, S32 content_height)
  2446. {
  2447. S32 new_width = llmax(getRect().getWidth(),
  2448. content_width + LLPANEL_BORDER_WIDTH * 2);
  2449. S32 new_height = llmax(getRect().getHeight(),
  2450. content_height + LLFLOATER_HEADER_SIZE +
  2451. TABCNTR_HEADER_HEIGHT);
  2452. if (isMinimized())
  2453. {
  2454. LLRect newrect;
  2455. newrect.setLeftTopAndSize(getExpandedRect().mLeft,
  2456. getExpandedRect().mTop,
  2457. new_width, new_height);
  2458. setExpandedRect(newrect);
  2459. }
  2460. else
  2461. {
  2462. S32 old_height = getRect().getHeight();
  2463. reshape(new_width, new_height);
  2464. // Keep top left corner in same position
  2465. translate(0, old_height - new_height);
  2466. }
  2467. }
  2468. // Adds the LLFloater pointed to by floaterp to this. If floaterp is already
  2469. // hosted by this, then it is re-added to get new titles, etc.
  2470. // If select_added_floater is true, the LLFloater pointed to by floaterp will
  2471. // become the selected tab in this
  2472. void LLMultiFloater::addFloater(LLFloater* floaterp, bool select_added_floater,
  2473. LLTabContainer::eInsertionPoint insertion_pt)
  2474. {
  2475. if (!floaterp)
  2476. {
  2477. return;
  2478. }
  2479. if (!mTabContainer)
  2480. {
  2481. llerrs << "Tab Container used without having been initialized."
  2482. << llendl;
  2483. return;
  2484. }
  2485. if (floaterp->getHost() == this)
  2486. {
  2487. // Already hosted by me, remove do this so we get updated title, etc.
  2488. mFloaterDataMap.erase(floaterp->getHandle());
  2489. mTabContainer->removeTabPanel(floaterp);
  2490. }
  2491. else if (floaterp->getHost())
  2492. {
  2493. // floaterp is hosted by somebody else and this is adding it, so remove
  2494. // it from its old host
  2495. floaterp->getHost()->removeFloater(floaterp);
  2496. }
  2497. else if (gFloaterViewp && floaterp->getParent() == gFloaterViewp)
  2498. {
  2499. // Re-host preview floater as child panel
  2500. gFloaterViewp->removeChild(floaterp);
  2501. }
  2502. // Store original configuration
  2503. LLFloaterData floater_data;
  2504. floater_data.mWidth = floaterp->getRect().getWidth();
  2505. floater_data.mHeight = floaterp->getRect().getHeight();
  2506. floater_data.mCanMinimize = floaterp->isMinimizeable();
  2507. floater_data.mCanResize = floaterp->isResizable();
  2508. // Remove minimize and close buttons
  2509. floaterp->setCanMinimize(false);
  2510. floaterp->setCanResize(false);
  2511. floaterp->setCanDrag(false);
  2512. floaterp->storeRectControl();
  2513. // Avoid double rendering of floater background (makes it more opaque)
  2514. floaterp->setBackgroundVisible(false);
  2515. if (mAutoResize)
  2516. {
  2517. growToFit(floater_data.mWidth, floater_data.mHeight);
  2518. }
  2519. // Add the panel, add it to proper maps
  2520. mTabContainer->addTabPanel(floaterp, floaterp->getTitle(), false,
  2521. onTabSelected, this, 0, false, insertion_pt);
  2522. mFloaterDataMap[floaterp->getHandle()] = floater_data;
  2523. updateResizeLimits();
  2524. if (select_added_floater)
  2525. {
  2526. mTabContainer->selectTabPanel(floaterp);
  2527. }
  2528. else
  2529. {
  2530. // Reassert visible tab (hiding new floater if necessary)
  2531. mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex());
  2532. }
  2533. floaterp->setHost(this);
  2534. if (isMinimized())
  2535. {
  2536. floaterp->setVisible(false);
  2537. }
  2538. }
  2539. // If the LLFloater pointed to by floaterp is hosted by this, then its tab is
  2540. // selected and returns true. Otherwise returns false.
  2541. bool LLMultiFloater::selectFloater(LLFloater* floaterp)
  2542. {
  2543. return mTabContainer->selectTabPanel(floaterp);
  2544. }
  2545. //virtual
  2546. void LLMultiFloater::selectNextFloater()
  2547. {
  2548. mTabContainer->selectNextTab();
  2549. }
  2550. //virtual
  2551. void LLMultiFloater::selectPrevFloater()
  2552. {
  2553. mTabContainer->selectPrevTab();
  2554. }
  2555. void LLMultiFloater::showFloater(LLFloater* floaterp)
  2556. {
  2557. // We won't select a panel that already is selected it is hard to do this
  2558. // internally to tab container as tab selection is handled via index and
  2559. // the tab at a given index might have changed
  2560. if (floaterp != mTabContainer->getCurrentPanel() &&
  2561. !mTabContainer->selectTabPanel(floaterp))
  2562. {
  2563. addFloater(floaterp, true);
  2564. }
  2565. }
  2566. void LLMultiFloater::removeFloater(LLFloater* floaterp)
  2567. {
  2568. if (floaterp->getHost() != this)
  2569. return;
  2570. floater_data_map_t::iterator found_data_it =
  2571. mFloaterDataMap.find(floaterp->getHandle());
  2572. if (found_data_it != mFloaterDataMap.end())
  2573. {
  2574. LLFloaterData& floater_data = found_data_it->second;
  2575. floaterp->setCanMinimize(floater_data.mCanMinimize);
  2576. if (!floater_data.mCanResize)
  2577. {
  2578. // Restore original size
  2579. floaterp->reshape(floater_data.mWidth, floater_data.mHeight);
  2580. }
  2581. floaterp->setCanResize(floater_data.mCanResize);
  2582. mFloaterDataMap.erase(found_data_it);
  2583. }
  2584. mTabContainer->removeTabPanel(floaterp);
  2585. floaterp->setBackgroundVisible(true);
  2586. floaterp->setCanDrag(true);
  2587. floaterp->setHost(NULL);
  2588. floaterp->applyRectControl();
  2589. updateResizeLimits();
  2590. tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false);
  2591. }
  2592. void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click)
  2593. {
  2594. // Default implementation does nothing
  2595. }
  2596. void LLMultiFloater::tabClose()
  2597. {
  2598. if (mTabContainer && mTabContainer->getTabCount() == 0)
  2599. {
  2600. // No more children, close myself
  2601. close();
  2602. }
  2603. }
  2604. void LLMultiFloater::setVisible(bool visible)
  2605. {
  2606. // *FIX: should not have to do this, fix adding to minimized multifloater
  2607. LLFloater::setVisible(visible);
  2608. if (mTabContainer)
  2609. {
  2610. LLPanel* cur_floaterp = mTabContainer->getCurrentPanel();
  2611. if (cur_floaterp)
  2612. {
  2613. cur_floaterp->setVisible(visible);
  2614. }
  2615. // if no tab selected, and we're being shown,
  2616. // select last tab to be added
  2617. if (visible && !cur_floaterp)
  2618. {
  2619. mTabContainer->selectLastTab();
  2620. }
  2621. }
  2622. }
  2623. bool LLMultiFloater::handleKeyHere(KEY key, MASK mask)
  2624. {
  2625. if (key == 'W' && mask == MASK_CONTROL)
  2626. {
  2627. LLFloater* floaterp = getActiveFloater();
  2628. // Is it user closeable and is system closeable ?
  2629. if (floaterp && floaterp->canClose() && floaterp->isCloseable())
  2630. {
  2631. floaterp->close();
  2632. }
  2633. return true;
  2634. }
  2635. return LLFloater::handleKeyHere(key, mask);
  2636. }
  2637. LLFloater* LLMultiFloater::getActiveFloater()
  2638. {
  2639. LLView* viewp = mTabContainer->getCurrentPanel();
  2640. if (viewp)
  2641. {
  2642. return viewp->asFloater();
  2643. }
  2644. return NULL;
  2645. }
  2646. S32 LLMultiFloater::getFloaterCount()
  2647. {
  2648. return mTabContainer->getTabCount();
  2649. }
  2650. // Returns true if the LLFloater pointed to by floaterp is currently in a
  2651. // flashing state and is hosted by this.
  2652. bool LLMultiFloater::isFloaterFlashing(LLFloater* floaterp)
  2653. {
  2654. if (floaterp && floaterp->getHost() == this)
  2655. {
  2656. return mTabContainer->getTabPanelFlashing(floaterp);
  2657. }
  2658. return false;
  2659. }
  2660. // Sets the current flashing state of the LLFloater pointed to by floaterp to
  2661. // be the bool flashing if the LLFloater pointed to by floaterp is hosted by
  2662. // this.
  2663. void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, bool flashing)
  2664. {
  2665. if (floaterp && floaterp->getHost() == this)
  2666. {
  2667. mTabContainer->setTabPanelFlashing(floaterp, flashing);
  2668. }
  2669. }
  2670. //static
  2671. void LLMultiFloater::onTabSelected(void* userdata, bool from_click)
  2672. {
  2673. LLMultiFloater* floaterp = (LLMultiFloater*)userdata;
  2674. floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(),
  2675. from_click);
  2676. }
  2677. void LLMultiFloater::setCanResize(bool can_resize)
  2678. {
  2679. LLFloater::setCanResize(can_resize);
  2680. if (isResizable() &&
  2681. mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
  2682. {
  2683. mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
  2684. }
  2685. else
  2686. {
  2687. mTabContainer->setRightTabBtnOffset(0);
  2688. }
  2689. }
  2690. bool LLMultiFloater::postBuild()
  2691. {
  2692. // Remember any original xml minimum size
  2693. getResizeLimits(&mOrigMinWidth, &mOrigMinHeight);
  2694. if (mTabContainer)
  2695. {
  2696. return true;
  2697. }
  2698. mTabContainer = getChild<LLTabContainer>("Preview Tabs");
  2699. return true;
  2700. }
  2701. void LLMultiFloater::updateResizeLimits()
  2702. {
  2703. // Initialize minimum size constraint to the original xml values.
  2704. S32 new_min_width = mOrigMinWidth;
  2705. S32 new_min_height = mOrigMinHeight;
  2706. // Possibly increase minimum size constraint due to children's minimums.
  2707. for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
  2708. {
  2709. LLFloater* floaterp =
  2710. (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
  2711. if (floaterp)
  2712. {
  2713. new_min_width = llmax(new_min_width,
  2714. floaterp->getMinWidth() +
  2715. LLPANEL_BORDER_WIDTH * 2);
  2716. new_min_height = llmax(new_min_height,
  2717. floaterp->getMinHeight() +
  2718. LLFLOATER_HEADER_SIZE +
  2719. TABCNTR_HEADER_HEIGHT);
  2720. }
  2721. }
  2722. setResizeLimits(new_min_width, new_min_height);
  2723. S32 cur_height = getRect().getHeight();
  2724. S32 new_width = llmax(getRect().getWidth(), new_min_width);
  2725. S32 new_height = llmax(getRect().getHeight(), new_min_height);
  2726. if (isMinimized())
  2727. {
  2728. const LLRect& expanded = getExpandedRect();
  2729. LLRect newrect;
  2730. newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop,
  2731. llmax(expanded.getWidth(), new_width),
  2732. llmax(expanded.getHeight(), new_height));
  2733. setExpandedRect(newrect);
  2734. }
  2735. else
  2736. {
  2737. reshape(new_width, new_height);
  2738. // Make sure upper left corner doesn't move
  2739. translate(0, cur_height - getRect().getHeight());
  2740. // Make sure this window is visible on screen when it has been modified
  2741. // (tab added, etc)
  2742. if (gFloaterViewp) // Paranoia
  2743. {
  2744. gFloaterViewp->adjustToFitScreen(this, true);
  2745. }
  2746. }
  2747. }
  2748. //virtual
  2749. const std::string& LLFloater::getTag() const
  2750. {
  2751. return LL_FLOATER_TAG;
  2752. }
  2753. //virtual
  2754. LLXMLNodePtr LLFloater::getXML(bool save_children) const
  2755. {
  2756. LLXMLNodePtr node = LLPanel::getXML();
  2757. node->setName(LL_FLOATER_TAG);
  2758. node->createChild("title", true)->setStringValue(getCurrentTitle());
  2759. node->createChild("can_resize", true)->setBoolValue(isResizable());
  2760. node->createChild("can_minimize", true)->setBoolValue(isMinimizeable());
  2761. node->createChild("can_close", true)->setBoolValue(isCloseable());
  2762. node->createChild("can_drag_on_left", true)->setBoolValue(isDragOnLeft());
  2763. node->createChild("min_width", true)->setIntValue(getMinWidth());
  2764. node->createChild("min_height", true)->setIntValue(getMinHeight());
  2765. node->createChild("can_tear_off", true)->setBoolValue(mCanTearOff);
  2766. return node;
  2767. }
  2768. //static
  2769. LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView* parent,
  2770. LLUICtrlFactory* factory)
  2771. {
  2772. std::string name = LL_FLOATER_TAG;
  2773. node->getAttributeString("name", name);
  2774. LLFloater* floaterp = new LLFloater(name);
  2775. std::string filename;
  2776. node->getAttributeString("filename", filename);
  2777. if (filename.empty())
  2778. {
  2779. // Load from node
  2780. floaterp->initFloaterXML(node, parent, factory);
  2781. }
  2782. else
  2783. {
  2784. // Load from file
  2785. factory->buildFloater(floaterp, filename);
  2786. }
  2787. return floaterp;
  2788. }
  2789. void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView* parent,
  2790. LLUICtrlFactory* factory, bool open_it)
  2791. {
  2792. std::string name = getName();
  2793. node->getAttributeString("name", name);
  2794. std::string title = getCurrentTitle();
  2795. node->getAttributeString("title", title);
  2796. std::string rect_control;
  2797. node->getAttributeString("rect_control", rect_control);
  2798. bool resizable = isResizable();
  2799. node->getAttributeBool("can_resize", resizable);
  2800. bool minimizable = isMinimizeable();
  2801. node->getAttributeBool("can_minimize", minimizable);
  2802. bool close_btn = isCloseable();
  2803. node->getAttributeBool("can_close", close_btn);
  2804. bool drag_on_left = isDragOnLeft();
  2805. node->getAttributeBool("can_drag_on_left", drag_on_left);
  2806. S32 min_width = getMinWidth();
  2807. node->getAttributeS32("min_width", min_width);
  2808. S32 min_height = getMinHeight();
  2809. node->getAttributeS32("min_height", min_height);
  2810. if (!rect_control.empty())
  2811. {
  2812. setRectControl(rect_control);
  2813. }
  2814. LLRect rect;
  2815. createRect(node, rect, parent, LLRect());
  2816. setRect(rect);
  2817. setName(name);
  2818. initFloater(title, resizable, min_width, min_height, drag_on_left,
  2819. minimizable, close_btn);
  2820. mTitle = title;
  2821. applyTitle();
  2822. bool can_tear_off;
  2823. if (node->getAttributeBool("can_tear_off", can_tear_off))
  2824. {
  2825. setCanTearOff(can_tear_off);
  2826. }
  2827. initFromXML(node, parent);
  2828. LLMultiFloater* last_host = sHostp;
  2829. bool is_multi_floater = node->hasName("multi_floater");
  2830. if (is_multi_floater)
  2831. {
  2832. sHostp = (LLMultiFloater*)this;
  2833. }
  2834. initChildrenXML(node, factory);
  2835. if (is_multi_floater)
  2836. {
  2837. sHostp = last_host;
  2838. }
  2839. if (!postBuild())
  2840. {
  2841. llerrs << "Failed to construct floater " << name << llendl;
  2842. }
  2843. applyRectControl();
  2844. if (open_it)
  2845. {
  2846. open();
  2847. }
  2848. moveResizeHandlesToFront();
  2849. }