PageRenderTime 32ms CodeModel.GetById 16ms RepoModel.GetById 0ms 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
Possible License(s): LGPL-2.1
  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. #include "linden_common.h"
  27. #include "llwindowshade.h"
  28. #include "lllayoutstack.h"
  29. #include "lltextbox.h"
  30. #include "lliconctrl.h"
  31. #include "llbutton.h"
  32. #include "llcheckboxctrl.h"
  33. #include "lllineeditor.h"
  34. const S32 MIN_NOTIFICATION_AREA_HEIGHT = 30;
  35. const S32 MAX_NOTIFICATION_AREA_HEIGHT = 100;
  36. static LLDefaultChildRegistry::Register<LLWindowShade> r("window_shade");
  37. LLWindowShade::Params::Params()
  38. : bg_image("bg_image"),
  39. modal("modal", false),
  40. text_color("text_color"),
  41. shade_color("shade_color"),
  42. can_close("can_close", true)
  43. {
  44. changeDefault(mouse_opaque, false);
  45. }
  46. LLWindowShade::LLWindowShade(const LLWindowShade::Params& params)
  47. : LLUICtrl(params),
  48. mModal(params.modal),
  49. mFormHeight(0),
  50. mTextColor(params.text_color)
  51. {
  52. setFocusRoot(true);
  53. }
  54. void LLWindowShade::initFromParams(const LLWindowShade::Params& params)
  55. {
  56. LLUICtrl::initFromParams(params);
  57. LLLayoutStack::Params layout_p;
  58. layout_p.name = "notification_stack";
  59. layout_p.rect = params.rect;
  60. layout_p.follows.flags = FOLLOWS_ALL;
  61. layout_p.mouse_opaque = false;
  62. layout_p.orientation = LLLayoutStack::VERTICAL;
  63. layout_p.border_size = 0;
  64. LLLayoutStack* stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
  65. addChild(stackp);
  66. LLLayoutPanel::Params panel_p;
  67. panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 800, 0);
  68. panel_p.name = "notification_area";
  69. panel_p.visible = false;
  70. panel_p.user_resize = false;
  71. panel_p.background_visible = true;
  72. panel_p.bg_alpha_image = params.bg_image;
  73. panel_p.auto_resize = false;
  74. LLLayoutPanel* notification_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
  75. stackp->addChild(notification_panel);
  76. panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
  77. panel_p.auto_resize = true;
  78. panel_p.user_resize = false;
  79. panel_p.rect = params.rect;
  80. panel_p.name = "background_area";
  81. panel_p.mouse_opaque = false;
  82. panel_p.background_visible = false;
  83. panel_p.bg_alpha_color = params.shade_color;
  84. LLLayoutPanel* dummy_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
  85. stackp->addChild(dummy_panel);
  86. layout_p = LLUICtrlFactory::getDefaultParams<LLLayoutStack>();
  87. layout_p.rect = LLRect(0, 30, 800, 0);
  88. layout_p.follows.flags = FOLLOWS_ALL;
  89. layout_p.orientation = LLLayoutStack::HORIZONTAL;
  90. stackp = LLUICtrlFactory::create<LLLayoutStack>(layout_p);
  91. notification_panel->addChild(stackp);
  92. panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
  93. panel_p.rect.height = 30;
  94. LLLayoutPanel* panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
  95. stackp->addChild(panel);
  96. LLIconCtrl::Params icon_p;
  97. icon_p.name = "notification_icon";
  98. icon_p.rect = LLRect(5, 25, 21, 10);
  99. panel->addChild(LLUICtrlFactory::create<LLIconCtrl>(icon_p));
  100. LLTextBox::Params text_p;
  101. text_p.rect = LLRect(31, 23, panel->getRect().getWidth() - 5, 3);
  102. text_p.follows.flags = FOLLOWS_ALL;
  103. text_p.text_color = mTextColor;
  104. text_p.font = LLFontGL::getFontSansSerifSmall();
  105. text_p.font.style = "BOLD";
  106. text_p.name = "notification_text";
  107. text_p.use_ellipses = true;
  108. text_p.wrap = true;
  109. panel->addChild(LLUICtrlFactory::create<LLTextBox>(text_p));
  110. panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
  111. panel_p.auto_resize = false;
  112. panel_p.user_resize = false;
  113. panel_p.name="form_elements";
  114. panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 130, 0);
  115. LLLayoutPanel* form_elements_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
  116. stackp->addChild(form_elements_panel);
  117. panel_p = LLUICtrlFactory::getDefaultParams<LLLayoutPanel>();
  118. panel_p.auto_resize = false;
  119. panel_p.user_resize = false;
  120. panel_p.rect = LLRect(0, MIN_NOTIFICATION_AREA_HEIGHT, 25, 0);
  121. panel_p.name = "close_panel";
  122. LLLayoutPanel* close_panel = LLUICtrlFactory::create<LLLayoutPanel>(panel_p);
  123. stackp->addChild(close_panel);
  124. LLButton::Params button_p;
  125. button_p.name = "close_notification";
  126. button_p.rect = LLRect(5, 23, 21, 7);
  127. button_p.image_color.control="DkGray_66";
  128. button_p.image_unselected.name="Icon_Close_Foreground";
  129. button_p.image_selected.name="Icon_Close_Press";
  130. button_p.click_callback.function = boost::bind(&LLWindowShade::onCloseNotification, this);
  131. close_panel->addChild(LLUICtrlFactory::create<LLButton>(button_p));
  132. close_panel->setVisible(params.can_close);
  133. }
  134. void LLWindowShade::draw()
  135. {
  136. LLRect message_rect = getChild<LLTextBox>("notification_text")->getTextBoundingRect();
  137. LLLayoutPanel* notification_area = getChild<LLLayoutPanel>("notification_area");
  138. notification_area->reshape(notification_area->getRect().getWidth(),
  139. llclamp(message_rect.getHeight() + 15,
  140. llmax(mFormHeight, MIN_NOTIFICATION_AREA_HEIGHT),
  141. MAX_NOTIFICATION_AREA_HEIGHT));
  142. LLUICtrl::draw();
  143. while(!mNotifications.empty() && !mNotifications.back()->isActive())
  144. {
  145. mNotifications.pop_back();
  146. // go ahead and hide
  147. hide();
  148. }
  149. if (mNotifications.empty())
  150. {
  151. hide();
  152. }
  153. else if (notification_area->getVisibleAmount() < 0.01f)
  154. {
  155. displayLatestNotification();
  156. }
  157. if (!notification_area->getVisible() && (notification_area->getVisibleAmount() < 0.001f))
  158. {
  159. getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(false);
  160. setMouseOpaque(false);
  161. }
  162. }
  163. void LLWindowShade::hide()
  164. {
  165. getChildRef<LLLayoutPanel>("notification_area").setVisible(false);
  166. }
  167. void LLWindowShade::onCloseNotification()
  168. {
  169. if (!mNotifications.empty())
  170. LLNotifications::instance().cancel(mNotifications.back());
  171. }
  172. void LLWindowShade::onClickIgnore(LLUICtrl* ctrl)
  173. {
  174. LLNotificationPtr notify = getCurrentNotification();
  175. if (!notify) return;
  176. bool check = ctrl->getValue().asBoolean();
  177. if (notify->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
  178. {
  179. // question was "show again" so invert value to get "ignore"
  180. check = !check;
  181. }
  182. notify->setIgnored(check);
  183. }
  184. void LLWindowShade::onClickNotificationButton(const std::string& name)
  185. {
  186. LLNotificationPtr notify = getCurrentNotification();
  187. if (!notify) return;
  188. mNotificationResponse[name] = true;
  189. notify->respond(mNotificationResponse);
  190. }
  191. void LLWindowShade::onEnterNotificationText(LLUICtrl* ctrl, const std::string& name)
  192. {
  193. mNotificationResponse[name] = ctrl->getValue().asString();
  194. }
  195. void LLWindowShade::show(LLNotificationPtr notification)
  196. {
  197. mNotifications.push_back(notification);
  198. displayLatestNotification();
  199. }
  200. void LLWindowShade::displayLatestNotification()
  201. {
  202. if (mNotifications.empty()) return;
  203. LLNotificationPtr notification = mNotifications.back();
  204. LLSD payload = notification->getPayload();
  205. LLNotificationFormPtr formp = notification->getForm();
  206. LLLayoutPanel& notification_area = getChildRef<LLLayoutPanel>("notification_area");
  207. notification_area.getChild<LLUICtrl>("notification_icon")->setValue(notification->getIcon());
  208. notification_area.getChild<LLUICtrl>("notification_text")->setValue(notification->getMessage());
  209. notification_area.getChild<LLUICtrl>("notification_text")->setToolTip(notification->getMessage());
  210. LLNotificationForm::EIgnoreType ignore_type = formp->getIgnoreType();
  211. LLLayoutPanel& form_elements = notification_area.getChildRef<LLLayoutPanel>("form_elements");
  212. form_elements.deleteAllChildren();
  213. form_elements.reshape(form_elements.getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT);
  214. const S32 FORM_PADDING_HORIZONTAL = 10;
  215. const S32 FORM_PADDING_VERTICAL = 3;
  216. const S32 WIDGET_HEIGHT = 24;
  217. const S32 LINE_EDITOR_WIDTH = 120;
  218. S32 cur_x = FORM_PADDING_HORIZONTAL;
  219. S32 cur_y = FORM_PADDING_VERTICAL + WIDGET_HEIGHT;
  220. S32 form_width = cur_x;
  221. if (ignore_type != LLNotificationForm::IGNORE_NO)
  222. {
  223. LLCheckBoxCtrl::Params checkbox_p;
  224. checkbox_p.name = "ignore_check";
  225. checkbox_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
  226. checkbox_p.label = formp->getIgnoreMessage();
  227. checkbox_p.label_text.text_color = LLColor4::black;
  228. checkbox_p.commit_callback.function = boost::bind(&LLWindowShade::onClickIgnore, this, _1);
  229. checkbox_p.initial_value = formp->getIgnored();
  230. LLCheckBoxCtrl* check = LLUICtrlFactory::create<LLCheckBoxCtrl>(checkbox_p);
  231. check->setRect(check->getBoundingRect());
  232. form_elements.addChild(check);
  233. cur_x = check->getRect().mRight + FORM_PADDING_HORIZONTAL;
  234. form_width = llmax(form_width, cur_x);
  235. }
  236. for (S32 i = 0; i < formp->getNumElements(); i++)
  237. {
  238. LLSD form_element = formp->getElement(i);
  239. std::string type = form_element["type"].asString();
  240. if (type == "button")
  241. {
  242. LLButton::Params button_p;
  243. button_p.name = form_element["name"];
  244. button_p.label = form_element["text"];
  245. button_p.rect = LLRect(cur_x, cur_y, cur_x, cur_y - WIDGET_HEIGHT);
  246. button_p.click_callback.function = boost::bind(&LLWindowShade::onClickNotificationButton, this, form_element["name"].asString());
  247. button_p.auto_resize = true;
  248. LLButton* button = LLUICtrlFactory::create<LLButton>(button_p);
  249. button->autoResize();
  250. form_elements.addChild(button);
  251. if (form_element["default"].asBoolean())
  252. {
  253. form_elements.setDefaultBtn(button);
  254. }
  255. cur_x = button->getRect().mRight + FORM_PADDING_HORIZONTAL;
  256. form_width = llmax(form_width, cur_x);
  257. }
  258. else if (type == "text" || type == "password")
  259. {
  260. // if not at beginning of line...
  261. if (cur_x != FORM_PADDING_HORIZONTAL)
  262. {
  263. // start new line
  264. cur_x = FORM_PADDING_HORIZONTAL;
  265. cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
  266. }
  267. LLTextBox::Params label_p;
  268. label_p.name = form_element["name"].asString() + "_label";
  269. label_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
  270. label_p.initial_value = form_element["text"];
  271. label_p.text_color = mTextColor;
  272. label_p.font_valign = LLFontGL::VCENTER;
  273. label_p.v_pad = 5;
  274. LLTextBox* textbox = LLUICtrlFactory::create<LLTextBox>(label_p);
  275. textbox->reshapeToFitText();
  276. textbox->reshape(textbox->getRect().getWidth(), MIN_NOTIFICATION_AREA_HEIGHT - 2 * FORM_PADDING_VERTICAL);
  277. form_elements.addChild(textbox);
  278. cur_x = textbox->getRect().mRight + FORM_PADDING_HORIZONTAL;
  279. LLLineEditor::Params line_p;
  280. line_p.name = form_element["name"];
  281. line_p.keystroke_callback = boost::bind(&LLWindowShade::onEnterNotificationText, this, _1, form_element["name"].asString());
  282. line_p.is_password = type == "password";
  283. line_p.rect = LLRect(cur_x, cur_y, cur_x + LINE_EDITOR_WIDTH, cur_y - WIDGET_HEIGHT);
  284. LLLineEditor* line_editor = LLUICtrlFactory::create<LLLineEditor>(line_p);
  285. form_elements.addChild(line_editor);
  286. form_width = llmax(form_width, cur_x + LINE_EDITOR_WIDTH + FORM_PADDING_HORIZONTAL);
  287. // reset to start of next line
  288. cur_x = FORM_PADDING_HORIZONTAL;
  289. cur_y -= WIDGET_HEIGHT + FORM_PADDING_VERTICAL;
  290. }
  291. }
  292. mFormHeight = form_elements.getRect().getHeight() - (cur_y - WIDGET_HEIGHT - FORM_PADDING_VERTICAL);
  293. form_elements.reshape(form_width, mFormHeight);
  294. form_elements.setMinDim(form_width);
  295. // move all form elements back onto form surface
  296. S32 delta_y = WIDGET_HEIGHT + FORM_PADDING_VERTICAL - cur_y;
  297. for (child_list_const_iter_t it = form_elements.getChildList()->begin(), end_it = form_elements.getChildList()->end();
  298. it != end_it;
  299. ++it)
  300. {
  301. (*it)->translate(0, delta_y);
  302. }
  303. getChildRef<LLLayoutPanel>("notification_area").setVisible(true);
  304. getChildRef<LLLayoutPanel>("background_area").setBackgroundVisible(mModal);
  305. setMouseOpaque(mModal);
  306. }
  307. void LLWindowShade::setBackgroundImage(LLUIImage* image)
  308. {
  309. getChild<LLLayoutPanel>("notification_area")->setTransparentImage(image);
  310. }
  311. void LLWindowShade::setTextColor(LLColor4 color)
  312. {
  313. getChild<LLTextBox>("notification_text")->setColor(color);
  314. }
  315. bool LLWindowShade::isShown() const
  316. {
  317. return getChildRef<LLLayoutPanel>("notification_area").getVisible();
  318. }
  319. void LLWindowShade::setCanClose(bool can_close)
  320. {
  321. getChildView("close_panel")->setVisible(can_close);
  322. }
  323. LLNotificationPtr LLWindowShade::getCurrentNotification()
  324. {
  325. if (mNotifications.empty())
  326. {
  327. return LLNotificationPtr();
  328. }
  329. return mNotifications.back();
  330. }