PageRenderTime 60ms CodeModel.GetById 19ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llui/llwindowshade.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 392 lines | 299 code | 62 blank | 31 comment | 29 complexity | 35a444da89056a0943c7bcf9e013a887 MD5 | raw file
  1/**
  2 * @file LLWindowShade.cpp
  3 * @brief Notification dialog that slides down and optionally disabled a piece of UI
  4 *
  5 * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "llwindowshade.h"
 29
 30#include "lllayoutstack.h"
 31#include "lltextbox.h"
 32#include "lliconctrl.h"
 33#include "llbutton.h"
 34#include "llcheckboxctrl.h"
 35#include "lllineeditor.h"
 36
 37const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;
 38const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100;
 39
 40static LLDefaultChildRegistry::Register<LLWindowShade> r("window_shade");
 41
 42LLWindowShade::Params::Params()
 43:	bg_image("bg_image"),
 44	modal("modal", false),
 45	text_color("text_color"),
 46	shade_color("shade_color"),
 47	can_close("can_close", true)
 48{
 49	changeDefault(mouse_opaque, false);
 50}
 51
 52LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)
 53:	LLUICtrl(params),
 54	mModal(params.modal),
 55	mFormHeight(0),
 56	mTextColor(params.text_color)
 57{
 58	setFocusRoot(true);
 59}
 60
 61void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
 62{
 63	LLUICtrl::initFromParams(params);
 64
 65	LLLayoutStack::Params layout_p;
 66	layout_p.name = "notification_stack";
 67	layout_p.rect = params.rect;
 68	layout_p.follows.flags = FOLLOWS_ALL;
 69	layout_p.mouse_opaque = false;
 70	layout_p.orientation = LLLayoutStack::VERTICAL;
 71	layout_p.border_size = 0;
 72
 73	LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
 74	addChild(stackp);
 75
 76	LLLayoutPanel::Params panel_p;
 77	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0);
 78	panel_p.name = "notification_area";
 79	panel_p.visible = false;
 80	panel_p.user_resize = false;
 81	panel_p.background_visible = true;
 82	panel_p.bg_alpha_image = params.bg_image;
 83	panel_p.auto_resize = false;
 84	LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
 85	stackp->addChild(notification_panel);
 86
 87	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
 88	panel_p.auto_resize = true;
 89	panel_p.user_resize = false;
 90	panel_p.rect = params.rect;
 91	panel_p.name = "background_area";
 92	panel_p.mouse_opaque = false;
 93	panel_p.background_visible = false;
 94	panel_p.bg_alpha_color = params.shade_color;
 95	LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
 96	stackp->addChild(dummy_panel);
 97
 98	layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
 99	layout_p.rect = LLRect(0, 30, 800, 0);
100	layout_p.follows.flags = FOLLOWS_ALL;
101	layout_p.orientation = LLLayoutStack::HORIZONTAL;
102	stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
103	notification_panel->addChild(stackp);
104
105	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
106	panel_p.rect.height = 30;
107	LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
108	stackp->addChild(panel);
109
110	LLIconCtrl::Params icon_p;
111	icon_p.name = "notification_icon";
112	icon_p.rect = LLRect(5, 25, 21, 10);
113	panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
114
115	LLTextBox::Params text_p;
116	text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3);
117	text_p.follows.flags = FOLLOWS_ALL;
118	text_p.text_color = mTextColor;
119	text_p.font = LLFontGL::getFontSansSerifSmall();
120	text_p.font.style = "BOLD";
121	text_p.name = "notification_text";
122	text_p.use_ellipses = true;
123	text_p.wrap = true;
124	panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
125
126	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
127	panel_p.auto_resize = false;
128	panel_p.user_resize = false;
129	panel_p.name="form_elements";
130	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0);
131	LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
132	stackp->addChild(form_elements_panel);
133
134	panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
135	panel_p.auto_resize = false;
136	panel_p.user_resize = false;
137	panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0);
138	panel_p.name = "close_panel";
139	LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
140	stackp->addChild(close_panel);
141
142	LLButton::Params button_p;
143	button_p.name = "close_notification";
144	button_p.rect = LLRect(5, 23, 21, 7);
145	button_p.image_color.control="DkGray_66";
146	button_p.image_unselected.name="Icon_Close_Foreground";
147	button_p.image_selected.name="Icon_Close_Press";
148	button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
149
150	close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
151	
152	close_panel->setVisible(params.can_close);
153}
154
155void LLWindowShade::draw()
156{
157	LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
158
159	LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
160
161	notification_area->reshape(notification_area->getRect().getWidth(), 
162		llclamp(message_rect.getHeight() + 15, 
163				llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT),
164				MAX_NOTIFICATION_AREA_HEIGHT));
165
166	LLUICtrl::draw();
167
168	while(!mNotifications.empty() && !mNotifications.back()->isActive())
169	{
170		mNotifications.pop_back();
171		// go ahead and hide 
172		hide();
173	}
174
175	if (mNotifications.empty())
176	{
177		hide();
178	}
179	else if (notification_area->getVisibleAmount() < 0.01f)
180	{
181		displayLatestNotification();
182	}
183
184	if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f))
185	{
186		getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
187		setMouseOpaque(false);
188	}
189}
190
191void LLWindowShade::hide()
192{
193	getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
194}
195
196void LLWindowShade::onCloseNotification()
197{
198	if (!mNotifications.empty())
199		LLNotifications::instance().cancel(mNotifications.back());
200}
201
202void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
203{
204	LLNotificationPtr notify = getCurrentNotification();
205	if (!notify) return;
206
207	bool check = ctrl->getValue().asBoolean();
208	if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
209	{
210		// question was "show again" so invert value to get "ignore"
211		check = !check;
212	}
213	notify->setIgnored(check);
214}
215
216void LLWindowShade::onClickNotificationButton(const std::string& name)
217{
218	LLNotificationPtr notify = getCurrentNotification();
219	if (!notify) return;
220
221	mNotificationResponse[name] = true;
222
223	notify->respond(mNotificationResponse);
224}
225
226void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
227{
228	mNotificationResponse[name] = ctrl->getValue().asString();
229}
230
231void LLWindowShade::show(LLNotificationPtr notification)
232{
233	mNotifications.push_back(notification);
234
235	displayLatestNotification();
236}
237
238void LLWindowShade::displayLatestNotification()
239{
240	if (mNotifications.empty()) return;
241
242	LLNotificationPtr notification = mNotifications.back();
243
244	LLSD payload = notification->getPayload();
245
246	LLNotificationFormPtr formp = notification->getForm();
247	LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area");
248	notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon());
249	notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage());
250	notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage());
251
252	LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType(); 
253	LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");
254	form_elements.deleteAllChildren();
255	form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT);
256
257	const S32 FORM_PADDING_HORIZONTAL = 10;
258	const S32 FORM_PADDING_VERTICAL = 3;
259	const S32 WIDGET_HEIGHT = 24;
260	const S32 LINE_EDITOR_WIDTH = 120;
261	S32 cur_x = FORM_PADDING_HORIZONTAL;
262	S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT;
263	S32 form_width = cur_x;
264
265	if (ignore_type != LLNotificationForm::IGNORE_NO)
266	{
267		LLCheckBoxCtrl::Params checkbox_p;
268		checkbox_p.name = "ignore_check";
269		checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
270		checkbox_p.label = formp->getIgnoreMessage();
271		checkbox_p.label_text.text_color = LLColor4::black;
272		checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1);
273		checkbox_p.initial_value = formp->getIgnored();
274
275		LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
276		check->setRect(check->getBoundingRect());
277		form_elements.addChild(check);
278		cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
279		form_width = llmax(form_width, cur_x);
280	}
281
282	for (S32 i = 0; i < formp->getNumElements(); i++)
283	{
284		LLSD form_element = formp->getElement(i);
285		std::string type = form_element["type"].asString();
286		if (type == "button")
287		{
288			LLButton::Params button_p;
289			button_p.name = form_element["name"];
290			button_p.label = form_element["text"];
291			button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
292			button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString());
293			button_p.auto_resize = true;
294
295			LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
296			button->autoResize();
297			form_elements.addChild(button);
298
299			if (form_element["default"].asBoolean())
300			{
301				form_elements.setDefaultBtn(button);
302			}
303
304			cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
305			form_width = llmax(form_width, cur_x);
306		}
307		else if (type == "text" || type == "password")
308		{
309			// if not at beginning of line...
310			if (cur_x != FORM_PADDING_HORIZONTAL)
311			{
312				// start new line
313				cur_x = FORM_PADDING_HORIZONTAL;
314				cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
315			}
316			LLTextBox::Params label_p;
317			label_p.name = form_element["name"].asString() + "_label";
318			label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
319			label_p.initial_value = form_element["text"];
320			label_p.text_color = mTextColor;
321			label_p.font_valign = LLFontGL::VCENTER;
322			label_p.v_pad = 5;
323			LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
324			textbox->reshapeToFitText();
325			textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL); 
326			form_elements.addChild(textbox);
327			cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
328
329			LLLineEditor::Params line_p;
330			line_p.name = form_element["name"];
331			line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString());
332			line_p.is_password = type == "password";
333			line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
334
335			LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p);
336			form_elements.addChild(line_editor);
337			form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL);
338
339			// reset to start of next line
340			cur_x = FORM_PADDING_HORIZONTAL;
341			cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
342		}
343	}
344
345	mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL);
346	form_elements.reshape(form_width, mFormHeight);
347	form_elements.setMinDim(form_width);
348
349	// move all form elements back onto form surface
350	S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y;
351	for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end();
352		it != end_it;
353		++it)
354	{
355		(*it)->translate(0, delta_y);
356	}
357
358	getChildRef<LLLayoutPanel>("notification_area").setVisible(true);
359	getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);
360
361	setMouseOpaque(mModal);
362}
363
364void LLWindowShade::setBackgroundImage(LLUIImage* image)
365{
366	getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image);
367}
368
369void LLWindowShade::setTextColor(LLColor4 color)
370{
371	getChild<LLTextBox>("notification_text")->setColor(color);
372}
373
374bool LLWindowShade::isShown() const
375{
376	return getChildRef<LLLayoutPanel>("notification_area").getVisible();
377}
378
379void LLWindowShade::setCanClose(bool can_close)
380{
381	getChildView("close_panel")->setVisible(can_close);
382}
383
384LLNotificationPtr LLWindowShade::getCurrentNotification()
385{
386	if (mNotifications.empty())
387	{
388		return LLNotificationPtr();
389	}
390	return mNotifications.back();
391}
392