//----------------------------------------------------------------------------- // buildPanel() //----------------------------------------------------------------------------- BOOL LLPanel::buildFromFile(const std::string& filename, LLXMLNodePtr output_node, const LLPanel::Params& default_params) { LLFastTimer timer(FTM_BUILD_PANELS); BOOL didPost = FALSE; LLXMLNodePtr root; //if exporting, only load the language being exported, //instead of layering localized version on top of english if (output_node) { if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root)) { llwarns << "Couldn't parse panel from: " << LLUI::getLocalizedSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; return didPost; } } else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) { llwarns << "Couldn't parse panel from: " << LLUI::getSkinPath() + gDirUtilp->getDirDelimiter() + filename << llendl; return didPost; } // root must be called panel if( !root->hasName("panel" ) ) { llwarns << "Root node should be named panel in : " << filename << llendl; return didPost; } lldebugs << "Building panel " << filename << llendl; LLUICtrlFactory::instance().pushFileName(filename); { if (!getFactoryMap().empty()) { sFactoryStack.push_back(&getFactoryMap()); } // for local registry callbacks; define in constructor, referenced in XUI or postBuild getCommitCallbackRegistrar().pushScope(); getEnableCallbackRegistrar().pushScope(); didPost = initPanelXML(root, NULL, output_node, default_params); getCommitCallbackRegistrar().popScope(); getEnableCallbackRegistrar().popScope(); setXMLFilename(filename); if (!getFactoryMap().empty()) { sFactoryStack.pop_back(); } } LLUICtrlFactory::instance().popFileName(); return didPost; }
BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) { const LLPanel::Params& default_params(LLUICtrlFactory::getDefaultParams<LLPanel>()); Params params(default_params); { LLFastTimer timer(FTM_PANEL_SETUP); LLXMLNodePtr referenced_xml; std::string xml_filename = mXMLFilename; // if the panel didn't provide a filename, check the node if (xml_filename.empty()) { node->getAttributeString("filename", xml_filename); setXMLFilename(xml_filename); } if (!xml_filename.empty()) { LLUICtrlFactory::instance().pushFileName(xml_filename); LLFastTimer timer(FTM_EXTERNAL_PANEL_LOAD); if (output_node) { //if we are exporting, we want to export the current xml //not the referenced xml LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); Params output_params(params); setupParamsForExport(output_params, parent); output_node->setName(node->getName()->mString); LLXUIParser::instance().writeXUI( output_node, output_params, &default_params); return TRUE; } if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) { llwarns << "Couldn't parse panel from: " << xml_filename << llendl; return FALSE; } LLXUIParser::instance().readXUI(referenced_xml, params, LLUICtrlFactory::getInstance()->getCurFileName()); // add children using dimensions from referenced xml for consistent layout setShape(params.rect); LLUICtrlFactory::createChildren(this, referenced_xml, child_registry_t::instance()); LLUICtrlFactory::instance().popFileName(); } // ask LLUICtrlFactory for filename, since xml_filename might be empty LLXUIParser::instance().readXUI(node, params, LLUICtrlFactory::getInstance()->getCurFileName()); if (output_node) { Params output_params(params); setupParamsForExport(output_params, parent); output_node->setName(node->getName()->mString); LLXUIParser::instance().writeXUI( output_node, output_params, &default_params); } params.from_xui = true; applyXUILayout(params, parent); { LLFastTimer timer(FTM_PANEL_CONSTRUCTION); initFromParams(params); } // add children LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); // Connect to parent after children are built, because tab containers // do a reshape() on their child panels, which requires that the children // be built/added. JC if (parent) { S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : parent->getLastTabGroup(); parent->addChild(this, tab_group); } { LLFastTimer timer(FTM_PANEL_POSTBUILD); postBuild(); } } return TRUE; }
void LLToastNotifyPanel::init( LLRect rect, bool show_images ) { deleteAllChildren(); mTextBox = NULL; mInfoPanel = NULL; mControlPanel = NULL; mNumOptions = 0; mNumButtons = 0; mAddedDefaultBtn = false; LLRect current_rect = getRect(); setXMLFilename(""); buildFromFile("panel_notification.xml"); if(rect != LLRect::null) { this->setShape(rect); } mInfoPanel = getChild<LLPanel>("info_panel"); mControlPanel = getChild<LLPanel>("control_panel"); BUTTON_WIDTH = gSavedSettings.getS32("ToastButtonWidth"); // customize panel's attributes // is it intended for displaying a tip? mIsTip = mNotification->getType() == "notifytip"; std::string notif_name = mNotification->getName(); // is it a script dialog? mIsScriptDialog = (notif_name == "ScriptDialog" || notif_name == "ScriptDialogGroup"); bool is_content_trusted = (notif_name != "LoadWebPage"); // is it a caution? // // 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 = mNotification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; // setup parameters // get a notification message mMessage = mNotification->getMessage(); // init font variables if (!sFont) { sFont = LLFontGL::getFontSansSerif(); sFontSmall = LLFontGL::getFontSansSerifSmall(); } // initialize setFocusRoot(!mIsTip); // get a form for the notification LLNotificationFormPtr form(mNotification->getForm()); // get number of elements mNumOptions = form->getNumElements(); // customize panel's outfit // preliminary adjust panel's layout //move to the end //mIsTip ? adjustPanelForTipNotice() : adjustPanelForScriptNotice(form); // adjust text options according to the notification type // add a caution textbox at the top of a caution notification if (mIsCaution && !mIsTip) { mTextBox = getChild<LLTextBox>("caution_text_box"); } else { mTextBox = getChild<LLTextEditor>("text_editor_box"); } mTextBox->setMaxTextLength(MAX_LENGTH); mTextBox->setVisible(TRUE); mTextBox->setPlainText(!show_images); mTextBox->setContentTrusted(is_content_trusted); mTextBox->setValue(mNotification->getMessage()); mTextBox->setIsFriendCallback(LLAvatarActions::isFriend); // add buttons for a script notification if (mIsTip) { adjustPanelForTipNotice(); } else { std::vector<index_button_pair_t> buttons; buttons.reserve(mNumOptions); S32 buttons_width = 0; // create all buttons and accumulate they total width to reshape mControlPanel for (S32 i = 0; i < mNumOptions; i++) { LLSD form_element = form->getElement(i); if (form_element["type"].asString() != "button") { // not a button. continue; } if (form_element["name"].asString() == TEXTBOX_MAGIC_TOKEN) { // a textbox pretending to be a button. continue; } LLButton* new_button = createButton(form_element, TRUE); buttons_width += new_button->getRect().getWidth(); S32 index = form_element["index"].asInteger(); buttons.push_back(index_button_pair_t(index,new_button)); } if (buttons.empty()) { addDefaultButton(); } else { const S32 button_panel_width = mControlPanel->getRect().getWidth();// do not change width of the panel S32 button_panel_height = mControlPanel->getRect().getHeight(); //try get an average h_pad to spread out buttons S32 h_pad = (button_panel_width - buttons_width) / (S32(buttons.size())); if(h_pad < 2*HPAD) { /* * Probably it is a scriptdialog toast * for a scriptdialog toast h_pad can be < 2*HPAD if we have a lot of buttons. * In last case set default h_pad to avoid heaping of buttons */ S32 button_per_row = button_panel_width / BUTTON_WIDTH; h_pad = (button_panel_width % BUTTON_WIDTH) / (button_per_row - 1);// -1 because we do not need space after last button in a row if(h_pad < 2*HPAD) // still not enough space between buttons ? { h_pad = 2*HPAD; } } if (mIsScriptDialog) { // we are using default width for script buttons so we can determinate button_rows //to get a number of rows we divide the required width of the buttons to button_panel_width S32 button_rows = llceil(F32(buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width); //S32 button_rows = (buttons.size() - 1) * (BUTTON_WIDTH + h_pad) / button_panel_width; //reserve one row for the ignore_btn button_rows++; //calculate required panel height for scripdialog notification. button_panel_height = button_rows * (BTN_HEIGHT + VPAD) + IGNORE_BTN_TOP_DELTA + BOTTOM_PAD; } else { // in common case buttons can have different widths so we need to calculate button_rows according to buttons_width //S32 button_rows = llceil(F32(buttons.size()) * (buttons_width + h_pad) / button_panel_width); S32 button_rows = llceil(F32((buttons.size() - 1) * h_pad + buttons_width) / button_panel_width); //calculate required panel height button_panel_height = button_rows * (BTN_HEIGHT + VPAD) + BOTTOM_PAD; } // we need to keep min width and max height to make visible all buttons, because width of the toast can not be changed adjustPanelForScriptNotice(button_panel_width, button_panel_height); updateButtonsLayout(buttons, h_pad); // save buttons for later use in disableButtons() //mButtons.assign(buttons.begin(), buttons.end()); } } //.xml file intially makes info panel only follow left/right/top. This is so that when control buttons are added the info panel //can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'. mInfoPanel->setFollowsAll(); snapToMessageHeight(mTextBox, MAX_LENGTH); // reshape the panel to its previous size if (current_rect.notEmpty()) { reshape(current_rect.getWidth(), current_rect.getHeight()); } }