phoenix-firestorm/indra/newview/lltoolbarview.cpp

407 lines
12 KiB
C++

/**
* @file lltoolbarview.cpp
* @author Merov Linden
* @brief User customizable toolbar class
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "lltoolbarview.h"
#include "lldir.h"
#include "llxmlnode.h"
#include "lltoolbar.h"
#include "llbutton.h"
#include "lltooldraganddrop.h"
#include "llclipboard.h"
#include <boost/foreach.hpp>
LLToolBarView* gToolBarView = NULL;
static LLDefaultChildRegistry::Register<LLToolBarView> r("toolbar_view");
bool LLToolBarView::sDragStarted = false;
LLToolBarView::Toolbar::Toolbar()
: button_display_mode("button_display_mode"),
commands("command")
{}
LLToolBarView::ToolbarSet::ToolbarSet()
: left_toolbar("left_toolbar"),
right_toolbar("right_toolbar"),
bottom_toolbar("bottom_toolbar")
{}
LLToolBarView::LLToolBarView(const LLToolBarView::Params& p)
: LLUICtrl(p),
mToolbarLeft(NULL),
mToolbarRight(NULL),
mToolbarBottom(NULL)
{
}
void LLToolBarView::initFromParams(const LLToolBarView::Params& p)
{
// Initialize the base object
LLUICtrl::initFromParams(p);
}
LLToolBarView::~LLToolBarView()
{
saveToolbars();
}
BOOL LLToolBarView::postBuild()
{
mToolbarLeft = getChild<LLToolBar>("toolbar_left");
mToolbarRight = getChild<LLToolBar>("toolbar_right");
mToolbarBottom = getChild<LLToolBar>("toolbar_bottom");
mToolbarLeft->setStartDragCallback(boost::bind(LLToolBarView::startDragItem,_1,_2,_3));
mToolbarLeft->setHandleDragCallback(boost::bind(LLToolBarView::handleDragItem,_1,_2,_3,_4));
mToolbarLeft->setHandleDropCallback(boost::bind(LLToolBarView::handleDrop,_1,_2,_3,_4));
mToolbarRight->setStartDragCallback(boost::bind(LLToolBarView::startDragItem,_1,_2,_3));
mToolbarRight->setHandleDragCallback(boost::bind(LLToolBarView::handleDragItem,_1,_2,_3,_4));
mToolbarRight->setHandleDropCallback(boost::bind(LLToolBarView::handleDrop,_1,_2,_3,_4));
mToolbarBottom->setStartDragCallback(boost::bind(LLToolBarView::startDragItem,_1,_2,_3));
mToolbarBottom->setHandleDragCallback(boost::bind(LLToolBarView::handleDragItem,_1,_2,_3,_4));
mToolbarBottom->setHandleDropCallback(boost::bind(LLToolBarView::handleDrop,_1,_2,_3,_4));
return TRUE;
}
bool LLToolBarView::hasCommand(const LLCommandId& commandId) const
{
bool has_command = false;
if (mToolbarLeft && !has_command)
{
has_command = mToolbarLeft->hasCommand(commandId);
}
if (mToolbarRight && !has_command)
{
has_command = mToolbarRight->hasCommand(commandId);
}
if (mToolbarBottom && !has_command)
{
has_command = mToolbarBottom->hasCommand(commandId);
}
return has_command;
}
bool LLToolBarView::addCommand(const LLCommandId& command, LLToolBar* toolbar)
{
LLCommandManager& mgr = LLCommandManager::instance();
if (mgr.getCommand(command))
{
toolbar->addCommand(command);
}
else
{
llwarns << "Toolbars creation : the command " << command.name() << " cannot be found in the command manager" << llendl;
return false;
}
return true;
}
bool LLToolBarView::loadToolbars(bool force_default)
{
LLToolBarView::ToolbarSet toolbar_set;
// Load the toolbars.xml file
std::string toolbar_file = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "toolbars.xml");
if (force_default)
{
toolbar_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "toolbars.xml");
}
else if (!gDirUtilp->fileExists(toolbar_file))
{
llwarns << "User toolbars def not found -> use default" << llendl;
toolbar_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "toolbars.xml");
}
LLXMLNodePtr root;
if(!LLXMLNode::parseFile(toolbar_file, root, NULL))
{
llerrs << "Unable to load toolbars from file: " << toolbar_file << llendl;
return false;
}
if(!root->hasName("toolbars"))
{
llwarns << toolbar_file << " is not a valid toolbars definition file" << llendl;
return false;
}
// Parse the toolbar settings
LLXUIParser parser;
parser.readXUI(root, toolbar_set, toolbar_file);
if (!toolbar_set.validateBlock())
{
llerrs << "Unable to validate toolbars from file: " << toolbar_file << llendl;
return false;
}
// Clear the toolbars now before adding the loaded commands and settings
if (mToolbarLeft)
{
mToolbarLeft->clearCommandsList();
}
if (mToolbarRight)
{
mToolbarRight->clearCommandsList();
}
if (mToolbarBottom)
{
mToolbarBottom->clearCommandsList();
}
// Add commands to each toolbar
if (toolbar_set.left_toolbar.isProvided() && mToolbarLeft)
{
if (toolbar_set.left_toolbar.button_display_mode.isProvided())
{
LLToolBarEnums::ButtonType button_type = toolbar_set.left_toolbar.button_display_mode;
mToolbarLeft->setButtonType(button_type);
}
BOOST_FOREACH(LLCommandId::Params& command, toolbar_set.left_toolbar.commands)
{
addCommand(LLCommandId(command),mToolbarLeft);
}
}
if (toolbar_set.right_toolbar.isProvided() && mToolbarRight)
{
if (toolbar_set.right_toolbar.button_display_mode.isProvided())
{
LLToolBarEnums::ButtonType button_type = toolbar_set.right_toolbar.button_display_mode;
mToolbarRight->setButtonType(button_type);
}
BOOST_FOREACH(LLCommandId::Params& command, toolbar_set.right_toolbar.commands)
{
addCommand(LLCommandId(command),mToolbarRight);
}
}
if (toolbar_set.bottom_toolbar.isProvided() && mToolbarBottom)
{
if (toolbar_set.bottom_toolbar.button_display_mode.isProvided())
{
LLToolBarEnums::ButtonType button_type = toolbar_set.bottom_toolbar.button_display_mode;
mToolbarBottom->setButtonType(button_type);
}
BOOST_FOREACH(LLCommandId::Params& command, toolbar_set.bottom_toolbar.commands)
{
addCommand(LLCommandId(command),mToolbarBottom);
}
}
return true;
}
//static
bool LLToolBarView::loadDefaultToolbars()
{
bool retval = false;
if (gToolBarView)
{
retval = gToolBarView->loadToolbars(true);
}
return retval;
}
void LLToolBarView::saveToolbars() const
{
// Build the parameter tree from the toolbar data
LLToolBarView::ToolbarSet toolbar_set;
if (mToolbarLeft)
{
toolbar_set.left_toolbar.button_display_mode = mToolbarLeft->getButtonType();
addToToolset(mToolbarLeft->getCommandsList(),toolbar_set.left_toolbar);
}
if (mToolbarRight)
{
toolbar_set.right_toolbar.button_display_mode = mToolbarRight->getButtonType();
addToToolset(mToolbarRight->getCommandsList(),toolbar_set.right_toolbar);
}
if (mToolbarBottom)
{
toolbar_set.bottom_toolbar.button_display_mode = mToolbarBottom->getButtonType();
addToToolset(mToolbarBottom->getCommandsList(),toolbar_set.bottom_toolbar);
}
// Serialize the parameter tree
LLXMLNodePtr output_node = new LLXMLNode("toolbars", false);
LLXUIParser parser;
parser.writeXUI(output_node, toolbar_set);
// Write the resulting XML to file
if(!output_node->isNull())
{
const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "toolbars.xml");
LLFILE *fp = LLFile::fopen(filename, "w");
if (fp != NULL)
{
LLXMLNode::writeHeaderToFile(fp);
output_node->writeToFile(fp);
fclose(fp);
}
}
}
// Enumerate the commands in command_list and add them as Params to the toolbar
void LLToolBarView::addToToolset(command_id_list_t& command_list, Toolbar& toolbar) const
{
for (command_id_list_t::const_iterator it = command_list.begin();
it != command_list.end();
++it)
{
LLCommandId::Params command;
command.name = it->name();
toolbar.commands.add(command);
}
}
void LLToolBarView::draw()
{
//LLPanel* sizer_left = getChild<LLPanel>("sizer_left");
LLRect bottom_rect, left_rect, right_rect;
if (mToolbarBottom)
{
mToolbarBottom->getParent()->reshape(mToolbarBottom->getParent()->getRect().getWidth(), mToolbarBottom->getRect().getHeight());
mToolbarBottom->localRectToOtherView(mToolbarBottom->getLocalRect(), &bottom_rect, this);
}
if (mToolbarLeft)
{
mToolbarLeft->getParent()->reshape(mToolbarLeft->getRect().getWidth(), mToolbarLeft->getParent()->getRect().getHeight());
mToolbarLeft->localRectToOtherView(mToolbarLeft->getLocalRect(), &left_rect, this);
}
if (mToolbarRight)
{
mToolbarRight->getParent()->reshape(mToolbarRight->getRect().getWidth(), mToolbarRight->getParent()->getRect().getHeight());
mToolbarRight->localRectToOtherView(mToolbarRight->getLocalRect(), &right_rect, this);
}
// Debug draw
LLColor4 back_color = LLColor4::blue;
LLColor4 back_color_vert = LLColor4::red;
LLColor4 back_color_hori = LLColor4::yellow;
back_color[VALPHA] = 0.5f;
back_color_hori[VALPHA] = 0.5f;
back_color_vert[VALPHA] = 0.5f;
//gl_rect_2d(getLocalRect(), back_color, TRUE);
//gl_rect_2d(bottom_rect, back_color_hori, TRUE);
//gl_rect_2d(left_rect, back_color_vert, TRUE);
//gl_rect_2d(right_rect, back_color_vert, TRUE);
LLUICtrl::draw();
}
// ----------------------------------------
// Drag and Drop hacks (under construction)
// ----------------------------------------
void LLToolBarView::startDragItem( S32 x, S32 y, const LLUUID& uuid)
{
//llinfos << "Merov debug: startDragItem() : x = " << x << ", y = " << y << llendl;
LLToolDragAndDrop::getInstance()->setDragStart( x, y );
sDragStarted = false;
}
BOOL LLToolBarView::handleDragItem( S32 x, S32 y, const LLUUID& uuid, LLAssetType::EType type)
{
// llinfos << "Merov debug: handleDragItem() : x = " << x << ", y = " << y << ", uuid = " << uuid << llendl;
if (LLToolDragAndDrop::getInstance()->isOverThreshold( x, y ))
{
if (!sDragStarted)
{
std::vector<EDragAndDropType> types;
uuid_vec_t cargo_ids;
types.push_back(DAD_WIDGET);
cargo_ids.push_back(uuid);
gClipboard.setSourceObject(uuid,LLAssetType::AT_WIDGET);
LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_VIEWER;
LLUUID srcID;
//llinfos << "Merov debug: handleDragItem() : beginMultiDrag()" << llendl;
LLToolDragAndDrop::getInstance()->beginMultiDrag(types, cargo_ids, src, srcID);
sDragStarted = true;
return TRUE;
}
else
{
MASK mask = 0;
return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask );
}
}
return FALSE;
}
BOOL LLToolBarView::handleDrop( void* cargo_data, S32 x, S32 y, LLToolBar* toolbar)
{
LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
//llinfos << "Merov debug : handleDrop. Drop " << inv_item->getUUID() << " named " << inv_item->getName() << " of type " << inv_item->getType() << llendl;
LLAssetType::EType type = inv_item->getType();
if (type == LLAssetType::AT_WIDGET)
{
//llinfos << "Merov debug : handleDrop. Drop source is a widget -> drop it in place..." << llendl;
// Get the command from its uuid
LLCommandManager& mgr = LLCommandManager::instance();
LLCommandId command_id(inv_item->getUUID());
LLCommand* command = mgr.getCommand(command_id);
if (command)
{
// Convert the (x,y) position in rank in toolbar
int rank = 0;
if (!toolbar->isReadOnly())
{
rank = toolbar->getRankFromPosition(x,y);
}
// Suppress the command from the toolbars (including the one it's dropped in,
// this will handle move position).
gToolBarView->mToolbarLeft->removeCommand(command->id());
gToolBarView->mToolbarRight->removeCommand(command->id());
gToolBarView->mToolbarBottom->removeCommand(command->id());
// Now insert it in the toolbar at the detected rank
if (!toolbar->isReadOnly())
{
toolbar->addCommand(command->id(),rank);
}
}
else
{
llwarns << "Command couldn't be found in command manager" << llendl;
}
}
return TRUE;
}