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

游戏引擎

开发平台:

C++ Builder

  1. /**
  2.  * @file lltoastalertpanel.cpp
  3.  * @brief Panel for alert 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" // must be first include
  33. #include "linden_common.h"
  34. #include "llboost.h"
  35. #include "lltoastalertpanel.h"
  36. #include "llfontgl.h"
  37. #include "lltextbox.h"
  38. #include "llbutton.h"
  39. #include "llcheckboxctrl.h"
  40. #include "llkeyboard.h"
  41. #include "llfocusmgr.h"
  42. #include "lliconctrl.h"
  43. #include "llui.h"
  44. #include "lllineeditor.h"
  45. #include "lluictrlfactory.h"
  46. #include "llnotifications.h"
  47. #include "llfunctorregistry.h"
  48. #include "llrootview.h"
  49. const S32 MAX_ALLOWED_MSG_WIDTH = 400;
  50. const F32 DEFAULT_BUTTON_DELAY = 0.5f;
  51. const S32 MSG_PAD = 8;
  52. /*static*/ LLControlGroup* LLToastAlertPanel::sSettings = NULL;
  53. /*static*/ LLToastAlertPanel::URLLoader* LLToastAlertPanel::sURLLoader;
  54. //-----------------------------------------------------------------------------
  55. // Private methods
  56. static const S32 VPAD = 16;
  57. static const S32 HPAD = 25;
  58. static const S32 BTN_HPAD = 8;
  59. LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal)
  60.   : LLToastPanel(notification),
  61. mDefaultOption( 0 ),
  62. mCheck(NULL),
  63. mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH),
  64. mLabel(notification->getName()),
  65. mLineEditor(NULL)
  66. {
  67. const LLFontGL* font = LLFontGL::getFontSansSerif();
  68. const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f);
  69. const S32 EDITOR_HEIGHT = 20;
  70. LLNotificationFormPtr form = mNotification->getForm();
  71. std::string edit_text_name;
  72. std::string edit_text_contents;
  73. bool is_password = false;
  74. LLToastPanel::setBackgroundVisible(FALSE);
  75. LLToastPanel::setBackgroundOpaque(TRUE);
  76. typedef std::vector<std::pair<std::string, std::string> > options_t;
  77. options_t supplied_options;
  78. // for now, get LLSD to iterator over form elements
  79. LLSD form_sd = form->asLLSD();
  80. S32 option_index = 0;
  81. for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it)
  82. {
  83. std::string type = (*it)["type"].asString();
  84. if (type == "button")
  85. {
  86. if((*it)["default"])
  87. {
  88. mDefaultOption = option_index;
  89. }
  90. supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString()));
  91. ButtonData data;
  92. if (option_index == mNotification->getURLOption())
  93. {
  94. data.mURL = mNotification->getURL();
  95. data.mURLExternal = mNotification->getURLOpenExternally();
  96. }
  97. mButtonData.push_back(data);
  98. option_index++;
  99. }
  100. else if (type == "text")
  101. {
  102. edit_text_contents = (*it)["value"].asString();
  103. edit_text_name = (*it)["name"].asString();
  104. }
  105. else if (type == "password")
  106. {
  107. edit_text_contents = (*it)["value"].asString();
  108. edit_text_name = (*it)["name"].asString();
  109. is_password = true;
  110. }
  111. }
  112. // Buttons
  113. options_t options;
  114. if (supplied_options.empty())
  115. {
  116. options.push_back(std::make_pair(std::string("close"), LLNotifications::instance().getGlobalString("implicitclosebutton")));
  117. // add data for ok button.
  118. ButtonData ok_button;
  119. mButtonData.push_back(ok_button);
  120. mDefaultOption = 0;
  121. }
  122. else
  123. {
  124. options = supplied_options;
  125. }
  126. S32 num_options = options.size();
  127. // Calc total width of buttons
  128. S32 button_width = 0;
  129. S32 sp = font->getWidth(std::string("OO"));
  130. for( S32 i = 0; i < num_options; i++ )
  131. {
  132. S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD;
  133. button_width = llmax( w, button_width );
  134. }
  135. S32 btn_total_width = button_width;
  136. if( num_options > 1 )
  137. {
  138. btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD);
  139. }
  140. // Message: create text box using raw string, as text has been structure deliberately
  141. // Use size of created text box to generate dialog box size
  142. std::string msg = mNotification->getMessage();
  143. llwarns << "Alert: " << msg << llendl;
  144. LLTextBox::Params params;
  145. params.name("Alert message");
  146. params.font(font);
  147. params.tab_stop(false);
  148. params.wrap(true);
  149. params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
  150. LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params);
  151. // Compute max allowable height for the dialog text, so we can allocate
  152. // space before wrapping the text to fit.
  153. S32 max_allowed_msg_height = 
  154. gFloaterView->getRect().getHeight()
  155. - LINE_HEIGHT // title bar
  156. - 3*VPAD - BTN_HEIGHT;
  157. msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height );
  158. msg_box->setValue(msg);
  159. msg_box->reshapeToFitText();
  160. const LLRect& text_rect = msg_box->getRect();
  161. S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD;
  162. S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT;
  163. if (hasTitleBar())
  164. {
  165. dialog_height += LINE_HEIGHT; // room for title bar
  166. }
  167. // it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it
  168. if (!edit_text_name.empty())
  169. {
  170. dialog_height += EDITOR_HEIGHT + VPAD;
  171. dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f));
  172. }
  173. if (mCaution)
  174. {
  175. // Make room for the caution icon.
  176. dialog_width += 32 + HPAD;
  177. }
  178. LLToastPanel::reshape( dialog_width, dialog_height, FALSE );
  179. S32 msg_y = LLToastPanel::getRect().getHeight() - VPAD;
  180. S32 msg_x = HPAD;
  181. if (hasTitleBar())
  182. {
  183. msg_y -= LINE_HEIGHT; // room for title
  184. }
  185. static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor");
  186. static LLUIColor alert_text_color = LLUIColorTable::instance().getColor("AlertTextColor");
  187. if (mCaution)
  188. {
  189. LLIconCtrl* icon = LLUICtrlFactory::getInstance()->createFromFile<LLIconCtrl>("alert_icon.xml", this, LLPanel::child_registry_t::instance());
  190. if(icon)
  191. {
  192. icon->setRect(LLRect(msg_x, msg_y, msg_x+32, msg_y-32));
  193. LLToastPanel::addChild(icon);
  194. }
  195. msg_x += 32 + HPAD;
  196. msg_box->setColor( alert_caution_text_color );
  197. }
  198. else
  199. {
  200. msg_box->setColor( alert_text_color );
  201. }
  202. LLRect rect;
  203. rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() );
  204. msg_box->setRect( rect );
  205. LLToastPanel::addChild(msg_box);
  206. // Buttons
  207. S32 button_left = (LLToastPanel::getRect().getWidth() - btn_total_width) / 2;
  208. for( S32 i = 0; i < num_options; i++ )
  209. {
  210. LLRect button_rect;
  211. LLButton* btn = LLUICtrlFactory::getInstance()->createFromFile<LLButton>("alert_button.xml", this, LLPanel::child_registry_t::instance());
  212. if(btn)
  213. {
  214. btn->setName(options[i].first);
  215. btn->setRect(button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ));
  216. btn->setLabel(options[i].second);
  217. btn->setFont(font);
  218. btn->setClickedCallback(boost::bind(&LLToastAlertPanel::onButtonPressed, this, _2, i));
  219. mButtonData[i].mButton = btn;
  220. LLToastPanel::addChild(btn);
  221. if( i == mDefaultOption )
  222. {
  223. btn->setFocus(TRUE);
  224. }
  225. }
  226. button_left += button_width + BTN_HPAD;
  227. }
  228. // (Optional) Edit Box
  229. if (!edit_text_name.empty())
  230. {
  231. S32 y = VPAD + BTN_HEIGHT + VPAD/2;
  232. mLineEditor = LLUICtrlFactory::getInstance()->createFromFile<LLLineEditor>("alert_line_editor.xml", this, LLPanel::child_registry_t::instance());
  233. if (mLineEditor)
  234. {
  235. LLRect leditor_rect = LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y);
  236. mLineEditor->setName(edit_text_name);
  237. mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight());
  238. mLineEditor->setRect(leditor_rect);
  239. mLineEditor->setText(edit_text_contents);
  240. mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1);
  241. // make sure all edit keys get handled properly (DEV-22396)
  242. mLineEditor->setHandleEditKeysDirectly(TRUE);
  243. LLToastPanel::addChild(mLineEditor);
  244. mLineEditor->setDrawAsterixes(is_password);
  245. setEditTextArgs(notification->getSubstitutions());
  246. }
  247. }
  248. std::string ignore_label;
  249. if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)
  250. {
  251. setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label);
  252. }
  253. else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
  254. {
  255. setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label);
  256. }
  257. // *TODO: check necessity of this code
  258. //gFloaterView->adjustToFitScreen(this, FALSE);
  259. if (mLineEditor)
  260. {
  261. mLineEditor->selectAll();
  262. }
  263. if(mDefaultOption >= 0)
  264. {
  265. // delay before enabling default button
  266. mDefaultBtnTimer.start();
  267. mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY);
  268. }
  269. }
  270. bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control )
  271. {
  272. mCheck = LLUICtrlFactory::getInstance()->createFromFile<LLCheckBoxCtrl>("alert_check_box.xml", this, LLPanel::child_registry_t::instance());
  273. if(!mCheck)
  274. {
  275. return false;
  276. }
  277. const LLFontGL* font =  mCheck->getFont();
  278. const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f);
  279. // Extend dialog for "check next time"
  280. S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD;
  281. S32 check_width = S32(font->getWidth(check_title) + 0.99f) + 16;
  282. max_msg_width = llmax(max_msg_width, check_width);
  283. S32 dialog_width = max_msg_width + 2 * HPAD;
  284. S32 dialog_height = LLToastPanel::getRect().getHeight();
  285. dialog_height += LINE_HEIGHT;
  286. dialog_height += LINE_HEIGHT / 2;
  287. LLToastPanel::reshape( dialog_width, dialog_height, FALSE );
  288. S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2;
  289. // set check_box's attributes
  290. LLRect check_rect;
  291. mCheck->setRect(check_rect.setOriginAndSize(msg_x, VPAD+BTN_HEIGHT+LINE_HEIGHT/2, max_msg_width, LINE_HEIGHT));
  292. mCheck->setLabel(check_title);
  293. mCheck->setCommitCallback(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1));
  294. LLToastPanel::addChild(mCheck);
  295. return true;
  296. }
  297. void LLToastAlertPanel::setVisible( BOOL visible )
  298. {
  299. // only make the "ding" sound if it's newly visible
  300. if( visible && !LLToastPanel::getVisible() )
  301. {
  302. make_ui_sound("UISndAlert");
  303. }
  304. LLToastPanel::setVisible( visible );
  305. }
  306. LLToastAlertPanel::~LLToastAlertPanel()
  307. {
  308. }
  309. BOOL LLToastAlertPanel::hasTitleBar() const
  310. {
  311. // *TODO: check necessity of this code
  312. /*
  313. return (getCurrentTitle() != "" && getCurrentTitle() != " ") // has title
  314. || isMinimizeable()
  315. || isCloseable();
  316. */
  317. return false;
  318. }
  319. BOOL LLToastAlertPanel::handleKeyHere(KEY key, MASK mask )
  320. {
  321. if( KEY_RETURN == key && mask == MASK_NONE )
  322. {
  323. LLButton* defaultBtn = getDefaultButton();
  324. if(defaultBtn && defaultBtn->getVisible() && defaultBtn->getEnabled())
  325. {
  326. // If we have a default button, click it when return is pressed
  327. defaultBtn->onCommit();
  328. }
  329. return TRUE;
  330. }
  331. else if (KEY_RIGHT == key)
  332. {
  333. LLToastPanel::focusNextItem(FALSE);
  334. return TRUE;
  335. }
  336. else if (KEY_LEFT == key)
  337. {
  338. LLToastPanel::focusPrevItem(FALSE);
  339. return TRUE;
  340. }
  341. else if (KEY_TAB == key && mask == MASK_NONE)
  342. {
  343. LLToastPanel::focusNextItem(FALSE);
  344. return TRUE;
  345. }
  346. else if (KEY_TAB == key && mask == MASK_SHIFT)
  347. {
  348. LLToastPanel::focusPrevItem(FALSE);
  349. return TRUE;
  350. }
  351. else
  352. {
  353. return TRUE;
  354. }
  355. }
  356. // virtual
  357. void LLToastAlertPanel::draw()
  358. {
  359. // if the default button timer has just expired, activate the default button
  360. if(mDefaultBtnTimer.hasExpired() && mDefaultBtnTimer.getStarted())
  361. {
  362. mDefaultBtnTimer.stop();  // prevent this block from being run more than once
  363. LLToastPanel::setDefaultBtn(mButtonData[mDefaultOption].mButton);
  364. }
  365. static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
  366. static LLUICachedControl<S32> shadow_lines ("DropShadowFloater");
  367. gl_drop_shadow( 0, LLToastPanel::getRect().getHeight(), LLToastPanel::getRect().getWidth(), 0,
  368. shadow_color, shadow_lines);
  369. LLToastPanel::draw();
  370. }
  371. void LLToastAlertPanel::setEditTextArgs(const LLSD& edit_args)
  372. {
  373. if (mLineEditor)
  374. {
  375. std::string msg = mLineEditor->getText();
  376. mLineEditor->setText(msg);
  377. }
  378. else
  379. {
  380. llwarns << "LLToastAlertPanel::setEditTextArgs called on dialog with no line editor" << llendl;
  381. }
  382. }
  383. void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button )
  384. {
  385. ButtonData* button_data = &mButtonData[button];
  386. LLSD response = mNotification->getResponseTemplate();
  387. if (mLineEditor)
  388. {
  389. response[mLineEditor->getName()] = mLineEditor->getValue();
  390. }
  391. response[button_data->mButton->getName()] = true;
  392. // If we declared a URL and chose the URL option, go to the url
  393. if (!button_data->mURL.empty() && sURLLoader != NULL)
  394. {
  395. sURLLoader->load(button_data->mURL, button_data->mURLExternal);
  396. }
  397. mNotification->respond(response); // new notification reponse
  398. }
  399. void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl)
  400. {
  401. // checkbox sometimes means "hide and do the default" and
  402. // other times means "warn me again".  Yuck. JC
  403. BOOL check = ctrl->getValue().asBoolean();
  404. if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
  405. {
  406. // question was "show again" so invert value to get "ignore"
  407. check = !check;
  408. }
  409. mNotification->setIgnored(check);
  410. }