aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--demos/main/main.cpp2
-rw-r--r--include/cru/base/Guard.h18
-rw-r--r--include/cru/platform/gui/sdl/Window.h1
-rw-r--r--include/cru/ui/controls/Button.h1
-rw-r--r--include/cru/ui/controls/CheckBox.h1
-rw-r--r--include/cru/ui/controls/Control.h7
-rw-r--r--include/cru/ui/controls/IconButton.h1
-rw-r--r--include/cru/ui/controls/Window.h4
-rw-r--r--src/platform/gui/sdl/OpenGLRenderer.cpp6
-rw-r--r--src/platform/gui/sdl/Window.cpp48
-rw-r--r--src/ui/components/Menu.cpp3
-rw-r--r--src/ui/controls/Button.cpp2
-rw-r--r--src/ui/controls/CheckBox.cpp2
-rw-r--r--src/ui/controls/Control.cpp16
-rw-r--r--src/ui/controls/ControlHost.cpp5
-rw-r--r--src/ui/controls/IconButton.cpp2
-rw-r--r--src/ui/controls/TextHostControlService.cpp2
-rw-r--r--src/ui/controls/Window.cpp20
19 files changed, 102 insertions, 40 deletions
diff --git a/.gitignore b/.gitignore
index e15a05ec..fde642fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,6 @@
build
build-clang
build-dynamic
+build-asan
compile_commands.json
diff --git a/demos/main/main.cpp b/demos/main/main.cpp
index 71c084ec..cef3e44d 100644
--- a/demos/main/main.cpp
+++ b/demos/main/main.cpp
@@ -64,5 +64,7 @@ int main() {
window.GetNativeWindow()->SetVisibility(
cru::platform::gui::WindowVisibilityType::Show);
+ application->SetQuitOnAllWindowClosed(true);
+
return application->Run();
}
diff --git a/include/cru/base/Guard.h b/include/cru/base/Guard.h
index ae120f5a..6097b4d3 100644
--- a/include/cru/base/Guard.h
+++ b/include/cru/base/Guard.h
@@ -46,26 +46,21 @@ inline AutoFreePtr<T> MakeAutoFree(T* ptr) {
template <typename T, typename Destructor>
class AutoDestruct {
public:
- AutoDestruct() : value_(std::nullopt), auto_destruct_(false) {}
+ AutoDestruct() : value_(std::nullopt) {}
- explicit AutoDestruct(T value, bool auto_destruct = true)
- : value_(std::move(value)), auto_destruct_(auto_destruct) {}
+ explicit AutoDestruct(T value) : value_(std::move(value)) {}
CRU_DELETE_COPY(AutoDestruct)
AutoDestruct(AutoDestruct&& other) noexcept
- : value_(std::move(other.value_)), auto_destruct_(other.auto_destruct_) {
+ : value_(std::move(other.value_)) {
other.value_ = std::nullopt;
- other.auto_destruct_ = false;
}
AutoDestruct& operator=(AutoDestruct&& other) noexcept {
if (this != &other) {
DoDestruct();
- value_ = other.value_;
- auto_destruct_ = other.auto_destruct_;
- other.value_ = std::nullopt;
- other.auto_destruct_ = false;
+ value_.swap(other.value_);
}
return *this;
}
@@ -96,7 +91,6 @@ class AutoDestruct {
CheckValid();
auto value = std::move(*value_);
value_ = std::nullopt;
- auto_destruct_ = false;
return value;
}
@@ -109,13 +103,13 @@ class AutoDestruct {
private:
void DoDestruct() {
- if (auto_destruct_ && value_) {
+ if (value_) {
Destructor{}(*value_);
+ value_ = std::nullopt;
}
}
private:
std::optional<T> value_;
- bool auto_destruct_;
};
} // namespace cru
diff --git a/include/cru/platform/gui/sdl/Window.h b/include/cru/platform/gui/sdl/Window.h
index 48d7c70a..5b8b17a2 100644
--- a/include/cru/platform/gui/sdl/Window.h
+++ b/include/cru/platform/gui/sdl/Window.h
@@ -104,6 +104,7 @@ class SdlWindow : public SdlResource, public virtual INativeWindow {
private:
SdlUiApplication* application_;
SDL_Window* sdl_window_;
+ bool sdl_is_popup_;
SDL_WindowID sdl_window_id_;
Rect client_rect_;
SdlWindow* parent_;
diff --git a/include/cru/ui/controls/Button.h b/include/cru/ui/controls/Button.h
index 80d21d08..5ae3de49 100644
--- a/include/cru/ui/controls/Button.h
+++ b/include/cru/ui/controls/Button.h
@@ -14,7 +14,6 @@ class CRU_UI_API Button : public SingleChildControl<render::BorderRenderObject>,
public:
Button();
- ~Button() override;
public:
helper::ClickState GetClickState() override {
diff --git a/include/cru/ui/controls/CheckBox.h b/include/cru/ui/controls/CheckBox.h
index 2e4685d5..16fe0725 100644
--- a/include/cru/ui/controls/CheckBox.h
+++ b/include/cru/ui/controls/CheckBox.h
@@ -15,7 +15,6 @@ class CRU_UI_API CheckBox : public Control,
static constexpr auto kControlName = "CheckBox";
CheckBox();
- ~CheckBox() override;
render::RenderObject* GetRenderObject() override {
return &container_render_object_;
diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h
index 8cd7a375..aa1cef8a 100644
--- a/include/cru/ui/controls/Control.h
+++ b/include/cru/ui/controls/Control.h
@@ -12,6 +12,11 @@
namespace cru::ui::controls {
+struct ControlHostChangeEventArgs {
+ ControlHost* old_host;
+ ControlHost* new_host;
+};
+
/**
* \remarks If you want to write a new control. You should override following
* methods:
@@ -143,6 +148,8 @@ class CRU_UI_API Control : public Object,
CRU_DEFINE_ROUTED_EVENT(GainFocus, events::FocusChangeEventArgs)
CRU_DEFINE_ROUTED_EVENT(LoseFocus, events::FocusChangeEventArgs)
+ CRU_DEFINE_EVENT(ControlHostChange, const ControlHostChangeEventArgs&)
+
//*************** region: tree ***************
protected:
virtual void OnParentChanged(Control* old_parent, Control* new_parent);
diff --git a/include/cru/ui/controls/IconButton.h b/include/cru/ui/controls/IconButton.h
index b061bc87..5b0f899d 100644
--- a/include/cru/ui/controls/IconButton.h
+++ b/include/cru/ui/controls/IconButton.h
@@ -21,7 +21,6 @@ class CRU_UI_API IconButton : public Control,
public:
IconButton();
IconButton(std::string_view icon_svg_path_data_string, const Rect& view_port);
- ~IconButton() override;
render::RenderObject* GetRenderObject() override {
return &container_render_object_;
diff --git a/include/cru/ui/controls/Window.h b/include/cru/ui/controls/Window.h
index 131d68a8..355b03a9 100644
--- a/include/cru/ui/controls/Window.h
+++ b/include/cru/ui/controls/Window.h
@@ -24,8 +24,9 @@ class CRU_UI_API Window
Window();
- static Window* CreatePopup();
+ static Window* CreatePopup(Control* attached_control);
+ Control* GetAttachedControl();
void SetAttachedControl(Control* control);
platform::gui::INativeWindow* GetNativeWindow();
@@ -36,6 +37,7 @@ class CRU_UI_API Window
std::unique_ptr<ControlHost> control_host_;
Control* attached_control_;
+ EventHandlerRevokerGuard parent_window_guard_;
EventHandlerRevokerListGuard
gain_focus_on_create_and_destroy_when_lose_focus_event_guard_;
diff --git a/src/platform/gui/sdl/OpenGLRenderer.cpp b/src/platform/gui/sdl/OpenGLRenderer.cpp
index dbd59db2..ae5ff957 100644
--- a/src/platform/gui/sdl/OpenGLRenderer.cpp
+++ b/src/platform/gui/sdl/OpenGLRenderer.cpp
@@ -114,10 +114,6 @@ SdlOpenGLRenderer::SdlOpenGLRenderer(SdlWindow* window, int width, int height) {
}
SdlOpenGLRenderer::~SdlOpenGLRenderer() {
- glad_gl_context_.DeleteBuffers(1, &gl_vertex_buffer_);
- glad_gl_context_.DeleteBuffers(1, &gl_element_buffer_);
- glad_gl_context_.DeleteTextures(1, &gl_texture_);
-
if (cairo_) {
cairo_destroy(cairo_);
cairo_ = nullptr;
@@ -216,7 +212,7 @@ GLuint SdlOpenGLRenderer::CreateGLProgram() {
auto check_program = [this](std::string_view name, GLuint program) {
int success;
char infoLog[512];
- glad_gl_context_.GetProgramiv(program, GL_COMPILE_STATUS, &success);
+ glad_gl_context_.GetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glad_gl_context_.GetProgramInfoLog(program, 512, nullptr, infoLog);
CruLogError(kLogTag, "Failed to link OpenGL {} program: {}", name,
diff --git a/src/platform/gui/sdl/Window.cpp b/src/platform/gui/sdl/Window.cpp
index e5de9310..d301efa9 100644
--- a/src/platform/gui/sdl/Window.cpp
+++ b/src/platform/gui/sdl/Window.cpp
@@ -1,5 +1,5 @@
#include "cru/platform/gui/sdl/Window.h"
-#include "cru/base/Base.h"
+#include "cru/base/log/Logger.h"
#include "cru/platform/Base.h"
#include "cru/platform/GraphicsBase.h"
#include "cru/platform/graphics/NullPainter.h"
@@ -21,9 +21,16 @@
namespace cru::platform::gui::sdl {
+namespace {
+bool IsWayland() {
+ return SDL_GetCurrentVideoDriver() == std::string_view("wayland");
+}
+} // namespace
+
SdlWindow::SdlWindow(SdlUiApplication* application)
: application_(application),
sdl_window_(nullptr),
+ sdl_is_popup_(false),
sdl_window_id_(0),
client_rect_(100, 100, 400, 200),
parent_(nullptr) {
@@ -237,12 +244,22 @@ void SdlWindow::DoCreateWindow() {
flags |= SDL_WINDOW_OPENGL;
#endif
- if (style_.Has(WindowStyleFlags::NoCaptionAndBorder)) {
+ auto no_border = style_.Has(WindowStyleFlags::NoCaptionAndBorder);
+ if (no_border) {
flags |= SDL_WINDOW_BORDERLESS;
}
- sdl_window_ = SDL_CreateWindow(title_.c_str(), client_rect_.width,
- client_rect_.height, flags);
+ if (no_border && parent_ && parent_->sdl_window_) {
+ flags |= SDL_WINDOW_POPUP_MENU;
+ sdl_window_ = SDL_CreatePopupWindow(parent_->sdl_window_, client_rect_.left,
+ client_rect_.top, client_rect_.width,
+ client_rect_.height, flags);
+ sdl_is_popup_ = true;
+ } else {
+ sdl_window_ = SDL_CreateWindow(title_.c_str(), client_rect_.width,
+ client_rect_.height, flags);
+ sdl_is_popup_ = false;
+ }
if (!sdl_window_) {
throw SdlException("Failed to create window.");
@@ -255,10 +272,16 @@ void SdlWindow::DoCreateWindow() {
CreateEvent_.Raise(nullptr);
- CheckSdlReturn(
- SDL_SetWindowPosition(sdl_window_, client_rect_.left, client_rect_.top));
+ if (!IsWayland() || sdl_is_popup_) {
+ CheckSdlReturn(SDL_SetWindowPosition(sdl_window_, client_rect_.left,
+ client_rect_.top));
+ }
+
+ if (!IsWayland() || !sdl_is_popup_) {
+ CheckSdlReturn(SDL_SetWindowParent(
+ sdl_window_, parent_ == nullptr ? nullptr : parent_->sdl_window_));
+ }
- DoUpdateParent();
DoUpdateCursor();
#ifdef __unix
@@ -270,8 +293,15 @@ void SdlWindow::DoCreateWindow() {
void SdlWindow::DoUpdateClientRect() {
assert(sdl_window_);
- CheckSdlReturn(
- SDL_SetWindowPosition(sdl_window_, client_rect_.left, client_rect_.top));
+
+ if (!IsWayland() || sdl_is_popup_) {
+ CheckSdlReturn(SDL_SetWindowPosition(sdl_window_, client_rect_.left,
+ client_rect_.top));
+ } else {
+ CruLogWarn(kLogTag,
+ "Wayland doesn't support set position of non-popup window.");
+ }
+
CheckSdlReturn(
SDL_SetWindowSize(sdl_window_, client_rect_.width, client_rect_.height));
CheckSdlReturn(SDL_SyncWindow(sdl_window_));
diff --git a/src/ui/components/Menu.cpp b/src/ui/components/Menu.cpp
index c6be942a..ea1afc07 100644
--- a/src/ui/components/Menu.cpp
+++ b/src/ui/components/Menu.cpp
@@ -78,8 +78,7 @@ void Menu::AddTextItemAt(std::string text, Index index,
PopupMenu::PopupMenu(controls::Control* attached_control)
: attached_control_(attached_control) {
menu_.SetOnItemClick([this](Index) { popup_->GetNativeWindow()->Close(); });
- popup_.reset(controls::Window::CreatePopup());
- popup_->SetAttachedControl(attached_control);
+ popup_.reset(controls::Window::CreatePopup(attached_control));
popup_->InsertChildAt(menu_.GetRootControl(), 0);
}
diff --git a/src/ui/controls/Button.cpp b/src/ui/controls/Button.cpp
index 4d897f08..d38ad108 100644
--- a/src/ui/controls/Button.cpp
+++ b/src/ui/controls/Button.cpp
@@ -13,8 +13,6 @@ Button::Button()
GetStyleRuleSet()->SetParent(std::move(default_button_style));
}
-Button::~Button() = default;
-
void Button::ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) {
GetContainerRenderObject()->ApplyBorderStyle(style);
}
diff --git a/src/ui/controls/CheckBox.cpp b/src/ui/controls/CheckBox.cpp
index a6cac1a1..3090505e 100644
--- a/src/ui/controls/CheckBox.cpp
+++ b/src/ui/controls/CheckBox.cpp
@@ -17,8 +17,6 @@ CheckBox::CheckBox()
[this](const helper::ClickEventArgs&) { Toggle(); });
}
-CheckBox::~CheckBox() {}
-
void CheckBox::SetChecked(bool checked) {
checked_ = checked;
checked_change_event_.Raise(checked);
diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp
index 548c9726..57937da2 100644
--- a/src/ui/controls/Control.cpp
+++ b/src/ui/controls/Control.cpp
@@ -111,6 +111,14 @@ void Control::InsertChildAt(Control* control, Index index) {
OnChildInserted(control, index);
if (host_) {
+ control->TraverseDescendents(
+ [this](Control* control) {
+ control->ControlHostChangeEvent_.Raise({nullptr, host_});
+ },
+ true);
+ }
+
+ if (host_) {
host_->ScheduleRelayout();
}
}
@@ -132,6 +140,14 @@ void Control::RemoveChildAt(Index index) {
OnChildRemoved(control, index);
if (host_) {
+ control->TraverseDescendents(
+ [this](Control* control) {
+ control->ControlHostChangeEvent_.Raise({host_, nullptr});
+ },
+ true);
+ }
+
+ if (host_) {
host_->ScheduleRelayout();
}
}
diff --git a/src/ui/controls/ControlHost.cpp b/src/ui/controls/ControlHost.cpp
index 1dabb26f..bfd7e580 100644
--- a/src/ui/controls/ControlHost.cpp
+++ b/src/ui/controls/ControlHost.cpp
@@ -22,6 +22,11 @@ ControlHost::ControlHost(Control* root_control)
ControlHost::~ControlHost() {
root_control_->TraverseDescendents(
[this](Control* control) { control->host_ = nullptr; }, true);
+ root_control_->TraverseDescendents(
+ [this](Control* control) {
+ control->ControlHostChangeEvent_.Raise({this, nullptr});
+ },
+ true);
}
platform::gui::INativeWindow* ControlHost::GetNativeWindow() {
diff --git a/src/ui/controls/IconButton.cpp b/src/ui/controls/IconButton.cpp
index e20e422f..ee6c9cac 100644
--- a/src/ui/controls/IconButton.cpp
+++ b/src/ui/controls/IconButton.cpp
@@ -22,8 +22,6 @@ IconButton::IconButton(std::string_view icon_svg_path_data_string,
SetIconWithSvgPathDataString(icon_svg_path_data_string, view_port);
}
-IconButton::~IconButton() {}
-
void IconButton::SetIconFillColor(const Color& color) {
SetIconFillBrush(platform::gui::IUiApplication::GetInstance()
->GetGraphicsFactory()
diff --git a/src/ui/controls/TextHostControlService.cpp b/src/ui/controls/TextHostControlService.cpp
index 9c57140c..9142bd69 100644
--- a/src/ui/controls/TextHostControlService.cpp
+++ b/src/ui/controls/TextHostControlService.cpp
@@ -695,7 +695,7 @@ void TextHostControlService::OpenContextMenu(const Point& position,
ContextMenuItem items) {
CruLogDebug(kLogTag, "Open context menu.");
if (!context_menu_) {
- context_menu_.reset(new components::PopupMenu());
+ context_menu_.reset(new components::PopupMenu(control_));
}
auto menu = context_menu_->GetMenu();
menu->ClearItems();
diff --git a/src/ui/controls/Window.cpp b/src/ui/controls/Window.cpp
index 8f06013e..f4714efa 100644
--- a/src/ui/controls/Window.cpp
+++ b/src/ui/controls/Window.cpp
@@ -2,6 +2,7 @@
#include "cru/platform/gui/UiApplication.h"
#include "cru/platform/gui/Window.h"
#include "cru/ui/Base.h"
+#include "cru/ui/controls/Control.h"
#include "cru/ui/controls/ControlHost.h"
#include <cassert>
@@ -15,16 +16,33 @@ Window::Window()
GetContainerRenderObject()->SetDefaultVerticalAlignment(Alignment::Stretch);
}
-Window* Window::CreatePopup() {
+Window* Window::CreatePopup(Control* attached_control) {
auto window = new Window();
window->GetNativeWindow()->SetStyleFlag(
platform::gui::WindowStyleFlags::NoCaptionAndBorder);
+ window->SetAttachedControl(attached_control);
window->SetGainFocusOnCreateAndDestroyWhenLoseFocus(true);
return window;
}
+Control* Window::GetAttachedControl() { return attached_control_; }
+
void Window::SetAttachedControl(Control* control) {
attached_control_ = control;
+ if (control) {
+ if (auto control_host = control->GetControlHost()) {
+ control_host_->GetNativeWindow()->SetParent(
+ control_host->GetNativeWindow());
+ }
+ parent_window_guard_.Reset(control->ControlHostChangeEvent()->AddHandler(
+ [this](const ControlHostChangeEventArgs& args) {
+ control_host_->GetNativeWindow()->SetParent(
+ args.new_host ? args.new_host->GetNativeWindow() : nullptr);
+ }));
+ } else {
+ control_host_->GetNativeWindow()->SetParent(nullptr);
+ parent_window_guard_.Reset();
+ }
}
platform::gui::INativeWindow* Window::GetNativeWindow() {