diff options
Diffstat (limited to 'indra/newview/lltoastnotifypanel.cpp')
-rw-r--r-- | indra/newview/lltoastnotifypanel.cpp | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp new file mode 100644 index 0000000000..a7b57802c1 --- /dev/null +++ b/indra/newview/lltoastnotifypanel.cpp @@ -0,0 +1,435 @@ +/** + * @file lltoastnotifypanel.cpp + * @brief Panel for notify 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" + +#include "lltoastnotifypanel.h" +#include "llviewercontrol.h" +#include "lluiconstants.h" +#include "llrect.h" +#include "lliconctrl.h" +#include "lltexteditor.h" +#include "lltextbox.h" +#include "lldbstrings.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "lltrans.h" +#include "lloverlaybar.h" + + +const S32 BOTTOM_PAD = VPAD * 3; + +//static +const LLFontGL* LLToastNotifyPanel::sFont = NULL; +const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; + +LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToastPanel(notification) { + mIsTip = notification->getType() == "notifytip"; + mNumOptions = 0; + mNumButtons = 0; + mIsScriptDialog = (notification->getName() == "ScriptDialog" + || notification->getName() == "ScriptDialogGroup"); + mAddedDefaultBtn = false; + + // clicking on a button does not steal current focus + setIsChrome(TRUE); + + // class init + if (!sFont) + { + sFont = LLFontGL::getFontSansSerif(); + sFontSmall = LLFontGL::getFontSansSerifSmall(); + } + + // setup paramaters + mMessage = notification->getMessage(); + + // initialize + setFocusRoot(!mIsTip); + + // caution flag can be set explicitly by specifying it in the + // notification payload, or it can be set implicitly if the + // notify xml template specifies that it is a caution + // + // tip-style notification handle 'caution' differently - + // they display the tip in a different color + mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; + + LLNotificationFormPtr form(notification->getForm()); + + mNumOptions = form->getNumElements(); + + LLRect rect = mIsTip ? getNotifyTipRect(mMessage) + : getNotifyRect(mNumOptions, mIsScriptDialog, mIsCaution); + setRect(rect); + setFollows(mIsTip ? (FOLLOWS_BOTTOM|FOLLOWS_RIGHT) : (FOLLOWS_TOP|FOLLOWS_RIGHT)); + setBackgroundVisible(FALSE); + setBackgroundOpaque(TRUE); + + LLIconCtrl* icon; + LLTextEditor* text; + + const S32 TOP = getRect().getHeight() - (mIsTip ? (S32)sFont->getLineHeight() : 32); + const S32 BOTTOM = (S32)sFont->getLineHeight(); + S32 x = HPAD + HPAD; + S32 y = TOP; + + LLIconCtrl::Params common_params; + common_params.rect(LLRect(x, y, x+32, TOP-32)); + common_params.mouse_opaque(false); + common_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + common_params.tab_stop(false); + + if (mIsTip) + { + // use the tip notification icon + common_params.image(LLUI::getUIImage("notify_tip_icon.tga")); + icon = LLUICtrlFactory::create<LLIconCtrl> (common_params); + } + else if (mIsCaution) + { + // use the caution notification icon + common_params.image(LLUI::getUIImage("notify_caution_icon.tga")); + icon = LLUICtrlFactory::create<LLIconCtrl> (common_params); + } + else + { + // use the default notification icon + common_params.image(LLUI::getUIImage("notify_box_icon.tga")); + icon = LLUICtrlFactory::create<LLIconCtrl> (common_params); + } + + icon->setMouseOpaque(FALSE); + addChild(icon); + + x += HPAD + HPAD + 32; + + // add a caution textbox at the top of a caution notification + LLTextBox* caution_box = NULL; + if (mIsCaution && !mIsTip) + { + S32 caution_height = ((S32)sFont->getLineHeight() * 2) + VPAD; + LLTextBox::Params params; + params.name("caution_box"); + params.rect(LLRect(x, y, getRect().getWidth() - 2, caution_height)); + params.font(sFont); + params.mouse_opaque(false); + params.font.style("BOLD"); + params.text_color(LLUIColorTable::instance().getColor("NotifyCautionWarnColor")); + params.background_color(LLUIColorTable::instance().getColor("NotifyCautionBoxColor")); + params.border_visible(false); + caution_box = LLUICtrlFactory::create<LLTextBox> (params); + caution_box->setWrappedText(notification->getMessage()); + + addChild(caution_box); + + // adjust the vertical position of the next control so that + // it appears below the caution textbox + y = y - caution_height; + } + else + { + + const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); + + // Tokenization on \n is handled by LLTextBox + + const S32 MAX_LENGTH = 512 + 20 + + DB_FIRST_NAME_BUF_SIZE + + DB_LAST_NAME_BUF_SIZE + + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. + + LLTextEditor::Params params; + params.name("box"); + params.rect(LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16)); + params.max_text_length(MAX_LENGTH); + params.default_text(mMessage); + params.font(sFont); + params.embedded_items(false); + params.word_wrap(true); + params.tab_stop(false); + params.mouse_opaque(false); + params.bg_readonly_color(LLColor4::transparent); + params.text_readonly_color(LLUIColorTable::instance().getColor("NotifyTextColor")); + params.takes_non_scroll_clicks(false); + params.hide_scrollbar(true); + params.enabled(false); + params.hide_border(true); + text = LLUICtrlFactory::create<LLTextEditor> (params); + addChild(text); + } + + if (mIsTip) + { + // TODO: Make a separate archive for these. + LLChat chat(mMessage); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChatHistory(chat); + } + else + { + LLButton::Params p; + p.name(std::string("next")); + p.rect(LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD)); + p.image_selected.name("notify_next.png"); + p.image_unselected.name("notify_next.png"); + p.font(sFont); + p.scale_image(true); + p.tool_tip(LLTrans::getString("next").c_str()); + + for (S32 i = 0; i < mNumOptions; i++) + { + + LLSD form_element = form->getElement(i); + if (form_element["type"].asString() != "button") + { + continue; + } + + addButton(form_element["name"].asString(), form_element["text"].asString(), TRUE, form_element["default"].asBoolean()); + } + + if (mNumButtons == 0) + { + addButton("OK", LLTrans::getString("ok"), FALSE, TRUE); + mAddedDefaultBtn = true; + } + + + } +} + +LLToastNotifyPanel::~LLToastNotifyPanel() { + std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer()); +} + + +LLRect LLToastNotifyPanel::getNotifyRect(S32 num_options, BOOL mIsScriptDialog, BOOL is_caution) +{ + S32 notify_height = gSavedSettings.getS32("NotifyBoxHeight"); + if (is_caution) + { + // make caution-style dialog taller to accomodate extra text, + // as well as causing the accept/decline buttons to be drawn + // in a different position, to help prevent "quick-click-through" + // of many permissions prompts + notify_height = gSavedSettings.getS32("PermissionsCautionNotifyBoxHeight"); + } + const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth"); + + const S32 TOP = getRect().getHeight(); + const S32 RIGHT =getRect().getWidth(); + const S32 LEFT = RIGHT - NOTIFY_WIDTH; + + if (num_options < 1) + { + num_options = 1; + } + + // Add two "blank" option spaces. + if (mIsScriptDialog) + { + num_options += 2; + } + + S32 additional_lines = (num_options-1) / 3; + + notify_height += additional_lines * (BTN_HEIGHT + VPAD); + + return LLRect(LEFT, TOP, RIGHT, TOP-notify_height); +} + +// static +LLRect LLToastNotifyPanel::getNotifyTipRect(const std::string &utf8message) +{ + S32 line_count = 1; + LLWString message = utf8str_to_wstring(utf8message); + S32 message_len = message.length(); + + const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth"); + // Make room for the icon area. + const S32 text_area_width = NOTIFY_WIDTH - HPAD * 4 - 32; + + const llwchar* wchars = message.c_str(); + const llwchar* start = wchars; + const llwchar* end; + S32 total_drawn = 0; + BOOL done = FALSE; + + do + { + line_count++; + + for (end=start; *end != 0 && *end != '\n'; end++) + ; + + if( *end == 0 ) + { + end = wchars + message_len; + done = TRUE; + } + + S32 remaining = end - start; + while( remaining ) + { + S32 drawn = sFont->maxDrawableChars( start, (F32)text_area_width, remaining, TRUE ); + + if( 0 == drawn ) + { + drawn = 1; // Draw at least one character, even if it doesn't all fit. (avoids an infinite loop) + } + + total_drawn += drawn; + start += drawn; + remaining -= drawn; + + if( total_drawn < message_len ) + { + if( (wchars[ total_drawn ] != '\n') ) + { + // wrap because line was too long + line_count++; + } + } + else + { + done = TRUE; + } + } + + total_drawn++; // for '\n' + end++; + start = end; + } while( !done ); + + const S32 MIN_NOTIFY_HEIGHT = 72; + const S32 MAX_NOTIFY_HEIGHT = 600; + S32 notify_height = llceil((F32) (line_count+1) * sFont->getLineHeight()); + if(gOverlayBar) + { + notify_height += gOverlayBar->getBoundingRect().mTop; + } + else + { + // *FIX: this is derived from the padding caused by the + // rounded rects, shouldn't be a const here. + notify_height += 10; + } + notify_height += VPAD; + notify_height = llclamp(notify_height, MIN_NOTIFY_HEIGHT, MAX_NOTIFY_HEIGHT); + + const S32 RIGHT = getRect().getWidth(); + const S32 LEFT = RIGHT - NOTIFY_WIDTH; + + return LLRect(LEFT, notify_height, RIGHT, 0); +} + + +// static +void LLToastNotifyPanel::onClickButton(void* data) +{ + InstanceAndS32* self_and_button = (InstanceAndS32*)data; + LLToastNotifyPanel* self = self_and_button->mSelf; + std::string button_name = self_and_button->mButtonName; + + LLSD response = self->mNotification->getResponseTemplate(); + if (!self->mAddedDefaultBtn && !button_name.empty()) + { + response[button_name] = true; + } + self->mNotification->respond(response); +} + +// virtual +LLButton* LLToastNotifyPanel::addButton(const std::string& name, const std::string& label, BOOL is_option, BOOL is_default) +{ + // make caution notification buttons slightly narrower + // so that 3 of them can fit without overlapping the "next" button + S32 btn_width = mIsCaution? 84 : 90; + + LLRect btn_rect; + LLButton* btn; + S32 btn_height= BTN_HEIGHT; + const LLFontGL* font = sFont; + S32 ignore_pad = 0; + S32 button_index = mNumButtons; + S32 index = button_index; + S32 x = (HPAD * 4) + 32; + + if (mIsScriptDialog) + { + // Add two "blank" option spaces, before the "Ignore" button + index = button_index + 2; + if (button_index == 0) + { + // Ignore button is smaller, less wide + btn_height = BTN_HEIGHT_SMALL; + font = sFontSmall; + ignore_pad = 10; + } + } + + btn_rect.setOriginAndSize(x + (index % 3) * (btn_width+HPAD+HPAD) + ignore_pad, + BOTTOM_PAD + (index / 3) * (BTN_HEIGHT+VPAD), + btn_width - 2*ignore_pad, + btn_height); + + InstanceAndS32* userdata = new InstanceAndS32; + userdata->mSelf = this; + userdata->mButtonName = is_option ? name : ""; + + mBtnCallbackData.push_back(userdata); + + LLButton::Params p; + p.name(name); + p.label(label); + p.rect(btn_rect); + p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata)); + p.font(font); + if (mIsCaution) + { + p.image_color(LLUIColorTable::instance().getColor("ButtonCautionImageColor")); + p.image_color_disabled(LLUIColorTable::instance().getColor("ButtonCautionImageColor")); + } + btn = LLUICtrlFactory::create<LLButton>(p); + + + addChild(btn, -1); + + if (is_default) + { + setDefaultBtn(btn); + } + + mNumButtons++; + return btn; +} |