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