GUI2/Distributor: further cleanup (#6622)

* GUI2/Distributor: further cleanup started in 988bf973e9

This restores the template to mouse_button, but it keeps the struct-based approach for specifying ui_events.
This commit is contained in:
Charles Dang 2022-04-11 07:52:54 -04:00 committed by GitHub
parent fafafbacf6
commit c1d7e65cbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 101 additions and 187 deletions

View file

@ -26,6 +26,7 @@
#include "gui/widgets/text_box_base.hpp" #include "gui/widgets/text_box_base.hpp"
#include "sdl/userevent.hpp" #include "sdl/userevent.hpp"
#include <array>
#include <functional> #include <functional>
namespace gui2 namespace gui2
@ -69,8 +70,7 @@ private:
#define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: " #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
mouse_motion::mouse_motion(widget& owner, mouse_motion::mouse_motion(widget& owner, const dispatcher::queue_position queue_position)
const dispatcher::queue_position queue_position)
: mouse_focus_(nullptr) : mouse_focus_(nullptr)
, mouse_captured_(false) , mouse_captured_(false)
, owner_(owner) , owner_(owner)
@ -358,92 +358,88 @@ void mouse_motion::stop_hover_timer()
#undef LOG_HEADER #undef LOG_HEADER
#define LOG_HEADER \ #define LOG_HEADER \
"distributor mouse button " << events_.name << " [" << owner_.id() << "]: " "distributor mouse button " << I << " [" << owner_.id() << "]: "
mouse_button::mouse_button(const mouse_button_event_types& events, widget& owner, namespace
const dispatcher::queue_position queue_position) {
struct data_pod
{
const ui_event sdl_button_down_event;
const ui_event sdl_button_up_event;
const ui_event button_down_event;
const ui_event button_up_event;
const ui_event button_click_event;
const ui_event button_double_click_event;
};
constexpr std::array mouse_data{
data_pod{
SDL_LEFT_BUTTON_DOWN,
SDL_LEFT_BUTTON_UP,
LEFT_BUTTON_DOWN,
LEFT_BUTTON_UP,
LEFT_BUTTON_CLICK,
LEFT_BUTTON_DOUBLE_CLICK,
},
data_pod{
SDL_MIDDLE_BUTTON_DOWN,
SDL_MIDDLE_BUTTON_UP,
MIDDLE_BUTTON_DOWN,
MIDDLE_BUTTON_UP,
MIDDLE_BUTTON_CLICK,
MIDDLE_BUTTON_DOUBLE_CLICK,
},
data_pod{
SDL_RIGHT_BUTTON_DOWN,
SDL_RIGHT_BUTTON_UP,
RIGHT_BUTTON_DOWN,
RIGHT_BUTTON_UP,
RIGHT_BUTTON_CLICK,
RIGHT_BUTTON_DOUBLE_CLICK,
},
};
} // namespace
template<std::size_t I>
mouse_button<I>::mouse_button(widget& owner, const dispatcher::queue_position queue_position)
: mouse_motion(owner, queue_position) : mouse_motion(owner, queue_position)
, last_click_stamp_(0) , last_click_stamp_(0)
, last_clicked_widget_(nullptr) , last_clicked_widget_(nullptr)
, focus_(nullptr) , focus_(nullptr)
, events_(events)
, is_down_(false) , is_down_(false)
, signal_handler_sdl_button_down_entered_(false) , signal_handler_sdl_button_down_entered_(false)
, signal_handler_sdl_button_up_entered_(false) , signal_handler_sdl_button_up_entered_(false)
{ {
// The connect_signal framework is currently using SFINAE checking to ensure that we only owner_.connect_signal<mouse_data[I].sdl_button_down_event>(
// register mouse button signal handlers for mouse buttons. That causes us to need this std::bind(&mouse_button::signal_handler_sdl_button_down,
// hardcoded (either directly or by making mouse_button a templated class), the manual handling this,
// of the three cases here is the current progress on refactoring. std::placeholders::_2,
switch(events_.sdl_button_down_event) { std::placeholders::_3,
case event::SDL_LEFT_BUTTON_DOWN: { std::placeholders::_5),
owner_.connect_signal<event::SDL_LEFT_BUTTON_DOWN>( queue_position);
std::bind(&mouse_button::signal_handler_sdl_button_down,
this, owner_.connect_signal<mouse_data[I].sdl_button_up_event>(
std::placeholders::_2, std::bind(&mouse_button::signal_handler_sdl_button_up,
std::placeholders::_3, this,
std::placeholders::_5), std::placeholders::_2,
queue_position); std::placeholders::_3,
owner_.connect_signal<event::SDL_LEFT_BUTTON_UP>( std::placeholders::_5),
std::bind(&mouse_button::signal_handler_sdl_button_up, queue_position);
this,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_5),
queue_position);
break;
}
case event::SDL_MIDDLE_BUTTON_DOWN: {
owner_.connect_signal<event::SDL_MIDDLE_BUTTON_DOWN>(
std::bind(&mouse_button::signal_handler_sdl_button_down,
this,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_5),
queue_position);
owner_.connect_signal<event::SDL_MIDDLE_BUTTON_UP>(
std::bind(&mouse_button::signal_handler_sdl_button_up,
this,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_5),
queue_position);
break;
}
case event::SDL_RIGHT_BUTTON_DOWN: {
owner_.connect_signal<event::SDL_RIGHT_BUTTON_DOWN>(
std::bind(&mouse_button::signal_handler_sdl_button_down,
this,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_5),
queue_position);
owner_.connect_signal<event::SDL_RIGHT_BUTTON_UP>(
std::bind(&mouse_button::signal_handler_sdl_button_up,
this,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_5),
queue_position);
break;
}
default: {
// There's exactly three instances of this class per instance of distributor, so this assert
// will be caught during the build-time-tests.
assert(!"Hardcoded assumption about button being LEFT / MIDDLE / RIGHT failed");
}
}
} }
void mouse_button::initialize_state(int32_t button_state) template<std::size_t I>
void mouse_button<I>::initialize_state(int32_t button_state)
{ {
last_click_stamp_ = 0; last_click_stamp_ = 0;
last_clicked_widget_ = nullptr; last_clicked_widget_ = nullptr;
focus_ = 0; focus_ = 0;
is_down_ = button_state & events_.mask; // SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, and SDL_BUTTON_RIGHT correspond to 1,2,3
is_down_ = button_state & SDL_BUTTON(I + 1);
} }
void mouse_button::signal_handler_sdl_button_down(const event::ui_event event, bool& handled, template<std::size_t I>
void mouse_button<I>::signal_handler_sdl_button_down(const event::ui_event event, bool& handled,
const point& coordinate) const point& coordinate)
{ {
if(signal_handler_sdl_button_down_entered_) { if(signal_handler_sdl_button_down_entered_) {
@ -466,10 +462,10 @@ void mouse_button::signal_handler_sdl_button_down(const event::ui_event event, b
if(mouse_captured_) { if(mouse_captured_) {
assert(mouse_focus_); assert(mouse_focus_);
focus_ = mouse_focus_; focus_ = mouse_focus_;
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_down_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_down_event << ".\n";
if(!owner_.fire(events_.sdl_button_down_event, *focus_, coordinate)) { if(!owner_.fire(mouse_data[I].sdl_button_down_event, *focus_, coordinate)) {
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_down_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_down_event << ".\n";
owner_.fire(events_.button_down_event, *mouse_focus_); owner_.fire(mouse_data[I].button_down_event, *mouse_focus_);
} }
} else { } else {
widget* mouse_over = owner_.find_at(coordinate, true); widget* mouse_over = owner_.find_at(coordinate, true);
@ -486,16 +482,17 @@ void mouse_button::signal_handler_sdl_button_down(const event::ui_event event, b
} }
focus_ = mouse_over; focus_ = mouse_over;
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_down_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_down_event << ".\n";
if(!owner_.fire(events_.sdl_button_down_event, *focus_, coordinate)) { if(!owner_.fire(mouse_data[I].sdl_button_down_event, *focus_, coordinate)) {
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_down_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_down_event << ".\n";
owner_.fire(events_.button_down_event, *focus_); owner_.fire(mouse_data[I].button_down_event, *focus_);
} }
} }
handled = true; handled = true;
} }
void mouse_button::signal_handler_sdl_button_up(const event::ui_event event, bool& handled, template<std::size_t I>
void mouse_button<I>::signal_handler_sdl_button_up(const event::ui_event event, bool& handled,
const point& coordinate) const point& coordinate)
{ {
if(signal_handler_sdl_button_up_entered_) { if(signal_handler_sdl_button_up_entered_) {
@ -515,10 +512,10 @@ void mouse_button::signal_handler_sdl_button_up(const event::ui_event event, boo
is_down_ = false; is_down_ = false;
if(focus_) { if(focus_) {
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_up_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].sdl_button_up_event << ".\n";
if(!owner_.fire(events_.sdl_button_up_event, *focus_, coordinate)) { if(!owner_.fire(mouse_data[I].sdl_button_up_event, *focus_, coordinate)) {
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_up_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_up_event << ".\n";
owner_.fire(events_.button_up_event, *focus_); owner_.fire(mouse_data[I].button_up_event, *focus_);
} }
} }
@ -552,22 +549,23 @@ void mouse_button::signal_handler_sdl_button_up(const event::ui_event event, boo
handled = true; handled = true;
} }
void mouse_button::mouse_button_click(widget* widget) template<std::size_t I>
void mouse_button<I>::mouse_button_click(widget* widget)
{ {
uint32_t stamp = SDL_GetTicks(); uint32_t stamp = SDL_GetTicks();
if(last_click_stamp_ + settings::double_click_time >= stamp if(last_click_stamp_ + settings::double_click_time >= stamp
&& last_clicked_widget_ == widget) { && last_clicked_widget_ == widget) {
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_double_click_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_double_click_event << ".\n";
owner_.fire(events_.button_double_click_event, *widget); owner_.fire(mouse_data[I].button_double_click_event, *widget);
last_click_stamp_ = 0; last_click_stamp_ = 0;
last_clicked_widget_ = nullptr; last_clicked_widget_ = nullptr;
} else { } else {
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_click_event << ".\n"; DBG_GUI_E << LOG_HEADER << "Firing: " << mouse_data[I].button_click_event << ".\n";
owner_.fire(events_.button_click_event, *widget); owner_.fire(mouse_data[I].button_click_event, *widget);
last_click_stamp_ = stamp; last_click_stamp_ = stamp;
last_clicked_widget_ = widget; last_clicked_widget_ = widget;
} }
@ -578,50 +576,15 @@ void mouse_button::mouse_button_click(widget* widget)
#undef LOG_HEADER #undef LOG_HEADER
#define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: " #define LOG_HEADER "distributor mouse motion [" << owner_.id() << "]: "
namespace
{
const auto mouse_button_left_events = mouse_button_event_types {
SDL_LEFT_BUTTON_DOWN,
SDL_LEFT_BUTTON_UP,
LEFT_BUTTON_DOWN,
LEFT_BUTTON_UP,
LEFT_BUTTON_CLICK,
LEFT_BUTTON_DOUBLE_CLICK,
SDL_BUTTON_LMASK,
"left"};
const auto mouse_button_middle_events = mouse_button_event_types {
SDL_MIDDLE_BUTTON_DOWN,
SDL_MIDDLE_BUTTON_UP,
MIDDLE_BUTTON_DOWN,
MIDDLE_BUTTON_UP,
MIDDLE_BUTTON_CLICK,
MIDDLE_BUTTON_DOUBLE_CLICK,
SDL_BUTTON_MMASK,
"middle"};
const auto mouse_button_right_events = mouse_button_event_types {
SDL_RIGHT_BUTTON_DOWN,
SDL_RIGHT_BUTTON_UP,
RIGHT_BUTTON_DOWN,
RIGHT_BUTTON_UP,
RIGHT_BUTTON_CLICK,
RIGHT_BUTTON_DOUBLE_CLICK,
SDL_BUTTON_RMASK,
"right"};
} // anonymous namespace
/** /**
* @todo Test whether the state is properly tracked when an input blocker is * @todo Test whether the state is properly tracked when an input blocker is
* used. * used.
*/ */
distributor::distributor(widget& owner, distributor::distributor(widget& owner,const dispatcher::queue_position queue_position)
const dispatcher::queue_position queue_position)
: mouse_motion(owner, queue_position) : mouse_motion(owner, queue_position)
, mouse_button_left(mouse_button_left_events, owner, queue_position) , mouse_button_left(owner, queue_position)
, mouse_button_middle(mouse_button_middle_events, owner, queue_position) , mouse_button_middle(owner, queue_position)
, mouse_button_right(mouse_button_right_events, owner, queue_position) , mouse_button_right(owner, queue_position)
, keyboard_focus_(nullptr) , keyboard_focus_(nullptr)
, keyboard_focus_chain_() , keyboard_focus_chain_()
{ {

View file

@ -155,29 +155,11 @@ private:
/***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/ /***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
/** template<std::size_t I>
* Small helper metastruct to configure instances of mouse_button.
*/
struct mouse_button_event_types
{
ui_event sdl_button_down_event;
ui_event sdl_button_up_event;
ui_event button_down_event;
ui_event button_up_event;
ui_event button_click_event;
ui_event button_double_click_event;
/** Bitmask corresponding to this button's bit in SDL_GetMouseState's return value */
int32_t mask;
/** used for debug messages. */
std::string name;
};
class mouse_button : public virtual mouse_motion class mouse_button : public virtual mouse_motion
{ {
public: public:
mouse_button(const mouse_button_event_types& events, mouse_button(widget& owner, const dispatcher::queue_position queue_position);
widget& owner,
const dispatcher::queue_position queue_position);
/** /**
* Initializes the state of the button. * Initializes the state of the button.
@ -202,9 +184,6 @@ protected:
widget* focus_; widget* focus_;
private: private:
/** Which set of SDL events correspond to this button. */
const mouse_button_event_types events_;
/** Is the button down? */ /** Is the button down? */
bool is_down_; bool is_down_;
@ -222,8 +201,15 @@ private:
void mouse_button_click(widget* widget); void mouse_button_click(widget* widget);
}; };
/***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
using mouse_button_left = mouse_button<0>;
using mouse_button_middle = mouse_button<1>;
using mouse_button_right = mouse_button<2>;
/** /**
* Three subclasses of mouse_button, so that the distributor class can inherit from them; * The event handler class for the widget library.
*
* C++ doesn't allow multiple inheritance to directly use more than one instance of a * C++ doesn't allow multiple inheritance to directly use more than one instance of a
* superclass. * superclass.
* *
@ -231,41 +217,6 @@ private:
* refactoring that would allow these multiple classes to be replaced with a simple * refactoring that would allow these multiple classes to be replaced with a simple
* (distributor has-a std::array<mouse_button, 3>) relationship. * (distributor has-a std::array<mouse_button, 3>) relationship.
*/ */
struct mouse_button_left : public mouse_button
{
mouse_button_left(const mouse_button_event_types& events,
widget& owner,
const dispatcher::queue_position queue_position)
: mouse_motion(owner, queue_position)
, mouse_button(events, owner, queue_position)
{
}
};
struct mouse_button_middle : public mouse_button
{
mouse_button_middle(const mouse_button_event_types& events,
widget& owner,
const dispatcher::queue_position queue_position)
: mouse_motion(owner, queue_position)
, mouse_button(events, owner, queue_position)
{
}
};
struct mouse_button_right : public mouse_button
{
mouse_button_right(const mouse_button_event_types& events,
widget& owner,
const dispatcher::queue_position queue_position)
: mouse_motion(owner, queue_position)
, mouse_button(events, owner, queue_position)
{
}
};
/***** ***** ***** ***** distributor ***** ***** ***** ***** *****/
/** The event handler class for the widget library. */
class distributor : class distributor :
public mouse_button_left, public mouse_button_left,
public mouse_button_middle, public mouse_button_middle,