Skip to content

Commit 63610b9

Browse files
authored
Add focus events (#68)
This commit updates interactive controls (not controls which only display information) to handle OnGainedFocus() and OnLostFocus() events. These interactive controls are given a behavior template parameter, which can implement these functions if they want to handle them.
1 parent eb75242 commit 63610b9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1637
-537
lines changed

Code/Examples/1-SimpleExample/EntryPoint.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class CustomForm {
1111

1212
void OnCreated(maxGUI::FormConcept* form) noexcept {
1313
// Add controls inside the Form's OnCreated().
14-
multiline_textbox_ = form->AddControl<maxGUI::MultilineTextBox>(max::Containers::MakeRectangle(0, 0, 100, 100), "Multi-line" MAXGUI_PLATFORM_NEWLINE "test");
14+
multiline_textbox_ = form->AddControl<maxGUI::MultilineTextBox<>>(max::Containers::MakeRectangle(0, 0, 100, 100), "Multi-line" MAXGUI_PLATFORM_NEWLINE "test");
1515
}
1616

1717
void OnResized(maxGUI::FormConcept* /*form*/, int new_width, int new_height) noexcept {
@@ -24,7 +24,7 @@ class CustomForm {
2424
maxGUI::PostExitMessage(0);
2525
}
2626

27-
maxGUI::MultilineTextBox* multiline_textbox_ = nullptr;
27+
maxGUI::MultilineTextBox<>* multiline_textbox_ = nullptr;
2828
};
2929

3030

Code/Examples/2-StylingExample/EntryPoint.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ class LoginForm {
2626
void OnCreated(maxGUI::FormConcept* form) noexcept {
2727
form->AddControl<maxGUI::Label>(max::Containers::MakeRectangle(50, 50, 300, 500), "Login");
2828

29-
username_textbox_ = form->AddControl<maxGUI::TextBox>(max::Containers::MakeRectangle(50, 100, 300, 50), "");
29+
username_textbox_ = form->AddControl<maxGUI::TextBox<>>(max::Containers::MakeRectangle(50, 100, 300, 50), "");
3030

3131
// The extra optional parameter at the end is a bitmask of styles.
3232
// Different controls have different optional styles available.
3333
// For example, a TextBox can have the Password style which hides the character typed by the user.
34-
password_textbox_ = form->AddControl<maxGUI::TextBox>(max::Containers::MakeRectangle(50, 150, 300, 50), "", maxGUI::TextBoxStyles::Password);
34+
password_textbox_ = form->AddControl<maxGUI::TextBox<>>(max::Containers::MakeRectangle(50, 150, 300, 50), "", maxGUI::TextBoxStyles::Password);
3535

3636
// A Button can have the Default style, which allows the user to press Enter at any time to press the button.
3737
form->AddControl<maxGUI::Button<LoginButtonBehavior>>(max::Containers::MakeRectangle(50, 250, 100, 100), "Login", maxGUI::ButtonStyles::Default | maxGUI::ButtonStyles::Disabled);
@@ -41,8 +41,8 @@ class LoginForm {
4141
maxGUI::PostExitMessage(0);
4242
}
4343

44-
maxGUI::TextBox* username_textbox_ = nullptr;
45-
maxGUI::TextBox* password_textbox_ = nullptr;
44+
maxGUI::TextBox<>* username_textbox_ = nullptr;
45+
maxGUI::TextBox<>* password_textbox_ = nullptr;
4646

4747
};
4848

Code/Examples/3-ControlGalleryExample/EntryPoint.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010
#include <maxGUI/maxGUI.hpp>
1111

12-
class CustomButtonBehavior
13-
{
12+
class CustomButtonBehavior {
1413
public:
1514

1615
static void OnPressed() noexcept {
@@ -26,28 +25,28 @@ class ControlGalleryForm {
2625
form->AddControl<maxGUI::Button<CustomButtonBehavior>>(max::Containers::MakeRectangle(25, 25, 150, 50), "Custom Button");
2726

2827
std::vector<std::string> dropdown_options{"Option 1", "Option 2", "Option 3"};
29-
form->AddControl<maxGUI::DropDownBox>(max::Containers::MakeRectangle(25, 100, 300, 250), std::move(dropdown_options));
28+
form->AddControl<maxGUI::DropDownBox<>>(max::Containers::MakeRectangle(25, 100, 300, 250), std::move(dropdown_options));
3029

3130
// TODO: Add the radio buttons inside the frame
3231
form->AddControl<maxGUI::Frame>(max::Containers::MakeRectangle(25, 150, 300, 50), "Frame");
3332

3433
form->AddControl<maxGUI::Label>(max::Containers::MakeRectangle(25, 225, 300, 25), "Label");
3534

3635
std::vector<std::string> listbox_options{"Item 1", "Item 2", "Item 3"};
37-
form->AddControl<maxGUI::ListBox>(max::Containers::MakeRectangle(25, 275, 300, 150), std::move(listbox_options));
36+
form->AddControl<maxGUI::ListBox<>>(max::Containers::MakeRectangle(25, 275, 300, 150), std::move(listbox_options));
3837

39-
form->AddControl<maxGUI::MultilineTextBox>(max::Containers::MakeRectangle(25, 450, 300, 150), "Multiline\r\ntextbox");
38+
form->AddControl<maxGUI::MultilineTextBox<>>(max::Containers::MakeRectangle(25, 450, 300, 150), "Multiline\r\ntextbox");
4039

4140
form->AddControl<maxGUI::ProgressBar>(max::Containers::MakeRectangle(25, 625, 300, 25), 0, 100, 50);
4241

43-
form->AddControl<maxGUI::CheckBox>(max::Containers::MakeRectangle(25, 675, 300, 25), "Check 1");
42+
form->AddControl<maxGUI::CheckBox<>>(max::Containers::MakeRectangle(25, 675, 300, 25), "Check 1");
4443

4544
// When using multiple RadioButtons that belong to one group, be sure to add the FirstInGroup style to the first option.
46-
form->AddControl<maxGUI::RadioButton>(max::Containers::MakeRectangle(25, 725, 300, 25), "Option 1", maxGUI::RadioButtonStyles::FirstInGroup);
45+
form->AddControl<maxGUI::RadioButton<>>(max::Containers::MakeRectangle(25, 725, 300, 25), "Option 1", maxGUI::RadioButtonStyles::FirstInGroup);
4746

48-
form->AddControl<maxGUI::RadioButton>(max::Containers::MakeRectangle(25, 750, 300, 25), "Option 2");
47+
form->AddControl<maxGUI::RadioButton<>>(max::Containers::MakeRectangle(25, 750, 300, 25), "Option 2");
4948

50-
form->AddControl<maxGUI::TextBox>(max::Containers::MakeRectangle(25, 800, 300, 25), "Textbox");
49+
form->AddControl<maxGUI::TextBox<>>(max::Containers::MakeRectangle(25, 800, 300, 25), "Textbox");
5150
}
5251

5352
void OnClosed(maxGUI::FormConcept* /*form*/) noexcept {

Code/maxGUI/Button.hpp

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,23 @@
66
#define MAXGUI_BUTTON_HPP
77

88
#include <max/Compiling/Configuration.hpp>
9-
#include <max/Compiling/Bitmask.hpp>
109
#include <max/Containers/Rectangle.hpp>
10+
#include <maxGUI/ButtonImplementation.hpp>
1111
#include <maxGUI/ControlWithText.hpp>
1212
#include <string>
13-
#include <utility>
1413

1514
#if defined(MAX_PLATFORM_WINDOWS)
1615
#ifndef WIN32_LEAN_AND_MEAN
17-
#define WIN32_LEAN_AND_MEAN
16+
#define WIN32_LEAN_AND_MEAN
1817
#endif
18+
1919
#include <Windows.h>
2020
#endif
2121

2222
#ifndef MAX_CONCEPTS_SUPPORTED
2323
#include <max/Compiling/Exists.hpp>
2424
#endif
2525

26-
namespace maxGUI
27-
{
28-
29-
enum class ButtonStyles : uint8_t {
30-
None = 0,
31-
Disabled = 1,
32-
Default = 2,
33-
Flat = 4,
34-
};
35-
36-
} // namespace maxGUI
37-
38-
MAX_BITMASKABLE_ENUM_CLASS(maxGUI::ButtonStyles);
39-
4026
namespace maxGUI
4127
{
4228

@@ -68,7 +54,7 @@ namespace maxGUI
6854
explicit Button(HWND window_handle) noexcept;
6955
#endif
7056

71-
~Button() noexcept override = default;
57+
~Button() noexcept override;
7258

7359
#if defined(MAX_PLATFORM_WINDOWS)
7460
static HWND Create(HWND parent_window_handle, max::Containers::Rectangle<int, int> rectangle, std::string text, ButtonStyles styles = ButtonStyles::None) noexcept;
@@ -81,6 +67,7 @@ namespace maxGUI
8167
#endif
8268

8369
Behavior behavior_;
70+
ButtonImplementation implementation_;
8471

8572
};
8673

Code/maxGUI/Button.inl

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <utility>
6+
57
#if defined(MAX_PLATFORM_WINDOWS)
68
#include <maxGUI/Win32String.hpp>
79
#endif
@@ -16,8 +18,9 @@ namespace maxGUI
1618
template< class Behavior >
1719
#endif
1820
Button< Behavior >::Button(HWND window_handle) noexcept
19-
: ControlWithText(std::move(window_handle))
21+
: ControlWithText(window_handle)
2022
, behavior_()
23+
, implementation_(window_handle)
2124
{}
2225
#endif
2326

@@ -27,27 +30,17 @@ namespace maxGUI
2730
#else
2831
template< class Behavior >
2932
#endif
30-
HWND Button< Behavior >::Create(HWND parent_window_handle, max::Containers::Rectangle<int, int> rectangle, std::string text, ButtonStyles styles) noexcept {
31-
DWORD win32_styles = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
32-
// MSVC at warning level 4 issues C26813 because it wants "if (styles & ButtonStyles::Default) {"
33-
// But this doesn't play nicely with enum classes because ultimately it needs to convert to bool.
34-
// See https://developercommunity.visualstudio.com/t/C26813-incompatible-with-enum-class/10145182
35-
#pragma warning(push)
36-
#pragma warning(disable: 26813)
37-
if ((styles & ButtonStyles::Disabled) == ButtonStyles::Disabled) {
38-
win32_styles |= WS_DISABLED;
39-
}
40-
if ((styles & ButtonStyles::Default) == ButtonStyles::Default) {
41-
win32_styles |= BS_DEFPUSHBUTTON;
42-
}
43-
if ((styles & ButtonStyles::Flat) == ButtonStyles::Flat) {
44-
win32_styles |= BS_FLAT;
45-
}
46-
#pragma warning(pop)
47-
48-
Win32String win32_text = Utf8ToWin32String(std::move(text));
33+
Button< Behavior >::~Button() noexcept = default;
34+
#endif
4935

50-
return CreateWindowEx(0, TEXT("BUTTON"), win32_text.text_, win32_styles, rectangle.TopLeft.X(), rectangle.TopLeft.Y(), rectangle.Width, rectangle.Height, parent_window_handle, NULL, reinterpret_cast<HINSTANCE>(GetWindowLongPtr(parent_window_handle, GWLP_HINSTANCE)), NULL);
36+
#if defined(MAX_PLATFORM_WINDOWS)
37+
#if defined(MAX_CONCEPTS_SUPPORTED)
38+
template< ButtonRequirements Behavior >
39+
#else
40+
template< class Behavior >
41+
#endif
42+
HWND Button< Behavior >::Create(HWND parent_window_handle, max::Containers::Rectangle<int, int> rectangle, std::string text, ButtonStyles styles) noexcept {
43+
return ButtonImplementation::Create(std::move(parent_window_handle), std::move(rectangle), std::move(text), std::move(styles));
5144
}
5245
#endif
5346

@@ -58,12 +51,21 @@ namespace maxGUI
5851
template< class Behavior >
5952
#endif
6053
void Button< Behavior >::OnCommand(WORD notification) noexcept {
61-
//if constexpr (Exists<Behavior, OnPressedTest>::value) {
62-
//if constexpr (Exists2<Behavior::OnPressed()>::value) {
63-
if (notification == BN_CLICKED) {
64-
behavior_.OnPressed();
54+
if constexpr (HasOnGainedFocus< Behavior >::value) {
55+
if (notification == BN_SETFOCUS ) {
56+
behavior_.OnGainedFocus(&implementation_);
57+
}
58+
}
59+
60+
if constexpr (HasOnLostFocus< Behavior >::value) {
61+
if (notification == BN_KILLFOCUS ) {
62+
behavior_.OnLostFocus(&implementation_);
6563
}
66-
//}
64+
}
65+
66+
if (notification == BN_CLICKED) {
67+
behavior_.OnPressed();
68+
}
6769
}
6870
#endif
6971

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2023, The maxGUI Contributors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include <maxGUI/ButtonImplementation.hpp>
6+
7+
#if defined(MAX_PLATFORM_WINDOWS)
8+
#include <maxGUI/Win32String.hpp>
9+
#endif
10+
11+
namespace maxGUI
12+
{
13+
14+
#if defined(MAX_PLATFORM_WINDOWS)
15+
ButtonImplementation::ButtonImplementation(HWND window_handle) noexcept
16+
: ControlWithTextImplementation(std::move(window_handle))
17+
{}
18+
#endif
19+
20+
ButtonImplementation::~ButtonImplementation() noexcept = default;
21+
22+
#if defined(MAX_PLATFORM_WINDOWS)
23+
HWND ButtonImplementation::Create(HWND parent_window_handle, max::Containers::Rectangle<int, int> rectangle, std::string text, ButtonStyles styles) noexcept {
24+
DWORD win32_styles = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_NOTIFY;
25+
// MSVC at warning level 4 issues C26813 because it wants "if (styles & ButtonStyles::Default) {"
26+
// But this doesn't play nicely with enum classes because ultimately it needs to convert to bool.
27+
// See https://developercommunity.visualstudio.com/t/C26813-incompatible-with-enum-class/10145182
28+
#pragma warning(push)
29+
#pragma warning(disable: 26813)
30+
if ((styles & ButtonStyles::Disabled) == ButtonStyles::Disabled) {
31+
win32_styles |= WS_DISABLED;
32+
}
33+
if ((styles & ButtonStyles::Default) == ButtonStyles::Default) {
34+
win32_styles |= BS_DEFPUSHBUTTON;
35+
}
36+
if ((styles & ButtonStyles::Flat) == ButtonStyles::Flat) {
37+
win32_styles |= BS_FLAT;
38+
}
39+
#pragma warning(pop)
40+
41+
Win32String win32_text = Utf8ToWin32String(std::move(text));
42+
43+
//return CreateWindowEx(0, TEXT("BUTTON"), win32_text.text_, win32_styles, rectangle.TopLeft.X(), rectangle.TopLeft.Y(), rectangle.Width, rectangle.Height, parent_window_handle, NULL, reinterpret_cast<HINSTANCE>(GetWindowLongPtr(parent_window_handle, GWLP_HINSTANCE)), NULL);
44+
HWND window_handle = CreateWindowEx(0, TEXT("BUTTON"), win32_text.text_, win32_styles, rectangle.TopLeft.X(), rectangle.TopLeft.Y(), rectangle.Width, rectangle.Height, parent_window_handle, NULL, reinterpret_cast<HINSTANCE>(GetWindowLongPtr(parent_window_handle, GWLP_HINSTANCE)), NULL);
45+
46+
const int font_height_in_points = 10;
47+
HDC screen_device_context = GetDC(NULL);
48+
const int font_height_in_logical_units = -MulDiv(font_height_in_points, GetDeviceCaps(screen_device_context, LOGPIXELSY), 72);
49+
//const int font_height_in_logical_units = -12;
50+
HFONT font = CreateFont(font_height_in_logical_units, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE | DEFAULT_PITCH, TEXT("Segoe UI"));
51+
52+
SendMessage(window_handle, WM_SETFONT, reinterpret_cast<WPARAM>(font), TRUE);
53+
54+
return window_handle;
55+
}
56+
#endif
57+
58+
} // namespace maxGUI
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2023, The maxGUI Contributors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef MAXGUI_BUTTONIMPLEMENTATION_HPP
6+
#define MAXGUI_BUTTONIMPLEMENTATION_HPP
7+
8+
#include <string>
9+
10+
#include <max/Compiling/Bitmask.hpp>
11+
#include <max/Containers/Rectangle.hpp>
12+
#include <max/Compiling/Configuration.hpp>
13+
14+
#if defined(MAX_PLATFORM_WINDOWS)
15+
#ifndef WIN32_LEAN_AND_MEAN
16+
#define WIN32_LEAN_AND_MEAN
17+
#endif
18+
19+
#include <Windows.h>
20+
#endif
21+
22+
#include <maxGUI/ControlWithTextImplementation.hpp>
23+
24+
namespace maxGUI
25+
{
26+
27+
enum class ButtonStyles : uint8_t {
28+
None = 0,
29+
Disabled = 1,
30+
Default = 2,
31+
Flat = 4,
32+
};
33+
34+
} // namespace maxGUI
35+
36+
MAX_BITMASKABLE_ENUM_CLASS(maxGUI::ButtonStyles);
37+
38+
namespace maxGUI
39+
{
40+
41+
class ButtonImplementation : public ControlWithTextImplementation
42+
{
43+
public:
44+
45+
#if defined(MAX_PLATFORM_WINDOWS)
46+
explicit ButtonImplementation(HWND window_handle) noexcept;
47+
#endif
48+
49+
~ButtonImplementation() noexcept;
50+
51+
#if defined(MAX_PLATFORM_WINDOWS)
52+
static HWND Create(HWND parent_window_handle, max::Containers::Rectangle<int, int> rectangle, std::string text, ButtonStyles styles) noexcept;
53+
#endif
54+
55+
};
56+
57+
} // namespace maxGUI
58+
59+
#endif // #ifndef MAXGUI_BUTTONIMPLEMENTATION_HPP

0 commit comments

Comments
 (0)