lltoastnotifypanel.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:12k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file lltoastnotifypanel.cpp
  3.  * @brief Panel for notify toasts.
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "lltoastnotifypanel.h"
  34. // project includes
  35. #include "llviewercontrol.h"
  36. // library includes
  37. #include "lldbstrings.h"
  38. #include "llnotifications.h"
  39. #include "lluiconstants.h"
  40. #include "llrect.h"
  41. #include "lltrans.h"
  42. #include "llnotificationsutil.h"
  43. const S32 BOTTOM_PAD = VPAD * 3;
  44. const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding
  45. S32 BUTTON_WIDTH = 90;
  46. //static
  47. const LLFontGL* LLToastNotifyPanel::sFont = NULL;
  48. const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL;
  49. LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : 
  50. LLToastPanel(notification),
  51. mTextBox(NULL),
  52. mInfoPanel(NULL),
  53. mControlPanel(NULL),
  54. mNumOptions(0),
  55. mNumButtons(0),
  56. mAddedDefaultBtn(false)
  57. {
  58. LLUICtrlFactory::getInstance()->buildPanel(this, "panel_notification.xml");
  59. mInfoPanel = getChild<LLPanel>("info_panel");
  60. mControlPanel = getChild<LLPanel>("control_panel");
  61. BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth");
  62. // customize panel's attributes
  63. // is it intended for displaying a tip
  64. mIsTip = notification->getType() == "notifytip";
  65. // is it a script dialog
  66. mIsScriptDialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup");
  67. // is it a caution
  68. //
  69. // caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the
  70. // notify xml template specifies that it is a caution
  71. // tip-style notification handle 'caution' differently -they display the tip in a different color
  72. mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH;
  73. // setup parameters
  74. // get a notification message
  75. mMessage = notification->getMessage();
  76. // init font variables
  77. if (!sFont)
  78. {
  79. sFont = LLFontGL::getFontSansSerif();
  80. sFontSmall = LLFontGL::getFontSansSerifSmall();
  81. }
  82. // clicking on a button does not steal current focus
  83. setIsChrome(TRUE);
  84. // initialize
  85. setFocusRoot(!mIsTip);
  86. // get a form for the notification
  87. LLNotificationFormPtr form(notification->getForm());
  88. // get number of elements
  89. mNumOptions = form->getNumElements();
  90. // customize panel's outfit
  91. // preliminary adjust panel's layout
  92. //move to the end 
  93. //mIsTip ? adjustPanelForTipNotice() : adjustPanelForScriptNotice(form);
  94. // adjust text options according to the notification type
  95. // add a caution textbox at the top of a caution notification
  96. if (mIsCaution && !mIsTip)
  97. {
  98. mTextBox = getChild<LLTextBox>("caution_text_box");
  99. }
  100. else
  101. {
  102. mTextBox = getChild<LLTextEditor>("text_editor_box"); 
  103. }
  104. // *TODO: magic numbers(???) - copied from llnotify.cpp(250)
  105. const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; 
  106. mTextBox->setMaxTextLength(MAX_LENGTH);
  107. mTextBox->setVisible(TRUE);
  108. mTextBox->setValue(notification->getMessage());
  109. // add buttons for a script notification
  110. if (mIsTip)
  111. {
  112. adjustPanelForTipNotice();
  113. }
  114. else
  115. {
  116. std::vector<index_button_pair_t> buttons;
  117. buttons.reserve(mNumOptions);
  118. S32 buttons_width = 0;
  119. // create all buttons and accumulate they total width to reshape mControlPanel
  120. for (S32 i = 0; i < mNumOptions; i++)
  121. {
  122. LLSD form_element = form->getElement(i);
  123. if (form_element["type"].asString() != "button")
  124. {
  125. continue;
  126. }
  127. LLButton* new_button = createButton(form_element, TRUE);
  128. buttons_width += new_button->getRect().getWidth();
  129. S32 index = form_element["index"].asInteger();
  130. buttons.push_back(index_button_pair_t(index,new_button));
  131. }
  132. if (buttons.empty())
  133. {
  134. addDefaultButton();
  135. }
  136. else
  137. {
  138. const S32 button_panel_width = mControlPanel->getRect().getWidth();// do not change width of the panel
  139. S32 button_panel_height = mControlPanel->getRect().getHeight();
  140. //try get an average h_pad to spread out buttons
  141. S32 h_pad = (button_panel_width - buttons_width) / (S32(buttons.size()));
  142. if(h_pad < 2*HPAD)
  143. {
  144. /*
  145.  * Probably it is  a scriptdialog toast
  146.  * for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons.
  147.  * In last case set default h_pad to avoid heaping of buttons 
  148.  */
  149. h_pad = 2*HPAD;
  150. }
  151. if (mIsScriptDialog)
  152. {
  153. // we are using default width for script buttons so we can determinate button_rows
  154. //to get a number of rows we divide the required width of the buttons to button_panel_width
  155. S32 button_rows = llceil(F32(buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width);
  156. //S32 button_rows = (buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width;
  157. //reserve one row for the ignore_btn
  158. button_rows++;
  159. //calculate required panel height for scripdialog notification.
  160. button_panel_height = button_rows * (BTN_HEIGHT + VPAD) + IGNORE_BTN_TOP_DELTA + BOTTOM_PAD;
  161. }
  162. else
  163. {
  164. // in common case buttons can have different widths so we need to calculate button_rows according to buttons_width
  165. //S32 button_rows = llceil(F32(buttons.size()) * (buttons_width + h_pad) / button_panel_width);
  166. S32 button_rows = llceil(F32((buttons.size() - 1) * h_pad + buttons_width) / button_panel_width);
  167. //calculate required panel height 
  168. button_panel_height = button_rows * (BTN_HEIGHT + VPAD) + BOTTOM_PAD;
  169. }
  170. // we need to keep min width and max height to make visible all buttons, because width of the toast can not be changed
  171. adjustPanelForScriptNotice(button_panel_width, button_panel_height);
  172. updateButtonsLayout(buttons, h_pad);
  173. }
  174. }
  175. // adjust panel's height to the text size
  176. mInfoPanel->setFollowsAll();
  177. snapToMessageHeight(mTextBox, MAX_LENGTH);
  178. }
  179. void LLToastNotifyPanel::addDefaultButton()
  180. {
  181. LLSD form_element;
  182. form_element.with("name", "OK").with("text", LLTrans::getString("ok")).with("default", true);
  183. LLButton* ok_btn = createButton(form_element, FALSE);
  184. LLRect new_btn_rect(ok_btn->getRect());
  185. new_btn_rect.setOriginAndSize(llabs(getRect().getWidth() - BUTTON_WIDTH)/ 2, BOTTOM_PAD,
  186. //auto_size for ok button makes it very small, so let's make it wider
  187. BUTTON_WIDTH, new_btn_rect.getHeight());
  188. ok_btn->setRect(new_btn_rect);
  189. addChild(ok_btn, -1);
  190. mNumButtons = 1;
  191. mAddedDefaultBtn = true;
  192. }
  193. LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_option)
  194. {
  195. InstanceAndS32* userdata = new InstanceAndS32;
  196. userdata->mSelf = this;
  197. userdata->mButtonName = is_option ? form_element["name"].asString() : "";
  198. mBtnCallbackData.push_back(userdata);
  199. LLButton::Params p;
  200. bool is_ignore_btn = form_element["index"].asInteger() == -1;
  201. const LLFontGL* font = is_ignore_btn ? sFontSmall: sFont; // for ignore button in script dialog
  202. p.name(form_element["name"].asString());
  203. p.label(form_element["text"].asString());
  204. p.font(font);
  205. p.rect.height = BTN_HEIGHT;
  206. p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata));
  207. p.rect.width = BUTTON_WIDTH;
  208. p.auto_resize = false;
  209. p.follows.flags(FOLLOWS_RIGHT | FOLLOWS_LEFT | FOLLOWS_BOTTOM);
  210. if (mIsCaution)
  211. {
  212. p.image_color(LLUIColorTable::instance().getColor("ButtonCautionImageColor"));
  213. p.image_color_disabled(LLUIColorTable::instance().getColor("ButtonCautionImageColor"));
  214. }
  215. // for the scriptdialog buttons we use fixed button size. This  is a limit!
  216. if (!mIsScriptDialog && font->getWidth(form_element["text"].asString()) > BUTTON_WIDTH)
  217. {
  218. p.rect.width = 1;
  219. p.auto_resize = true;
  220. }
  221. else if (mIsScriptDialog && is_ignore_btn)
  222. {
  223. // this is ignore button,make it smaller
  224. p.rect.height = BTN_HEIGHT_SMALL;
  225. p.rect.width = 1;
  226. p.auto_resize = true;
  227. }
  228. LLButton* btn = LLUICtrlFactory::create<LLButton>(p);
  229. mNumButtons++;
  230. btn->autoResize();
  231. if (form_element["default"].asBoolean())
  232. {
  233. setDefaultBtn(btn);
  234. }
  235. return btn;
  236. }
  237. LLToastNotifyPanel::~LLToastNotifyPanel() 
  238. {
  239. std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer());
  240. if (LLNotificationsUtil::find(mNotification->getID()) != NULL)
  241. {
  242. LLNotifications::getInstance()->cancel(mNotification);
  243. }
  244. }
  245. void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair_t>& buttons, S32 h_pad)
  246. {
  247. S32 left = 0;
  248. //reserve place for ignore button
  249. S32 bottom_offset = mIsScriptDialog ? (BTN_HEIGHT + IGNORE_BTN_TOP_DELTA + BOTTOM_PAD) : BOTTOM_PAD;
  250. S32 max_width = mControlPanel->getRect().getWidth();
  251. LLButton* ignore_btn = NULL;
  252. for (std::vector<index_button_pair_t>::const_iterator it = buttons.begin(); it != buttons.end(); it++)
  253. {
  254. if (it->first == -1)
  255. {
  256. ignore_btn = it->second;
  257. continue;
  258. }
  259. LLButton* btn = it->second;
  260. LLRect btn_rect(btn->getRect());
  261. if (left + btn_rect.getWidth() > max_width)// whether there is still some place for button+h_pad in the mControlPanel
  262. {
  263. // looks like we need to add button to the next row
  264. left = 0;
  265. bottom_offset += (BTN_HEIGHT + VPAD);
  266. }
  267. //we arrange buttons from bottom to top for backward support of old script
  268. btn_rect.setOriginAndSize(left, bottom_offset, btn_rect.getWidth(), btn_rect.getHeight());
  269. btn->setRect(btn_rect);
  270. left = btn_rect.mLeft + btn_rect.getWidth() + h_pad;
  271. mControlPanel->addChild(btn, -1);
  272. }
  273. if (mIsScriptDialog && ignore_btn != NULL)
  274. {
  275. LLRect ignore_btn_rect(ignore_btn->getRect());
  276. S32 buttons_per_row = max_width / BUTTON_WIDTH; //assume that h_pad far less than BUTTON_WIDTH
  277. S32 ignore_btn_left = buttons_per_row * BUTTON_WIDTH + (buttons_per_row - 1) * h_pad - ignore_btn_rect.getWidth();
  278. if (ignore_btn_left + ignore_btn_rect.getWidth() > max_width)// make sure that the ignore button is in panel
  279. {
  280. ignore_btn_left = max_width - ignore_btn_rect.getWidth() - 2 * HPAD;
  281. }
  282. ignore_btn_rect.setOriginAndSize(ignore_btn_left, BOTTOM_PAD,// always move ignore button at the bottom
  283. ignore_btn_rect.getWidth(), ignore_btn_rect.getHeight());
  284. ignore_btn->setRect(ignore_btn_rect);
  285. mControlPanel->addChild(ignore_btn, -1);
  286. }
  287. }
  288. void LLToastNotifyPanel::adjustPanelForScriptNotice(S32 button_panel_width, S32 button_panel_height)
  289. {
  290. //adjust layout
  291. // we need to keep min width and max height to make visible all buttons, because width of the toast can not be changed
  292. reshape(getRect().getWidth(), mInfoPanel->getRect().getHeight() + button_panel_height + VPAD);
  293. mControlPanel->reshape( button_panel_width, button_panel_height);
  294. }
  295. void LLToastNotifyPanel::adjustPanelForTipNotice()
  296. {
  297. LLRect info_rect = mInfoPanel->getRect();
  298. LLRect this_rect = getRect();
  299. //we don't need display ControlPanel for tips because they doesn't contain any buttons. 
  300. mControlPanel->setVisible(FALSE);
  301. reshape(getRect().getWidth(), mInfoPanel->getRect().getHeight());
  302. if (mNotification->getPayload().has("respond_on_mousedown")
  303. && mNotification->getPayload()["respond_on_mousedown"] )
  304. {
  305. mInfoPanel->setMouseDownCallback(
  306. boost::bind(&LLNotification::respond,
  307. mNotification,
  308. mNotification->getResponseTemplate()));
  309. }
  310. }
  311. // static
  312. void LLToastNotifyPanel::onClickButton(void* data)
  313. {
  314. InstanceAndS32* self_and_button = (InstanceAndS32*)data;
  315. LLToastNotifyPanel* self = self_and_button->mSelf;
  316. std::string button_name = self_and_button->mButtonName;
  317. LLSD response = self->mNotification->getResponseTemplate();
  318. if (!self->mAddedDefaultBtn && !button_name.empty())
  319. {
  320. response[button_name] = true;
  321. }
  322. self->mNotification->respond(response);
  323. // disable all buttons
  324. self->mControlPanel->setEnabled(FALSE);
  325. }