aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/osx/gui/CMakeLists.txt1
-rw-r--r--src/osx/gui/Menu.mm148
-rw-r--r--src/osx/gui/MenuPrivate.h63
-rw-r--r--src/osx/gui/UiApplication.mm3
-rw-r--r--src/platform/gui/CMakeLists.txt1
-rw-r--r--src/platform/gui/Menu.cpp11
-rw-r--r--src/platform/gui/UiApplication.cpp4
7 files changed, 230 insertions, 1 deletions
diff --git a/src/osx/gui/CMakeLists.txt b/src/osx/gui/CMakeLists.txt
index 27efbe0e..5446c9df 100644
--- a/src/osx/gui/CMakeLists.txt
+++ b/src/osx/gui/CMakeLists.txt
@@ -3,6 +3,7 @@ add_library(cru_osx_gui SHARED
Cursor.mm
InputMethod.mm
Keyboard.mm
+ Menu.mm
Resource.cpp
UiApplication.mm
Window.mm
diff --git a/src/osx/gui/Menu.mm b/src/osx/gui/Menu.mm
new file mode 100644
index 00000000..a980b7f6
--- /dev/null
+++ b/src/osx/gui/Menu.mm
@@ -0,0 +1,148 @@
+#import "MenuPrivate.h"
+
+#include "cru/common/platform/osx/Convert.hpp"
+
+#import <AppKit/NSApplication.h>
+
+namespace cru::platform::gui::osx {
+using platform::osx::Convert;
+
+namespace {
+std::unique_ptr<OsxMenu> application_menu = nullptr;
+}
+
+namespace details {
+OsxMenuItemPrivate::OsxMenuItemPrivate(OsxMenuItem* d) {
+ d_ = d;
+ sub_menu_ = new OsxMenu(d->GetUiApplication());
+ handler_ = [[CruOsxMenuItemClickHandler alloc] init:this];
+}
+
+OsxMenuItemPrivate::~OsxMenuItemPrivate() { delete sub_menu_; }
+
+void OsxMenuItemPrivate::AttachToNative(NSMenuItem* native_menu_item, bool check_submenu) {
+ Expects(sub_menu_);
+
+ menu_item_ = native_menu_item;
+ [native_menu_item setTarget:handler_];
+ [native_menu_item setAction:@selector(handleClick)];
+ if (check_submenu && [native_menu_item hasSubmenu]) {
+ sub_menu_->p_->AttachToNative([native_menu_item submenu]);
+ }
+}
+
+OsxMenuPrivate::OsxMenuPrivate(OsxMenu* d) { d_ = d; }
+
+OsxMenuPrivate::~OsxMenuPrivate() {
+ for (auto item : items_) {
+ delete item;
+ }
+}
+
+void OsxMenuPrivate::AttachToNative(NSMenu* native_menu) {
+ menu_ = native_menu;
+
+ auto item_count = [native_menu numberOfItems];
+ for (int i = 0; i < item_count; i++) {
+ auto native_item = [native_menu itemAtIndex:i];
+ auto item = new OsxMenuItem(d_->GetUiApplication());
+ item->p_->SetParentMenu(d_);
+ item->p_->AttachToNative(native_item, true);
+ items_.push_back(item);
+ }
+}
+}
+
+OsxMenuItem::OsxMenuItem(IUiApplication* ui_application) : OsxGuiResource(ui_application) {
+ p_ = new details::OsxMenuItemPrivate(this);
+}
+
+OsxMenuItem::~OsxMenuItem() { delete p_; }
+
+String OsxMenuItem::GetTitle() { return Convert((CFStringRef)[p_->menu_item_ title]); }
+
+void OsxMenuItem::SetTitle(String title) { [p_->menu_item_ setTitle:(NSString*)Convert(title)]; }
+
+bool OsxMenuItem::IsEnabled() { return [p_->menu_item_ isEnabled]; }
+
+void OsxMenuItem::SetEnabled(bool enabled) { [p_->menu_item_ setEnabled:enabled]; }
+
+IMenu* OsxMenuItem::GetParentMenu() { return p_->parent_menu_; }
+
+IMenu* OsxMenuItem::GetSubmenu() { return p_->sub_menu_; }
+
+void OsxMenuItem::SetOnClickHandler(std::function<void()> handler) {
+ p_->on_click_handler_ = std::move(handler);
+}
+
+OsxMenu* OsxMenu::CreateOrGetApplicationMenu(IUiApplication* ui_application) {
+ if (application_menu) {
+ return application_menu.get();
+ }
+
+ application_menu.reset(new OsxMenu(ui_application));
+ application_menu->p_->AttachToNative([NSApp mainMenu]);
+
+ return application_menu.get();
+}
+
+OsxMenu::OsxMenu(IUiApplication* ui_application) : OsxGuiResource(ui_application) {
+ p_ = new details::OsxMenuPrivate(this);
+}
+
+OsxMenu::~OsxMenu() { delete p_; }
+
+IMenuItem* OsxMenu::GetItemAt(int index) {
+ if (index < 0 || index >= p_->items_.size()) {
+ return nullptr;
+ }
+
+ return p_->items_[index];
+}
+
+int OsxMenu::GetItemCount() { return p_->items_.size(); }
+
+IMenuItem* OsxMenu::CreateItemAt(int index) {
+ if (index < 0) index = 0;
+ if (index > p_->items_.size()) index = p_->items_.size();
+
+ auto native_item = [[NSMenuItem alloc] init];
+ [p_->menu_ insertItem:native_item atIndex:index];
+
+ auto item = new OsxMenuItem(GetUiApplication());
+ item->p_->SetParentMenu(this);
+ item->p_->AttachToNative(native_item, false);
+ p_->items_.insert(p_->items_.begin() + index, item);
+
+ return item;
+}
+
+void OsxMenu::RemoveItemAt(int index) {
+ if (index < 0 || index >= p_->items_.size()) {
+ return;
+ }
+
+ auto item = p_->items_[index];
+ [p_->menu_ removeItem:item->p_->GetNative()];
+ p_->items_.erase(p_->items_.begin() + index);
+
+ delete item;
+}
+}
+
+@implementation CruOsxMenuItemClickHandler {
+ cru::platform::gui::osx::details::OsxMenuItemPrivate* p_;
+}
+
+- (id)init:(cru::platform::gui::osx::details::OsxMenuItemPrivate*)p {
+ p_ = p;
+ return self;
+}
+
+- (void)handleClick:(id)sender {
+ if (p_->GetOnClickHandler()) {
+ p_->GetOnClickHandler()();
+ }
+}
+
+@end
diff --git a/src/osx/gui/MenuPrivate.h b/src/osx/gui/MenuPrivate.h
new file mode 100644
index 00000000..433f246d
--- /dev/null
+++ b/src/osx/gui/MenuPrivate.h
@@ -0,0 +1,63 @@
+#pragma once
+#include "cru/osx/gui/Menu.hpp"
+
+#import <AppKit/NSMenu.h>
+#import <AppKit/NSMenuItem.h>
+
+@interface CruOsxMenuItemClickHandler : NSObject
+- init:(cru::platform::gui::osx::details::OsxMenuItemPrivate*)p;
+- (void)handleClick:(id)sender;
+@end
+
+namespace cru::platform::gui::osx {
+namespace details {
+
+class OsxMenuItemPrivate {
+ friend OsxMenuItem;
+
+ public:
+ explicit OsxMenuItemPrivate(OsxMenuItem* d);
+
+ CRU_DELETE_COPY(OsxMenuItemPrivate)
+ CRU_DELETE_MOVE(OsxMenuItemPrivate)
+
+ ~OsxMenuItemPrivate();
+
+ public:
+ NSMenuItem* GetNative() { return menu_item_; }
+ void SetParentMenu(OsxMenu* menu) { parent_menu_ = menu; }
+ void AttachToNative(NSMenuItem* native_menu_item, bool check_submenu);
+
+ const std::function<void()> GetOnClickHandler() const { return on_click_handler_; }
+
+ private:
+ OsxMenuItem* d_;
+ OsxMenu* parent_menu_ = nullptr;
+ NSMenuItem* menu_item_ = nullptr;
+ OsxMenu* sub_menu_ = nullptr;
+ std::function<void()> on_click_handler_;
+ CruOsxMenuItemClickHandler* handler_;
+};
+
+class OsxMenuPrivate {
+ friend OsxMenu;
+
+ public:
+ explicit OsxMenuPrivate(OsxMenu* d);
+
+ CRU_DELETE_COPY(OsxMenuPrivate)
+ CRU_DELETE_MOVE(OsxMenuPrivate)
+
+ ~OsxMenuPrivate();
+
+ public:
+ void AttachToNative(NSMenu* native_menu);
+
+ private:
+ OsxMenu* d_;
+ NSMenu* menu_ = nullptr;
+ std::vector<OsxMenuItem*> items_;
+};
+} // namespace details
+
+} // namespace cru::platform::gui::osx
diff --git a/src/osx/gui/UiApplication.mm b/src/osx/gui/UiApplication.mm
index 7ec2a049..b923742e 100644
--- a/src/osx/gui/UiApplication.mm
+++ b/src/osx/gui/UiApplication.mm
@@ -5,6 +5,7 @@
#include "cru/osx/graphics/quartz/Factory.hpp"
#include "cru/osx/gui/Clipboard.hpp"
#include "cru/osx/gui/Cursor.hpp"
+#include "cru/osx/gui/Menu.hpp"
#include "cru/osx/gui/Window.hpp"
#include "cru/platform/graphics/Factory.hpp"
#include "cru/platform/gui/Base.hpp"
@@ -172,6 +173,8 @@ ICursorManager* OsxUiApplication::GetCursorManager() { return p_->cursor_manager
IClipboard* OsxUiApplication::GetClipboard() { return p_->clipboard_.get(); }
+IMenu* OsxUiApplication::GetApplicationMenu() { return OsxMenu::CreateOrGetApplicationMenu(this); }
+
graphics::IGraphicsFactory* OsxUiApplication::GetGraphicsFactory() {
return p_->quartz_graphics_factory_.get();
}
diff --git a/src/platform/gui/CMakeLists.txt b/src/platform/gui/CMakeLists.txt
index 81be85d9..bd899ecd 100644
--- a/src/platform/gui/CMakeLists.txt
+++ b/src/platform/gui/CMakeLists.txt
@@ -1,5 +1,6 @@
add_library(cru_platform_gui SHARED
Keyboard.cpp
+ Menu.cpp
UiApplication.cpp
)
target_link_libraries(cru_platform_gui PUBLIC cru_platform_graphics)
diff --git a/src/platform/gui/Menu.cpp b/src/platform/gui/Menu.cpp
new file mode 100644
index 00000000..7b02a8a4
--- /dev/null
+++ b/src/platform/gui/Menu.cpp
@@ -0,0 +1,11 @@
+#include "cru/platform/gui/Menu.hpp"
+
+namespace cru::platform::gui {
+std::vector<IMenuItem*> IMenu::GetItems() {
+ std::vector<IMenuItem*> items;
+ for (int i = 0; i < GetItemCount(); ++i) {
+ items.push_back(GetItemAt(i));
+ }
+ return items;
+}
+} // namespace cru::platform::gui
diff --git a/src/platform/gui/UiApplication.cpp b/src/platform/gui/UiApplication.cpp
index f095361e..1f77653f 100644
--- a/src/platform/gui/UiApplication.cpp
+++ b/src/platform/gui/UiApplication.cpp
@@ -7,9 +7,11 @@ IUiApplication::IUiApplication() {
if (instance) {
throw std::runtime_error("An ui application has already been created.");
}
-
+
instance = this;
}
IUiApplication::~IUiApplication() { instance = nullptr; }
+
+IMenu* IUiApplication::GetApplicationMenu() { return nullptr; }
} // namespace cru::platform::gui