Fix menu_button widget trying to be two things at the same time.
The menu_button is now only a drop-down menu that supports a single selection. A new multimenu_button widget supports a drop-down menu with multiple selections. The new multimenu_button widget displays its current selection while not open.
This commit is contained in:
parent
b7aea011f9
commit
1793133a59
14 changed files with 820 additions and 78 deletions
|
@ -717,6 +717,12 @@
|
||||||
max="-1"
|
max="-1"
|
||||||
super="gui/button_definition"
|
super="gui/button_definition"
|
||||||
[/tag]
|
[/tag]
|
||||||
|
[tag]
|
||||||
|
name="multimenu_button_definition"
|
||||||
|
min="0"
|
||||||
|
max="-1"
|
||||||
|
super="gui/button_definition"
|
||||||
|
[/tag]
|
||||||
[tag]
|
[tag]
|
||||||
name="drawing_definition"
|
name="drawing_definition"
|
||||||
min="0"
|
min="0"
|
||||||
|
@ -1591,6 +1597,37 @@
|
||||||
[/key]
|
[/key]
|
||||||
[/tag]
|
[/tag]
|
||||||
[/tag]
|
[/tag]
|
||||||
|
[tag]
|
||||||
|
name="multimenu_button"
|
||||||
|
min="0"
|
||||||
|
max="-1"
|
||||||
|
super="gui/window/resolution/grid/row/column/button"
|
||||||
|
[key]
|
||||||
|
name="maximum_shown"
|
||||||
|
type="int"
|
||||||
|
default="-1"
|
||||||
|
[/key]
|
||||||
|
[tag]
|
||||||
|
name = "option"
|
||||||
|
min="0"
|
||||||
|
max="-1"
|
||||||
|
[key]
|
||||||
|
name="label"
|
||||||
|
type="string"
|
||||||
|
default=""
|
||||||
|
[/key]
|
||||||
|
[key]
|
||||||
|
name="tooltip"
|
||||||
|
type="string"
|
||||||
|
default=""
|
||||||
|
[/key]
|
||||||
|
[key]
|
||||||
|
name="checkbox"
|
||||||
|
type="bool"
|
||||||
|
default=""
|
||||||
|
[/key]
|
||||||
|
[/tag]
|
||||||
|
[/tag]
|
||||||
[tag]
|
[tag]
|
||||||
name="drawing"
|
name="drawing"
|
||||||
min="0"
|
min="0"
|
||||||
|
|
159
data/gui/widget/multimenu_button_default.cfg
Normal file
159
data/gui/widget/multimenu_button_default.cfg
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
#textdomain wesnoth-lib
|
||||||
|
###
|
||||||
|
### Definition of the default button.
|
||||||
|
###
|
||||||
|
|
||||||
|
#define _GUI_DRAW_BORDER _COLOR
|
||||||
|
[rectangle]
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
w = "(width)"
|
||||||
|
h = "(height)"
|
||||||
|
|
||||||
|
border_thickness = 1
|
||||||
|
border_color = {_COLOR}
|
||||||
|
|
||||||
|
[/rectangle]
|
||||||
|
#enddef
|
||||||
|
|
||||||
|
#define _GUI_TEXT FONT_SIZE FONT_COLOR
|
||||||
|
[text]
|
||||||
|
x = 5
|
||||||
|
y = {GUI__TEXT_VERTICALLY_CENTRED}
|
||||||
|
w = "(text_width)"
|
||||||
|
h = "(text_height)"
|
||||||
|
# 25 offset to accomadate the arrow
|
||||||
|
maximum_width = "(width - 25)"
|
||||||
|
font_size = {FONT_SIZE}
|
||||||
|
color = {FONT_COLOR}
|
||||||
|
text = "(text)"
|
||||||
|
text_markup = false
|
||||||
|
[/text]
|
||||||
|
#enddef
|
||||||
|
|
||||||
|
#define _GUI_RESOLUTION RESOLUTION MIN_WIDTH DEFAULT_WIDTH HEIGHT EXTRA_WIDTH EXTRA_HEIGHT FONT_SIZE BASE_NAME IPF
|
||||||
|
[resolution]
|
||||||
|
|
||||||
|
{RESOLUTION}
|
||||||
|
|
||||||
|
min_width = {MIN_WIDTH}
|
||||||
|
min_height = {HEIGHT}
|
||||||
|
|
||||||
|
default_width = {DEFAULT_WIDTH}
|
||||||
|
default_height = {HEIGHT}
|
||||||
|
|
||||||
|
max_width = 0
|
||||||
|
max_height = {HEIGHT}
|
||||||
|
|
||||||
|
text_extra_width = {EXTRA_WIDTH}
|
||||||
|
text_extra_height = {EXTRA_HEIGHT}
|
||||||
|
text_font_size = {FONT_SIZE}
|
||||||
|
|
||||||
|
[state_enabled]
|
||||||
|
|
||||||
|
[draw]
|
||||||
|
|
||||||
|
[image]
|
||||||
|
w = "(width)"
|
||||||
|
h = "(height)"
|
||||||
|
name = "buttons/{BASE_NAME}.png{IPF}"
|
||||||
|
[/image]
|
||||||
|
|
||||||
|
{_GUI_DRAW_BORDER ({GUI__BORDER_COLOR_DARK})}
|
||||||
|
|
||||||
|
{_GUI_TEXT ({FONT_SIZE}) ({GUI__FONT_COLOR_ENABLED__TITLE})}
|
||||||
|
|
||||||
|
[image]
|
||||||
|
x = "(width - 25)"
|
||||||
|
y = 2
|
||||||
|
name = "icons/arrows/short_arrow_left_25.png~ROTATE(-90)"
|
||||||
|
[/image]
|
||||||
|
[/draw]
|
||||||
|
|
||||||
|
[/state_enabled]
|
||||||
|
|
||||||
|
[state_disabled]
|
||||||
|
|
||||||
|
[draw]
|
||||||
|
|
||||||
|
[image]
|
||||||
|
w = "(width)"
|
||||||
|
h = "(height)"
|
||||||
|
name = "buttons/{BASE_NAME}.png~GS(){IPF}"
|
||||||
|
[/image]
|
||||||
|
|
||||||
|
{_GUI_DRAW_BORDER ({GUI__FONT_COLOR_DISABLED__DEFAULT})}
|
||||||
|
|
||||||
|
{_GUI_TEXT ({FONT_SIZE}) ({GUI__FONT_COLOR_DISABLED__TITLE})}
|
||||||
|
|
||||||
|
[image]
|
||||||
|
x = "(width - 25)"
|
||||||
|
y = 2
|
||||||
|
name = "icons/arrows/short_arrow_left_25.png~ROTATE(-90)~GS()"
|
||||||
|
[/image]
|
||||||
|
[/draw]
|
||||||
|
|
||||||
|
[/state_disabled]
|
||||||
|
|
||||||
|
[state_pressed]
|
||||||
|
|
||||||
|
[draw]
|
||||||
|
|
||||||
|
[image]
|
||||||
|
w = "(width)"
|
||||||
|
h = "(height)"
|
||||||
|
name = "buttons/{BASE_NAME}-pressed.png{IPF}"
|
||||||
|
[/image]
|
||||||
|
|
||||||
|
{_GUI_DRAW_BORDER ({GUI__BORDER_COLOR_DARK})}
|
||||||
|
|
||||||
|
{_GUI_TEXT ({FONT_SIZE}) ({GUI__FONT_COLOR_ENABLED__TITLE})}
|
||||||
|
|
||||||
|
[image]
|
||||||
|
x = "(width - 25)"
|
||||||
|
y = 2
|
||||||
|
name = "icons/arrows/short_arrow_left_25-active.png~ROTATE(-90)"
|
||||||
|
[/image]
|
||||||
|
[/draw]
|
||||||
|
|
||||||
|
[/state_pressed]
|
||||||
|
|
||||||
|
[state_focused]
|
||||||
|
|
||||||
|
[draw]
|
||||||
|
|
||||||
|
[image]
|
||||||
|
w = "(width)"
|
||||||
|
h = "(height)"
|
||||||
|
# Doesn't have its own 'active' variation image
|
||||||
|
name = "buttons/{BASE_NAME}-pressed.png{IPF}"
|
||||||
|
[/image]
|
||||||
|
|
||||||
|
{_GUI_DRAW_BORDER ({GUI__BORDER_COLOR_DARK})}
|
||||||
|
|
||||||
|
{_GUI_TEXT ({FONT_SIZE}) ({GUI__FONT_COLOR_ENABLED__TITLE})}
|
||||||
|
|
||||||
|
[image]
|
||||||
|
x = "(width - 25)"
|
||||||
|
y = 2
|
||||||
|
name = "icons/arrows/short_arrow_left_25-active.png~ROTATE(-90)"
|
||||||
|
[/image]
|
||||||
|
[/draw]
|
||||||
|
|
||||||
|
[/state_focused]
|
||||||
|
|
||||||
|
[/resolution]
|
||||||
|
#enddef
|
||||||
|
|
||||||
|
[multimenu_button_definition]
|
||||||
|
|
||||||
|
id = "default"
|
||||||
|
description = "Default button"
|
||||||
|
|
||||||
|
{_GUI_RESOLUTION () 40 180 30 13 4 ({GUI_FONT_SIZE_SMALL}) "button_dropdown/button_dropdown" ()}
|
||||||
|
|
||||||
|
[/multimenu_button_definition]
|
||||||
|
|
||||||
|
#undef _GUI_RESOLUTION
|
||||||
|
#undef _GUI_DRAW_BORDER
|
||||||
|
#undef _GUI_TEXT
|
|
@ -740,10 +740,11 @@
|
||||||
|
|
||||||
horizontal_alignment = "left"
|
horizontal_alignment = "left"
|
||||||
|
|
||||||
[menu_button]
|
[multimenu_button]
|
||||||
id = "type_filter"
|
id = "type_filter"
|
||||||
definition = "default"
|
definition = "default"
|
||||||
[/menu_button]
|
maximum_shown = 2
|
||||||
|
[/multimenu_button]
|
||||||
[/column]
|
[/column]
|
||||||
|
|
||||||
[column]
|
[column]
|
||||||
|
|
|
@ -236,10 +236,10 @@
|
||||||
border = "all"
|
border = "all"
|
||||||
border_size = 5
|
border_size = 5
|
||||||
|
|
||||||
[menu_button]
|
[multimenu_button]
|
||||||
id = "mods_menu"
|
id = "mods_menu"
|
||||||
definition = "default"
|
definition = "default"
|
||||||
[/menu_button]
|
[/multimenu_button]
|
||||||
|
|
||||||
[/column]
|
[/column]
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,11 @@
|
||||||
border_size = 5
|
border_size = 5
|
||||||
horizontal_alignment = "left"
|
horizontal_alignment = "left"
|
||||||
|
|
||||||
[menu_button]
|
[multimenu_button]
|
||||||
id = "hotkey_category_menu"
|
id = "hotkey_category_menu"
|
||||||
definition = "default"
|
definition = "default"
|
||||||
[/menu_button]
|
maximum_shown = 3
|
||||||
|
[/multimenu_button]
|
||||||
[/column]
|
[/column]
|
||||||
|
|
||||||
[/row]
|
[/row]
|
||||||
|
|
|
@ -2177,6 +2177,12 @@
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\gui\widgets\multimenu_button.cpp">
|
||||||
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\gui\widgets\multi_page.cpp">
|
<ClCompile Include="..\..\src\gui\widgets\multi_page.cpp">
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Gui\Widgets\</ObjectFileName>
|
||||||
|
@ -3760,6 +3766,7 @@
|
||||||
<ClInclude Include="..\..\src\gui\widgets\matrix.hpp" />
|
<ClInclude Include="..\..\src\gui\widgets\matrix.hpp" />
|
||||||
<ClInclude Include="..\..\src\gui\widgets\menu_button.hpp" />
|
<ClInclude Include="..\..\src\gui\widgets\menu_button.hpp" />
|
||||||
<ClInclude Include="..\..\src\gui\widgets\minimap.hpp" />
|
<ClInclude Include="..\..\src\gui\widgets\minimap.hpp" />
|
||||||
|
<ClInclude Include="..\..\src\gui\widgets\multimenu_button.hpp" />
|
||||||
<ClInclude Include="..\..\src\gui\widgets\multi_page.hpp" />
|
<ClInclude Include="..\..\src\gui\widgets\multi_page.hpp" />
|
||||||
<ClInclude Include="..\..\src\gui\widgets\pane.hpp" />
|
<ClInclude Include="..\..\src\gui\widgets\pane.hpp" />
|
||||||
<ClInclude Include="..\..\src\gui\widgets\panel.hpp" />
|
<ClInclude Include="..\..\src\gui\widgets\panel.hpp" />
|
||||||
|
|
|
@ -1529,6 +1529,9 @@
|
||||||
<ClCompile Include="..\..\src\gui\dialogs\outro.cpp">
|
<ClCompile Include="..\..\src\gui\dialogs\outro.cpp">
|
||||||
<Filter>Gui\Dialogs</Filter>
|
<Filter>Gui\Dialogs</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\gui\widgets\multimenu_button.cpp">
|
||||||
|
<Filter>Gui\Widgets</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\src\addon\client.hpp">
|
<ClInclude Include="..\..\src\addon\client.hpp">
|
||||||
|
@ -2972,6 +2975,9 @@
|
||||||
<ClInclude Include="..\..\src\gui\core\canvas_private.hpp">
|
<ClInclude Include="..\..\src\gui\core\canvas_private.hpp">
|
||||||
<Filter>Gui\Core</Filter>
|
<Filter>Gui\Core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\gui\widgets\multimenu_button.hpp">
|
||||||
|
<Filter>Gui\Widgets</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="..\..\src\tests\test_sdl_utils.hpp">
|
<CustomBuild Include="..\..\src\tests\test_sdl_utils.hpp">
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "gui/widgets/button.hpp"
|
#include "gui/widgets/button.hpp"
|
||||||
#include "gui/widgets/label.hpp"
|
#include "gui/widgets/label.hpp"
|
||||||
#include "gui/widgets/menu_button.hpp"
|
#include "gui/widgets/menu_button.hpp"
|
||||||
|
#include "gui/widgets/multimenu_button.hpp"
|
||||||
#include "gui/widgets/stacked_widget.hpp"
|
#include "gui/widgets/stacked_widget.hpp"
|
||||||
#include "gui/widgets/drawing.hpp"
|
#include "gui/widgets/drawing.hpp"
|
||||||
#include "gui/widgets/image.hpp"
|
#include "gui/widgets/image.hpp"
|
||||||
|
@ -359,7 +360,7 @@ void addon_manager::pre_show(window& window)
|
||||||
status_filter.set_values(status_filter_entries);
|
status_filter.set_values(status_filter_entries);
|
||||||
status_filter.connect_click_handler(std::bind(&addon_manager::apply_filters, this, std::ref(window)));
|
status_filter.connect_click_handler(std::bind(&addon_manager::apply_filters, this, std::ref(window)));
|
||||||
|
|
||||||
menu_button& type_filter = find_widget<menu_button>(&window, "type_filter", false);
|
multimenu_button& type_filter = find_widget<multimenu_button>(&window, "type_filter", false);
|
||||||
|
|
||||||
std::vector<config> type_filter_entries;
|
std::vector<config> type_filter_entries;
|
||||||
for(const auto& f : type_filter_types_) {
|
for(const auto& f : type_filter_types_) {
|
||||||
|
@ -538,7 +539,7 @@ boost::dynamic_bitset<> addon_manager::get_status_filter_visibility(const window
|
||||||
|
|
||||||
boost::dynamic_bitset<> addon_manager::get_type_filter_visibility(const window& window) const
|
boost::dynamic_bitset<> addon_manager::get_type_filter_visibility(const window& window) const
|
||||||
{
|
{
|
||||||
const menu_button& type_filter = find_widget<const menu_button>(&window, "type_filter", false);
|
const multimenu_button& type_filter = find_widget<const multimenu_button>(&window, "type_filter", false);
|
||||||
|
|
||||||
boost::dynamic_bitset<> toggle_states = type_filter.get_toggle_states();
|
boost::dynamic_bitset<> toggle_states = type_filter.get_toggle_states();
|
||||||
if(toggle_states.none()) {
|
if(toggle_states.none()) {
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#else
|
#else
|
||||||
#include "gui/widgets/listbox.hpp"
|
#include "gui/widgets/listbox.hpp"
|
||||||
#endif
|
#endif
|
||||||
#include "gui/widgets/menu_button.hpp"
|
#include "gui/widgets/multimenu_button.hpp"
|
||||||
#include "gui/widgets/multi_page.hpp"
|
#include "gui/widgets/multi_page.hpp"
|
||||||
#include "gui/widgets/scroll_label.hpp"
|
#include "gui/widgets/scroll_label.hpp"
|
||||||
#include "gui/widgets/settings.hpp"
|
#include "gui/widgets/settings.hpp"
|
||||||
|
@ -165,7 +165,7 @@ void campaign_selection::pre_show(window& window)
|
||||||
//
|
//
|
||||||
// Set up Mods selection dropdown
|
// Set up Mods selection dropdown
|
||||||
//
|
//
|
||||||
menu_button& mods_menu = find_widget<menu_button>(&window, "mods_menu", false);
|
multimenu_button& mods_menu = find_widget<multimenu_button>(&window, "mods_menu", false);
|
||||||
|
|
||||||
if(!engine_.get_const_extras_by_type(ng::create_engine::MOD).empty()) {
|
if(!engine_.get_const_extras_by_type(ng::create_engine::MOD).empty()) {
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ void campaign_selection::post_show(window& window)
|
||||||
|
|
||||||
void campaign_selection::mod_toggled(window& window)
|
void campaign_selection::mod_toggled(window& window)
|
||||||
{
|
{
|
||||||
boost::dynamic_bitset<> new_mod_states = find_widget<menu_button>(&window, "mods_menu", false).get_toggle_states();
|
boost::dynamic_bitset<> new_mod_states = find_widget<multimenu_button>(&window, "mods_menu", false).get_toggle_states();
|
||||||
|
|
||||||
// Get a mask of any mods that were toggled, regardless of new state
|
// Get a mask of any mods that were toggled, regardless of new state
|
||||||
mod_states_ = mod_states_ ^ new_mod_states;
|
mod_states_ = mod_states_ ^ new_mod_states;
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "gui/dialogs/transient_message.hpp"
|
#include "gui/dialogs/transient_message.hpp"
|
||||||
#include "gui/widgets/button.hpp"
|
#include "gui/widgets/button.hpp"
|
||||||
#include "gui/widgets/menu_button.hpp"
|
#include "gui/widgets/menu_button.hpp"
|
||||||
|
#include "gui/widgets/multimenu_button.hpp"
|
||||||
#include "gui/widgets/grid.hpp"
|
#include "gui/widgets/grid.hpp"
|
||||||
#include "gui/widgets/image.hpp"
|
#include "gui/widgets/image.hpp"
|
||||||
#include "gui/widgets/label.hpp"
|
#include "gui/widgets/label.hpp"
|
||||||
|
@ -704,7 +705,7 @@ void preferences_dialog::post_build(window& window)
|
||||||
hotkey_category_entries.emplace_back(config_of("label", name)("checkbox", false));
|
hotkey_category_entries.emplace_back(config_of("label", name)("checkbox", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
menu_button& hotkey_menu = find_widget<menu_button>(&window, "hotkey_category_menu", false);
|
multimenu_button& hotkey_menu = find_widget<multimenu_button>(&window, "hotkey_category_menu", false);
|
||||||
|
|
||||||
hotkey_menu.set_values(hotkey_category_entries);
|
hotkey_menu.set_values(hotkey_category_entries);
|
||||||
hotkey_menu.set_keep_open(true);
|
hotkey_menu.set_keep_open(true);
|
||||||
|
@ -859,7 +860,7 @@ void preferences_dialog::default_hotkey_callback(window& window)
|
||||||
listbox& hotkey_list = setup_hotkey_list(window);
|
listbox& hotkey_list = setup_hotkey_list(window);
|
||||||
hotkey_list.set_active_sorting_option({0, listbox::SORT_ASCENDING}, true);
|
hotkey_list.set_active_sorting_option({0, listbox::SORT_ASCENDING}, true);
|
||||||
|
|
||||||
find_widget<menu_button>(&window, "hotkey_category_menu", false).reset_toggle_states();
|
find_widget<multimenu_button>(&window, "hotkey_category_menu", false).reset_toggle_states();
|
||||||
}
|
}
|
||||||
|
|
||||||
void preferences_dialog::remove_hotkey_callback(listbox& hotkeys)
|
void preferences_dialog::remove_hotkey_callback(listbox& hotkeys)
|
||||||
|
@ -872,7 +873,7 @@ void preferences_dialog::remove_hotkey_callback(listbox& hotkeys)
|
||||||
|
|
||||||
void preferences_dialog::hotkey_type_filter_callback(window& window) const
|
void preferences_dialog::hotkey_type_filter_callback(window& window) const
|
||||||
{
|
{
|
||||||
const menu_button& hotkey_menu = find_widget<const menu_button>(&window, "hotkey_category_menu", false);
|
const multimenu_button& hotkey_menu = find_widget<const multimenu_button>(&window, "hotkey_category_menu", false);
|
||||||
|
|
||||||
boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
|
boost::dynamic_bitset<> toggle_states = hotkey_menu.get_toggle_states();
|
||||||
boost::dynamic_bitset<> res(visible_hotkeys_.size());
|
boost::dynamic_bitset<> res(visible_hotkeys_.size());
|
||||||
|
|
|
@ -45,7 +45,6 @@ menu_button::menu_button()
|
||||||
, retval_(0)
|
, retval_(0)
|
||||||
, values_()
|
, values_()
|
||||||
, selected_()
|
, selected_()
|
||||||
, toggle_states_()
|
|
||||||
, keep_open_(false)
|
, keep_open_(false)
|
||||||
, droplist_(nullptr)
|
, droplist_(nullptr)
|
||||||
{
|
{
|
||||||
|
@ -141,7 +140,7 @@ void menu_button::signal_handler_left_button_click(const event::ui_event event,
|
||||||
|
|
||||||
// If a button has a retval do the default handling.
|
// If a button has a retval do the default handling.
|
||||||
dialogs::drop_down_menu droplist(this->get_rectangle(), this->values_, this->selected_, this->get_use_markup(), this->keep_open_,
|
dialogs::drop_down_menu droplist(this->get_rectangle(), this->values_, this->selected_, this->get_use_markup(), this->keep_open_,
|
||||||
std::bind(&menu_button::toggle_state_changed, this));
|
nullptr);
|
||||||
|
|
||||||
droplist_ = &droplist;
|
droplist_ = &droplist;
|
||||||
|
|
||||||
|
@ -176,47 +175,9 @@ void menu_button::signal_handler_left_button_click(const event::ui_event event,
|
||||||
|
|
||||||
droplist_ = nullptr;
|
droplist_ = nullptr;
|
||||||
|
|
||||||
/* In order to allow toggle button states to be specified by verious dialogs in the values config, we write the state
|
|
||||||
* bools to the values_ config here, but only if a checkbox= key was already provided. The value of the checkbox= key
|
|
||||||
* is handled by the drop_down_menu widget.
|
|
||||||
*
|
|
||||||
* Passing the dynamic_bitset directly to the drop_down_menu ctor would mean bool values would need to be passed to this
|
|
||||||
* class independently of the values config by dialogs that use this widget. However, the bool states are also saved
|
|
||||||
* in a dynamic_bitset class member which can be fetched for other uses if necessary.
|
|
||||||
*/
|
|
||||||
update_config_from_toggle_states();
|
|
||||||
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void menu_button::update_config_from_toggle_states()
|
|
||||||
{
|
|
||||||
for(unsigned i = 0; i < values_.size(); i++) {
|
|
||||||
::config& c = values_[i];
|
|
||||||
|
|
||||||
if(c.has_attribute("checkbox")) {
|
|
||||||
c["checkbox"] = toggle_states_[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void menu_button::reset_toggle_states()
|
|
||||||
{
|
|
||||||
toggle_states_.reset();
|
|
||||||
update_config_from_toggle_states();
|
|
||||||
}
|
|
||||||
|
|
||||||
void menu_button::toggle_state_changed()
|
|
||||||
{
|
|
||||||
assert(droplist_ != nullptr);
|
|
||||||
|
|
||||||
toggle_states_ = droplist_->get_toggle_states();
|
|
||||||
|
|
||||||
if(callback_toggle_state_change_ != nullptr) {
|
|
||||||
callback_toggle_state_change_(toggle_states_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void menu_button::set_values(const std::vector<::config>& values, int selected)
|
void menu_button::set_values(const std::vector<::config>& values, int selected)
|
||||||
{
|
{
|
||||||
assert(static_cast<size_t>(selected) < values.size());
|
assert(static_cast<size_t>(selected) < values.size());
|
||||||
|
@ -228,7 +189,6 @@ void menu_button::set_values(const std::vector<::config>& values, int selected)
|
||||||
|
|
||||||
values_ = values;
|
values_ = values;
|
||||||
selected_ = selected;
|
selected_ = selected;
|
||||||
toggle_states_.resize(values_.size(), false);
|
|
||||||
|
|
||||||
set_label(values_[selected_]["label"]);
|
set_label(values_[selected_]["label"]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,27 +88,12 @@ public:
|
||||||
callback_state_change_ = callback;
|
callback_state_change_ = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a callback that will be called immediately when any toggle button is selected or deselected.
|
|
||||||
*/
|
|
||||||
virtual void set_callback_toggle_state_change(std::function<void(boost::dynamic_bitset<>)> callback)
|
|
||||||
{
|
|
||||||
callback_toggle_state_change_ = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns the value of the selected row */
|
/** Returns the value of the selected row */
|
||||||
std::string get_value_string() const
|
std::string get_value_string() const
|
||||||
{
|
{
|
||||||
return values_[selected_]["label"];
|
return values_[selected_]["label"];
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::dynamic_bitset<> get_toggle_states() const
|
|
||||||
{
|
|
||||||
return toggle_states_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_toggle_states();
|
|
||||||
|
|
||||||
void set_keep_open(const bool keep_open)
|
void set_keep_open(const bool keep_open)
|
||||||
{
|
{
|
||||||
keep_open_ = keep_open;
|
keep_open_ = keep_open;
|
||||||
|
@ -150,8 +135,6 @@ private:
|
||||||
|
|
||||||
int selected_;
|
int selected_;
|
||||||
|
|
||||||
boost::dynamic_bitset<> toggle_states_;
|
|
||||||
|
|
||||||
bool keep_open_;
|
bool keep_open_;
|
||||||
|
|
||||||
dialogs::drop_down_menu* droplist_;
|
dialogs::drop_down_menu* droplist_;
|
||||||
|
@ -159,10 +142,6 @@ private:
|
||||||
/** See selectable_item::set_callback_state_change. */
|
/** See selectable_item::set_callback_state_change. */
|
||||||
std::function<void(widget&)> callback_state_change_;
|
std::function<void(widget&)> callback_state_change_;
|
||||||
|
|
||||||
std::function<void(boost::dynamic_bitset<>)> callback_toggle_state_change_;
|
|
||||||
|
|
||||||
void update_config_from_toggle_states();
|
|
||||||
|
|
||||||
/** See @ref styled_widget::get_control_type. */
|
/** See @ref styled_widget::get_control_type. */
|
||||||
virtual const std::string& get_control_type() const override;
|
virtual const std::string& get_control_type() const override;
|
||||||
|
|
||||||
|
@ -177,8 +156,6 @@ private:
|
||||||
void signal_handler_left_button_up(const event::ui_event event, bool& handled);
|
void signal_handler_left_button_up(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
void signal_handler_left_button_click(const event::ui_event event, bool& handled);
|
void signal_handler_left_button_click(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
void toggle_state_changed();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// }---------- DEFINITION ---------{
|
// }---------- DEFINITION ---------{
|
||||||
|
|
379
src/gui/widgets/multimenu_button.cpp
Normal file
379
src/gui/widgets/multimenu_button.cpp
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2008 - 2017 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 as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GETTEXT_DOMAIN "wesnoth-lib"
|
||||||
|
|
||||||
|
#include "gui/widgets/multimenu_button.hpp"
|
||||||
|
|
||||||
|
#include "gui/core/log.hpp"
|
||||||
|
#include "gui/core/widget_definition.hpp"
|
||||||
|
#include "gui/core/window_builder.hpp"
|
||||||
|
#include "gui/core/window_builder/helper.hpp"
|
||||||
|
#include "gui/core/register_widget.hpp"
|
||||||
|
#include "gui/widgets/settings.hpp"
|
||||||
|
#include "gui/widgets/window.hpp"
|
||||||
|
#include "config_assign.hpp"
|
||||||
|
#include "sound.hpp"
|
||||||
|
|
||||||
|
#include "formula/string_utils.hpp"
|
||||||
|
#include "utils/functional.hpp"
|
||||||
|
#include "gettext.hpp"
|
||||||
|
|
||||||
|
#define LOG_SCOPE_HEADER get_control_type() + " [" + id() + "] " + __func__
|
||||||
|
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
|
||||||
|
|
||||||
|
namespace gui2
|
||||||
|
{
|
||||||
|
|
||||||
|
// ------------ WIDGET -----------{
|
||||||
|
|
||||||
|
REGISTER_WIDGET(multimenu_button)
|
||||||
|
|
||||||
|
multimenu_button::multimenu_button()
|
||||||
|
: styled_widget(COUNT)
|
||||||
|
, state_(ENABLED)
|
||||||
|
, retval_(0)
|
||||||
|
, values_()
|
||||||
|
, toggle_states_()
|
||||||
|
, keep_open_(false)
|
||||||
|
, droplist_(nullptr)
|
||||||
|
{
|
||||||
|
values_.emplace_back(config_of("label", this->get_label()));
|
||||||
|
|
||||||
|
connect_signal<event::MOUSE_ENTER>(
|
||||||
|
std::bind(&multimenu_button::signal_handler_mouse_enter, this, _2, _3));
|
||||||
|
connect_signal<event::MOUSE_LEAVE>(
|
||||||
|
std::bind(&multimenu_button::signal_handler_mouse_leave, this, _2, _3));
|
||||||
|
|
||||||
|
connect_signal<event::LEFT_BUTTON_DOWN>(std::bind(
|
||||||
|
&multimenu_button::signal_handler_left_button_down, this, _2, _3));
|
||||||
|
connect_signal<event::LEFT_BUTTON_UP>(
|
||||||
|
std::bind(&multimenu_button::signal_handler_left_button_up, this, _2, _3));
|
||||||
|
connect_signal<event::LEFT_BUTTON_CLICK>(std::bind(
|
||||||
|
&multimenu_button::signal_handler_left_button_click, this, _2, _3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::set_active(const bool active)
|
||||||
|
{
|
||||||
|
if(get_active() != active) {
|
||||||
|
set_state(active ? ENABLED : DISABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool multimenu_button::get_active() const
|
||||||
|
{
|
||||||
|
return state_ != DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned multimenu_button::get_state() const
|
||||||
|
{
|
||||||
|
return state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::set_state(const state_t state)
|
||||||
|
{
|
||||||
|
if(state != state_) {
|
||||||
|
state_ = state;
|
||||||
|
set_is_dirty(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& multimenu_button::get_control_type() const
|
||||||
|
{
|
||||||
|
static const std::string type = "multimenu_button";
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::signal_handler_mouse_enter(const event::ui_event event, bool& handled)
|
||||||
|
{
|
||||||
|
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
|
||||||
|
|
||||||
|
set_state(FOCUSED);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::signal_handler_mouse_leave(const event::ui_event event, bool& handled)
|
||||||
|
{
|
||||||
|
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
|
||||||
|
|
||||||
|
set_state(ENABLED);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::signal_handler_left_button_down(const event::ui_event event, bool& handled)
|
||||||
|
{
|
||||||
|
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
|
||||||
|
|
||||||
|
window* window = get_window();
|
||||||
|
if(window) {
|
||||||
|
window->mouse_capture();
|
||||||
|
}
|
||||||
|
|
||||||
|
set_state(PRESSED);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::signal_handler_left_button_up(const event::ui_event event, bool& handled)
|
||||||
|
{
|
||||||
|
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
|
||||||
|
|
||||||
|
set_state(FOCUSED);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::signal_handler_left_button_click(const event::ui_event event, bool& handled)
|
||||||
|
{
|
||||||
|
assert(get_window());
|
||||||
|
DBG_GUI_E << LOG_HEADER << ' ' << event << ".\n";
|
||||||
|
|
||||||
|
sound::play_UI_sound(settings::sound_button_click);
|
||||||
|
|
||||||
|
// If a button has a retval do the default handling.
|
||||||
|
dialogs::drop_down_menu droplist(this->get_rectangle(), this->values_, -1, this->get_use_markup(), this->keep_open_,
|
||||||
|
std::bind(&multimenu_button::toggle_state_changed, this));
|
||||||
|
|
||||||
|
droplist_ = &droplist;
|
||||||
|
droplist.show(get_window()->video());
|
||||||
|
droplist_ = nullptr;
|
||||||
|
|
||||||
|
if(retval_ != 0) {
|
||||||
|
if(window* window = get_window()) {
|
||||||
|
window->set_retval(retval_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In order to allow toggle button states to be specified by verious dialogs in the values config, we write the state
|
||||||
|
* bools to the values_ config here, but only if a checkbox= key was already provided. The value of the checkbox= key
|
||||||
|
* is handled by the drop_down_menu widget.
|
||||||
|
*
|
||||||
|
* Passing the dynamic_bitset directly to the drop_down_menu ctor would mean bool values would need to be passed to this
|
||||||
|
* class independently of the values config by dialogs that use this widget. However, the bool states are also saved
|
||||||
|
* in a dynamic_bitset class member which can be fetched for other uses if necessary.
|
||||||
|
*/
|
||||||
|
update_config_from_toggle_states();
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::update_label() {
|
||||||
|
std::vector<t_string> selected;
|
||||||
|
for(size_t i = 0; i < toggle_states_.size() && i < values_.size(); i++) {
|
||||||
|
if(!toggle_states_[i]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
selected.push_back(values_[i]["label"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selected.size() == 0) {
|
||||||
|
set_label(_("multimenu^None Selected"));
|
||||||
|
} else if(selected.size() == 1) {
|
||||||
|
set_label(selected[0]);
|
||||||
|
} else if(selected.size() == 2) {
|
||||||
|
const string_map variables = {{"first", selected[0]}, {"second", selected[1]}, {"excess", "1"}};
|
||||||
|
if(max_shown_ == 1) {
|
||||||
|
set_label(VNGETTEXT("multimenu^$first and 1 other","multimenu^$first and $excess others", 1, variables));
|
||||||
|
} else {
|
||||||
|
set_label(VGETTEXT("multimenu^$first and $second", variables));
|
||||||
|
}
|
||||||
|
} else if(selected.size() == values_.size()) {
|
||||||
|
set_label(_("multimenu^All Selected"));
|
||||||
|
} else {
|
||||||
|
int excess = selected.size() - max_shown_;
|
||||||
|
if(max_shown_ > 0 && excess > 0) {
|
||||||
|
selected.resize(max_shown_);
|
||||||
|
}
|
||||||
|
std::string first = selected[0];
|
||||||
|
for(size_t i = 1; i < selected.size() - 1; i++) {
|
||||||
|
const string_map variables = {{"first", first}, {"second", selected[i]}};
|
||||||
|
first = VGETTEXT("multimenu^$first, $second", variables);
|
||||||
|
}
|
||||||
|
if(max_shown_ > 0 && excess > 0) {
|
||||||
|
const string_map variables = {{"first", first}, {"excess", std::to_string(excess + 1)}};
|
||||||
|
set_label(VNGETTEXT("multimenu^$first and 1 other","$first and $excess others", excess + 1, variables));
|
||||||
|
} else {
|
||||||
|
const string_map variables = {{"first", first}, {"second", selected.back()}};
|
||||||
|
set_label(VGETTEXT("multimenu^$first and $second", variables));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::update_config_from_toggle_states()
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < values_.size(); i++) {
|
||||||
|
::config& c = values_[i];
|
||||||
|
|
||||||
|
if(c.has_attribute("checkbox")) {
|
||||||
|
c["checkbox"] = toggle_states_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::reset_toggle_states()
|
||||||
|
{
|
||||||
|
toggle_states_.reset();
|
||||||
|
update_config_from_toggle_states();
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::toggle_state_changed()
|
||||||
|
{
|
||||||
|
assert(droplist_ != nullptr);
|
||||||
|
|
||||||
|
toggle_states_ = droplist_->get_toggle_states();
|
||||||
|
fire(event::NOTIFY_MODIFIED, *this, nullptr);
|
||||||
|
update_label();
|
||||||
|
|
||||||
|
if(callback_toggle_state_change_ != nullptr) {
|
||||||
|
callback_toggle_state_change_(toggle_states_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void multimenu_button::set_values(const std::vector<::config>& values)
|
||||||
|
{
|
||||||
|
set_is_dirty(true);
|
||||||
|
|
||||||
|
values_ = values;
|
||||||
|
toggle_states_.resize(values_.size(), false);
|
||||||
|
toggle_states_.reset();
|
||||||
|
|
||||||
|
set_label(_("multimenu^None Selected"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// }---------- DEFINITION ---------{
|
||||||
|
|
||||||
|
multimenu_button_definition::multimenu_button_definition(const config& cfg)
|
||||||
|
: styled_widget_definition(cfg)
|
||||||
|
{
|
||||||
|
DBG_GUI_P << "Parsing multimenu_button " << id << '\n';
|
||||||
|
|
||||||
|
load_resolutions<resolution>(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*WIKI
|
||||||
|
* @page = GUIWidgetDefinitionWML
|
||||||
|
* @order = 1_multimenu_button
|
||||||
|
*
|
||||||
|
* == multimenu_button ==
|
||||||
|
*
|
||||||
|
* @macro = multimenu_button_description
|
||||||
|
*
|
||||||
|
* The following states exist:
|
||||||
|
* * state_enabled, the multimenu_button is enabled.
|
||||||
|
* * state_disabled, the multimenu_button is disabled.
|
||||||
|
* * state_pressed, the left mouse multimenu_button is down.
|
||||||
|
* * state_focused, the mouse is over the multimenu_button.
|
||||||
|
* @begin{parent}{name="gui/"}
|
||||||
|
* @begin{tag}{name="multimenu_button_definition"}{min=0}{max=-1}{super="generic/widget_definition"}
|
||||||
|
* @begin{tag}{name="resolution"}{min=0}{max=-1}{super="generic/widget_definition/resolution"}
|
||||||
|
* @begin{tag}{name="state_enabled"}{min=0}{max=1}{super="generic/state"}
|
||||||
|
* @end{tag}{name="state_enabled"}
|
||||||
|
* @begin{tag}{name="state_disabled"}{min=0}{max=1}{super="generic/state"}
|
||||||
|
* @end{tag}{name="state_disabled"}
|
||||||
|
* @begin{tag}{name="state_pressed"}{min=0}{max=1}{super="generic/state"}
|
||||||
|
* @end{tag}{name="state_pressed"}
|
||||||
|
* @begin{tag}{name="state_focused"}{min=0}{max=1}{super="generic/state"}
|
||||||
|
* @end{tag}{name="state_focused"}
|
||||||
|
* @end{tag}{name="resolution"}
|
||||||
|
* @end{tag}{name="multimenu_button_definition"}
|
||||||
|
* @end{parent}{name="gui/"}
|
||||||
|
*/
|
||||||
|
multimenu_button_definition::resolution::resolution(const config& cfg)
|
||||||
|
: resolution_definition(cfg)
|
||||||
|
{
|
||||||
|
// Note the order should be the same as the enum state_t in multimenu_button.hpp.
|
||||||
|
state.emplace_back(cfg.child("state_enabled"));
|
||||||
|
state.emplace_back(cfg.child("state_disabled"));
|
||||||
|
state.emplace_back(cfg.child("state_pressed"));
|
||||||
|
state.emplace_back(cfg.child("state_focused"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// }---------- BUILDER -----------{
|
||||||
|
|
||||||
|
/*WIKI_MACRO
|
||||||
|
* @begin{macro}{multimenu_button_description}
|
||||||
|
*
|
||||||
|
* A multimenu_button is a styled_widget to choose an element from a list of elements.
|
||||||
|
* @end{macro}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*WIKI
|
||||||
|
* @page = GUIWidgetInstanceWML
|
||||||
|
* @order = 2_multimenu_button
|
||||||
|
* @begin{parent}{name="gui/window/resolution/grid/row/column/"}
|
||||||
|
* @begin{tag}{name="multimenu_button"}{min=0}{max=-1}{super="generic/widget_instance"}
|
||||||
|
* == multimenu_button ==
|
||||||
|
*
|
||||||
|
* @macro = multimenu_button_description
|
||||||
|
*
|
||||||
|
* Instance of a multimenu_button. When a multimenu_button has a return value it sets the
|
||||||
|
* return value for the window. Normally this closes the window and returns
|
||||||
|
* this value to the caller. The return value can either be defined by the
|
||||||
|
* user or determined from the id of the multimenu_button. The return value has a
|
||||||
|
* higher precedence as the one defined by the id. (Of course it's weird to
|
||||||
|
* give a multimenu_button an id and then override its return value.)
|
||||||
|
*
|
||||||
|
* When the multimenu_button doesn't have a standard id, but you still want to use the
|
||||||
|
* return value of that id, use return_value_id instead. This has a higher
|
||||||
|
* precedence as return_value.
|
||||||
|
*
|
||||||
|
* List with the multimenu_button specific variables:
|
||||||
|
* @begin{table}{config}
|
||||||
|
* return_value_id & string & "" & The return value id. $
|
||||||
|
* return_value & int & 0 & The return value. $
|
||||||
|
* maximum_shown & int & -1 & The maximum number of currently selected values to list on the button. $
|
||||||
|
*
|
||||||
|
* @end{table}
|
||||||
|
* @end{tag}{name="multimenu_button"}
|
||||||
|
* @end{parent}{name="gui/window/resolution/grid/row/column/"}
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace implementation
|
||||||
|
{
|
||||||
|
|
||||||
|
builder_multimenu_button::builder_multimenu_button(const config& cfg)
|
||||||
|
: builder_styled_widget(cfg)
|
||||||
|
, retval_id_(cfg["return_value_id"])
|
||||||
|
, retval_(cfg["return_value"])
|
||||||
|
, max_shown_(cfg["maximum_shown"])
|
||||||
|
, options_()
|
||||||
|
{
|
||||||
|
for(const auto& option : cfg.child_range("option")) {
|
||||||
|
options_.push_back(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
widget* builder_multimenu_button::build() const
|
||||||
|
{
|
||||||
|
multimenu_button* widget = new multimenu_button();
|
||||||
|
|
||||||
|
init_control(widget);
|
||||||
|
|
||||||
|
widget->set_retval(get_retval(retval_id_, retval_, id));
|
||||||
|
widget->set_max_shown(max_shown_);
|
||||||
|
if(!options_.empty()) {
|
||||||
|
widget->set_values(options_);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG_GUI_G << "Window builder: placed multimenu_button '" << id
|
||||||
|
<< "' with definition '" << definition << "'.\n";
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace implementation
|
||||||
|
|
||||||
|
// }------------ END --------------
|
||||||
|
|
||||||
|
} // namespace gui2
|
213
src/gui/widgets/multimenu_button.hpp
Normal file
213
src/gui/widgets/multimenu_button.hpp
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2008 - 2017 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 as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "gui/core/widget_definition.hpp"
|
||||||
|
#include "gui/core/window_builder.hpp"
|
||||||
|
|
||||||
|
#include "gui/dialogs/drop_down_menu.hpp"
|
||||||
|
|
||||||
|
#include "gui/widgets/styled_widget.hpp"
|
||||||
|
#include "gui/widgets/selectable_item.hpp"
|
||||||
|
|
||||||
|
#include <boost/dynamic_bitset.hpp>
|
||||||
|
|
||||||
|
class config;
|
||||||
|
|
||||||
|
namespace gui2
|
||||||
|
{
|
||||||
|
|
||||||
|
// ------------ WIDGET -----------{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple push button.
|
||||||
|
*/
|
||||||
|
class multimenu_button : public styled_widget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
multimenu_button();
|
||||||
|
|
||||||
|
/***** ***** ***** ***** Inherited ***** ***** ***** *****/
|
||||||
|
|
||||||
|
/** See @ref styled_widget::set_active. */
|
||||||
|
virtual void set_active(const bool active) override;
|
||||||
|
|
||||||
|
/** See @ref styled_widget::get_active. */
|
||||||
|
virtual bool get_active() const override;
|
||||||
|
|
||||||
|
/** See @ref styled_widget::get_state. */
|
||||||
|
virtual unsigned get_state() const override;
|
||||||
|
|
||||||
|
/** Inherited from tclickable. */
|
||||||
|
void connect_click_handler(const event::signal_function& signal)
|
||||||
|
{
|
||||||
|
connect_signal_mouse_left_click(*this, signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inherited from tclickable. */
|
||||||
|
void disconnect_click_handler(const event::signal_function& signal)
|
||||||
|
{
|
||||||
|
disconnect_signal_mouse_left_click(*this, signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||||
|
|
||||||
|
void set_retval(const int retval)
|
||||||
|
{
|
||||||
|
retval_ = retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_max_shown(const int max)
|
||||||
|
{
|
||||||
|
max_shown_ = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_max_shown()
|
||||||
|
{
|
||||||
|
return max_shown_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_values(const std::vector<::config>& values);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a callback that will be called immediately when any toggle button is selected or deselected.
|
||||||
|
*/
|
||||||
|
virtual void set_callback_toggle_state_change(std::function<void(boost::dynamic_bitset<>)> callback)
|
||||||
|
{
|
||||||
|
callback_toggle_state_change_ = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the value of the selected row */
|
||||||
|
//std::string get_value_string() const;
|
||||||
|
|
||||||
|
boost::dynamic_bitset<> get_toggle_states() const
|
||||||
|
{
|
||||||
|
return toggle_states_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_toggle_states();
|
||||||
|
|
||||||
|
void set_keep_open(const bool keep_open)
|
||||||
|
{
|
||||||
|
keep_open_ = keep_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Possible states of the widget.
|
||||||
|
*
|
||||||
|
* Note the order of the states must be the same as defined in settings.hpp.
|
||||||
|
*/
|
||||||
|
enum state_t {
|
||||||
|
ENABLED,
|
||||||
|
DISABLED,
|
||||||
|
PRESSED,
|
||||||
|
FOCUSED,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_state(const state_t state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current state of the widget.
|
||||||
|
*
|
||||||
|
* The state of the widget determines what to render and how the widget
|
||||||
|
* reacts to certain 'events'.
|
||||||
|
*/
|
||||||
|
state_t state_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The return value of the button.
|
||||||
|
*
|
||||||
|
* If this value is not 0 and the button is clicked it sets the retval of
|
||||||
|
* the window and the window closes itself.
|
||||||
|
*/
|
||||||
|
int retval_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of selected states to list in the label
|
||||||
|
*/
|
||||||
|
int max_shown_;
|
||||||
|
|
||||||
|
std::vector<::config> values_;
|
||||||
|
|
||||||
|
boost::dynamic_bitset<> toggle_states_;
|
||||||
|
|
||||||
|
bool keep_open_;
|
||||||
|
|
||||||
|
dialogs::drop_down_menu* droplist_;
|
||||||
|
|
||||||
|
std::function<void(boost::dynamic_bitset<>)> callback_toggle_state_change_;
|
||||||
|
|
||||||
|
void update_config_from_toggle_states();
|
||||||
|
void update_label();
|
||||||
|
|
||||||
|
/** See @ref styled_widget::get_control_type. */
|
||||||
|
virtual const std::string& get_control_type() const override;
|
||||||
|
|
||||||
|
/***** ***** ***** signal handlers ***** ****** *****/
|
||||||
|
|
||||||
|
void signal_handler_mouse_enter(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
|
void signal_handler_mouse_leave(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
|
void signal_handler_left_button_down(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
|
void signal_handler_left_button_up(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
|
void signal_handler_left_button_click(const event::ui_event event, bool& handled);
|
||||||
|
|
||||||
|
void toggle_state_changed();
|
||||||
|
};
|
||||||
|
|
||||||
|
// }---------- DEFINITION ---------{
|
||||||
|
|
||||||
|
struct multimenu_button_definition : public styled_widget_definition
|
||||||
|
{
|
||||||
|
explicit multimenu_button_definition(const config& cfg);
|
||||||
|
|
||||||
|
struct resolution : public resolution_definition
|
||||||
|
{
|
||||||
|
explicit resolution(const config& cfg);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// }---------- BUILDER -----------{
|
||||||
|
|
||||||
|
class styled_widget;
|
||||||
|
|
||||||
|
namespace implementation
|
||||||
|
{
|
||||||
|
|
||||||
|
struct builder_multimenu_button : public builder_styled_widget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit builder_multimenu_button(const config& cfg);
|
||||||
|
|
||||||
|
using builder_styled_widget::build;
|
||||||
|
|
||||||
|
widget* build() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string retval_id_;
|
||||||
|
int retval_, max_shown_;
|
||||||
|
std::vector<::config> options_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace implementation
|
||||||
|
|
||||||
|
// }------------ END --------------
|
||||||
|
|
||||||
|
} // namespace gui2
|
Loading…
Add table
Reference in a new issue