mirror of
https://github.com/edeproject/ede.git
synced 2023-08-10 21:13:03 +03:00
371 lines
9.8 KiB
C++
371 lines
9.8 KiB
C++
|
//
|
||
|
// ActionMenu.cc for pekwm
|
||
|
// Copyright © 2002-2009 Claes Nästén <me@pekdon.net>
|
||
|
//
|
||
|
// This program is licensed under the GNU GPL.
|
||
|
// See the LICENSE file for more information.
|
||
|
//
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif // HAVE_CONFIG_H
|
||
|
|
||
|
#include <cstdio>
|
||
|
#include <iostream>
|
||
|
#include <set>
|
||
|
|
||
|
#include "PWinObj.hh"
|
||
|
#include "PDecor.hh"
|
||
|
#include "PMenu.hh"
|
||
|
#include "WORefMenu.hh"
|
||
|
#include "ActionMenu.hh"
|
||
|
#include "TextureHandler.hh"
|
||
|
#include "ImageHandler.hh"
|
||
|
|
||
|
#include "Config.hh"
|
||
|
#include "ActionHandler.hh"
|
||
|
#include "Client.hh"
|
||
|
#include "Frame.hh"
|
||
|
#include "WindowManager.hh"
|
||
|
#include "Util.hh"
|
||
|
|
||
|
using std::cerr;
|
||
|
using std::endl;
|
||
|
using std::find;
|
||
|
using std::list;
|
||
|
using std::string;
|
||
|
using std::wstring;
|
||
|
|
||
|
//! @brief ActionMenu constructor
|
||
|
//! @param type Type of menu
|
||
|
//! @param title Title of menu
|
||
|
//! @param name Name of the menu, empty for dynamic else should be unique
|
||
|
//! @param decor_name Name of decor to use, defaults to MENU.
|
||
|
ActionMenu::ActionMenu(MenuType type,
|
||
|
const std::wstring &title, const std::string &name,
|
||
|
const std::string &decor_name) :
|
||
|
WORefMenu(WindowManager::instance()->getScreen(),
|
||
|
WindowManager::instance()->getTheme(), title, name, decor_name),
|
||
|
_act(WindowManager::instance()->getActionHandler()),
|
||
|
_has_dynamic(false)
|
||
|
{
|
||
|
// when creating dynamic submenus, this needs to be initialized as
|
||
|
// dynamic inserting will be done
|
||
|
_insert_at = _item_list.begin();
|
||
|
_menu_type = type;
|
||
|
|
||
|
if (_menu_type == WINDOWMENU_TYPE) {
|
||
|
_action_ok = WINDOWMENU_OK;
|
||
|
} else if ((_menu_type == ROOTMENU_TYPE) || (_menu_type == ROOTMENU_STANDALONE_TYPE)) {
|
||
|
_action_ok = ROOTMENU_OK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief ActionMenu destructor
|
||
|
ActionMenu::~ActionMenu(void)
|
||
|
{
|
||
|
removeAll();
|
||
|
}
|
||
|
|
||
|
// START - PWinObj interface.
|
||
|
|
||
|
//! @brief Rebuilds the vmenu and if it has any items after it shows it.
|
||
|
void
|
||
|
ActionMenu::mapWindow(void)
|
||
|
{
|
||
|
// find and rebuild the dynamic entries
|
||
|
if (! isMapped() && _has_dynamic) {
|
||
|
uint size_before = _item_list.size();
|
||
|
rebuildDynamic();
|
||
|
if (size_before != _item_list.size()) {
|
||
|
buildMenu();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PMenu::mapWindow();
|
||
|
}
|
||
|
|
||
|
//! @brief Hides and removes all items created by dynamic entries.
|
||
|
void
|
||
|
ActionMenu::unmapWindow(void)
|
||
|
{
|
||
|
if (! isMapped()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (_has_dynamic) {
|
||
|
removeDynamic();
|
||
|
}
|
||
|
|
||
|
PMenu::unmapWindow();
|
||
|
}
|
||
|
|
||
|
// END - PWinObj interface.
|
||
|
|
||
|
//! @brief Handle item exec.
|
||
|
void
|
||
|
ActionMenu::handleItemExec(PMenu::Item *item)
|
||
|
{
|
||
|
if (! item) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ActionPerformed ap(getWORef(), item->getAE());
|
||
|
_act->handleAction(ap);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Re-reads the configuration clearing old entries from the menu. This
|
||
|
* adds the ICON_PATH to the ImageHandler before loading to support
|
||
|
* loading icons properly.
|
||
|
*
|
||
|
* @param section CfgParser::Entry with menu configuration
|
||
|
*/
|
||
|
void
|
||
|
ActionMenu::reload(CfgParser::Entry *section)
|
||
|
{
|
||
|
// Clear menu
|
||
|
removeAll();
|
||
|
|
||
|
// Parse section (if any)
|
||
|
ImageHandler::instance()->path_push_back(Config::instance()->getSystemIconPath());
|
||
|
ImageHandler::instance()->path_push_back(Config::instance()->getIconPath());
|
||
|
_insert_at = _item_list.begin();
|
||
|
parse(section);
|
||
|
ImageHandler::instance()->path_pop_back();
|
||
|
ImageHandler::instance()->path_pop_back();
|
||
|
|
||
|
// Build menu from parsed content
|
||
|
buildMenu();
|
||
|
}
|
||
|
|
||
|
//! @brief Checks if we have a position set for where to insert.
|
||
|
void
|
||
|
ActionMenu::insert(PMenu::Item *item)
|
||
|
{
|
||
|
if (! item) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
checkItemWORef(item);
|
||
|
|
||
|
_insert_at = _item_list.insert(++_insert_at, item);
|
||
|
}
|
||
|
|
||
|
//! @brief Non-shadowing PMenu::insert
|
||
|
void
|
||
|
ActionMenu::insert(const std::wstring &name, PWinObj *wo_ref, PTexture *icon)
|
||
|
{
|
||
|
PMenu::insert(name, wo_ref, icon);
|
||
|
}
|
||
|
|
||
|
//! @brief Non-shadowing PMenu::insert
|
||
|
void
|
||
|
ActionMenu::insert(const std::wstring &name, const ActionEvent &ae, PWinObj *wo_ref, PTexture *icon)
|
||
|
{
|
||
|
PMenu::insert(name, ae, wo_ref);
|
||
|
}
|
||
|
|
||
|
//! @brief Removes a BaseMenuItem from the menu
|
||
|
void
|
||
|
ActionMenu::remove(PMenu::Item *item)
|
||
|
{
|
||
|
if (! item) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (item->getIcon()) {
|
||
|
TextureHandler::instance()->returnTexture(item->getIcon());
|
||
|
}
|
||
|
|
||
|
if (item->getWORef() && (item->getWORef()->getType() == WO_MENU)) {
|
||
|
delete item->getWORef();
|
||
|
}
|
||
|
|
||
|
PMenu::remove(item);
|
||
|
}
|
||
|
|
||
|
//! @brief Removes all items from the menu
|
||
|
void
|
||
|
ActionMenu::removeAll(void)
|
||
|
{
|
||
|
while (_item_list.size() > 0) {
|
||
|
remove(_item_list.back());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! @brief Parse config and push items into menu
|
||
|
//! @param cs Section object to read config from
|
||
|
//! @param menu BaseMenu object to push object in
|
||
|
//! @param has_dynamic If true the menu being parsed is dynamic, defaults to false.
|
||
|
void
|
||
|
ActionMenu::parse(CfgParser::Entry *section, PMenu::Item *parent)
|
||
|
{
|
||
|
if (! section) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (section->get_value().size()) {
|
||
|
wstring title(Util::to_wide_str(section->get_value()));
|
||
|
setTitle(title);
|
||
|
_title_base = title;
|
||
|
}
|
||
|
|
||
|
CfgParser::Entry *value;
|
||
|
ActionEvent ae;
|
||
|
|
||
|
ActionMenu *submenu = 0;
|
||
|
PMenu::Item *item = 0;
|
||
|
PTexture *icon = 0;
|
||
|
|
||
|
CfgParser::iterator it(section->begin());
|
||
|
for (; it != section->end(); ++it) {
|
||
|
item = 0;
|
||
|
|
||
|
if (*(*it) == "SUBMENU") {
|
||
|
CfgParser::Entry *sub_section = (*it)->get_section();
|
||
|
if (sub_section) {
|
||
|
icon = getIcon(sub_section->find_entry("ICON"));
|
||
|
|
||
|
submenu = new ActionMenu(_menu_type, Util::to_wide_str((*it)->get_value()), (*it)->get_value());
|
||
|
submenu->_menu_parent = this;
|
||
|
submenu->parse(sub_section, parent);
|
||
|
submenu->buildMenu();
|
||
|
|
||
|
item = new PMenu::Item(Util::to_wide_str(sub_section->get_value()), submenu, icon);
|
||
|
item->setCreator(parent);
|
||
|
} else {
|
||
|
cerr << " *** WARNING: submenu entry does not contain any section." << endl;
|
||
|
}
|
||
|
} else if (*(*it) == "SEPARATOR") {
|
||
|
// No icon support on separators.
|
||
|
item = new PMenu::Item(L"", 0, 0);
|
||
|
item->setType(PMenu::Item::MENU_ITEM_SEPARATOR);
|
||
|
item->setCreator(parent);
|
||
|
|
||
|
} else {
|
||
|
CfgParser::Entry *sub_section = (*it)->get_section();
|
||
|
if (sub_section) {
|
||
|
// Inside of the Entry = "foo" { ... } section, here
|
||
|
// Actions and Icon are the valid options.
|
||
|
value = sub_section->find_entry("ACTIONS");
|
||
|
if (value && Config::instance()->parseActions(value->get_value(), ae, _action_ok)) {
|
||
|
icon = getIcon(sub_section->find_entry("ICON"));
|
||
|
|
||
|
item = new PMenu::Item(Util::to_wide_str(sub_section->get_value()), 0, icon);
|
||
|
item->setCreator(parent);
|
||
|
item->setAE(ae);
|
||
|
|
||
|
if (ae.isOnlyAction(ACTION_MENU_DYN)) {
|
||
|
_has_dynamic = true;
|
||
|
item->setType(PMenu::Item::MENU_ITEM_HIDDEN);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If an item was successfully created, insert it to the menu.
|
||
|
if (item) {
|
||
|
ActionMenu::insert (item);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get icon texture from parser value.
|
||
|
*
|
||
|
* @param value Entry to get icon name from.
|
||
|
* @return PTexture if icon was loaded, else 0.
|
||
|
*/
|
||
|
PTexture*
|
||
|
ActionMenu::getIcon(CfgParser::Entry *value)
|
||
|
{
|
||
|
// Skip blank icons
|
||
|
if (! value || ! value->get_value().size()) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTexture *icon = 0;
|
||
|
|
||
|
// Try to load the icon as a complete texture specification, if
|
||
|
// that fails load is an scaled image.
|
||
|
icon = TextureHandler::instance()->getTexture(value->get_value());
|
||
|
if (! icon) {
|
||
|
icon = TextureHandler::instance()->getTexture("IMAGE " + value->get_value() + "#SCALED");
|
||
|
}
|
||
|
|
||
|
return icon;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Executes all Dynamic entries in the menu.
|
||
|
*/
|
||
|
void
|
||
|
ActionMenu::rebuildDynamic(void)
|
||
|
{
|
||
|
PWinObj *wo_ref = getWORef();
|
||
|
|
||
|
// Export environment before to dynamic script.
|
||
|
Client *client = 0;
|
||
|
if (wo_ref && wo_ref->getType() == WO_CLIENT) {
|
||
|
client = static_cast<Client*>(wo_ref);
|
||
|
}
|
||
|
Client::setClientEnvironment(client);
|
||
|
|
||
|
// Setup icon path before parsing.
|
||
|
ImageHandler::instance()->path_push_back(Config::instance()->getSystemIconPath());
|
||
|
ImageHandler::instance()->path_push_back(Config::instance()->getIconPath());
|
||
|
|
||
|
PMenu::Item* item = 0;
|
||
|
list<PMenu::Item*>::iterator it;
|
||
|
for (it = _item_list.begin(); it != _item_list.end(); ++it) {
|
||
|
if ((*it)->getAE().isOnlyAction(ACTION_MENU_DYN)) {
|
||
|
_insert_at = it;
|
||
|
|
||
|
item = *it;
|
||
|
|
||
|
CfgParser dynamic;
|
||
|
if (dynamic.parse((*it)->getAE().action_list.front().getParamS(),
|
||
|
CfgParserSource::SOURCE_COMMAND)) {
|
||
|
_has_dynamic = true;
|
||
|
parse(dynamic.get_entry_root()->find_section("DYNAMIC"), *it);
|
||
|
}
|
||
|
|
||
|
it = find(_item_list.begin(), _item_list.end(), item);
|
||
|
_insert_at = _item_list.end();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Cleanup icon path
|
||
|
ImageHandler::instance()->path_pop_back();
|
||
|
ImageHandler::instance()->path_pop_back();
|
||
|
}
|
||
|
|
||
|
//! @brief Remove all entries from the menu created by dynamic entries.
|
||
|
void
|
||
|
ActionMenu::removeDynamic(void)
|
||
|
{
|
||
|
std::set<PMenu::Item *> dynlist;
|
||
|
|
||
|
list<PMenu::Item*>::iterator it(_item_list.begin());
|
||
|
for (; it != _item_list.end(); ++it) {
|
||
|
if ((*it)->getType() == PMenu::Item::MENU_ITEM_HIDDEN) {
|
||
|
dynlist.insert(*it);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
it = _item_list.begin();
|
||
|
for (; it != _item_list.end();) {
|
||
|
if (dynlist.find((*it)->getCreator()) != dynlist.end()) {
|
||
|
if ((*it)->getWORef() && ((*it)->getWORef()->getType() == WO_MENU)) {
|
||
|
delete (*it)->getWORef();
|
||
|
}
|
||
|
delete (*it);
|
||
|
it = _item_list.erase(it);
|
||
|
} else {
|
||
|
++it;
|
||
|
}
|
||
|
}
|
||
|
}
|