summaryrefslogtreecommitdiff
path: root/indra/newview/lltoastalertpanel.cpp
diff options
context:
space:
mode:
authorSteven Bennetts <steve@lindenlab.com>2009-07-21 00:59:14 +0000
committerSteven Bennetts <steve@lindenlab.com>2009-07-21 00:59:14 +0000
commitcef46d16453873691406c22be39ce0ee5e8076d1 (patch)
treed7df442ce4af8e8001d7e7bf5647f116b35f929e /indra/newview/lltoastalertpanel.cpp
parent73a97010e6c8c7874fdc1778ab46e492f77d9394 (diff)
merge https://svn.aws.productengine.com/secondlife/pe/stable-1/indra -r 1078-1091 -> viewer-2.0.0-3
Diffstat (limited to 'indra/newview/lltoastalertpanel.cpp')
-rw-r--r--indra/newview/lltoastalertpanel.cpp474
1 files changed, 474 insertions, 0 deletions
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
new file mode 100644
index 0000000000..afaa01a77a
--- /dev/null
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -0,0 +1,474 @@
+/**
+ * @file lltoastalertpanel.cpp
+ * @brief Panel for alert toasts.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h" // must be first include
+
+#include "linden_common.h"
+
+#include "llboost.h"
+
+#include "lltoastalertpanel.h"
+#include "llfontgl.h"
+#include "lltextbox.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llkeyboard.h"
+#include "llfocusmgr.h"
+#include "lliconctrl.h"
+#include "llui.h"
+#include "lllineeditor.h"
+#include "lluictrlfactory.h"
+#include "llnotifications.h"
+#include "llfunctorregistry.h"
+
+const S32 MAX_ALLOWED_MSG_WIDTH = 400;
+const F32 DEFAULT_BUTTON_DELAY = 0.5f;
+const S32 MSG_PAD = 8;
+
+/*static*/ LLControlGroup* LLToastAlertPanel::sSettings = NULL;
+/*static*/ LLToastAlertPanel::URLLoader* LLToastAlertPanel::sURLLoader;
+
+//-----------------------------------------------------------------------------
+// Private methods
+
+static const S32 VPAD = 16;
+static const S32 HPAD = 25;
+static const S32 BTN_HPAD = 8;
+
+LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal)
+ : LLToastPanel(notification),
+ mDefaultOption( 0 ),
+ mCheck(NULL),
+ mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH),
+ mLabel(notification->getName()),
+ mLineEditor(NULL)
+{
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f);
+ const S32 EDITOR_HEIGHT = 20;
+
+ LLNotificationFormPtr form = mNotification->getForm();
+ std::string edit_text_name;
+ std::string edit_text_contents;
+ bool is_password = false;
+
+ LLToastPanel::setBackgroundVisible(FALSE);
+ LLToastPanel::setBackgroundOpaque(TRUE);
+
+
+ typedef std::vector<std::pair<std::string, std::string> > options_t;
+ options_t supplied_options;
+
+ // for now, get LLSD to iterator over form elements
+ LLSD form_sd = form->asLLSD();
+
+ S32 option_index = 0;
+ for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it)
+ {
+ std::string type = (*it)["type"].asString();
+ if (type == "button")
+ {
+ if((*it)["default"])
+ {
+ mDefaultOption = option_index;
+ }
+
+ supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString()));
+
+ ButtonData data;
+ if (option_index == mNotification->getURLOption())
+ {
+ data.mURL = mNotification->getURL();
+ data.mURLExternal = mNotification->getURLOpenExternally();
+ }
+
+ mButtonData.push_back(data);
+ option_index++;
+ }
+ else if (type == "text")
+ {
+ edit_text_contents = (*it)["value"].asString();
+ edit_text_name = (*it)["name"].asString();
+ }
+ else if (type == "password")
+ {
+ edit_text_contents = (*it)["value"].asString();
+ edit_text_name = (*it)["name"].asString();
+ is_password = true;
+ }
+ }
+
+ // Buttons
+ options_t options;
+ if (supplied_options.empty())
+ {
+ options.push_back(std::make_pair(std::string("close"), LLNotifications::instance().getGlobalString("implicitclosebutton")));
+
+ // add data for ok button.
+ ButtonData ok_button;
+ mButtonData.push_back(ok_button);
+ mDefaultOption = 0;
+ }
+ else
+ {
+ options = supplied_options;
+ }
+
+ S32 num_options = options.size();
+
+ // Calc total width of buttons
+ S32 button_width = 0;
+ S32 sp = font->getWidth(std::string("OO"));
+ for( S32 i = 0; i < num_options; i++ )
+ {
+ S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD;
+ button_width = llmax( w, button_width );
+ }
+ S32 btn_total_width = button_width;
+ if( num_options > 1 )
+ {
+ btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD);
+ }
+
+ // Message: create text box using raw string, as text has been structure deliberately
+ // Use size of created text box to generate dialog box size
+ std::string msg = mNotification->getMessage();
+ llwarns << "Alert: " << msg << llendl;
+ LLTextBox::Params params;
+ params.name("Alert message");
+ params.font(font);
+ params.tab_stop(false);
+ params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+
+ LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params);
+ // Compute max allowable height for the dialog text, so we can allocate
+ // space before wrapping the text to fit.
+ S32 max_allowed_msg_height =
+ gFloaterView->getRect().getHeight()
+ - LINE_HEIGHT // title bar
+ - 3*VPAD - BTN_HEIGHT;
+ msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height );
+ msg_box->setWrappedText(msg, (F32)MAX_ALLOWED_MSG_WIDTH);
+ msg_box->reshapeToFitText();
+
+ const LLRect& text_rect = msg_box->getRect();
+ S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD;
+ S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT;
+
+ if (hasTitleBar())
+ {
+ dialog_height += LINE_HEIGHT; // room for title bar
+ }
+
+ // 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
+ if (!edit_text_name.empty())
+ {
+ dialog_height += EDITOR_HEIGHT + VPAD;
+ dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f));
+ }
+
+ if (mCaution)
+ {
+ // Make room for the caution icon.
+ dialog_width += 32 + HPAD;
+ }
+
+ LLToastPanel::reshape( dialog_width, dialog_height, FALSE );
+
+ S32 msg_y = LLToastPanel::getRect().getHeight() - VPAD;
+ S32 msg_x = HPAD;
+ if (hasTitleBar())
+ {
+ msg_y -= LINE_HEIGHT; // room for title
+ }
+
+ static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor");
+ static LLUIColor alert_text_color = LLUIColorTable::instance().getColor("AlertTextColor");
+ if (mCaution)
+ {
+ LLIconCtrl::Params params;
+ params.name("icon");
+ params.rect(LLRect(msg_x, msg_y, msg_x+32, msg_y-32));
+ params.mouse_opaque(false);
+ params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
+ params.tab_stop(false);
+ LLIconCtrl * icon = LLUICtrlFactory::create<LLIconCtrl> (params);
+ icon->setValue ("notify_caution_icon.tga");
+ icon->setMouseOpaque(FALSE);
+ LLToastPanel::addChild(icon);
+ msg_x += 32 + HPAD;
+ msg_box->setColor( alert_caution_text_color );
+ }
+ else
+ {
+ msg_box->setColor( alert_text_color );
+ }
+
+ LLRect rect;
+ rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() );
+ msg_box->setRect( rect );
+ LLToastPanel::addChild(msg_box);
+
+ // Buttons
+ S32 button_left = (LLToastPanel::getRect().getWidth() - btn_total_width) / 2;
+
+ for( S32 i = 0; i < num_options; i++ )
+ {
+ LLRect button_rect;
+ button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT );
+
+ LLButton::Params p;
+ p.name(options[i].first);
+ p.rect(button_rect);
+ p.click_callback.function(boost::bind(&LLToastAlertPanel::onButtonPressed, this, _2, i));
+ p.font(font);
+ p.label(options[i].second);
+
+ LLButton* btn = LLUICtrlFactory::create<LLButton>(p);
+ mButtonData[i].mButton = btn;
+
+ LLToastPanel::addChild(btn);
+
+ if( i == mDefaultOption )
+ {
+ btn->setFocus(TRUE);
+ }
+
+ button_left += button_width + BTN_HPAD;
+ }
+
+ // (Optional) Edit Box
+ if (!edit_text_name.empty())
+ {
+ S32 y = VPAD + BTN_HEIGHT + VPAD/2;
+
+ LLLineEditor::Params params;
+ params.name(edit_text_name);
+ params.rect(LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y));
+ params.default_text(edit_text_contents);
+ params.max_length_bytes(STD_STRING_STR_LEN);
+ mLineEditor = LLUICtrlFactory::create<LLLineEditor> (params);
+
+ // make sure all edit keys get handled properly (DEV-22396)
+ mLineEditor->setHandleEditKeysDirectly(TRUE);
+
+ LLToastPanel::addChild(mLineEditor);
+ }
+
+ if (mLineEditor)
+ {
+ mLineEditor->setDrawAsterixes(is_password);
+
+ setEditTextArgs(notification->getSubstitutions());
+ }
+
+ std::string ignore_label;
+
+ if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)
+ {
+ setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label);
+ }
+ else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
+ {
+ setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label);
+ }
+
+ gFloaterView->adjustToFitScreen(this, FALSE);
+ LLFloater::setFocus(TRUE);
+ if (mLineEditor)
+ {
+ mLineEditor->setFocus(TRUE);
+ mLineEditor->selectAll();
+ }
+ if(mDefaultOption >= 0)
+ {
+ // delay before enabling default button
+ mDefaultBtnTimer.start();
+ mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY);
+ }
+}
+
+bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control )
+{
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f);
+
+ // Extend dialog for "check next time"
+ S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD;
+ S32 check_width = S32(font->getWidth(check_title) + 0.99f) + 16;
+ max_msg_width = llmax(max_msg_width, check_width);
+ S32 dialog_width = max_msg_width + 2 * HPAD;
+
+ S32 dialog_height = LLToastPanel::getRect().getHeight();
+ dialog_height += LINE_HEIGHT;
+ dialog_height += LINE_HEIGHT / 2;
+
+ LLToastPanel::reshape( dialog_width, dialog_height, FALSE );
+
+ S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2;
+
+ LLCheckBoxCtrl::Params p;
+ p.name("check");
+ p.rect.left(msg_x).bottom(VPAD+BTN_HEIGHT+LINE_HEIGHT/2).width(max_msg_width).height(LINE_HEIGHT);
+ p.label(check_title);
+ p.font(font);
+ p.commit_callback.function(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1));
+ mCheck = LLUICtrlFactory::create<LLCheckBoxCtrl>(p);
+ LLToastPanel::addChild(mCheck);
+
+ return true;
+}
+
+void LLToastAlertPanel::setVisible( BOOL visible )
+{
+ LLToastPanel::setVisible( visible );
+
+ if( visible )
+ {
+ make_ui_sound("UISndAlert");
+ }
+}
+
+void LLToastAlertPanel::onClose(bool app_quitting)
+{
+ LLFloater::onClose(app_quitting);
+}
+
+LLToastAlertPanel::~LLToastAlertPanel()
+{
+}
+
+BOOL LLToastAlertPanel::hasTitleBar() const
+{
+ return (getCurrentTitle() != "" && getCurrentTitle() != " ") // has title
+ || isMinimizeable()
+ || isCloseable();
+}
+
+BOOL LLToastAlertPanel::handleKeyHere(KEY key, MASK mask )
+{
+ if( KEY_RETURN == key && mask == MASK_NONE )
+ {
+ return TRUE;
+ }
+ else if (KEY_RIGHT == key)
+ {
+ LLToastPanel::focusNextItem(FALSE);
+ return TRUE;
+ }
+ else if (KEY_LEFT == key)
+ {
+ LLToastPanel::focusPrevItem(FALSE);
+ return TRUE;
+ }
+ else if (KEY_TAB == key && mask == MASK_NONE)
+ {
+ LLToastPanel::focusNextItem(FALSE);
+ return TRUE;
+ }
+ else if (KEY_TAB == key && mask == MASK_SHIFT)
+ {
+ LLToastPanel::focusPrevItem(FALSE);
+ return TRUE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+// virtual
+void LLToastAlertPanel::draw()
+{
+ // if the default button timer has just expired, activate the default button
+ if(mDefaultBtnTimer.hasExpired() && mDefaultBtnTimer.getStarted())
+ {
+ mDefaultBtnTimer.stop(); // prevent this block from being run more than once
+ LLToastPanel::setDefaultBtn(mButtonData[mDefaultOption].mButton);
+ }
+
+ static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow");
+ static LLUICachedControl<S32> shadow_lines ("DropShadowFloater");
+
+ gl_drop_shadow( 0, LLToastPanel::getRect().getHeight(), LLToastPanel::getRect().getWidth(), 0,
+ shadow_color, shadow_lines);
+
+ LLToastPanel::draw();
+}
+
+void LLToastAlertPanel::setEditTextArgs(const LLSD& edit_args)
+{
+ if (mLineEditor)
+ {
+ std::string msg = mLineEditor->getText();
+ mLineEditor->setText(msg);
+ }
+ else
+ {
+ llwarns << "LLToastAlertPanel::setEditTextArgs called on dialog with no line editor" << llendl;
+ }
+}
+
+void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button )
+{
+ ButtonData* button_data = &mButtonData[button];
+
+ LLSD response = mNotification->getResponseTemplate();
+ if (mLineEditor)
+ {
+ response[mLineEditor->getName()] = mLineEditor->getValue();
+ }
+ response[button_data->mButton->getName()] = true;
+
+ // If we declared a URL and chose the URL option, go to the url
+ if (!button_data->mURL.empty() && sURLLoader != NULL)
+ {
+ sURLLoader->load(button_data->mURL, button_data->mURLExternal);
+ }
+
+ mNotification->respond(response); // new notification reponse
+ closeFloater(); // deletes self
+}
+
+void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl)
+{
+ // checkbox sometimes means "hide and do the default" and
+ // other times means "warn me again". Yuck. JC
+ BOOL check = ctrl->getValue().asBoolean();
+ if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN)
+ {
+ // question was "show again" so invert value to get "ignore"
+ check = !check;
+ }
+ mNotification->setIgnored(check);
+}