diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/llfloater.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 2953 |
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 | |||
56 | extern BOOL gNoRender; | ||
57 | |||
58 | const S32 MINIMIZED_WIDTH = 160; | ||
59 | const S32 CLOSE_BOX_FROM_TOP = 1; | ||
60 | |||
61 | LLString 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 | |||
70 | LLString 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 | |||
79 | LLString 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 | |||
88 | LLString 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 | |||
97 | LLString 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 | |||
110 | LLFloater::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 | |||
119 | LLMultiFloater* LLFloater::sHostp = NULL; | ||
120 | BOOL LLFloater::sEditModeEnabled; | ||
121 | LLFloater::handle_map_t LLFloater::sFloaterMap; | ||
122 | |||
123 | LLFloaterView* gFloaterView = NULL; | ||
124 | |||
125 | LLFloater::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 | |||
137 | LLFloater::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 | |||
153 | LLFloater::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 | |||
173 | LLFloater::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! | ||
195 | void 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 | ||
420 | LLFloater::~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 | ||
459 | EWidgetType LLFloater::getWidgetType() const | ||
460 | { | ||
461 | return WIDGET_TYPE_FLOATER; | ||
462 | } | ||
463 | |||
464 | // virtual | ||
465 | LLString LLFloater::getWidgetTag() const | ||
466 | { | ||
467 | return LL_FLOATER_TAG; | ||
468 | } | ||
469 | |||
470 | void LLFloater::destroy() | ||
471 | { | ||
472 | die(); | ||
473 | } | ||
474 | |||
475 | void 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 | |||
509 | LLView* 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 | |||
520 | void 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 | |||
550 | void 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 | |||
610 | void 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 | |||
629 | void 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 | |||
648 | void 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 | |||
663 | void 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 | |||
676 | void LLFloater::setTitle( const LLString& title ) | ||
677 | { | ||
678 | if (gNoRender) | ||
679 | { | ||
680 | return; | ||
681 | } | ||
682 | mDragHandle->setTitle( title ); | ||
683 | } | ||
684 | |||
685 | const LLString& LLFloater::getTitle() const | ||
686 | { | ||
687 | return mDragHandle ? mDragHandle->getTitle() : LLString::null; | ||
688 | } | ||
689 | |||
690 | void 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 | |||
709 | BOOL 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 | |||
725 | void 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 | |||
740 | void 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 | |||
780 | void 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 | |||
880 | void 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 | |||
915 | void 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. | ||
933 | void 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 | |||
949 | void 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 | |||
967 | void 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 | |||
1000 | void LLFloater::moveResizeHandleToFront() | ||
1001 | { | ||
1002 | // 0 is the bottom right | ||
1003 | if( mResizeHandle[0] ) | ||
1004 | { | ||
1005 | sendChildToFront(mResizeHandle[0]); | ||
1006 | } | ||
1007 | } | ||
1008 | |||
1009 | BOOL LLFloater::isFrontmost() | ||
1010 | { | ||
1011 | return gFloaterView && gFloaterView->getFrontmost() == this && getVisible(); | ||
1012 | } | ||
1013 | |||
1014 | void 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 | |||
1032 | void 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 | |||
1041 | void LLFloater::removeDependentFloater(LLFloater* floaterp) | ||
1042 | { | ||
1043 | mDependents.erase(floaterp->getHandle()); | ||
1044 | floaterp->mDependeeHandle = LLViewHandle::sDeadHandle; | ||
1045 | } | ||
1046 | |||
1047 | // virtual | ||
1048 | BOOL 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 | ||
1079 | BOOL 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 | ||
1088 | BOOL 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 | |||
1095 | void 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 | ||
1117 | void LLFloater::setVisibleAndFrontmost(BOOL take_focus) | ||
1118 | { | ||
1119 | setVisible(TRUE); | ||
1120 | setFrontmost(take_focus); | ||
1121 | } | ||
1122 | |||
1123 | void 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 | ||
1141 | LLFloater* 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 | ||
1159 | void 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 | ||
1181 | BOOL LLFloater::getEditModeEnabled() | ||
1182 | { | ||
1183 | return sEditModeEnabled; | ||
1184 | } | ||
1185 | |||
1186 | // static | ||
1187 | void LLFloater::onClickMinimize(void *userdata) | ||
1188 | { | ||
1189 | LLFloater* self = (LLFloater*) userdata; | ||
1190 | if (!self) return; | ||
1191 | |||
1192 | self->setMinimized( !self->isMinimized() ); | ||
1193 | } | ||
1194 | |||
1195 | void 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 | ||
1228 | void 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 | ||
1237 | void 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 | ||
1259 | void LLFloater::onClickClose( void* userdata ) | ||
1260 | { | ||
1261 | LLFloater* self = (LLFloater*) userdata; | ||
1262 | if (!self) return; | ||
1263 | |||
1264 | self->close(); | ||
1265 | } | ||
1266 | |||
1267 | |||
1268 | // virtual | ||
1269 | void 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 | ||
1358 | void LLFloater::onClose(bool app_quitting) | ||
1359 | { | ||
1360 | destroy(); | ||
1361 | } | ||
1362 | |||
1363 | // virtual | ||
1364 | BOOL LLFloater::canClose() | ||
1365 | { | ||
1366 | return TRUE; | ||
1367 | } | ||
1368 | |||
1369 | // virtual | ||
1370 | BOOL LLFloater::canSaveAs() | ||
1371 | { | ||
1372 | return FALSE; | ||
1373 | } | ||
1374 | |||
1375 | // virtual | ||
1376 | void LLFloater::saveAs() | ||
1377 | { | ||
1378 | } | ||
1379 | |||
1380 | void 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 | |||
1411 | void LLFloater::setCanClose(BOOL can_close) | ||
1412 | { | ||
1413 | mButtonsEnabled[BUTTON_CLOSE] = can_close; | ||
1414 | |||
1415 | updateButtons(); | ||
1416 | } | ||
1417 | |||
1418 | void 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 | |||
1427 | void 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 | |||
1526 | void 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 | |||
1540 | void 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 | |||
1583 | void 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 | |||
1634 | LLFloaterView::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 | |||
1643 | EWidgetType LLFloaterView::getWidgetType() const | ||
1644 | { | ||
1645 | return WIDGET_TYPE_FLOATER_VIEW; | ||
1646 | } | ||
1647 | |||
1648 | LLString LLFloaterView::getWidgetTag() const | ||
1649 | { | ||
1650 | return LL_FLOATER_VIEW_TAG; | ||
1651 | } | ||
1652 | |||
1653 | // By default, adjust vertical. | ||
1654 | void 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. | ||
1660 | void 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 | |||
1729 | void 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 | |||
1744 | void 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 | |||
1789 | void 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 | |||
1807 | LLRect 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 | |||
1871 | void LLFloaterView::setCycleMode(BOOL mode) | ||
1872 | { | ||
1873 | mFocusCycleMode = mode; | ||
1874 | } | ||
1875 | |||
1876 | BOOL LLFloaterView::getCycleMode() | ||
1877 | { | ||
1878 | return mFocusCycleMode; | ||
1879 | } | ||
1880 | |||
1881 | void 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 | |||
1958 | void 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 | |||
2000 | void 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 | |||
2010 | void LLFloaterView::focusFrontFloater() | ||
2011 | { | ||
2012 | LLFloater* floaterp = getFrontmost(); | ||
2013 | if (floaterp) | ||
2014 | { | ||
2015 | floaterp->setFocus(TRUE); | ||
2016 | } | ||
2017 | } | ||
2018 | |||
2019 | void 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 | |||
2041 | void LLFloaterView::destroyAllChildren() | ||
2042 | { | ||
2043 | LLView::deleteAllChildren(); | ||
2044 | } | ||
2045 | |||
2046 | void 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 | |||
2074 | BOOL 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 | |||
2094 | void 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 | |||
2107 | void 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 | |||
2157 | void 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 | |||
2188 | const LLRect LLFloaterView::getSnapRect() const | ||
2189 | { | ||
2190 | LLRect snap_rect = mRect; | ||
2191 | snap_rect.mBottom += mSnapOffsetBottom; | ||
2192 | |||
2193 | return snap_rect; | ||
2194 | } | ||
2195 | |||
2196 | LLFloater *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 | |||
2209 | LLFloater *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 | |||
2222 | LLFloater *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 | |||
2236 | void 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 | |||
2257 | LLFloater* 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 | |||
2274 | LLFloater* 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 | |||
2292 | S32 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 | |||
2307 | void 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 | |||
2320 | void 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 | |||
2337 | LLMultiFloater::LLMultiFloater() : | ||
2338 | mTabContainer(NULL), | ||
2339 | mTabPos(LLTabContainerCommon::TOP), | ||
2340 | mAutoResize(FALSE) | ||
2341 | { | ||
2342 | |||
2343 | } | ||
2344 | |||
2345 | LLMultiFloater::LLMultiFloater(LLTabContainerCommon::TabPosition tab_pos) : | ||
2346 | mTabContainer(NULL), | ||
2347 | mTabPos(tab_pos), | ||
2348 | mAutoResize(FALSE) | ||
2349 | { | ||
2350 | |||
2351 | } | ||
2352 | |||
2353 | LLMultiFloater::LLMultiFloater(const LLString &name) : | ||
2354 | LLFloater(name), | ||
2355 | mTabContainer(NULL), | ||
2356 | mTabPos(LLTabContainerCommon::TOP), | ||
2357 | mAutoResize(FALSE) | ||
2358 | { | ||
2359 | } | ||
2360 | |||
2361 | LLMultiFloater::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 | |||
2385 | LLMultiFloater::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 | |||
2410 | LLMultiFloater::~LLMultiFloater() | ||
2411 | { | ||
2412 | } | ||
2413 | |||
2414 | // virtual | ||
2415 | EWidgetType LLMultiFloater::getWidgetType() const | ||
2416 | { | ||
2417 | return WIDGET_TYPE_MULTI_FLOATER; | ||
2418 | } | ||
2419 | |||
2420 | // virtual | ||
2421 | LLString LLMultiFloater::getWidgetTag() const | ||
2422 | { | ||
2423 | return LL_MULTI_FLOATER_TAG; | ||
2424 | } | ||
2425 | |||
2426 | void 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 | |||
2446 | void 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 | |||
2460 | void 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 | |||
2468 | void 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 | |||
2489 | BOOL 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 | |||
2513 | void 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 | **/ | ||
2545 | void 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 | **/ | ||
2619 | BOOL LLMultiFloater::selectFloater(LLFloater* floaterp) | ||
2620 | { | ||
2621 | return mTabContainer->selectTabPanel(floaterp); | ||
2622 | } | ||
2623 | |||
2624 | // virtual | ||
2625 | void LLMultiFloater::selectNextFloater() | ||
2626 | { | ||
2627 | mTabContainer->selectNextTab(); | ||
2628 | } | ||
2629 | |||
2630 | // virtual | ||
2631 | void LLMultiFloater::selectPrevFloater() | ||
2632 | { | ||
2633 | mTabContainer->selectPrevTab(); | ||
2634 | } | ||
2635 | |||
2636 | void 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 | |||
2650 | void 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 | |||
2697 | void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click) | ||
2698 | { | ||
2699 | // default implementation does nothing | ||
2700 | } | ||
2701 | |||
2702 | void LLMultiFloater::tabClose() | ||
2703 | { | ||
2704 | if (mTabContainer->getTabCount() == 0) | ||
2705 | { | ||
2706 | // no more children, close myself | ||
2707 | close(); | ||
2708 | } | ||
2709 | } | ||
2710 | |||
2711 | void 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 | |||
2727 | BOOL 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 | |||
2746 | LLFloater* LLMultiFloater::getActiveFloater() | ||
2747 | { | ||
2748 | return (LLFloater*)mTabContainer->getCurrentPanel(); | ||
2749 | } | ||
2750 | |||
2751 | S32 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 | **/ | ||
2765 | BOOL 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 | **/ | ||
2782 | void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) | ||
2783 | { | ||
2784 | if ( floaterp && floaterp->getHost() == this ) | ||
2785 | mTabContainer->setTabPanelFlashing(floaterp, flashing); | ||
2786 | } | ||
2787 | |||
2788 | //static | ||
2789 | void 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 | |||
2796 | void 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 | |||
2809 | BOOL 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 | ||
2827 | LLXMLNodePtr 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 | ||
2851 | LLView* 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 | |||
2875 | void 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 | } | ||