Another go at refactoring distributor.cpp (builds and runs successfully)
This is part-way though a refactor, but I'm not committing myself to completing it; publishing for the comments and discussion. This solves PR #5198's compile errors about undefined references, but the solution here is to expand the templates into the multiple hardcoded copies block starting with `switch(events_.sdl_button_down_event)`.
This commit is contained in:
parent
a1f44d8f64
commit
8b1c6cf59d
2 changed files with 189 additions and 103 deletions
|
@ -357,47 +357,92 @@ void mouse_motion::stop_hover_timer()
|
|||
|
||||
#undef LOG_HEADER
|
||||
#define LOG_HEADER \
|
||||
"distributor mouse button " << name_ << " [" << owner_.id() << "]: "
|
||||
"distributor mouse button " << events_.name << " [" << owner_.id() << "]: "
|
||||
|
||||
template<typename T>
|
||||
mouse_button<T>::mouse_button(const std::string& name_, widget& owner,
|
||||
mouse_button::mouse_button(const mouse_button_event_types& events, widget& owner,
|
||||
const dispatcher::queue_position queue_position)
|
||||
: mouse_motion(owner, queue_position)
|
||||
, last_click_stamp_(0)
|
||||
, last_clicked_widget_(nullptr)
|
||||
, focus_(nullptr)
|
||||
, name_(name_)
|
||||
, events_(events)
|
||||
, is_down_(false)
|
||||
, signal_handler_sdl_button_down_entered_(false)
|
||||
, signal_handler_sdl_button_up_entered_(false)
|
||||
{
|
||||
owner_.connect_signal<T::sdl_button_down_event>(
|
||||
std::bind(&mouse_button<T>::signal_handler_sdl_button_down,
|
||||
this,
|
||||
_2,
|
||||
_3,
|
||||
_5),
|
||||
queue_position);
|
||||
owner_.connect_signal<T::sdl_button_up_event>(
|
||||
std::bind(&mouse_button<T>::signal_handler_sdl_button_up,
|
||||
this,
|
||||
_2,
|
||||
_3,
|
||||
_5),
|
||||
queue_position);
|
||||
// The connect_signal framework is currently using SFINAE checking to ensure that we only
|
||||
// register mouse button signal handlers for mouse buttons. That causes us to need this
|
||||
// hardcoded (either directly or by making mouse_button a templated class), the manual handling
|
||||
// of the three cases here is the current progress on refactoring.
|
||||
switch(events_.sdl_button_down_event) {
|
||||
case event::SDL_LEFT_BUTTON_DOWN: {
|
||||
owner_.connect_signal<event::SDL_LEFT_BUTTON_DOWN>(
|
||||
std::bind(&mouse_button::signal_handler_sdl_button_down,
|
||||
this,
|
||||
_2,
|
||||
_3,
|
||||
_5),
|
||||
queue_position);
|
||||
owner_.connect_signal<event::SDL_LEFT_BUTTON_UP>(
|
||||
std::bind(&mouse_button::signal_handler_sdl_button_up,
|
||||
this,
|
||||
_2,
|
||||
_3,
|
||||
_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,
|
||||
_2,
|
||||
_3,
|
||||
_5),
|
||||
queue_position);
|
||||
owner_.connect_signal<event::SDL_MIDDLE_BUTTON_UP>(
|
||||
std::bind(&mouse_button::signal_handler_sdl_button_up,
|
||||
this,
|
||||
_2,
|
||||
_3,
|
||||
_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,
|
||||
_2,
|
||||
_3,
|
||||
_5),
|
||||
queue_position);
|
||||
owner_.connect_signal<event::SDL_RIGHT_BUTTON_UP>(
|
||||
std::bind(&mouse_button::signal_handler_sdl_button_up,
|
||||
this,
|
||||
_2,
|
||||
_3,
|
||||
_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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void mouse_button<T>::initialize_state(const bool is_down)
|
||||
void mouse_button::initialize_state(int32_t button_state)
|
||||
{
|
||||
last_click_stamp_ = 0;
|
||||
last_clicked_widget_ = nullptr;
|
||||
focus_ = 0;
|
||||
is_down_ = is_down;
|
||||
is_down_ = button_state & events_.mask;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void mouse_button<T>::signal_handler_sdl_button_down(const event::ui_event event, bool& handled,
|
||||
void mouse_button::signal_handler_sdl_button_down(const event::ui_event event, bool& handled,
|
||||
const point& coordinate)
|
||||
{
|
||||
if(signal_handler_sdl_button_down_entered_) {
|
||||
|
@ -420,10 +465,10 @@ void mouse_button<T>::signal_handler_sdl_button_down(const event::ui_event event
|
|||
if(mouse_captured_) {
|
||||
assert(mouse_focus_);
|
||||
focus_ = mouse_focus_;
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::sdl_button_down_event << ".\n";
|
||||
if(!owner_.fire(T::sdl_button_down_event, *focus_, coordinate)) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::button_down_event << ".\n";
|
||||
owner_.fire(T::button_down_event, *mouse_focus_);
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_down_event << ".\n";
|
||||
if(!owner_.fire(events_.sdl_button_down_event, *focus_, coordinate)) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_down_event << ".\n";
|
||||
owner_.fire(events_.button_down_event, *mouse_focus_);
|
||||
}
|
||||
} else {
|
||||
widget* mouse_over = owner_.find_at(coordinate, true);
|
||||
|
@ -440,17 +485,16 @@ void mouse_button<T>::signal_handler_sdl_button_down(const event::ui_event event
|
|||
}
|
||||
|
||||
focus_ = mouse_over;
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::sdl_button_down_event << ".\n";
|
||||
if(!owner_.fire(T::sdl_button_down_event, *focus_, coordinate)) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::button_down_event << ".\n";
|
||||
owner_.fire(T::button_down_event, *focus_);
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_down_event << ".\n";
|
||||
if(!owner_.fire(events_.sdl_button_down_event, *focus_, coordinate)) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_down_event << ".\n";
|
||||
owner_.fire(events_.button_down_event, *focus_);
|
||||
}
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void mouse_button<T>::signal_handler_sdl_button_up(const event::ui_event event, bool& handled,
|
||||
void mouse_button::signal_handler_sdl_button_up(const event::ui_event event, bool& handled,
|
||||
const point& coordinate)
|
||||
{
|
||||
if(signal_handler_sdl_button_up_entered_) {
|
||||
|
@ -470,13 +514,17 @@ void mouse_button<T>::signal_handler_sdl_button_up(const event::ui_event event,
|
|||
is_down_ = false;
|
||||
|
||||
if(focus_) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::sdl_button_up_event << ".\n";
|
||||
if(!owner_.fire(T::sdl_button_up_event, *focus_, coordinate)) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::button_up_event << ".\n";
|
||||
owner_.fire(T::button_up_event, *focus_);
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.sdl_button_up_event << ".\n";
|
||||
if(!owner_.fire(events_.sdl_button_up_event, *focus_, coordinate)) {
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_up_event << ".\n";
|
||||
owner_.fire(events_.button_up_event, *focus_);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: The block below is strange diamond inheritance - it's code that could be in
|
||||
// mouse_motion which applies to all three buttons, but it will be run in one of the
|
||||
// three mouse_button<T> subclasses, and then the other two mouse_button<T> subclasses
|
||||
// will reach here with mouse_captured_ == false.
|
||||
widget* mouse_over = owner_.find_at(coordinate, true);
|
||||
if(mouse_captured_) {
|
||||
const unsigned mask = SDL_BUTTON_LMASK | SDL_BUTTON_MMASK
|
||||
|
@ -503,23 +551,22 @@ void mouse_button<T>::signal_handler_sdl_button_up(const event::ui_event event,
|
|||
handled = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void mouse_button<T>::mouse_button_click(widget* widget)
|
||||
void mouse_button::mouse_button_click(widget* widget)
|
||||
{
|
||||
uint32_t stamp = SDL_GetTicks();
|
||||
if(last_click_stamp_ + settings::double_click_time >= stamp
|
||||
&& last_clicked_widget_ == widget) {
|
||||
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::button_double_click_event << ".\n";
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_double_click_event << ".\n";
|
||||
|
||||
owner_.fire(T::button_double_click_event, *widget);
|
||||
owner_.fire(events_.button_double_click_event, *widget);
|
||||
last_click_stamp_ = 0;
|
||||
last_clicked_widget_ = nullptr;
|
||||
|
||||
} else {
|
||||
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << T::button_click_event << ".\n";
|
||||
owner_.fire(T::button_click_event, *widget);
|
||||
DBG_GUI_E << LOG_HEADER << "Firing: " << events_.button_click_event << ".\n";
|
||||
owner_.fire(events_.button_click_event, *widget);
|
||||
last_click_stamp_ = stamp;
|
||||
last_clicked_widget_ = widget;
|
||||
}
|
||||
|
@ -530,6 +577,40 @@ void mouse_button<T>::mouse_button_click(widget* widget)
|
|||
#undef LOG_HEADER
|
||||
#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
|
||||
* used.
|
||||
|
@ -537,9 +618,9 @@ void mouse_button<T>::mouse_button_click(widget* widget)
|
|||
distributor::distributor(widget& owner,
|
||||
const dispatcher::queue_position queue_position)
|
||||
: mouse_motion(owner, queue_position)
|
||||
, mouse_button_left("left", owner, queue_position)
|
||||
, mouse_button_middle("middle", owner, queue_position)
|
||||
, mouse_button_right("right", owner, queue_position)
|
||||
, mouse_button_left(mouse_button_left_events, owner, queue_position)
|
||||
, mouse_button_middle(mouse_button_middle_events, owner, queue_position)
|
||||
, mouse_button_right(mouse_button_right_events, owner, queue_position)
|
||||
, keyboard_focus_(nullptr)
|
||||
, keyboard_focus_chain_()
|
||||
{
|
||||
|
@ -581,11 +662,11 @@ distributor::~distributor()
|
|||
|
||||
void distributor::initialize_state()
|
||||
{
|
||||
const uint8_t button_state = SDL_GetMouseState(nullptr, nullptr);
|
||||
const uint32_t button_state = SDL_GetMouseState(nullptr, nullptr);
|
||||
|
||||
mouse_button_left::initialize_state((button_state & SDL_BUTTON(1)) != 0);
|
||||
mouse_button_middle::initialize_state((button_state & SDL_BUTTON(2)) != 0);
|
||||
mouse_button_right::initialize_state((button_state & SDL_BUTTON(3)) != 0);
|
||||
mouse_button_left::initialize_state(button_state);
|
||||
mouse_button_middle::initialize_state(button_state);
|
||||
mouse_button_right::initialize_state(button_state);
|
||||
|
||||
init_mouse_location();
|
||||
}
|
||||
|
|
|
@ -155,41 +155,36 @@ private:
|
|||
/***** ***** ***** ***** mouse_button ***** ***** ***** ***** *****/
|
||||
|
||||
/**
|
||||
* Small helper metastruct to specialize mouse_button with and provide ui_event type
|
||||
* aliases without needing to make mouse_button take a million template types.
|
||||
* Small helper metastruct to configure instances of mouse_button.
|
||||
*/
|
||||
template<
|
||||
ui_event sdl_button_down,
|
||||
ui_event sdl_button_up,
|
||||
ui_event button_down,
|
||||
ui_event button_up,
|
||||
ui_event button_click,
|
||||
ui_event button_double_click>
|
||||
struct mouse_button_event_types_wrapper
|
||||
struct mouse_button_event_types
|
||||
{
|
||||
static const ui_event sdl_button_down_event = sdl_button_down;
|
||||
static const ui_event sdl_button_up_event = sdl_button_up;
|
||||
static const ui_event button_down_event = button_down;
|
||||
static const ui_event button_up_event = button_up;
|
||||
static const ui_event button_click_event = button_click;
|
||||
static const ui_event button_double_click_event = button_double_click;
|
||||
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;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class mouse_button : public virtual mouse_motion
|
||||
{
|
||||
public:
|
||||
mouse_button(const std::string& name_,
|
||||
mouse_button(const mouse_button_event_types& events,
|
||||
widget& owner,
|
||||
const dispatcher::queue_position queue_position);
|
||||
|
||||
/**
|
||||
* Initializes the state of the button.
|
||||
*
|
||||
* @param is_down The initial state of the button, if true down
|
||||
* else initialized as up.
|
||||
* @param button_state The initial state of all buttons, in which the bit corresponding to
|
||||
mouse_button_event_types.mask will be set if the button is down, or unset if it is up.
|
||||
*/
|
||||
void initialize_state(const bool is_down);
|
||||
void initialize_state(int32_t button_state);
|
||||
|
||||
protected:
|
||||
/** The time of the last click used for double clicking. */
|
||||
|
@ -206,8 +201,8 @@ protected:
|
|||
widget* focus_;
|
||||
|
||||
private:
|
||||
/** used for debug messages. */
|
||||
const std::string name_;
|
||||
/** Which set of SDL events correspond to this button. */
|
||||
const mouse_button_event_types events_;
|
||||
|
||||
/** Is the button down? */
|
||||
bool is_down_;
|
||||
|
@ -226,38 +221,48 @@ private:
|
|||
void mouse_button_click(widget* widget);
|
||||
};
|
||||
|
||||
/**
|
||||
* Three subclasses of mouse_button, so that the distributor class can inherit from them;
|
||||
* C++ doesn't allow multiple inheritance to directly use more than one instance of a
|
||||
* superclass.
|
||||
*
|
||||
* It's a diamond inheritance, as all of these have virtual base class mouse_motion;
|
||||
* refactoring that would allow these multiple classes to be replaced with a simple
|
||||
* (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 ***** ***** ***** ***** *****/
|
||||
|
||||
using mouse_button_left = mouse_button<
|
||||
mouse_button_event_types_wrapper<
|
||||
SDL_LEFT_BUTTON_DOWN,
|
||||
SDL_LEFT_BUTTON_UP,
|
||||
LEFT_BUTTON_DOWN,
|
||||
LEFT_BUTTON_UP,
|
||||
LEFT_BUTTON_CLICK,
|
||||
LEFT_BUTTON_DOUBLE_CLICK>
|
||||
>;
|
||||
|
||||
using mouse_button_middle = mouse_button<
|
||||
mouse_button_event_types_wrapper<
|
||||
SDL_MIDDLE_BUTTON_DOWN,
|
||||
SDL_MIDDLE_BUTTON_UP,
|
||||
MIDDLE_BUTTON_DOWN,
|
||||
MIDDLE_BUTTON_UP,
|
||||
MIDDLE_BUTTON_CLICK,
|
||||
MIDDLE_BUTTON_DOUBLE_CLICK>
|
||||
>;
|
||||
|
||||
using mouse_button_right = mouse_button<
|
||||
mouse_button_event_types_wrapper<
|
||||
SDL_RIGHT_BUTTON_DOWN,
|
||||
SDL_RIGHT_BUTTON_UP,
|
||||
RIGHT_BUTTON_DOWN,
|
||||
RIGHT_BUTTON_UP,
|
||||
RIGHT_BUTTON_CLICK,
|
||||
RIGHT_BUTTON_DOUBLE_CLICK>
|
||||
>;
|
||||
|
||||
|
||||
/** The event handler class for the widget library. */
|
||||
class distributor :
|
||||
|
|
Loading…
Add table
Reference in a new issue