Add the new menubar code, which isn't used yet.

This commit is contained in:
Mark de Wever 2008-07-18 20:41:09 +00:00
parent 0873271bde
commit 477e594938
10 changed files with 566 additions and 0 deletions

View file

@ -0,0 +1,40 @@
###
### Definition of a menubar
###
### This type of widget is used for menus but also as tablist in a tabcontrol.
### The menubar has one row/column of items and not scrolloptions if too
### wide/high. Thus too wide/high shouldn't happen...
###
[menubar_definition]
id = "default"
description = "a menubar as used for a menu"
must_have_one_item_selected = "false"
[resolution]
min_width = 22
min_height = 22
default_width = 22
default_height = 22
max_width = 0
max_height = 0
text_font_size = 16
[state_enabled]
[draw]
[/draw]
[/state_enabled]
[state_disabled]
[draw]
[/draw]
[/state_disabled]
[/resolution]
[/menubar_definition]

View file

@ -18,6 +18,7 @@ src/gui/widgets/grid.cpp
src/gui/widgets/helper.cpp
src/gui/widgets/label.cpp
src/gui/widgets/listbox.cpp
src/gui/widgets/menubar.cpp
src/gui/widgets/panel.cpp
src/gui/widgets/scrollbar.cpp
src/gui/widgets/settings.cpp

View file

@ -238,6 +238,7 @@ SET(wesnoth-main_SRC
gui/widgets/helper.cpp
gui/widgets/label.cpp
gui/widgets/listbox.cpp
gui/widgets/menubar.cpp
gui/widgets/panel.cpp
gui/widgets/settings.cpp
gui/widgets/slider.cpp

View file

@ -85,6 +85,7 @@ wesnoth_source = \
gui/widgets/helper.cpp \
gui/widgets/label.cpp \
gui/widgets/listbox.cpp \
gui/widgets/menubar.cpp \
gui/widgets/panel.cpp \
gui/widgets/settings.cpp \
gui/widgets/scrollbar.cpp \

View file

@ -212,6 +212,7 @@ wesnoth_sources = Split("""
gui/widgets/helper.cpp
gui/widgets/label.cpp
gui/widgets/listbox.cpp
gui/widgets/menubar.cpp
gui/widgets/panel.cpp
gui/widgets/settings.cpp
gui/widgets/scrollbar.cpp

188
src/gui/widgets/menubar.cpp Normal file
View file

@ -0,0 +1,188 @@
/* $Id$ */
/*
copyright (C) 2008 by mark de wever <koraq@xs4all.nl>
part of the battle for wesnoth project http://www.wesnoth.org/
this program is free software; you can redistribute it and/or modify
it under the terms of the gnu general public license version 2
or at your option any later version.
this program is distributed in the hope that it will be useful,
but without any warranty.
see the copying file for more details.
*/
#include "gui/widgets/menubar.hpp"
#include "foreach.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/toggle_panel.hpp"
#include "log.hpp"
#define DBG_G LOG_STREAM_INDENT(debug, gui)
#define LOG_G LOG_STREAM_INDENT(info, gui)
#define WRN_G LOG_STREAM_INDENT(warn, gui)
#define ERR_G LOG_STREAM_INDENT(err, gui)
#define DBG_G_D LOG_STREAM_INDENT(debug, gui_draw)
#define LOG_G_D LOG_STREAM_INDENT(info, gui_draw)
#define WRN_G_D LOG_STREAM_INDENT(warn, gui_draw)
#define ERR_G_D LOG_STREAM_INDENT(err, gui_draw)
#define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
#define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
#define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
#define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
#define DBG_G_P LOG_STREAM_INDENT(debug, gui_parse)
#define LOG_G_P LOG_STREAM_INDENT(info, gui_parse)
#define WRN_G_P LOG_STREAM_INDENT(warn, gui_parse)
#define ERR_G_P LOG_STREAM_INDENT(err, gui_parse)
namespace gui2 {
static tmenubar* get_menubar(twidget* widget)
{
do {
widget = widget->parent();
} while (widget && !dynamic_cast<tmenubar*>(widget));
tmenubar* menubar = dynamic_cast<tmenubar*>(widget);
assert(menubar);
return menubar;
}
static void callback_select_item(twidget* caller)
{
get_menubar(caller)->item_selected(caller);
}
size_t tmenubar::get_item_count() const
{
if(direction_ == VERTICAL) {
return grid().get_rows();
} else {
return grid().get_cols();
}
}
void tmenubar::set_must_select(const bool must_select)
{
assert(!must_select || selected_item_ != -1);
must_select_ = must_select;
}
void tmenubar::set_selected_item(const int item)
{
assert(!must_select_ || item != -1);
if(item == selected_item_) {
return;
}
if(selected_item_ != -1) {
(*(*this)[selected_item_]).set_selected(false);
}
selected_item_ = item;
if(selected_item_ != -1) {
(*(*this)[selected_item_]).set_selected(true);
}
}
void tmenubar::set_state(const tstate state)
{
if(state != state_) {
state_ = state;
set_dirty(true);
}
}
void tmenubar::item_selected(twidget* widget)
{
std::cerr << "click.\n";
tselectable_* item = dynamic_cast<tselectable_*>(widget);
assert(item);
// Find the widget clicked upon.
size_t index = 0;
for(; index < get_item_count(); ++index) {
if((*this)[index] == item) {
break;
}
}
assert(index < get_item_count());
// Set the selection.
if(!item->is_selected()) {
// Deselected an item, allowed?
if(must_select_) {
item->set_selected();
} else {
selected_item_ = -1;
}
} else {
set_selected_item(index);
}
}
const tselectable_* tmenubar::operator[](const size_t index) const
{
assert(index < get_item_count());
const tselectable_* widget = NULL;
if(direction_ == VERTICAL) {
widget = dynamic_cast<const tselectable_*>(grid().widget(index, 0));
} else {
widget = dynamic_cast<const tselectable_*>(grid().widget(0, index));
}
assert(widget);
return widget;
}
tselectable_* tmenubar::operator[](const size_t index)
{
assert(index < get_item_count());
tselectable_* widget = NULL;
if(direction_ == VERTICAL) {
widget = dynamic_cast<tselectable_*>(grid().widget(index, 0));
} else {
widget = dynamic_cast<tselectable_*>(grid().widget(0, index));
}
assert(widget);
return widget;
}
void tmenubar::finalize_setup()
{
for(unsigned row = 0; row < grid().get_rows(); ++row) {
for(unsigned col = 0; col < grid().get_cols(); ++col) {
twidget* widget = grid().widget(row, col);
assert(widget);
ttoggle_button* btn = dynamic_cast<ttoggle_button*>(widget);
ttoggle_panel* panel = dynamic_cast<ttoggle_panel*>(widget);
if(btn) {
btn->set_callback_mouse_left_click(callback_select_item);
} else if(panel) {
panel->set_callback_mouse_left_click(callback_select_item);
} else {
std::cerr << "Widget type " << typeid(*widget).name() << ".\n";
assert(false);
}
}
}
}
} // namespace gui2

125
src/gui/widgets/menubar.hpp Normal file
View file

@ -0,0 +1,125 @@
/* $Id$ */
/*
copyright (C) 2008 by mark de wever <koraq@xs4all.nl>
part of the battle for wesnoth project http://www.wesnoth.org/
this program is free software; you can redistribute it and/or modify
it under the terms of the gnu general public license version 2
or at your option any later version.
this program is distributed in the hope that it will be useful,
but without any warranty.
see the copying file for more details.
*/
#ifndef GUI_WIDGETS_MENUBAR_HPP_INCLUDED
#define GUI_WIDGETS_MENUBAR_HPP_INCLUDED
#include "gui/widgets/container.hpp"
namespace gui2 {
/**
* A menu bar.
*
* A menu bar is a generic component which can hold mutiple toggle items of which
* zero or one are selected. Whether zero is allowed depends on the selection mode.
* The elements can be order horizontally or vertically which is set in WML.
*/
class tmenubar : public tcontainer_
{
friend class tbuilder_menubar;
public:
/** The direction is which the items are next to eachother. */
enum tdirection { HORIZONTAL, VERTICAL };
tmenubar(const tdirection direction) :
tcontainer_(COUNT),
state_(ENABLED),
callback_selection_change_(0),
must_select_(false),
selected_item_(-1),
direction_(direction)
{
}
/** Returns the number of items in the menu. */
size_t get_item_count() const;
/***** ***** ***** ***** Inherited ***** ***** ***** *****/
/** Inherited from tcontrol. */
void set_active(const bool active) {} ; // FIXME implement
/** Inherited from tcontrol. */
bool get_active() const { return state_ != DISABLED; }
/** Inherited from tcontrol. */
unsigned get_state() const { return state_; }
/** Inherited from tcontainer_. */
bool has_vertical_scrollbar() const { return false; }
/**
* Update our state when a widget selected or deselected an item.
*
* @param widget The widget that changed its state by a user
* action.
*/
void item_selected(twidget* widget) ;
/***** ***** ***** setters / getters for members ***** ****** *****/
void set_callback_selection_change(void (*callback) (twidget*))
{ callback_selection_change_ = callback; }
void set_must_select(const bool must_select);
void set_selected_item(const int item);
int get_selected_item() const { return selected_item_; }
private:
/**
* Possible states of the widget.
*
* Note the order of the states must be the same as defined in settings.hpp.
*/
enum tstate { ENABLED, DISABLED, COUNT };
void set_state(const tstate state);
/**
* Current state of the widget.
*
* The state of the widget determines what to render and how the widget
* reacts to certain 'events'.
*/
tstate state_;
/** This callback is used when the selection is changed by the user. */
void (*callback_selection_change_) (twidget*);
/** Do we always need to select an item? */
bool must_select_;
/** The selected item -1 for none. */
int selected_item_;
/** The direction of the menu bar. */
tdirection direction_;
/** Returns an item. */
const tselectable_* operator[](const size_t index) const;
tselectable_* operator[](const size_t index);
/** The builder needs to call us so we can wire in the proper callbacks. */
void finalize_setup();
/** Inherited from tcontrol. */
const std::string& get_control_type() const
{ static const std::string type = "menubar"; return type; }
};
} // namespace gui2
#endif

View file

@ -174,6 +174,7 @@ const std::string& tgui_definition::read(const config& cfg)
* <span id="widget_list"></span>List of available widgets:
* @start_table = widget_definition
* button_definition A push button.
* menubar_definition A menubar which is used in menus and the tabbar in a tabcontrol.
* label_definition A label.
* listbox_definition A listbox.
* panel_definition A panel.
@ -209,6 +210,7 @@ const std::string& tgui_definition::read(const config& cfg)
/***** Control definitions *****/
load_definitions<tbutton_definition>("button", cfg.get_children("button_definition"));
load_definitions<tmenubar_definition>("menubar", cfg.get_children("menubar_definition"));
load_definitions<tlabel_definition>("label", cfg.get_children("label_definition"));
load_definitions<tlistbox_definition>("listbox", cfg.get_children("listbox_definition"));
load_definitions<tpanel_definition>("panel", cfg.get_children("panel_definition"));
@ -494,6 +496,35 @@ tbutton_definition::tresolution::tresolution(const config& cfg) :
state.push_back(tstate_definition(cfg.child("state_focussed")));
}
tmenubar_definition::tmenubar_definition(const config& cfg) :
tcontrol_definition(cfg)
{
DBG_G_P << "Parsing menubar " << id << '\n';
load_resolutions<tresolution>(cfg.get_children("resolution"));
}
tmenubar_definition::tresolution::tresolution(const config& cfg) :
tresolution_definition_(cfg)
{
/*WIKI
* @page = GUIToolkitWML
* @order = 1_widget_menubar
*
* == Horizontal menubar ==
*
* The definition of a normal menubar.
*
* The following states exist:
* * state_enabled, the menubar is enabled.
* * state_disabled, the menubar is disabled.
*
*/
// Note the order should be the same as the enum tstate is menubar.hpp.
state.push_back(tstate_definition(cfg.child("state_enabled")));
state.push_back(tstate_definition(cfg.child("state_disabled")));
}
tlabel_definition::tlabel_definition(const config& cfg) :
tcontrol_definition(cfg)
{

View file

@ -121,6 +121,17 @@ struct tbutton_definition : public tcontrol_definition
};
struct tmenubar_definition : public tcontrol_definition
{
tmenubar_definition(const config& cfg);
struct tresolution : public tresolution_definition_
{
tresolution(const config& cfg);
};
};
struct tlabel_definition : public tcontrol_definition
{

View file

@ -20,6 +20,7 @@
#include "gui/widgets/button.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/listbox.hpp"
#include "gui/widgets/menubar.hpp"
#include "gui/widgets/slider.hpp"
#include "gui/widgets/spacer.hpp"
#include "gui/widgets/text_box.hpp"
@ -93,6 +94,45 @@ private:
int retval_;
};
/**
* A temporary helper class.
*
* @todo refactore with the grid builder.
*/
struct tbuilder_gridcell : public tbuilder_widget
{
tbuilder_gridcell(const config& cfg);
//! The flags for the cell.
unsigned flags;
//! The bordersize for the cell.
unsigned border_size;
//! The widgets for the cell.
tbuilder_widget_ptr widget;
// We're a dummy the building is done on construction.
twidget* build () const { return NULL; }
};
struct tbuilder_menubar : public tbuilder_control
{
tbuilder_menubar(const config& cfg);
twidget* build () const;
private:
bool must_have_one_item_selected_;
tmenubar::tdirection direction_;
int selected_item_;
std::vector<tbuilder_gridcell> cells_;
};
struct tbuilder_label : public tbuilder_control
{
@ -631,6 +671,8 @@ tbuilder_grid::tbuilder_grid(const config& cfg) :
if((**col_itor).child("button")) {
widgets.push_back(new tbuilder_button(*((**col_itor).child("button"))));
} else if((**col_itor).child("menubar")) {
widgets.push_back(new tbuilder_menubar(*((**col_itor).child("menubar"))));
} else if((**col_itor).child("label")) {
widgets.push_back(new tbuilder_label(*((**col_itor).child("label"))));
} else if((**col_itor).child("listbox")) {
@ -653,6 +695,7 @@ tbuilder_grid::tbuilder_grid(const config& cfg) :
} else if((**col_itor).child("grid")) {
widgets.push_back(new tbuilder_grid(*((**col_itor).child("grid"))));
} else {
std::cerr << (**col_itor);
assert(false);
}
@ -791,6 +834,129 @@ twidget* tbuilder_button::build() const
return button;
}
tbuilder_gridcell::tbuilder_gridcell(const config& cfg) :
tbuilder_widget(cfg),
flags(read_flags(cfg)),
border_size(lexical_cast_default<unsigned>((cfg)["border_size"])),
widget(NULL)
{
if((cfg).child("button")) {
widget=new tbuilder_button(*((cfg).child("button")));
} else if((cfg).child("menubar")) {
widget=new tbuilder_menubar(*((cfg).child("menubar")));
} else if((cfg).child("label")) {
widget=new tbuilder_label(*((cfg).child("label")));
} else if((cfg).child("listbox")) {
widget=new tbuilder_listbox(*((cfg).child("listbox")));
} else if((cfg).child("panel")) {
widget=new tbuilder_panel(*((cfg).child("panel")));
} else if((cfg).child("slider")) {
widget=new tbuilder_slider(*((cfg).child("slider")));
} else if((cfg).child("spacer")) {
widget=new tbuilder_spacer(*((cfg).child("spacer")));
} else if((cfg).child("text_box")) {
widget=new tbuilder_text_box(*((cfg).child("text_box")));
} else if((cfg).child("toggle_button")) {
widget=new tbuilder_toggle_button(*((cfg).child("toggle_button")));
} else if((cfg).child("toggle_panel")) {
widget=new tbuilder_toggle_panel(*((cfg).child("toggle_panel")));
} else if((cfg).child("vertical_scrollbar")) {
widget=
new tbuilder_vertical_scrollbar(*((cfg).child("vertical_scrollbar")));
} else if((cfg).child("grid")) {
widget=new tbuilder_grid(*((cfg).child("grid")));
} else {
std::cerr << cfg;
assert(false);
}
}
static tmenubar::tdirection read_direction(const std::string& direction)
{
if(direction == "vertical") {
return tmenubar::VERTICAL;
} else if(direction == "horizontal") {
return tmenubar::HORIZONTAL;
} else {
ERR_G_E << "Invalid direction "
<< direction << "' falling back to 'horizontal'.\n";
return tmenubar::HORIZONTAL;
}
}
tbuilder_menubar::tbuilder_menubar(const config& cfg) :
tbuilder_control(cfg),
must_have_one_item_selected_(utils::string_bool(cfg["must_have_one_item_selected"])),
direction_(read_direction(cfg["direction"])),
selected_item_(lexical_cast_default<int>(
cfg["selected_item"], must_have_one_item_selected_ ? 0 : -1)),
cells_()
{
/*WIKI
* @page = GUIToolkitWML
* @order = 3_widget_menubar
*
* == Menubar ==
*
* A menu bar used for menus and tab controls.
*
* List with the listbox specific variables:
* @start_table = config
* must_have_one_item_selected (bool = false)
* Does the menu always have one item
* selected. This makes sense for tabsheets
* but not for menus.
* direction (direction = "") The direction of the menubar.
* selected_item(int = -1) The item to select upon creation, when
* 'must_have_one_item_selected' is true the
* default value is 0 instead of -1. -1
* means no item selected.
* @end_table
*/
const config* data = cfg.child("data");
if(data) {
foreach(const config* cell, data->get_children("cell")) {
cells_.push_back(tbuilder_gridcell(*cell));
}
}
}
twidget* tbuilder_menubar::build() const
{
tmenubar* menubar = new tmenubar(direction_);
init_control(menubar);
DBG_G << "Window builder: placed menubar '" << id << "' with defintion '"
<< definition << "'.\n";
if(direction_ == tmenubar::HORIZONTAL) {
menubar->set_rows_cols(1, cells_.size());
for(size_t i = 0; i < cells_.size(); ++i) {
menubar->set_child(cells_[i].widget->build(),
0, i, cells_[i].flags, cells_[i].border_size);
}
} else {
// vertical growth
menubar->set_rows_cols(cells_.size(), 1);
for(size_t i = 0; i < cells_.size(); ++i) {
menubar->set_child(cells_[i].widget->build(),
i, 0, cells_[i].flags, cells_[i].border_size);
}
}
menubar->set_selected_item(selected_item_);
menubar->set_must_select(must_have_one_item_selected_);
menubar->finalize_setup();
return menubar;
}
twidget* tbuilder_label::build() const
{
tlabel* tmp_label = new tlabel();
@ -860,6 +1026,7 @@ tbuilder_listbox::tbuilder_listbox(const config& cfg) :
* * grid (to nest)
* * selectable widgets which are
* ** toggle_button
* ** toggle_panel
*
*/