//-----------------------------------------------------------------------------
// 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;
}
Exemple #2
0
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());
    }
}