Implement the ability to use toggle buttons in drop down menus
This commit is contained in:
parent
cfb2792932
commit
83f159be8d
5 changed files with 107 additions and 16 deletions
|
@ -22,6 +22,7 @@
|
|||
#include "gui/widgets/integer_selector.hpp"
|
||||
#include "gui/widgets/scrollbar.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/toggle_button.hpp"
|
||||
#include "gui/widgets/toggle_panel.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
|
||||
|
@ -38,6 +39,28 @@ REGISTER_DIALOG(drop_down_menu)
|
|||
namespace {
|
||||
void click_callback(window& window, bool&, bool&, point coordinate)
|
||||
{
|
||||
listbox& list = find_widget<listbox>(&window, "list", true);
|
||||
|
||||
/* Disregard clicks on scrollbars and toggle buttons so the dropdown menu can be scrolled or have an embedded
|
||||
* toggle button selected without the menu closing.
|
||||
*
|
||||
* This works since this click_callback function is called before widgets' left-button-up handlers.
|
||||
|
||||
* Additionally, this is done before row deselection so selecting/deselecting a toggle button doesn't also leave
|
||||
* the list with no row visually selected. Oddly, the visial deselection doesn't seem to cause any crashes, and
|
||||
* the previously selected row is reselected when the menu is opened again. Still, it's odd to see your selection
|
||||
* vanish.
|
||||
*/
|
||||
if(list.vertical_scrollbar()->get_state() == scrollbar_base::PRESSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(toggle_button* checkbox = dynamic_cast<toggle_button*>(window.find_at(coordinate, true))) {
|
||||
if(checkbox->get_state() == toggle_button::FOCUSED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: This dialog uses a listbox with 'has_minimum = false'. This allows a listbox to have 0 or more selections,
|
||||
* and selecting the same entry toggles that entry's state (ie, if it was selected, it will be deselected). Because
|
||||
* of this, selecting the same entry in the dropdown list essentially sets the list's selected row to -1, causing problems.
|
||||
|
@ -45,18 +68,11 @@ namespace {
|
|||
* In order to work around this, we first manually deselect the selected entry here. This handler is called *before*
|
||||
* the listbox's click handler, and as such the selected item will remain toggled on when the click handler fires.
|
||||
*/
|
||||
listbox& list = find_widget<listbox>(&window, "list", true);
|
||||
const int sel = list.get_selected_row();
|
||||
if(sel >= 0) {
|
||||
list.select_row(sel, false);
|
||||
}
|
||||
|
||||
// Disregard clicks if they're on the scrollbar
|
||||
// This check works since this function is called before scrollbar_base's left-button-up handler
|
||||
if(list.vertical_scrollbar()->get_state() == scrollbar_base::PRESSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Rect rect = window.get_rectangle();
|
||||
if(!sdl::point_in_rect(coordinate, rect)) {
|
||||
window.set_retval(window::CANCEL);
|
||||
|
@ -117,6 +133,18 @@ void drop_down_menu::pre_show(window& window)
|
|||
delete mi_grid->swap_child("label", img, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(entry.has_attribute("checkbox")) {
|
||||
toggle_button* checkbox = new toggle_button;
|
||||
checkbox->set_definition("default");
|
||||
checkbox->set_id("checkbox");
|
||||
checkbox->set_value_bool(entry["checkbox"].to_bool(false));
|
||||
|
||||
grid* mi_grid = dynamic_cast<grid*>(new_row.find("menu_item", false));
|
||||
if(mi_grid) {
|
||||
delete mi_grid->swap_child("icon", checkbox, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(selected_item_ >= 0 && unsigned(selected_item_) < list.get_item_count()) {
|
||||
|
@ -134,7 +162,19 @@ void drop_down_menu::pre_show(window& window)
|
|||
|
||||
void drop_down_menu::post_show(window& window)
|
||||
{
|
||||
selected_item_ = find_widget<listbox>(&window, "list", true).get_selected_row();
|
||||
listbox& list = find_widget<listbox>(&window, "list", true);
|
||||
|
||||
selected_item_ = list.get_selected_row();
|
||||
|
||||
for(unsigned i = 0; i < list.get_item_count(); i++) {
|
||||
grid* row_grid = list.get_row_grid(i);
|
||||
|
||||
if(toggle_button* checkbox = find_widget<toggle_button>(row_grid, "checkbox", false, false)) {
|
||||
toggle_states_.push_back(checkbox->get_value_bool());
|
||||
} else {
|
||||
toggle_states_.push_back(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dialogs
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "gui/dialogs/modal_dialog.hpp"
|
||||
#include "sdl/rect.hpp"
|
||||
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
class config;
|
||||
|
||||
namespace gui2
|
||||
|
@ -28,22 +30,43 @@ class drop_down_menu : public modal_dialog
|
|||
{
|
||||
public:
|
||||
drop_down_menu(SDL_Rect button_pos, const std::vector<config>& items, int selected_item, bool use_markup)
|
||||
: button_pos_(button_pos)
|
||||
, items_(items)
|
||||
: items_(items)
|
||||
, toggle_states_()
|
||||
, button_pos_(button_pos)
|
||||
, selected_item_(selected_item)
|
||||
, use_markup_(use_markup)
|
||||
{
|
||||
set_restore(true);
|
||||
}
|
||||
int selected_item() const { return selected_item_; }
|
||||
|
||||
int selected_item() const
|
||||
{
|
||||
return selected_item_;
|
||||
}
|
||||
|
||||
boost::dynamic_bitset<> get_toggle_states() const
|
||||
{
|
||||
return toggle_states_;
|
||||
}
|
||||
|
||||
private:
|
||||
/// The screen location of the menu_button button that triggred this droplist.
|
||||
/// Note: we don't adjust the location of this dialog to when resizing the window.
|
||||
/// Instead this dialog automatically closes itself on resizing.
|
||||
SDL_Rect button_pos_;
|
||||
/** Configuration of rach row. */
|
||||
std::vector<config> items_;
|
||||
|
||||
/** If a toggle button widget is present, returns the toggled state of each row's button. */
|
||||
boost::dynamic_bitset<> toggle_states_;
|
||||
|
||||
/**
|
||||
* The screen location of the menu_button button that triggered this droplist.
|
||||
* Note: we don't adjust the location of this dialog to when resizing the window.
|
||||
* Instead this dialog automatically closes itself on resizing.
|
||||
*/
|
||||
SDL_Rect button_pos_;
|
||||
|
||||
int selected_item_;
|
||||
|
||||
bool use_markup_;
|
||||
|
||||
/** Inherited from modal_dialog, implemented by REGISTER_DIALOG. */
|
||||
virtual const std::string& window_id() const;
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ menu_button::menu_button()
|
|||
, retval_(0)
|
||||
, values_()
|
||||
, selected_()
|
||||
, toggle_states_()
|
||||
{
|
||||
values_.push_back(config_of("label", this->get_label()));
|
||||
|
||||
|
@ -172,6 +173,25 @@ void menu_button::signal_handler_left_button_click(const event::ui_event event,
|
|||
}
|
||||
}
|
||||
|
||||
// Toggle states are recorded regardless of dismissal type
|
||||
toggle_states_ = droplist.get_toggle_states();
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
for(unsigned i = 0; i < values_.size(); i++) {
|
||||
::config& c = values_[i];
|
||||
|
||||
if(c.has_attribute("checkbox")) {
|
||||
c["checkbox"] = toggle_states_[i];
|
||||
}
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
|
||||
|
@ -184,6 +204,7 @@ void menu_button::set_values(const std::vector<::config>& values, int selected)
|
|||
}
|
||||
values_ = values;
|
||||
selected_ = selected;
|
||||
toggle_states_.resize(values_.size(), false);
|
||||
set_label(values_[selected_]["label"]);
|
||||
}
|
||||
void menu_button::set_selected(int selected)
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "gui/widgets/styled_widget.hpp"
|
||||
#include "gui/widgets/selectable_item.hpp"
|
||||
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
class config;
|
||||
|
||||
namespace gui2
|
||||
|
@ -88,6 +90,8 @@ public:
|
|||
/** Returns the value of the selected row */
|
||||
std::string get_value_string() const { return values_[selected_]["label"]; }
|
||||
|
||||
boost::dynamic_bitset<> get_toggle_states() const { return toggle_states_; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Possible states of the widget.
|
||||
|
@ -125,6 +129,8 @@ private:
|
|||
*/
|
||||
int selected_;
|
||||
|
||||
boost::dynamic_bitset<> toggle_states_;
|
||||
|
||||
/** See @ref styled_widget::get_control_type. */
|
||||
virtual const std::string& get_control_type() const override;
|
||||
|
||||
|
|
|
@ -81,7 +81,6 @@ public:
|
|||
return icon_name_;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Possible states of the widget.
|
||||
*
|
||||
|
@ -97,6 +96,8 @@ private:
|
|||
COUNT
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void set_state(const state_t state);
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue