Skip to content

Commit 9e6a21b

Browse files
committed
Better Button:click + don't react to mouse up if downed on another frame
1 parent d5ae621 commit 9e6a21b

File tree

5 files changed

+184
-44
lines changed

5 files changed

+184
-44
lines changed

include/lxgui/gui_button.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,21 @@ class button : public frame {
310310
*/
311311
virtual void release();
312312

313+
/**
314+
* \brief Handle a mouse click over this button.
315+
* \param mouse_event The mouse event with which to generate a click
316+
* \note This calls the OnClick() handler only if the event is registered for clicks.
317+
*/
318+
void click(const std::string& mouse_event);
319+
320+
/**
321+
* \brief Handle a mouse click over this button.
322+
* \param button_id The mouse button with which to generate a click
323+
* \param button_event The mouse button event with which to generate a click
324+
* \note This calls the OnClick() handler only if the event is registered for clicks.
325+
*/
326+
void click(input::mouse_button button_id, input::mouse_button_event button_event);
327+
313328
/**
314329
* \brief Highlights this button.
315330
* \note The button will be highlighted even if the
@@ -456,6 +471,11 @@ class button : public frame {
456471
void parse_attributes_(const layout_node& node) override;
457472
void parse_all_nodes_before_children_(const layout_node& node) override;
458473

474+
bool is_button_clicks_enabled_(input::mouse_button button_id) const;
475+
476+
virtual void click_(
477+
input::mouse_button button_id, input::mouse_button_event button_event, float mx, float my);
478+
459479
const std::vector<std::string>& get_type_list_() const override;
460480

461481
state state_ = state::up;

include/lxgui/input_keys.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "lxgui/lxgui.hpp"
55

66
#include <cstdint>
7+
#include <optional>
78
#include <string_view>
89

910
namespace lxgui::input {
@@ -164,6 +165,7 @@ enum class key : std::uint8_t {
164165
/**
165166
* \brief Returns a standard English name for the provided mouse button.
166167
* \param button_id The ID code of the mouse button
168+
* \return The corresponding code name in English
167169
* \note This will return a standard English button name, e.g., "LeftButton" for the left mouse
168170
* button. This can be used for string-based key identification in scripts, where key
169171
* integer codes would be less usable, or for displaying debug or error messages.
@@ -182,6 +184,7 @@ std::string_view get_localizable_mouse_button_name(mouse_button button_id);
182184
/**
183185
* \brief Returns a standard English name for the provided mouse button event.
184186
* \param button_event The ID code of the mouse button event
187+
* \return The corresponding code name in English
185188
* \note This will return a standard English button name, e.g., "Up" for the mouse up event.
186189
* This can be used for string-based key identification in scripts, where key
187190
* integer codes would be less usable, or for displaying debug or error messages.
@@ -197,6 +200,26 @@ std::string_view get_mouse_button_event_codename(mouse_button_event button_event
197200
*/
198201
std::string_view get_localizable_mouse_button_event_name(mouse_button_event button_event);
199202

203+
/**
204+
* \brief Returns a standard Engilsh name for the provided mouse button and event.
205+
* \param button_id The ID code of the mouse button
206+
* \param button_event The ID code of the mouse button event
207+
* \return The corresponding code name in English
208+
* \note This will return a string with the format "<button>:<event>".
209+
* \see get_mouse_button_codename()
210+
* \see get_mouse_button_event_codename()
211+
*/
212+
std::string_view
213+
get_mouse_button_and_event_codename(mouse_button button_id, mouse_button_event button_event);
214+
215+
/**
216+
* \brief Returns a mouse button and a button event ID from a string formatted as "<button>:<event>".
217+
* \param event_name The name of the mouse button event, as "<button>:<event>"
218+
* \return The pair of decoded button and event ID, or std::nullopt if parsing failed.
219+
*/
220+
std::optional<std::pair<mouse_button, mouse_button_event>>
221+
get_mouse_button_and_event_from_codename(std::string_view button_and_event_name);
222+
200223
/**
201224
* \brief Returns a standard English name for the provided key.
202225
* \param key_id The key

src/gui_button.cpp

Lines changed: 89 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -34,46 +34,52 @@ void button::fire_script(const std::string& script_name, const event_data& data)
3434
if (!checker.is_alive())
3535
return;
3636

37-
if (is_enabled()) {
38-
if (script_name == "OnEnter")
39-
highlight();
37+
if (!is_enabled())
38+
return;
4039

41-
if (script_name == "OnLeave") {
42-
unlight();
40+
if (script_name == "OnEnter")
41+
highlight();
4342

44-
if (state_ == state::down)
45-
release();
43+
if (script_name == "OnLeave") {
44+
unlight();
45+
46+
if (state_ == state::down)
47+
release();
48+
}
49+
50+
bool try_handle_click = false;
51+
if (script_name == "OnMouseDown" || script_name == "OnMouseUp" ||
52+
script_name == "OnDoubleClick") {
53+
54+
try_handle_click = true;
55+
56+
// If reacting to a "mouse up" event, only handle as a click if
57+
// the mouse was pressed down on this button.
58+
if (script_name == "OnMouseUp" && !data.get<bool>(5)) {
59+
try_handle_click = false;
4660
}
61+
}
4762

48-
if (script_name == "OnMouseDown" || script_name == "OnMouseUp" ||
49-
script_name == "OnDoubleClick") {
50-
51-
const input::mouse_button_event event_id =
52-
script_name == "OnMouseDown" ? input::mouse_button_event::down
53-
: script_name == "OnMouseUp" ? input::mouse_button_event::up
54-
: input::mouse_button_event::double_click;
55-
56-
const auto event_name = data.get<std::string>(1) +
57-
std::string{input::get_mouse_button_event_codename(event_id)};
58-
59-
if (is_button_clicks_enabled(event_name)) {
60-
if (event_id == input::mouse_button_event::down)
61-
push();
62-
else if (event_id == input::mouse_button_event::up)
63-
release();
64-
65-
event_data new_data;
66-
new_data.add(data.get(0)); // Mouse button ID
67-
new_data.add(static_cast<std::underlying_type_t<input::mouse_button_event>>(
68-
event_id)); // Mouse button event
69-
new_data.add(event_name); // Mouse button event name
70-
new_data.add(data.get(2)); // Mouse pos X
71-
new_data.add(data.get(3)); // Mouse pos Y
72-
fire_script("OnClick", new_data);
73-
if (!checker.is_alive())
74-
return;
75-
}
63+
if (try_handle_click) {
64+
const input::mouse_button button_id = data.get<input::mouse_button>(0);
65+
const input::mouse_button_event event_id =
66+
script_name == "OnMouseDown" ? input::mouse_button_event::down
67+
: script_name == "OnMouseUp" ? input::mouse_button_event::up
68+
: input::mouse_button_event::double_click;
69+
70+
if (is_button_clicks_enabled_(button_id)) {
71+
if (event_id == input::mouse_button_event::down)
72+
push();
73+
else if (event_id == input::mouse_button_event::up)
74+
release();
7675
}
76+
77+
float mx = data.get<float>(2);
78+
float my = data.get<float>(3);
79+
80+
click_(button_id, event_id, mx, my);
81+
if (!checker.is_alive())
82+
return;
7783
}
7884
}
7985

@@ -389,6 +395,39 @@ void button::release() {
389395
state_ = state::up;
390396
}
391397

398+
void button::click(const std::string& mouse_event) {
399+
auto mouse_event_id = input::get_mouse_button_and_event_from_codename(mouse_event);
400+
if (!mouse_event_id.has_value()) {
401+
return;
402+
}
403+
404+
click(mouse_event_id.value().first, mouse_event_id.value().second);
405+
}
406+
407+
void button::click(input::mouse_button button_id, input::mouse_button_event button_event) {
408+
vector2f center = get_center();
409+
click_(button_id, button_event, center.x, center.y);
410+
}
411+
412+
void button::click_(
413+
input::mouse_button button_id, input::mouse_button_event button_event, float mx, float my) {
414+
415+
if (!is_button_clicks_enabled(button_id, button_event)) {
416+
return;
417+
}
418+
419+
std::string event_name =
420+
std::string{input::get_mouse_button_and_event_codename(button_id, button_event)};
421+
422+
event_data new_data;
423+
new_data.add(static_cast<std::underlying_type_t<input::mouse_button>>(button_id));
424+
new_data.add(static_cast<std::underlying_type_t<input::mouse_button_event>>(button_event));
425+
new_data.add(event_name);
426+
new_data.add(mx);
427+
new_data.add(my);
428+
fire_script("OnClick", new_data);
429+
}
430+
392431
void button::highlight() {
393432
if (is_highlighted_)
394433
return;
@@ -464,8 +503,7 @@ void button::enable_button_clicks(const std::string& mouse_state) {
464503
void button::enable_button_clicks(
465504
input::mouse_button button_id, input::mouse_button_event button_event) {
466505
reg_click_list_.insert(
467-
std::string{input::get_mouse_button_codename(button_id)} +
468-
std::string{input::get_mouse_button_event_codename(button_event)});
506+
std::string{input::get_mouse_button_and_event_codename(button_id, button_event)});
469507
}
470508

471509
void button::disable_button_clicks(const std::string& mouse_state) {
@@ -475,8 +513,7 @@ void button::disable_button_clicks(const std::string& mouse_state) {
475513
void button::disable_button_clicks(
476514
input::mouse_button button_id, input::mouse_button_event button_event) {
477515
reg_click_list_.erase(
478-
std::string{input::get_mouse_button_codename(button_id)} +
479-
std::string{input::get_mouse_button_event_codename(button_event)});
516+
std::string{input::get_mouse_button_and_event_codename(button_id, button_event)});
480517
}
481518

482519
void button::disable_button_clicks() {
@@ -489,10 +526,19 @@ bool button::is_button_clicks_enabled(const std::string& mouse_event) const {
489526

490527
bool button::is_button_clicks_enabled(
491528
input::mouse_button button_id, input::mouse_button_event button_event) const {
492-
return reg_click_list_.find(
493-
std::string{input::get_mouse_button_codename(button_id)} +
494-
std::string{input::get_mouse_button_event_codename(button_event)}) !=
495-
reg_click_list_.end();
529+
return reg_click_list_.find(std::string{input::get_mouse_button_and_event_codename(
530+
button_id, button_event)}) != reg_click_list_.end();
531+
}
532+
533+
bool button::is_button_clicks_enabled_(input::mouse_button button_id) const {
534+
auto button_name = input::get_mouse_button_codename(button_id);
535+
for (const auto& click : reg_click_list_) {
536+
if (click.find(button_name) == 0) {
537+
return true;
538+
}
539+
}
540+
541+
return false;
496542
}
497543

498544
const std::vector<std::string>& button::get_type_list_() const {

src/gui_button_glues.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ void button::register_on_lua(sol::state& lua) {
5858

5959
/** @function click
6060
*/
61-
type.set_function("click", [](button& self) { self.fire_script("OnClick"); });
61+
type.set_function(
62+
"click", member_function< // select the right overload for Lua
63+
static_cast<void (button::*)(const std::string&)>(&button::click)>());
6264

6365
/** @function disable
6466
*/

src/input_keys.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "lxgui/input_keys.hpp"
22

3+
#include "lxgui/utils_string.hpp"
4+
35
namespace lxgui::input {
46

57
std::string_view get_mouse_button_codename(mouse_button button_id) {
@@ -38,6 +40,53 @@ std::string_view get_localizable_mouse_button_event_name(mouse_button_event butt
3840
}
3941
}
4042

43+
std::string_view
44+
get_mouse_button_and_event_codename(mouse_button button_id, mouse_button_event button_event) {
45+
switch (button_id) {
46+
case mouse_button::left:
47+
switch (button_event) {
48+
case mouse_button_event::up: return "LeftButton:Up";
49+
case mouse_button_event::down: return "LeftButton:Down";
50+
case mouse_button_event::double_click: return "LeftButton:DoubleClick";
51+
default: return "";
52+
}
53+
case mouse_button::right:
54+
switch (button_event) {
55+
case mouse_button_event::up: return "RightButton:Up";
56+
case mouse_button_event::down: return "RightButton:Down";
57+
case mouse_button_event::double_click: return "RightButton:DoubleClick";
58+
default: return "";
59+
};
60+
case mouse_button::middle:
61+
switch (button_event) {
62+
case mouse_button_event::up: return "MiddleButton:Up";
63+
case mouse_button_event::down: return "MiddleButton:Down";
64+
case mouse_button_event::double_click: return "MiddleButton:DoubleClick";
65+
default: return "";
66+
};
67+
default: return "";
68+
}
69+
}
70+
71+
std::optional<std::pair<mouse_button, mouse_button_event>>
72+
get_mouse_button_and_event_from_codename(std::string_view button_and_event_name) {
73+
const auto pos = button_and_event_name.find_first_of(':');
74+
if (pos == std::string_view::npos)
75+
return {};
76+
77+
auto button_name = button_and_event_name.substr(0, pos);
78+
auto event_name = button_and_event_name.substr(pos + 1);
79+
80+
auto button_id = utils::from_string<mouse_button>(button_name);
81+
auto event_id = utils::from_string<mouse_button_event>(event_name);
82+
83+
if (!button_id.has_value() || !event_id.has_value()) {
84+
return {};
85+
}
86+
87+
return std::make_pair(button_id.value(), event_id.value());
88+
}
89+
4190
std::string_view get_key_codename(key key_id) {
4291
switch (key_id) {
4392
case key::k_escape: return "Escape";

0 commit comments

Comments
 (0)