From 0c87bdabedb533a44972e505015989c91969ccc7 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 30 Aug 2015 12:08:26 +1000 Subject: [PATCH] Update to v094r43 release. byuu says: Updated to compile with all of the new hiro changes. My next step is to write up hiro API documentation, and move the API from alpha (constantly changing) to beta (rarely changing), in preparation for the first stable release (backward-compatible changes only.) Added "--fullscreen" command-line option. I like this over a configuration file option. Lets you use the emulator in both modes without having to modify the config file each time. Also enhanced the command-line game loading. You can now use any of these methods: higan /path/to/game-folder.sfc higan /path/to/game-folder.sfc/ higan /path/to/game-folder.sfc/program.rom The idea is to support launchers that insist on loading files only. Technically, the file can be any name (manifest.bml also works); the only criteria is that the file actually exists and is a file, and not a directory. This is a requirement to support the first version (a directory lacking the trailing / identifier), because I don't want my nall::string class to query the file system to determine if the string is an actual existing file or directory for its pathname() / dirname() functions. Anyway, every game folder I've made so far has program.rom, and that's very unlikely to change, so this should be fine. Now, of course, if you drop a regular "game.sfc" file on the emulator, it won't even try to load it, unless it's in a folder that ends in .fc, .sfc, etc. In which case, it'll bail out immediately by being unable to produce a manifest for what is obviously not really a game folder. --- emulator/emulator.hpp | 2 +- hiro/components.hpp | 12 +- hiro/core/action/menu-item.cpp | 10 +- hiro/core/action/menu-radio-item.cpp | 3 +- hiro/core/action/menu.cpp | 17 +- hiro/core/alignment.cpp | 4 + hiro/core/application.cpp | 4 +- hiro/core/color.cpp | 12 +- hiro/core/core.cpp | 6 +- hiro/core/core.hpp | 451 ++++++++++++-------- hiro/core/cursor.cpp | 43 ++ hiro/core/font.cpp | 41 +- hiro/core/geometry.cpp | 8 + hiro/core/gradient.cpp | 37 ++ hiro/core/hotkey.cpp | 65 +-- hiro/core/image.cpp | 83 ++++ hiro/core/keyboard.cpp | 35 +- hiro/core/menu-bar.cpp | 7 + hiro/core/object.cpp | 4 +- hiro/core/popup-menu.cpp | 2 +- hiro/core/position.cpp | 8 + hiro/core/shared.hpp | 104 ++--- hiro/core/size.cpp | 8 + hiro/core/widget/button.cpp | 10 +- hiro/core/widget/canvas.cpp | 47 +- hiro/core/widget/check-button.cpp | 10 +- hiro/core/widget/combo-button-item.cpp | 10 +- hiro/core/widget/frame.cpp | 7 + hiro/core/widget/icon-view-item.cpp | 10 +- hiro/core/widget/icon-view.cpp | 49 ++- hiro/core/widget/list-view-cell.cpp | 12 +- hiro/core/widget/list-view-column.cpp | 10 +- hiro/core/widget/list-view.cpp | 2 +- hiro/core/widget/radio-button.cpp | 13 +- hiro/core/widget/radio-label.cpp | 3 +- hiro/core/widget/source-edit.cpp | 23 +- hiro/core/widget/tab-frame-item.cpp | 10 +- hiro/core/widget/tab-frame.cpp | 17 +- hiro/core/widget/text-edit.cpp | 10 +- hiro/core/widget/tree-view-item.cpp | 69 ++- hiro/core/widget/tree-view.cpp | 31 +- hiro/extension/browser-dialog.cpp | 12 +- hiro/extension/fixed-layout.cpp | 10 +- hiro/extension/fixed-layout.hpp | 3 +- hiro/extension/horizontal-layout.cpp | 12 +- hiro/extension/horizontal-layout.hpp | 3 +- hiro/extension/message-dialog.cpp | 12 +- hiro/extension/message-dialog.hpp | 2 +- hiro/extension/shared.hpp | 3 + hiro/extension/vertical-layout.cpp | 12 +- hiro/extension/vertical-layout.hpp | 3 +- hiro/gtk/action/action.cpp | 2 +- hiro/gtk/action/action.hpp | 2 +- hiro/gtk/action/menu-item.cpp | 7 +- hiro/gtk/action/menu-item.hpp | 2 +- hiro/gtk/action/menu-radio-item.cpp | 12 +- hiro/gtk/action/menu.cpp | 9 +- hiro/gtk/action/menu.hpp | 4 +- hiro/gtk/font.cpp | 81 ++-- hiro/gtk/font.hpp | 13 +- hiro/gtk/hotkey.cpp | 13 - hiro/gtk/hotkey.hpp | 11 - hiro/gtk/layout.cpp | 2 +- hiro/gtk/layout.hpp | 2 +- hiro/gtk/menu-bar.cpp | 2 +- hiro/gtk/menu-bar.hpp | 2 +- hiro/gtk/object.cpp | 2 +- hiro/gtk/object.hpp | 2 +- hiro/gtk/platform.cpp | 1 - hiro/gtk/platform.hpp | 1 - hiro/gtk/popup-menu.cpp | 2 +- hiro/gtk/popup-menu.hpp | 2 +- hiro/gtk/status-bar.cpp | 2 +- hiro/gtk/status-bar.hpp | 2 +- hiro/gtk/utility.cpp | 35 ++ hiro/gtk/widget/button.cpp | 16 +- hiro/gtk/widget/button.hpp | 2 +- hiro/gtk/widget/canvas.cpp | 56 +-- hiro/gtk/widget/canvas.hpp | 8 +- hiro/gtk/widget/check-button.cpp | 16 +- hiro/gtk/widget/check-button.hpp | 2 +- hiro/gtk/widget/combo-button-item.cpp | 5 +- hiro/gtk/widget/combo-button-item.hpp | 2 +- hiro/gtk/widget/combo-button.cpp | 8 +- hiro/gtk/widget/combo-button.hpp | 2 +- hiro/gtk/widget/frame.cpp | 2 +- hiro/gtk/widget/frame.hpp | 2 +- hiro/gtk/widget/icon-view-item.cpp | 4 +- hiro/gtk/widget/icon-view-item.hpp | 2 +- hiro/gtk/widget/icon-view.cpp | 22 +- hiro/gtk/widget/icon-view.hpp | 4 +- hiro/gtk/widget/list-view-cell.cpp | 4 +- hiro/gtk/widget/list-view-cell.hpp | 2 +- hiro/gtk/widget/list-view-column.cpp | 8 +- hiro/gtk/widget/list-view-column.hpp | 4 +- hiro/gtk/widget/list-view.cpp | 14 +- hiro/gtk/widget/list-view.hpp | 2 +- hiro/gtk/widget/radio-button.cpp | 27 +- hiro/gtk/widget/radio-button.hpp | 2 +- hiro/gtk/widget/radio-label.cpp | 14 +- hiro/gtk/widget/source-edit.cpp | 24 +- hiro/gtk/widget/source-edit.hpp | 3 +- hiro/gtk/widget/tab-frame-item.cpp | 4 +- hiro/gtk/widget/tab-frame-item.hpp | 2 +- hiro/gtk/widget/tab-frame.cpp | 41 +- hiro/gtk/widget/tab-frame.hpp | 6 +- hiro/gtk/widget/text-edit.cpp | 28 +- hiro/gtk/widget/text-edit.hpp | 3 +- hiro/gtk/widget/tree-view-item.cpp | 49 ++- hiro/gtk/widget/tree-view-item.hpp | 6 +- hiro/gtk/widget/tree-view.cpp | 67 +-- hiro/gtk/widget/tree-view.hpp | 5 +- hiro/gtk/widget/widget.cpp | 2 +- hiro/gtk/widget/widget.hpp | 2 +- hiro/gtk/window.cpp | 4 +- hiro/gtk/window.hpp | 4 +- hiro/qt/action/action.cpp | 2 +- hiro/qt/action/action.hpp | 2 +- hiro/qt/action/menu-item.cpp | 4 +- hiro/qt/action/menu-item.hpp | 2 +- hiro/qt/action/menu-radio-item.cpp | 19 +- hiro/qt/action/menu.cpp | 4 +- hiro/qt/action/menu.hpp | 2 +- hiro/qt/font.cpp | 65 +-- hiro/qt/font.hpp | 9 +- hiro/qt/hotkey.cpp | 13 - hiro/qt/hotkey.hpp | 11 - hiro/qt/menu-bar.cpp | 2 +- hiro/qt/menu-bar.hpp | 2 +- hiro/qt/object.cpp | 2 +- hiro/qt/object.hpp | 2 +- hiro/qt/platform.cpp | 1 - hiro/qt/platform.hpp | 1 - hiro/qt/popup-menu.cpp | 2 +- hiro/qt/popup-menu.hpp | 2 +- hiro/qt/status-bar.cpp | 2 +- hiro/qt/status-bar.hpp | 2 +- hiro/qt/utility.cpp | 6 + hiro/qt/widget/button.cpp | 18 +- hiro/qt/widget/button.hpp | 2 +- hiro/qt/widget/canvas.cpp | 54 +-- hiro/qt/widget/canvas.hpp | 8 +- hiro/qt/widget/check-button.cpp | 14 +- hiro/qt/widget/check-button.hpp | 2 +- hiro/qt/widget/combo-button-item.cpp | 4 +- hiro/qt/widget/combo-button-item.hpp | 2 +- hiro/qt/widget/list-view-cell.cpp | 4 +- hiro/qt/widget/list-view-cell.hpp | 2 +- hiro/qt/widget/list-view-column.cpp | 4 +- hiro/qt/widget/list-view-column.hpp | 4 +- hiro/qt/widget/list-view-item.cpp | 2 +- hiro/qt/widget/list-view-item.hpp | 2 +- hiro/qt/widget/list-view.cpp | 12 +- hiro/qt/widget/radio-button.cpp | 31 +- hiro/qt/widget/radio-button.hpp | 2 +- hiro/qt/widget/radio-label.cpp | 17 +- hiro/qt/widget/tab-frame-item.cpp | 4 +- hiro/qt/widget/tab-frame-item.hpp | 2 +- hiro/qt/widget/tab-frame.cpp | 14 +- hiro/qt/widget/tab-frame.hpp | 2 +- hiro/qt/widget/text-edit.cpp | 7 +- hiro/qt/widget/text-edit.hpp | 2 +- hiro/qt/widget/widget.cpp | 2 +- hiro/qt/widget/widget.hpp | 2 +- hiro/windows/action/menu-item.cpp | 8 +- hiro/windows/action/menu-item.hpp | 2 +- hiro/windows/action/menu-radio-item.cpp | 17 +- hiro/windows/action/menu.cpp | 8 +- hiro/windows/action/menu.hpp | 2 +- hiro/windows/font.cpp | 72 +--- hiro/windows/font.hpp | 11 +- hiro/windows/header.hpp | 24 ++ hiro/windows/hotkey.cpp | 13 - hiro/windows/hotkey.hpp | 11 - hiro/windows/layout.cpp | 2 +- hiro/windows/layout.hpp | 2 +- hiro/windows/menu-bar.cpp | 2 +- hiro/windows/menu-bar.hpp | 2 +- hiro/windows/object.cpp | 2 +- hiro/windows/object.hpp | 2 +- hiro/windows/platform.cpp | 1 - hiro/windows/platform.hpp | 1 - hiro/windows/popup-menu.cpp | 2 +- hiro/windows/popup-menu.hpp | 2 +- hiro/windows/status-bar.cpp | 2 +- hiro/windows/status-bar.hpp | 2 +- hiro/windows/utility.cpp | 53 ++- hiro/windows/widget/button.cpp | 170 ++++++-- hiro/windows/widget/button.hpp | 8 +- hiro/windows/widget/canvas.cpp | 71 ++- hiro/windows/widget/canvas.hpp | 8 +- hiro/windows/widget/check-button.cpp | 84 ++-- hiro/windows/widget/check-button.hpp | 8 +- hiro/windows/widget/check-label.cpp | 2 +- hiro/windows/widget/combo-button-item.cpp | 2 +- hiro/windows/widget/combo-button-item.hpp | 2 +- hiro/windows/widget/line-edit.cpp | 2 +- hiro/windows/widget/list-view-cell.cpp | 2 +- hiro/windows/widget/list-view-cell.hpp | 2 +- hiro/windows/widget/list-view-column.cpp | 4 +- hiro/windows/widget/list-view-column.hpp | 2 +- hiro/windows/widget/list-view.cpp | 29 +- hiro/windows/widget/list-view.hpp | 2 +- hiro/windows/widget/radio-button.cpp | 107 +++-- hiro/windows/widget/radio-button.hpp | 8 +- hiro/windows/widget/radio-label.cpp | 24 +- hiro/windows/widget/radio-label.hpp | 2 +- hiro/windows/widget/tab-frame-item.cpp | 2 +- hiro/windows/widget/tab-frame-item.hpp | 2 +- hiro/windows/widget/tab-frame.cpp | 21 +- hiro/windows/widget/tab-frame.hpp | 2 +- hiro/windows/widget/text-edit.cpp | 10 +- hiro/windows/widget/text-edit.hpp | 2 +- hiro/windows/widget/widget.cpp | 6 +- hiro/windows/widget/widget.hpp | 2 +- hiro/windows/window.cpp | 2 +- hiro/windows/window.hpp | 2 +- nall/image/base.hpp | 1 + nall/image/utility.hpp | 24 ++ target-tomoko/presentation/presentation.cpp | 2 +- target-tomoko/program/program.cpp | 11 +- target-tomoko/settings/advanced.cpp | 6 +- target-tomoko/settings/audio.cpp | 2 +- target-tomoko/settings/hotkeys.cpp | 2 +- target-tomoko/settings/input.cpp | 2 +- target-tomoko/settings/settings.cpp | 2 +- target-tomoko/settings/timing.cpp | 2 +- target-tomoko/settings/video.cpp | 6 +- target-tomoko/tools/cheat-editor.cpp | 2 +- target-tomoko/tools/state-manager.cpp | 2 +- 230 files changed, 1939 insertions(+), 1408 deletions(-) create mode 100644 hiro/core/cursor.cpp create mode 100644 hiro/core/gradient.cpp create mode 100644 hiro/core/image.cpp delete mode 100644 hiro/gtk/hotkey.cpp delete mode 100644 hiro/gtk/hotkey.hpp delete mode 100644 hiro/qt/hotkey.cpp delete mode 100644 hiro/qt/hotkey.hpp delete mode 100644 hiro/windows/hotkey.cpp delete mode 100644 hiro/windows/hotkey.hpp diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index ad1e105b..7e8466ee 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -8,7 +8,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "094.42"; + static const string Version = "094.43"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/hiro/components.hpp b/hiro/components.hpp index be188659..87131829 100644 --- a/hiro/components.hpp +++ b/hiro/components.hpp @@ -9,15 +9,17 @@ * As such, this file is really only meant for disabling individual widgets or menu items. */ -#define Hiro_Application - #define Hiro_Color +#define Hiro_Gradient #define Hiro_Alignment +#define Hiro_Cursor #define Hiro_Position #define Hiro_Size #define Hiro_Geometry - #define Hiro_Font +#define Hiro_Image + +#define Hiro_Application #define Hiro_Desktop #define Hiro_Monitor #define Hiro_Keyboard @@ -63,7 +65,7 @@ #define Hiro_ProgressBar #define Hiro_RadioButton #define Hiro_RadioLabel -#define Hiro_SourceView +#define Hiro_SourceEdit #define Hiro_TabFrame #define Hiro_TextEdit #define Hiro_TreeView @@ -86,6 +88,6 @@ #if defined(HIRO_WINDOWS) || defined(HIRO_QT) #undef Hiro_Console #undef Hiro_IconView - #undef Hiro_SourceView + #undef Hiro_SourceEdit #undef Hiro_TreeView #endif diff --git a/hiro/core/action/menu-item.cpp b/hiro/core/action/menu-item.cpp index 8f5ce5fe..3b09a8c4 100644 --- a/hiro/core/action/menu-item.cpp +++ b/hiro/core/action/menu-item.cpp @@ -10,8 +10,8 @@ auto mMenuItem::doActivate() const -> void { if(state.onActivate) return state.onActivate(); } -auto mMenuItem::icon() const -> image { - return state.icon; +auto mMenuItem::image() const -> Image { + return state.image; } auto mMenuItem::onActivate(const function& callback) -> type& { @@ -19,9 +19,9 @@ auto mMenuItem::onActivate(const function& callback) -> type& { return *this; } -auto mMenuItem::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mMenuItem::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/action/menu-radio-item.cpp b/hiro/core/action/menu-radio-item.cpp index 36d4eada..a8c74e50 100644 --- a/hiro/core/action/menu-radio-item.cpp +++ b/hiro/core/action/menu-radio-item.cpp @@ -39,9 +39,8 @@ auto mMenuRadioItem::setChecked() -> type& { } auto mMenuRadioItem::setGroup(sGroup group) -> type& { - state.group = group; + state.group = group ? group : Group{&instance}; signal(setGroup, group); - if(group && group->objectCount() == 1) setChecked(); return *this; } diff --git a/hiro/core/action/menu.cpp b/hiro/core/action/menu.cpp index 97f3f797..0549185a 100644 --- a/hiro/core/action/menu.cpp +++ b/hiro/core/action/menu.cpp @@ -33,8 +33,8 @@ auto mMenu::append(sAction action) -> type& { return *this; } -auto mMenu::icon() const -> image { - return state.icon; +auto mMenu::image() const -> Image { + return state.image; } auto mMenu::remove(sAction action) -> type& { @@ -51,9 +51,16 @@ auto mMenu::reset() -> type& { return *this; } -auto mMenu::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mMenu::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); + return *this; +} + +auto mMenu::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.actions)) state.actions[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& action : state.actions) action->setParent(this, action->offset()); return *this; } diff --git a/hiro/core/alignment.cpp b/hiro/core/alignment.cpp index c682d000..210a0aa6 100644 --- a/hiro/core/alignment.cpp +++ b/hiro/core/alignment.cpp @@ -17,6 +17,10 @@ auto Alignment::horizontal() const -> double { return state.horizontal; } +auto Alignment::reset() -> type& { + return setAlignment(-1.0, -1.0); +} + auto Alignment::setAlignment(double horizontal, double vertical) -> type& { state.horizontal = horizontal; state.vertical = vertical; diff --git a/hiro/core/application.cpp b/hiro/core/application.cpp index 1e8f84d1..949f5d3f 100644 --- a/hiro/core/application.cpp +++ b/hiro/core/application.cpp @@ -6,7 +6,7 @@ auto Application::doMain() -> void { if(state.onMain) return state.onMain(); } -auto Application::font() -> string { +auto Application::font() -> Font { return state.font; } @@ -35,7 +35,7 @@ auto Application::quit() -> void { return pApplication::quit(); } -auto Application::setFont(const string& font) -> void { +auto Application::setFont(const Font& font) -> void { state.font = font; } diff --git a/hiro/core/color.cpp b/hiro/core/color.cpp index 012545c9..63d8f005 100644 --- a/hiro/core/color.cpp +++ b/hiro/core/color.cpp @@ -9,7 +9,7 @@ Color::Color(signed red, signed green, signed blue, signed alpha) { } Color::operator bool() const { - return !empty(); + return state.red || state.green || state.blue || state.alpha; } auto Color::operator==(const Color& source) const -> bool { @@ -28,10 +28,6 @@ auto Color::blue() const -> uint8_t { return state.blue; } -auto Color::empty() const -> bool { - return state.red == 0 && state.green == 0 && state.blue == 0 && state.alpha == 0; -} - auto Color::green() const -> uint8_t { return state.green; } @@ -40,6 +36,10 @@ auto Color::red() const -> uint8_t { return state.red; } +auto Color::reset() -> type& { + return setColor(0, 0, 0, 0); +} + auto Color::setAlpha(signed alpha) -> type& { state.alpha = max(0, min(255, alpha)); return *this; @@ -73,7 +73,7 @@ auto Color::setRed(signed red) -> type& { } auto Color::value() const -> uint32_t { - return (state.alpha << 24) + (state.red << 16) + (state.green << 8) + (state.blue << 0); + return state.alpha << 24 | state.red << 16 | state.green << 8 | state.blue << 0; } #endif diff --git a/hiro/core/core.cpp b/hiro/core/core.cpp index d25f6c6a..c9bdb6b1 100644 --- a/hiro/core/core.cpp +++ b/hiro/core/core.cpp @@ -31,13 +31,17 @@ using namespace nall; (delegate ? self()->function(__VA_ARGS__) : decltype(self()->function(__VA_ARGS__))()) namespace hiro { - #include "application.cpp" #include "color.cpp" + #include "gradient.cpp" #include "alignment.cpp" + #include "cursor.cpp" #include "position.cpp" #include "size.cpp" #include "geometry.cpp" #include "font.cpp" + #include "image.cpp" + + #include "application.cpp" #include "desktop.cpp" #include "monitor.cpp" #include "keyboard.cpp" diff --git a/hiro/core/core.hpp b/hiro/core/core.hpp index ebee01fd..4f83ec6d 100644 --- a/hiro/core/core.hpp +++ b/hiro/core/core.hpp @@ -13,7 +13,6 @@ #include using nall::function; -using nall::image; using nall::lstring; using nall::maybe; using nall::shared_pointer; @@ -23,6 +22,9 @@ using nall::vector; namespace hiro { +struct Font; +struct Keyboard; + #define Declare(Name) \ struct Name; \ struct m##Name; \ @@ -30,11 +32,9 @@ namespace hiro { using s##Name = shared_pointer; \ using w##Name = shared_pointer_weak; \ -Declare(Keyboard) Declare(Object) Declare(Group) Declare(Timer) -Declare(Hotkey) Declare(Window) Declare(StatusBar) Declare(MenuBar) @@ -83,64 +83,8 @@ Declare(Viewport) #undef Declare -enum class Edge : unsigned { Top, Bottom, Left, Right }; - enum class Orientation : unsigned { Horizontal, Vertical }; -enum class Placement : unsigned { Top, Bottom, Left, Right }; - -#if defined(Hiro_Application) -struct Application { - Application() = delete; - - static auto doMain() -> void; - static auto font() -> string; - static auto name() -> string; - static auto onMain(const function& callback = {}) -> void; - static auto run() -> void; - static auto pendingEvents() -> bool; - static auto processEvents() -> void; - static auto quit() -> void; - static auto setFont(const string& font = "") -> void; - static auto setName(const string& name = "") -> void; - - struct Windows { - static auto doModalChange(bool modal) -> void; - static auto onModalChange(const function& callback = {}) -> void; - }; - - struct Cocoa { - static auto doAbout() -> void; - static auto doActivate() -> void; - static auto doPreferences() -> void; - static auto doQuit() -> void; - static auto onAbout(const function& callback = {}) -> void; - static auto onActivate(const function& callback = {}) -> void; - static auto onPreferences(const function& callback = {}) -> void; - static auto onQuit(const function& callback = {}) -> void; - }; - -//private: - struct State { - string font; - string name; - function onMain; - bool quit = false; - - struct Windows { - function onModalChange; - } windows; - - struct Cocoa { - function onAbout; - function onActivate; - function onPreferences; - function onQuit; - } cocoa; - }; - static State state; - static auto initialize() -> void; -}; -#endif +enum class Navigation : unsigned { Top, Bottom, Left, Right }; #if defined(Hiro_Color) struct Color { @@ -155,9 +99,9 @@ struct Color { auto alpha() const -> uint8_t; auto blue() const -> uint8_t; - auto empty() const -> bool; auto green() const -> uint8_t; auto red() const -> uint8_t; + auto reset() -> type&; auto setAlpha(signed alpha) -> type&; auto setBlue(signed blue) -> type&; auto setColor(Color color = {}) -> type&; @@ -168,10 +112,31 @@ struct Color { //private: struct State { - signed red; - signed green; - signed blue; - signed alpha; + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t alpha; + } state; +}; +#endif + +#if defined(Hiro_Gradient) +struct Gradient { + using type = Gradient; + + Gradient(); + + explicit operator bool() const; + auto operator==(const Gradient& source) const -> bool; + auto operator!=(const Gradient& source) const -> bool; + + auto setBilinear(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type&; + auto setHorizontal(Color left, Color right) -> type&; + auto setVertical(Color top, Color bottom) -> type&; + +//private: + struct State { + vector colors; } state; }; #endif @@ -188,6 +153,7 @@ struct Alignment { auto operator!=(const Alignment& source) const -> bool; auto horizontal() const -> double; + auto reset() -> type&; auto setAlignment(double horizontal = -1.0, double vertical = 0.5) -> type&; auto setHorizontal(double horizontal) -> type&; auto setVertical(double vertical) -> type&; @@ -195,8 +161,32 @@ struct Alignment { //private: struct State { - double horizontal; - double vertical; + float horizontal; + float vertical; + } state; +}; +#endif + +#if defined(Hiro_Cursor) +struct Cursor { + using type = Cursor; + + Cursor(signed offset = 0, signed length = 0); + + explicit operator bool() const; + auto operator==(const Cursor& source) const -> bool; + auto operator!=(const Cursor& source) const -> bool; + + auto length() const -> signed; + auto offset() const -> signed; + auto setCursor(signed offset = 0, signed length = 0) -> type&; + auto setLength(signed length = 0) -> type&; + auto setOffset(signed offset = 0) -> type&; + +//private: + struct State { + signed offset; + signed length; } state; }; #endif @@ -208,9 +198,11 @@ struct Position { Position(); Position(signed x, signed y); + explicit operator bool() const; auto operator==(const Position& source) const -> bool; auto operator!=(const Position& source) const -> bool; + auto reset() -> type&; auto setPosition(Position position = {}) -> type&; auto setPosition(signed x, signed y) -> type&; auto setX(signed x) -> type&; @@ -233,10 +225,12 @@ struct Size { Size(); Size(signed width, signed height); + explicit operator bool() const; auto operator==(const Size& source) const -> bool; auto operator!=(const Size& source) const -> bool; auto height() const -> signed; + auto reset() -> type&; auto setHeight(signed height) -> type&; auto setSize(Size source = {}) -> type&; auto setSize(signed width, signed height) -> type&; @@ -263,11 +257,13 @@ struct Geometry { Geometry(signed x, signed y, signed width, signed height); Geometry(const string& text); + explicit operator bool() const; auto operator==(const Geometry& source) const -> bool; auto operator!=(const Geometry& source) const -> bool; auto height() const -> signed; auto position() const -> Position; + auto reset() -> type&; auto setGeometry(Geometry geometry = {}) -> type&; auto setGeometry(Position position, Size size) -> type&; auto setGeometry(signed x, signed y, signed width, signed height) -> type&; @@ -299,8 +295,7 @@ struct Geometry { struct Font { using type = Font; - Font(); - Font(const string& family, unsigned size = 0); + Font(const string& family = "", unsigned size = 0); explicit operator bool() const; auto operator==(const Font& source) const -> bool; @@ -309,27 +304,143 @@ struct Font { auto bold() const -> bool; auto family() const -> string; auto italic() const -> bool; + auto reset() -> type&; auto setBold(bool bold = true) -> type&; auto setFamily(const string& family = "") -> type&; auto setItalic(bool italic = true) -> type&; auto setSize(unsigned size = 0) -> type&; auto size() const -> unsigned; + auto size(const string& text) const -> Size; - static auto serif(unsigned size = 0, const string& style = "") -> string; - static auto sans(unsigned size = 0, const string& style = "") -> string; - static auto monospace(unsigned size = 0, const string& style = "") -> string; - static auto size(const string& font, const string& text = " ") -> Size; + static const string Sans; + static const string Serif; + static const string Mono; //private: struct State { string family; - unsigned size = 0; - bool bold = false; - bool italic = false; + unsigned size; + bool bold; + bool italic; } state; }; #endif +#if defined(Hiro_Image) +struct Image { + using type = Image; + + Image(); + Image(const Image& source); + Image(const string& source); + Image(const vector& source); + Image(const uint32_t* data, Size size); + ~Image(); + + explicit operator bool() const; + auto operator=(const Image& source) -> type&; + + auto data() const -> uint32_t*; + auto height() const -> signed; + auto reset() -> type&; + auto setImage(const uint32_t* data, Size size) -> type&; + auto setSize(Size size = {}) -> type&; + auto size() const -> Size; + auto width() const -> signed; + +//private: + struct State { + uint32_t* data = nullptr; + Size size; + } state; +}; +#endif + +#if defined(Hiro_Hotkey) +struct Hotkey { + using type = Hotkey; + + Hotkey(); + Hotkey(const string& sequence); + + explicit operator bool() const; + auto operator==(const Hotkey& source) const -> bool; + auto operator!=(const Hotkey& source) const -> bool; + + auto doPress() const -> void; + auto doRelease() const -> void; + auto onPress(const function& callback = {}) -> type&; + auto onRelease(const function& callback = {}) -> type&; + auto reset() -> type&; + auto sequence() const -> string; + auto setSequence(const string& sequence = "") -> type&; + +//private: + struct State { + bool active = false; + vector keys; + function onPress; + function onRelease; + string sequence; + }; + shared_pointer state; +}; +#endif + +#if defined(Hiro_Application) +struct Application { + Application() = delete; + + static auto doMain() -> void; + static auto font() -> Font; + static auto name() -> string; + static auto onMain(const function& callback = {}) -> void; + static auto run() -> void; + static auto pendingEvents() -> bool; + static auto processEvents() -> void; + static auto quit() -> void; + static auto setFont(const Font& font = {}) -> void; + static auto setName(const string& name = "") -> void; + + struct Windows { + static auto doModalChange(bool modal) -> void; + static auto onModalChange(const function& callback = {}) -> void; + }; + + struct Cocoa { + static auto doAbout() -> void; + static auto doActivate() -> void; + static auto doPreferences() -> void; + static auto doQuit() -> void; + static auto onAbout(const function& callback = {}) -> void; + static auto onActivate(const function& callback = {}) -> void; + static auto onPreferences(const function& callback = {}) -> void; + static auto onQuit(const function& callback = {}) -> void; + }; + +//private: + struct State { + Font font; + string name; + function onMain; + bool quit = false; + + struct Windows { + function onModalChange; + } windows; + + struct Cocoa { + function onAbout; + function onActivate; + function onPreferences; + function onQuit; + } cocoa; + }; + static State state; + static auto initialize() -> void; +}; +#endif + #if defined(Hiro_Desktop) struct Desktop { Desktop() = delete; @@ -353,19 +464,20 @@ struct Monitor { struct Keyboard { Keyboard() = delete; - static auto append(sHotkey hotkey) -> void; + static auto append(Hotkey hotkey) -> void; static auto hotkey(unsigned position) -> Hotkey; - static auto hotkeys() -> unsigned; + static auto hotkeyCount() -> unsigned; + static auto hotkeys() -> vector; static auto poll() -> vector; static auto pressed(const string& key) -> bool; static auto released(const string& key) -> bool; - static auto remove(sHotkey hotkey) -> void; + static auto remove(Hotkey hotkey) -> void; static const vector keys; //private: struct State { - vector hotkeys; + vector hotkeys; }; static State state; }; @@ -439,6 +551,7 @@ struct MessageWindow { auto self() const -> const p##Name* { return (const p##Name*)delegate; } \ auto bind(const s##Name& instance) -> void { \ this->instance = instance; \ + setGroup(); \ if(!abstract()) construct(); \ } \ auto unbind() -> void { \ @@ -463,7 +576,7 @@ struct mObject { auto adjustOffset(signed displacement) -> type&; auto enabled(bool recursive = false) const -> bool; virtual auto focused() const -> bool; - auto font(bool recursive = false) const -> string; + auto font(bool recursive = false) const -> Font; virtual auto group() const -> Group; auto offset() const -> signed; auto parent() const -> mObject*; @@ -488,7 +601,7 @@ struct mObject { virtual auto reset() -> type&; virtual auto setEnabled(bool enabled = true) -> type&; virtual auto setFocused() -> type&; - virtual auto setFont(const string& font = "") -> type&; + virtual auto setFont(const Font& font = {}) -> type&; virtual auto setGroup(sGroup group = {}) -> type&; virtual auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; virtual auto setVisible(bool visible = true) -> type&; @@ -497,7 +610,7 @@ struct mObject { //private: struct State { bool enabled = true; - string font; + Font font; signed offset = -1; mObject* parent = nullptr; bool visible = true; @@ -529,32 +642,6 @@ struct mGroup : mObject { }; #endif -#if defined(Hiro_Hotkey) -struct mHotkey : mObject { - Declare(Hotkey) - - auto doPress() const -> void; - auto doRelease() const -> void; - auto onPress(const function& callback = {}) -> type&; - auto onRelease(const function& callback = {}) -> type&; - auto owner() const -> wObject; - auto remove() -> type& override; - auto sequence() const -> string; - auto setOwner(sObject owner) -> type&; - auto setSequence(const string& sequence = "") -> type&; - -//private: - struct State { - bool active = false; - vector keys; - function onPress; - function onRelease; - wObject owner; - string sequence; - } state; -}; -#endif - #if defined(Hiro_Timer) struct mTimer : mObject { Declare(Timer) @@ -672,7 +759,7 @@ struct mMenuBar : mObject { auto remove() -> type& override; auto remove(sMenu menu) -> type&; auto reset() -> type&; -//TODO setParent + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; //private: struct State { @@ -727,18 +814,18 @@ struct mMenu : mAction { auto actionCount() const -> unsigned; auto actions() const -> vector; auto append(sAction action) -> type&; - auto icon() const -> image; + auto image() const -> Image; auto remove(sAction action) -> type&; auto reset() -> type&; - auto setIcon(const image& icon = {}) -> type&; -//TODO setParent + auto setImage(const Image& image = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; auto setText(const string& text = "") -> type&; auto text() const -> string; //private: struct State { vector actions; - image icon; + Image image; string text; } state; @@ -761,15 +848,15 @@ struct mMenuItem : mAction { Declare(MenuItem) auto doActivate() const -> void; - auto icon() const -> image; + auto image() const -> Image; auto onActivate(const function& callback = {}) -> type&; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; //private: struct State { - image icon; + Image image; function onActivate; string text; } state; @@ -877,11 +964,11 @@ struct mButton : mWidget { auto bordered() const -> bool; auto doActivate() const -> void; - auto icon() const -> image; + auto image() const -> Image; auto onActivate(const function& callback = {}) -> type&; auto orientation() const -> Orientation; auto setBordered(bool bordered = true) -> type&; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; @@ -889,7 +976,7 @@ struct mButton : mWidget { //private: struct State { bool bordered = true; - image icon; + Image image; function onActivate; Orientation orientation = Orientation::Horizontal; string text; @@ -909,36 +996,32 @@ struct mCanvas : mWidget { auto doMouseMove(Position position) const -> void; auto doMousePress(Mouse::Button button) const -> void; auto doMouseRelease(Mouse::Button button) const -> void; - auto gradient() const -> vector; - auto icon() const -> image; + auto gradient() const -> Gradient; + auto image() const -> Image; auto onDrop(const function& callback = {}) -> type&; auto onMouseLeave(const function& callback = {}) -> type&; auto onMouseMove(const function& callback = {}) -> type&; auto onMousePress(const function& callback = {}) -> type&; auto onMouseRelease(const function& callback = {}) -> type&; - auto setColor(Color color) -> type&; - auto setData(Size size) -> type&; + auto setColor(Color color = {}) -> type&; auto setDroppable(bool droppable = true) -> type&; - auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type&; - auto setHorizontalGradient(Color left, Color right) -> type&; - auto setIcon(const image& icon = {}) -> type&; - auto setVerticalGradient(Color top, Color bottom) -> type&; + auto setGradient(Gradient gradient = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; + auto setSize(Size size = {}) -> type&; auto size() const -> Size; auto update() -> type&; //private: struct State { Color color; - vector data; bool droppable = false; - vector gradient = {{}, {}, {}, {}}; - image icon; + Gradient gradient; + Image image; function onDrop; function onMouseLeave; function onMouseMove; function onMousePress; function onMouseRelease; - Size size; } state; }; #endif @@ -950,12 +1033,12 @@ struct mCheckButton : mWidget { auto bordered() const -> bool; auto checked() const -> bool; auto doToggle() const -> void; - auto icon() const -> image; + auto image() const -> Image; auto onToggle(const function& callback = {}) -> type&; auto orientation() const -> Orientation; auto setBordered(bool bordered = true) -> type&; auto setChecked(bool checked = true) -> type&; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; @@ -964,7 +1047,7 @@ struct mCheckButton : mWidget { struct State { bool bordered = true; bool checked = false; - image icon; + Image image; function onToggle; Orientation orientation = Orientation::Horizontal; string text; @@ -1022,17 +1105,17 @@ struct mComboButton : mWidget { struct mComboButtonItem : mObject { Declare(ComboButtonItem) - auto icon() const -> image; + auto image() const -> Image; auto remove() -> type& override; auto selected() const -> bool; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setSelected() -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; //private: struct State { - image icon; + Image image; bool selected = false; string text; } state; @@ -1073,7 +1156,7 @@ struct mFrame : mWidget { auto layout() const -> Layout; auto remove(sLayout layout) -> type&; auto reset() -> type&; -//TODO setParent() + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; auto setText(const string& text = "") -> type&; auto text() const -> string; @@ -1170,6 +1253,8 @@ struct mIconView : mWidget { auto append(sIconViewItem item) -> type&; auto backgroundColor() const -> Color; + auto batchable() const -> bool; + auto batched() const -> vector; auto doActivate() const -> void; auto doChange() const -> void; auto doContext() const -> void; @@ -1178,30 +1263,28 @@ struct mIconView : mWidget { auto item(unsigned position) const -> IconViewItem; auto itemCount() const -> unsigned; auto items() const -> vector; - auto multiSelect() const -> bool; auto onActivate(const function& callback = {}) -> type&; auto onChange(const function& callback = {}) -> type&; auto onContext(const function& callback = {}) -> type&; auto orientation() const -> Orientation; auto remove(sIconViewItem item) -> type&; auto reset() -> type&; - auto selected() const -> maybe; - auto selectedItems() const -> vector; + auto selected() const -> IconViewItem; auto setBackgroundColor(Color color = {}) -> type&; + auto setBatchable(bool batchable = true) -> type&; auto setFlow(Orientation flow = Orientation::Vertical) -> type&; auto setForegroundColor(Color color = {}) -> type&; - auto setMultiSelect(bool multipleSelections = true) -> type&; auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; -//TODO setParent() + auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; auto setSelected(const vector& selections) -> type&; //private: struct State { Color backgroundColor; + bool batchable = false; Color foregroundColor; Orientation flow = Orientation::Vertical; vector items; - bool multiSelect = false; function onActivate; function onChange; function onContext; @@ -1216,17 +1299,17 @@ struct mIconView : mWidget { struct mIconViewItem : mObject { Declare(IconViewItem) - auto icon() const -> image; + auto image() const -> Image; auto remove() -> type& override; auto selected() const -> bool; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setSelected(bool selected = true) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; //private: struct State { - image icon; + Image image; bool selected = false; string text; } state; @@ -1318,7 +1401,6 @@ struct mListView : mWidget { auto setBatchable(bool batchable = true) -> type&; auto setBordered(bool bordered = true) -> type&; auto setForegroundColor(Color color = {}) -> type&; - auto setGridVisible(bool visible = true) -> type&; auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override; //private: @@ -1373,7 +1455,7 @@ struct mListViewColumn : mObject { auto expandable() const -> bool; auto foregroundColor() const -> Color; auto horizontalAlignment() const -> double; - auto icon() const -> image; + auto image() const -> Image; auto remove() -> type& override; auto resizable() const -> bool; auto setActive() -> type&; @@ -1383,7 +1465,7 @@ struct mListViewColumn : mObject { auto setExpandable(bool expandable = true) -> type&; auto setForegroundColor(Color color = {}) -> type&; auto setHorizontalAlignment(double alignment = 0.0) -> type&; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setResizable(bool resizable = true) -> type&; auto setSortable(bool sortable = true) -> type&; auto setText(const string& text = "") -> type&; @@ -1403,7 +1485,7 @@ struct mListViewColumn : mObject { bool expandable = false; Color foregroundColor; double horizontalAlignment = 0.0; - image icon; + Image image; bool resizable = true; bool sortable = false; string text; @@ -1454,15 +1536,15 @@ struct mListViewCell : mObject { auto backgroundColor(bool recursive = false) const -> Color; auto checkable() const -> bool; auto checked() const -> bool; - auto font(bool recursive = false) const -> string; + auto font(bool recursive = false) const -> Font; auto foregroundColor(bool recursive = false) const -> Color; - auto icon() const -> image; + auto image() const -> Image; auto setAlignment(Alignment alignment = {}) -> type&; auto setBackgroundColor(Color color = {}) -> type&; auto setCheckable(bool checkable = true) -> type&; auto setChecked(bool checked = true) -> type&; auto setForegroundColor(Color color = {}) -> type&; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; @@ -1473,7 +1555,7 @@ struct mListViewCell : mObject { bool checkable = false; bool checked = false; Color foregroundColor; - image icon; + Image image; string text; } state; }; @@ -1501,13 +1583,13 @@ struct mRadioButton : mWidget { auto checked() const -> bool; auto doActivate() const -> void; auto group() const -> Group override; - auto icon() const -> image; + auto image() const -> Image; auto onActivate(const function& callback = {}) -> type&; auto orientation() const -> Orientation; auto setBordered(bool bordered = true) -> type&; auto setChecked() -> type&; auto setGroup(sGroup group = {}) -> type& override; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; @@ -1517,7 +1599,7 @@ struct mRadioButton : mWidget { bool bordered = true; bool checked = false; sGroup group; - image icon; + Image image; function onActivate; Orientation orientation = Orientation::Horizontal; string text; @@ -1552,22 +1634,20 @@ struct mRadioLabel : mWidget { struct mSourceEdit : mWidget { Declare(SourceEdit) + auto cursor() const -> Cursor; auto doChange() const -> void; auto doMove() const -> void; auto onChange(const function& callback = {}) -> type&; auto onMove(const function& callback = {}) -> type&; - auto position() const -> unsigned; - auto setPosition(signed position) -> type&; - auto setSelected(Position selected) -> type&; + auto setCursor(Cursor cursor = {}) -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; //private: struct State { + Cursor cursor; function onChange; function onMove; - unsigned position = 0; - Position selected; string text; } state; }; @@ -1583,23 +1663,23 @@ struct mTabFrame : mWidget { auto doChange() const -> void; auto doClose(sTabFrameItem item) const -> void; auto doMove(sTabFrameItem from, sTabFrameItem to) const -> void; - auto edge() const -> Edge; auto item(unsigned position) const -> TabFrameItem; auto itemCount() const -> unsigned; auto items() const -> vector; + auto navigation() const -> Navigation; auto onChange(const function& callback = {}) -> type&; auto onClose(const function& callback = {}) -> type&; auto onMove(const function& callback = {}) -> type&; auto remove(sTabFrameItem item) -> type&; auto reset() -> type&; auto selected() const -> TabFrameItem; - auto setEdge(Edge edge = Edge::Top) -> type&; + auto setNavigation(Navigation navigation = Navigation::Top) -> type&; auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; //private: struct State { - Edge edge = Edge::Top; vector items; + Navigation navigation = Navigation::Top; function onChange; function onClose; function onMove; @@ -1615,7 +1695,7 @@ struct mTabFrameItem : mObject { auto append(sLayout layout) -> type&; auto closable() const -> bool; - auto icon() const -> image; + auto image() const -> Image; auto layout() const -> Layout; auto movable() const -> bool; auto remove() -> type& override; @@ -1623,7 +1703,7 @@ struct mTabFrameItem : mObject { auto reset() -> type&; auto selected() const -> bool; auto setClosable(bool closable = true) -> type&; - auto setIcon(const image& icon = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; auto setMovable(bool movable = true) -> type&; auto setParent(mObject* object = nullptr, signed offset = -1) -> type& override; auto setSelected() -> type&; @@ -1633,7 +1713,7 @@ struct mTabFrameItem : mObject { //private: struct State { bool closable = false; - image icon; + Image image; sLayout layout; bool movable = false; bool selected = false; @@ -1649,7 +1729,7 @@ struct mTextEdit : mWidget { Declare(TextEdit) auto backgroundColor() const -> Color; - auto cursorPosition() const -> unsigned; + auto cursor() const -> Cursor; auto doChange() const -> void; auto doMove() const -> void; auto editable() const -> bool; @@ -1657,7 +1737,7 @@ struct mTextEdit : mWidget { auto onChange(const function& callback = {}) -> type&; auto onMove(const function& callback = {}) -> type&; auto setBackgroundColor(Color color = {}) -> type&; - auto setCursorPosition(unsigned position) -> type&; + auto setCursor(Cursor cursor = {}) -> type&; auto setEditable(bool editable = true) -> type&; auto setForegroundColor(Color color = {}) -> type&; auto setText(const string& text = "") -> type&; @@ -1668,7 +1748,7 @@ struct mTextEdit : mWidget { //private: struct State { Color backgroundColor; - unsigned cursorPosition = 0; + Cursor cursor; bool editable = true; Color foregroundColor; function onChange; @@ -1686,13 +1766,10 @@ struct mTreeView : mWidget { auto append(sTreeViewItem item) -> type&; auto backgroundColor() const -> Color; - auto checkable() const -> bool; - auto collapse() -> type&; auto doActivate() const -> void; auto doChange() const -> void; auto doContext() const -> void; auto doToggle(sTreeViewItem item) const -> void; - auto expand() -> type&; auto foregroundColor() const -> Color; auto item(const string& path) const -> TreeViewItem; auto itemCount() const -> unsigned; @@ -1705,14 +1782,12 @@ struct mTreeView : mWidget { auto reset() -> type&; auto selected() const -> TreeViewItem; auto setBackgroundColor(Color color = {}) -> type&; - auto setCheckable(bool checkable = true) -> type&; auto setForegroundColor(Color color = {}) -> type&; -//TODO setParent + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; //private: struct State { Color backgroundColor; - bool checkable = false; Color foregroundColor; vector items; function onActivate; @@ -1731,8 +1806,11 @@ struct mTreeViewItem : mObject { Declare(TreeViewItem) auto append(sTreeViewItem item) -> type&; + auto backgroundColor(bool recursive = false) const -> Color; + auto checkable() const -> bool; auto checked() const -> bool; - auto icon() const -> image; + auto foregroundColor(bool recursive = false) const -> Color; + auto image() const -> Image; auto item(const string& path) const -> TreeViewItem; auto itemCount() const -> unsigned; auto items() const -> vector; @@ -1740,18 +1818,25 @@ struct mTreeViewItem : mObject { auto remove() -> type& override; auto remove(sTreeViewItem item) -> type&; auto selected() const -> bool; + auto setBackgroundColor(Color color = {}) -> type&; + auto setCheckable(bool checkable = true) -> type&; auto setChecked(bool checked = true) -> type&; + auto setExpanded(bool expanded = true) -> type&; auto setFocused() -> type& override; - auto setIcon(const image& icon = {}) -> type&; -//TODO setParent + auto setForegroundColor(Color color = {}) -> type&; + auto setImage(const Image& image = {}) -> type&; + auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; auto setSelected() -> type&; auto setText(const string& text = "") -> type&; auto text() const -> string; //private: struct State { + Color backgroundColor; + bool checkable = false; bool checked = false; - image icon; + Color foregroundColor; + Image image; vector items; string text; } state; diff --git a/hiro/core/cursor.cpp b/hiro/core/cursor.cpp new file mode 100644 index 00000000..4db6e46f --- /dev/null +++ b/hiro/core/cursor.cpp @@ -0,0 +1,43 @@ +#if defined(Hiro_Cursor) + +Cursor::Cursor(signed offset, signed length) { + setCursor(offset, length); +} + +Cursor::operator bool() const { + return offset() && length(); +} + +auto Cursor::operator==(const Cursor& source) const -> bool { + return offset() == source.offset() && length() == source.length(); +} + +auto Cursor::operator!=(const Cursor& source) const -> bool { + return !operator==(source); +} + +auto Cursor::length() const -> signed { + return state.length; +} + +auto Cursor::offset() const -> signed { + return state.offset; +} + +auto Cursor::setCursor(signed offset, signed length) -> type& { + state.offset = offset; + state.length = length; + return *this; +} + +auto Cursor::setOffset(signed offset) -> type& { + state.offset = offset; + return *this; +} + +auto Cursor::setLength(signed length) -> type& { + state.length = length; + return *this; +} + +#endif diff --git a/hiro/core/font.cpp b/hiro/core/font.cpp index ec32f614..d082c9c1 100644 --- a/hiro/core/font.cpp +++ b/hiro/core/font.cpp @@ -1,11 +1,14 @@ #if defined(Hiro_Font) -Font::Font() { -} +const string Font::Sans = "{sans}"; +const string Font::Serif = "{serif}"; +const string Font::Mono = "{mono}"; Font::Font(const string& family, unsigned size) { - state.family = family; - state.size = size; + setFamily(family); + setSize(size); + state.bold = false; + state.italic = false; } Font::operator bool() const { @@ -13,8 +16,8 @@ Font::operator bool() const { } auto Font::operator==(const Font& source) const -> bool { - return family() == source.family() || size() == source.size() && bold() == source.bold() && italic() == source.italic(); -}; + return family() == source.family() && size() == source.size() && bold() == source.bold() && italic() == source.italic(); +} auto Font::operator!=(const Font& source) const -> bool { return !operator==(source); @@ -32,6 +35,14 @@ auto Font::italic() const -> bool { return state.italic; } +auto Font::reset() -> type& { + state.family = ""; + state.size = 0; + state.bold = false; + state.italic = false; + return *this; +} + auto Font::setBold(bool bold) -> type& { state.bold = bold; return *this; @@ -56,22 +67,8 @@ auto Font::size() const -> unsigned { return state.size; } -// - -auto Font::serif(unsigned size, const string& style) -> string { - return pFont::serif(size, style); -} - -auto Font::sans(unsigned size, const string& style) -> string { - return pFont::sans(size, style); -} - -auto Font::monospace(unsigned size, const string& style) -> string { - return pFont::monospace(size, style); -} - -auto Font::size(const string& font, const string& text) -> Size { - return pFont::size(font, text); +auto Font::size(const string& text) const -> Size { + return pFont::size(*this, text); } #endif diff --git a/hiro/core/geometry.cpp b/hiro/core/geometry.cpp index 6a2d320d..4cd15443 100644 --- a/hiro/core/geometry.cpp +++ b/hiro/core/geometry.cpp @@ -20,6 +20,10 @@ Geometry::Geometry(const string& text) { state.height = integer(part(3)); } +Geometry::operator bool() const { + return state.x || state.y || state.width || state.height; +} + auto Geometry::operator==(const Geometry& source) const -> bool { return x() == source.x() && y() == source.y() && width() == source.width() && height() == source.height(); } @@ -36,6 +40,10 @@ auto Geometry::position() const -> Position { return {state.x, state.y}; } +auto Geometry::reset() -> type& { + return setGeometry(0, 0, 0, 0); +} + auto Geometry::setHeight(signed height) -> type& { state.height = height; return *this; diff --git a/hiro/core/gradient.cpp b/hiro/core/gradient.cpp new file mode 100644 index 00000000..946ad0f5 --- /dev/null +++ b/hiro/core/gradient.cpp @@ -0,0 +1,37 @@ +#if defined(Hiro_Gradient) + +Gradient::Gradient() { +} + +Gradient::operator bool() const { + return state.colors.size() == 4; +} + +auto Gradient::operator==(const Gradient& source) const -> bool { + if(state.colors.size() != source.state.colors.size()) return false; + for(auto n : range(state.colors)) { + if(state.colors[n] != source.state.colors[n]) return false; + } + return true; +} + +auto Gradient::operator!=(const Gradient& source) const -> bool { + return !operator==(source); +} + +auto Gradient::setBilinear(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type& { + state.colors = {topLeft, topRight, bottomLeft, bottomRight}; + return *this; +} + +auto Gradient::setHorizontal(Color left, Color right) -> type& { + state.colors = {left, right, left, right}; + return *this; +} + +auto Gradient::setVertical(Color top, Color bottom) -> type& { + state.colors = {top, top, bottom, bottom}; + return *this; +} + +#endif diff --git a/hiro/core/hotkey.cpp b/hiro/core/hotkey.cpp index 8a4d71cd..da5516e9 100644 --- a/hiro/core/hotkey.cpp +++ b/hiro/core/hotkey.cpp @@ -1,54 +1,59 @@ #if defined(Hiro_Hotkey) -auto mHotkey::allocate() -> pObject* { - return new pHotkey(*this); +Hotkey::Hotkey() : state(new Hotkey::State) { + setSequence(); } -// - -auto mHotkey::doPress() const -> void { - if(state.onPress) return state.onPress(); +Hotkey::Hotkey(const string& sequence) : state(new Hotkey::State) { + setSequence(sequence); } -auto mHotkey::doRelease() const -> void { - if(state.onRelease) return state.onRelease(); +Hotkey::operator bool() const { + return state->sequence; } -auto mHotkey::onPress(const function& callback) -> type& { - state.onPress = callback; +auto Hotkey::operator==(const Hotkey& source) const -> bool { + return state == source.state; +} + +auto Hotkey::operator!=(const Hotkey& source) const -> bool { + return !operator==(source); +} + +auto Hotkey::doPress() const -> void { + if(state->onPress) state->onPress(); +} + +auto Hotkey::doRelease() const -> void { + if(state->onRelease) state->onRelease(); +} + +auto Hotkey::onPress(const function& callback) -> type& { + state->onPress = callback; return *this; } -auto mHotkey::onRelease(const function& callback) -> type& { - state.onRelease = callback; +auto Hotkey::onRelease(const function& callback) -> type& { + state->onRelease = callback; return *this; } -auto mHotkey::owner() const -> wObject { - return state.owner; -} - -auto mHotkey::remove() -> type& { -//todo: remove from Keyboard::hotkeys +auto Hotkey::reset() -> type& { + setSequence(); return *this; } -auto mHotkey::sequence() const -> string { - return state.sequence; +auto Hotkey::sequence() const -> string { + return state->sequence; } -auto mHotkey::setOwner(sObject owner) -> type& { - state.owner = owner; - return *this; -} - -auto mHotkey::setSequence(const string& sequence) -> type& { - state.active = false; - state.sequence = sequence; - state.keys.reset(); +auto Hotkey::setSequence(const string& sequence) -> type& { + state->active = false; + state->sequence = sequence; + state->keys.reset(); for(auto& key : sequence.split("+")) { if(auto position = Keyboard::keys.find(key)) { - state.keys.append(*position); + state->keys.append(*position); } } return *this; diff --git a/hiro/core/image.cpp b/hiro/core/image.cpp new file mode 100644 index 00000000..503530e1 --- /dev/null +++ b/hiro/core/image.cpp @@ -0,0 +1,83 @@ +#if defined(Hiro_Image) + +Image::Image() { +} + +Image::Image(const Image& source) { + operator=(source); +} + +Image::Image(const string& source) { + nall::image image{source}; + image.transform(); + setImage((const uint32_t*)image.data(), Size{(signed)image.width(), (signed)image.height()}); +} + +Image::Image(const vector& source) { + nall::image image{source}; + image.transform(); + setImage((const uint32_t*)image.data(), Size{(signed)image.width(), (signed)image.height()}); +} + +Image::Image(const uint32_t* data, Size size) { + setImage(data, size); +} + +Image::~Image() { + reset(); +} + +Image::operator bool() const { + return state.data; +} + +auto Image::operator=(const Image& source) -> type& { + reset(); + if(state.size = source.state.size) { + state.data = new uint32_t[state.size.width() * state.size.height()]; + memory::copy(state.data, source.state.data, state.size.width() * state.size.height() * sizeof(uint32_t)); + } + return *this; +} + +auto Image::data() const -> uint32_t* { + return state.data; +} + +auto Image::height() const -> signed { + return state.size.height(); +} + +auto Image::reset() -> type& { + if(state.data) delete[] state.data; + state.data = nullptr; + state.size = {}; + return *this; +} + +auto Image::setImage(const uint32_t* data, Size size) -> type& { + reset(); + if(data && size) { + state.size = size; + state.data = new uint32_t[size.width() * size.height()]; + memory::copy(state.data, data, size.width() * size.height() * sizeof(uint32_t)); + } + return *this; +} + +auto Image::setSize(Size size) -> type& { + state.size = size; + if(state.data) delete[] state.data; + if(state.size) state.data = new uint32_t[size.width() * size.height()]; + return *this; +} + +auto Image::size() const -> Size { + return state.size; +} + +auto Image::width() const -> signed { + return state.size.width(); +} + +#endif diff --git a/hiro/core/keyboard.cpp b/hiro/core/keyboard.cpp index 82f3bbc9..8abbbf3d 100644 --- a/hiro/core/keyboard.cpp +++ b/hiro/core/keyboard.cpp @@ -18,44 +18,43 @@ const vector Keyboard::keys = { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Zero", //group aliases - "Shift", //"LeftShift" | "RightShift" + "Shift", //"LeftShift" | "RightShift" "Control", //"LeftControl" | "RightControl" - "Alt", //"LeftAlt" | "RightAlt" - "Super", //"LeftSuper" | "RightSuper" - "Enter", //"LeftEnter" | "RightEnter" + "Alt", //"LeftAlt" | "RightAlt" + "Super", //"LeftSuper" | "RightSuper" + "Enter", //"LeftEnter" | "RightEnter" }; -auto Keyboard::append(sHotkey hotkey) -> void { +auto Keyboard::append(Hotkey hotkey) -> void { state.hotkeys.append(hotkey); } auto Keyboard::hotkey(unsigned position) -> Hotkey { - if(position < hotkeys()) return state.hotkeys[position]; + if(position < hotkeyCount()) return state.hotkeys[position]; return {}; } -auto Keyboard::hotkeys() -> unsigned { +auto Keyboard::hotkeyCount() -> unsigned { return state.hotkeys.size(); } +auto Keyboard::hotkeys() -> vector { + return state.hotkeys; +} + auto Keyboard::poll() -> vector { auto pressed = pKeyboard::poll(); for(auto& hotkey : state.hotkeys) { - bool active = hotkey->state.sequence.size() > 0; - for(auto& key : hotkey->state.keys) { + bool active = hotkey.state->sequence.size() > 0; + for(auto& key : hotkey.state->keys) { if(pressed[key]) continue; active = false; break; } - if(auto owner = hotkey->state.owner.acquire()) { - //todo: set active = false if owner no longer exists - active &= owner->focused(); - } - if(hotkey->state.active != active) { - hotkey->state.active = active; - if( active) hotkey->doPress(); - if(!active) hotkey->doRelease(); + if(hotkey.state->active != active) { + hotkey.state->active = active; + active ? hotkey.doPress() : hotkey.doRelease(); } } @@ -71,7 +70,7 @@ auto Keyboard::released(const string& key) -> bool { return !pressed(key); } -auto Keyboard::remove(sHotkey hotkey) -> void { +auto Keyboard::remove(Hotkey hotkey) -> void { if(auto offset = state.hotkeys.find(hotkey)) { state.hotkeys.remove(*offset); } diff --git a/hiro/core/menu-bar.cpp b/hiro/core/menu-bar.cpp index c977c7f0..329f0826 100644 --- a/hiro/core/menu-bar.cpp +++ b/hiro/core/menu-bar.cpp @@ -54,4 +54,11 @@ auto mMenuBar::reset() -> type& { return *this; } +auto mMenuBar::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.menus)) state.menus[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& menu : state.menus) menu->setParent(this, menu->offset()); + return *this; +} + #endif diff --git a/hiro/core/object.cpp b/hiro/core/object.cpp index c378a1c3..c420da14 100644 --- a/hiro/core/object.cpp +++ b/hiro/core/object.cpp @@ -68,7 +68,7 @@ auto mObject::focused() const -> bool { return false; } -auto mObject::font(bool recursive) const -> string { +auto mObject::font(bool recursive) const -> Font { if(!recursive || state.font) return state.font; if(auto object = parent()) return object->font(true); return Application::font(); @@ -277,7 +277,7 @@ auto mObject::setFocused() -> type& { return *this; } -auto mObject::setFont(const string& font) -> type& { +auto mObject::setFont(const Font& font) -> type& { state.font = font; signal(setFont, this->font(true)); return *this; diff --git a/hiro/core/popup-menu.cpp b/hiro/core/popup-menu.cpp index 17a08388..f064df7c 100644 --- a/hiro/core/popup-menu.cpp +++ b/hiro/core/popup-menu.cpp @@ -50,7 +50,7 @@ auto mPopupMenu::reset() -> type& { } auto mPopupMenu::setParent(mObject* parent, signed offset) -> type& { - for(auto& action : state.actions) action->destruct(); + for(auto n : rrange(state.actions)) state.actions[n]->destruct(); mObject::setParent(parent, offset); for(auto& action : state.actions) action->construct(); return *this; diff --git a/hiro/core/position.cpp b/hiro/core/position.cpp index 8d5dc744..0bab72ed 100644 --- a/hiro/core/position.cpp +++ b/hiro/core/position.cpp @@ -8,6 +8,10 @@ Position::Position(signed x, signed y) { setPosition(x, y); } +Position::operator bool() const { + return state.x || state.y; +} + auto Position::operator==(const Position& source) const -> bool { return x() == source.x() && y() == source.y(); } @@ -16,6 +20,10 @@ auto Position::operator!=(const Position& source) const -> bool { return !operator==(source); } +auto Position::reset() -> type& { + return setPosition(0, 0); +} + auto Position::setPosition(Position position) -> type& { return setPosition(position.x(), position.y()); } diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index efbf7c65..3b79ab56 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -28,7 +28,7 @@ auto remove() { return self().remove(), *this; } \ auto setEnabled(bool enabled = true) { return self().setEnabled(enabled), *this; } \ auto setFocused() { return self().setFocused(), *this; } \ - auto setFont(const string& font = "") { return self().setFont(font), *this; } \ + auto setFont(const Font& font = {}) { return self().setFont(font), *this; } \ auto setVisible(bool visible = true) { return self().setVisible(visible), *this; } \ auto visible(bool recursive = false) const { return self().visible(recursive); } \ @@ -81,21 +81,6 @@ private: }; #endif -#if defined(Hiro_Hotkey) -struct Hotkey : sHotkey { - DeclareSharedObject(Hotkey) - - auto doPress() const { return self().doPress(); } - auto doRelease() const { return self().doRelease(); } - auto onPress(const function& callback = {}) { return self().onPress(callback), *this; } - auto onRelease(const function& callback = {}) { return self().onRelease(callback), *this; } - auto owner() const { return self().owner(); } - auto sequence() const { return self().sequence(); } - auto setOwner(sObject owner) { return self().setOwner(owner), *this; } - auto setSequence(const string& sequence = "") { return self().setSequence(sequence), *this; } -}; -#endif - #if defined(Hiro_Timer) struct Timer : sTimer { DeclareSharedObject(Timer) @@ -121,10 +106,10 @@ struct Menu : sMenu { auto actionCount() const { return self().actionCount(); } auto actions() const { return self().actions(); } auto append(sAction action) { return self().append(action), *this; } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto remove(sAction action) { return self().remove(action), *this; } auto reset() { return self().reset(), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } }; @@ -141,9 +126,9 @@ struct MenuItem : sMenuItem { DeclareSharedAction(MenuItem) auto doActivate() const { return self().doActivate(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } }; @@ -200,11 +185,11 @@ struct Button : sButton { auto bordered() const { return self().bordered(); } auto doActivate() const { return self().doActivate(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } auto orientation() const { return self().orientation(); } auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } @@ -224,20 +209,17 @@ struct Canvas : sCanvas { auto doMousePress(Mouse::Button button) const { return self().doMousePress(button); } auto doMouseRelease(Mouse::Button button) const { return self().doMouseRelease(button); } auto gradient() const { return self().gradient(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto onDrop(const function& callback = {}) { return self().onDrop(callback), *this; } auto onMouseLeave(const function& callback = {}) { return self().onMouseLeave(callback), *this; } auto onMouseMove(const function& callback = {}) { return self().onMouseMove(callback), *this; } auto onMousePress(const function& callback = {}) { return self().onMousePress(callback), *this; } auto onMouseRelease(const function& callback = {}) { return self().onMouseRelease(callback), *this; } auto setColor(Color color) { return self().setColor(color), *this; } - auto setData(Size size) { return self().setData(size), *this; } auto setDroppable(bool droppable = true) { return self().setDroppable(droppable), *this; } - auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) { return self().setGradient(topLeft, topRight, bottomLeft, bottomRight), *this; } - auto setHorizontalGradient(Color left, Color right) { return self().setGradient(left, right, left, right), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } - auto setVerticalGradient(Color top, Color bottom) { return self().setGradient(top, top, bottom, bottom), *this; } - auto size() const { return self().size(); } + auto setGradient(Gradient gradient = {}) { return self().setGradient(gradient), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } + auto setSize(Size size = {}) { return self().setSize(size), *this; } auto update() { return self().update(), *this; } }; #endif @@ -249,12 +231,12 @@ struct CheckButton : sCheckButton { auto bordered() const { return self().bordered(); } auto checked() const { return self().checked(); } auto doToggle() const { return self().doToggle(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto onToggle(const function& callback = {}) { return self().onToggle(callback), *this; } auto orientation() const { return self().orientation(); } auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } @@ -278,9 +260,9 @@ struct CheckLabel : sCheckLabel { struct ComboButtonItem : sComboButtonItem { DeclareSharedObject(ComboButtonItem) - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto selected() const { return self().selected(); } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setSelected() { return self().setSelected(), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } @@ -388,9 +370,9 @@ struct HorizontalSlider : sHorizontalSlider { struct IconViewItem : sIconViewItem { DeclareSharedObject(IconViewItem) - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto selected() const { return self().selected(); } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setSelected(bool selected = true) { return self().setSelected(selected), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } @@ -403,6 +385,8 @@ struct IconView : sIconView { auto append(sIconViewItem item) { return self().append(item), *this; } auto backgroundColor() const { return self().backgroundColor(); } + auto batchable() const { return self().batchable(); } + auto batched() const { return self().batched(); } auto doActivate() const { return self().doActivate(); } auto doChange() const { return self().doChange(); } auto doContext() const { return self().doContext(); } @@ -411,7 +395,6 @@ struct IconView : sIconView { auto item(unsigned position) const { return self().item(position); } auto itemCount() const { return self().itemCount(); } auto items() const { return self().items(); } - auto multiSelect() const { return self().multiSelect(); } auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } auto onContext(const function& callback = {}) { return self().onContext(callback), *this; } @@ -419,11 +402,10 @@ struct IconView : sIconView { auto remove(sIconViewItem item) { return self().remove(item), *this; } auto reset() { return self().reset(), *this; } auto selected() const { return self().selected(); } - auto selectedItems() const { return self().selectedItems(); } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setBatchable(bool batchable = true) { return self().setBatchable(batchable), *this; } auto setFlow(Orientation orientation = Orientation::Vertical) { return self().setFlow(orientation), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } - auto setMultiSelect(bool multiSelect = true) { return self().setMultiSelect(multiSelect), *this; } auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } auto setSelected(const vector& selections) { return self().setSelected(selections), *this; } }; @@ -470,7 +452,7 @@ struct ListViewColumn : sListViewColumn { auto expandable() const { return self().expandable(); } auto foregroundColor() const { return self().foregroundColor(); } auto horizontalAlignment() const { return self().horizontalAlignment(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto resizable() const { return self().resizable(); } auto setActive() { return self().setActive(), *this; } auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } @@ -478,12 +460,10 @@ struct ListViewColumn : sListViewColumn { auto setEditable(bool editable = true) { return self().setEditable(editable), *this; } auto setExpandable(bool expandable = true) { return self().setExpandable(expandable), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } - auto setHorizontalAlignment(double alignment = 0.0) { return self().setHorizontalAlignment(alignment), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setResizable(bool resizable = true) { return self().setResizable(resizable), *this; } auto setSortable(bool sortable = true) { return self().setSortable(sortable), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } - auto setVerticalAlignment(double alignment = 0.5) { return self().setVerticalAlignment(alignment), *this; } auto setWidth(signed width = 0) { return self().setWidth(width), *this; } auto sortable() const { return self().sortable(); } auto text() const { return self().text(); } @@ -513,13 +493,13 @@ struct ListViewCell : sListViewCell { auto checkable() const { return self().checkable(); } auto checked() const { return self().checked(); } auto foregroundColor() const { return self().foregroundColor(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } auto setCheckable(bool checkable = true) const { return self().setCheckable(checkable), *this; } auto setChecked(bool checked = true) const { return self().setChecked(checked), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } }; @@ -603,12 +583,12 @@ struct RadioButton : sRadioButton { auto checked() const { return self().checked(); } auto doActivate() const { return self().doActivate(); } auto group() const { return self().group(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto onActivate(const function& callback = {}) { return self().onActivate(callback), *this; } auto orientation() const { return self().orientation(); } auto setBordered(bool bordered = true) { return self().setBordered(bordered), *this; } auto setChecked() { return self().setChecked(), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setOrientation(Orientation orientation = Orientation::Horizontal) { return self().setOrientation(orientation), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } @@ -633,13 +613,12 @@ struct RadioLabel : sRadioLabel { struct SourceEdit : sSourceEdit { DeclareSharedWidget(SourceEdit) + auto cursor() const { return self().cursor(); } auto doChange() const { return self().doChange(); } auto doMove() const { return self().doMove(); } auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } - auto position() const { return self().position(); } - auto setPosition(signed position) { return self().setPosition(position), *this; } - auto setSelected(Position selected) { return self().setSelected(selected), *this; } + auto setCursor(Cursor cursor = {}) { return self().setCursor(cursor), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } }; @@ -651,14 +630,14 @@ struct TabFrameItem : sTabFrameItem { auto append(sLayout layout) { return self().append(layout), *this; } auto closable() const { return self().closable(); } - auto icon() const { return self().icon(); } + auto image() const { return self().image(); } auto layout() const { return self().layout(); } auto movable() const { return self().movable(); } auto remove(sLayout layout) { return self().remove(layout), *this; } auto reset() { return self().reset(), *this; } auto selected() const { return self().selected(); } auto setClosable(bool closable = true) { return self().setClosable(closable), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setMovable(bool movable = true) { return self().setMovable(movable), *this; } auto setSelected() { return self().setSelected(), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } @@ -674,17 +653,17 @@ struct TabFrame : sTabFrame { auto doChange() const { return self().doChange(); } auto doClose(sTabFrameItem item) const { return self().doClose(item); } auto doMove(sTabFrameItem from, sTabFrameItem to) const { return self().doMove(from, to); } - auto edge() const { return self().edge(); } auto item(unsigned position) const { return self().item(position); } auto itemCount() const { return self().itemCount(); } auto items() const { return self().items(); } + auto navigation() const { return self().navigation(); } auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } auto onClose(const function& callback = {}) { return self().onClose(callback), *this; } auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } auto remove(sTabFrameItem item) { return self().remove(item), *this; } auto reset() { return self().reset(), *this; } auto selected() const { return self().selected(); } - auto setEdge(Edge edge = Edge::Top) { return self().setEdge(edge), *this; } + auto setNavigation(Navigation navigation = Navigation::Top) { return self().setNavigation(navigation), *this; } }; #endif @@ -693,7 +672,7 @@ struct TextEdit : sTextEdit { DeclareSharedWidget(TextEdit) auto backgroundColor() const { return self().backgroundColor(); } - auto cursorPosition() const { return self().cursorPosition(); } + auto cursor() const { return self().cursor(); } auto doChange() const { return self().doChange(); } auto doMove() const { return self().doMove(); } auto editable() const { return self().editable(); } @@ -701,7 +680,7 @@ struct TextEdit : sTextEdit { auto onChange(const function& callback = {}) { return self().onChange(callback), *this; } auto onMove(const function& callback = {}) { return self().onMove(callback), *this; } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } - auto setCursorPosition(unsigned position) { return self().setCursorPosition(position), *this; } + auto setCursor(Cursor cursor = {}) { return self().setCursor(cursor), *this; } auto setEditable(bool editable = true) { return self().setEditable(editable), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } @@ -716,16 +695,23 @@ struct TreeViewItem : sTreeViewItem { DeclareSharedObject(TreeViewItem) auto append(sTreeViewItem item) { return self().append(item), *this; } + auto backgroundColor() const { return self().backgroundColor(); } + auto checkable() const { return self().checkable(); } auto checked() const { return self().checked(); } - auto icon() const { return self().icon(); } + auto foregroundColor() const { return self().foregroundColor(); } + auto image() const { return self().image(); } auto item(const string& path) const { return self().item(path); } auto itemCount() const { return self().itemCount(); } auto items() const { return self().items(); } auto path() const { return self().path(); } auto remove(sTreeViewItem item) { return self().remove(item), *this; } auto selected() const { return self().selected(); } + auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setCheckable(bool checkable = true) { return self().setCheckable(checkable), *this; } auto setChecked(bool checked = true) { return self().setChecked(checked), *this; } - auto setIcon(const image& icon = {}) { return self().setIcon(icon), *this; } + auto setExpanded(bool expanded = true) { return self().setExpanded(expanded), *this; } + auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } + auto setImage(const Image& image = {}) { return self().setImage(image), *this; } auto setSelected() { return self().setSelected(), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } @@ -738,13 +724,10 @@ struct TreeView : sTreeView { auto append(sTreeViewItem item) { return self().append(item), *this; } auto backgroundColor() const { return self().backgroundColor(); } - auto checkable() const { return self().checkable(); } - auto collapse() { return self().collapse(), *this; } auto doActivate() const { return self().doActivate(); } auto doChange() const { return self().doChange(); } auto doContext() const { return self().doContext(); } auto doToggle(sTreeViewItem item) const { return self().doToggle(item); } - auto expand() { return self().expand(), *this; } auto foregroundColor() const { return self().foregroundColor(); } auto item(const string& path) const { return self().item(path); } auto itemCount() const { return self().itemCount(); } @@ -757,7 +740,6 @@ struct TreeView : sTreeView { auto reset() { return self().reset(), *this; } auto selected() const { return self().selected(); } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } - auto setCheckable(bool checkable = true) { return self().setCheckable(checkable), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } }; #endif diff --git a/hiro/core/size.cpp b/hiro/core/size.cpp index bbf79efc..26cd3168 100644 --- a/hiro/core/size.cpp +++ b/hiro/core/size.cpp @@ -8,6 +8,10 @@ Size::Size(signed width, signed height) { setSize(width, height); } +Size::operator bool() const { + return state.width || state.height; +} + auto Size::operator==(const Size& source) const -> bool { return width() == source.width() && height() == source.height(); } @@ -20,6 +24,10 @@ auto Size::height() const -> signed { return state.height; } +auto Size::reset() -> type& { + return setSize(0, 0); +} + auto Size::setHeight(signed height) -> type& { state.height = height; return *this; diff --git a/hiro/core/widget/button.cpp b/hiro/core/widget/button.cpp index d754ba03..07f7f344 100644 --- a/hiro/core/widget/button.cpp +++ b/hiro/core/widget/button.cpp @@ -14,8 +14,8 @@ auto mButton::doActivate() const -> void { if(state.onActivate) return state.onActivate(); } -auto mButton::icon() const -> image { - return state.icon; +auto mButton::image() const -> Image { + return state.image; } auto mButton::onActivate(const function& callback) -> type& { @@ -33,9 +33,9 @@ auto mButton::setBordered(bool bordered) -> type& { return *this; } -auto mButton::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mButton::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/canvas.cpp b/hiro/core/widget/canvas.cpp index f7ab59ce..0dfd405b 100644 --- a/hiro/core/widget/canvas.cpp +++ b/hiro/core/widget/canvas.cpp @@ -11,7 +11,7 @@ auto mCanvas::color() const -> Color { } auto mCanvas::data() -> uint32_t* { - return state.data.data(); + return state.image.data(); } auto mCanvas::droppable() const -> bool { @@ -38,12 +38,12 @@ auto mCanvas::doMouseRelease(Mouse::Button button) const -> void { if(state.onMouseRelease) return state.onMouseRelease(button); } -auto mCanvas::gradient() const -> vector { +auto mCanvas::gradient() const -> Gradient { return state.gradient; } -auto mCanvas::icon() const -> image { - return state.icon; +auto mCanvas::image() const -> Image { + return state.image; } auto mCanvas::onDrop(const function& callback) -> type& { @@ -72,53 +72,38 @@ auto mCanvas::onMouseRelease(const function& callback) -> } auto mCanvas::setColor(Color color) -> type& { - state.size = {}; state.color = color; signal(setColor, color); return *this; } -auto mCanvas::setData(Size size) -> type& { - state.size = size; - state.data.resize(size.width() * size.height()); - memory::fill(state.data.data(), size.width() * size.height() * sizeof(uint32_t)); - signal(setData, size); - return *this; -} - auto mCanvas::setDroppable(bool droppable) -> type& { state.droppable = droppable; signal(setDroppable, droppable); return *this; } -auto mCanvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> type& { - state.size = {}; - state.gradient[0] = topLeft; - state.gradient[1] = topRight; - state.gradient[2] = bottomLeft; - state.gradient[3] = bottomRight; - signal(setGradient, topLeft, topRight, bottomLeft, bottomRight); +auto mCanvas::setGradient(Gradient gradient) -> type& { + state.gradient = gradient; + signal(setGradient, gradient); return *this; } -auto mCanvas::setHorizontalGradient(Color left, Color right) -> type& { - return setGradient(left, right, left, right); -} - -auto mCanvas::setIcon(const image& icon) -> type& { - state.size = {(signed)icon.width(), (signed)icon.height()}; - state.icon = icon; - signal(setIcon, icon); +auto mCanvas::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } -auto mCanvas::setVerticalGradient(Color top, Color bottom) -> type& { - return setGradient(top, top, bottom, bottom); +auto mCanvas::setSize(Size size) -> type& { + Image image; + image.setSize(size); + memory::fill(image.data(), size.width() * size.height() * sizeof(uint32_t), 0x00); + return setImage(image); } auto mCanvas::size() const -> Size { - return state.size; + return state.image.size(); } auto mCanvas::update() -> type& { diff --git a/hiro/core/widget/check-button.cpp b/hiro/core/widget/check-button.cpp index e67bf17d..a72db387 100644 --- a/hiro/core/widget/check-button.cpp +++ b/hiro/core/widget/check-button.cpp @@ -18,8 +18,8 @@ auto mCheckButton::doToggle() const -> void { if(state.onToggle) return state.onToggle(); } -auto mCheckButton::icon() const -> image { - return state.icon; +auto mCheckButton::image() const -> Image { + return state.image; } auto mCheckButton::onToggle(const function& callback) -> type& { @@ -43,9 +43,9 @@ auto mCheckButton::setChecked(bool checked) -> type& { return *this; } -auto mCheckButton::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mCheckButton::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/combo-button-item.cpp b/hiro/core/widget/combo-button-item.cpp index ff836d36..9d006aea 100644 --- a/hiro/core/widget/combo-button-item.cpp +++ b/hiro/core/widget/combo-button-item.cpp @@ -6,8 +6,8 @@ auto mComboButtonItem::allocate() -> pObject* { // -auto mComboButtonItem::icon() const -> image { - return state.icon; +auto mComboButtonItem::image() const -> Image { + return state.image; } auto mComboButtonItem::remove() -> type& { @@ -19,9 +19,9 @@ auto mComboButtonItem::selected() const -> bool { return state.selected; } -auto mComboButtonItem::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mComboButtonItem::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/frame.cpp b/hiro/core/widget/frame.cpp index e21b2b30..9a172a36 100644 --- a/hiro/core/widget/frame.cpp +++ b/hiro/core/widget/frame.cpp @@ -33,6 +33,13 @@ auto mFrame::reset() -> type& { return *this; } +auto mFrame::setParent(mObject* object, signed offset) -> type& { + if(auto& layout = state.layout) layout->destruct(); + mObject::setParent(object, offset); + if(auto& layout = state.layout) layout->setParent(this, 0); + return *this; +} + auto mFrame::setText(const string& text) -> type& { state.text = text; signal(setText, text); diff --git a/hiro/core/widget/icon-view-item.cpp b/hiro/core/widget/icon-view-item.cpp index bff5694e..61fc4031 100644 --- a/hiro/core/widget/icon-view-item.cpp +++ b/hiro/core/widget/icon-view-item.cpp @@ -6,8 +6,8 @@ auto mIconViewItem::allocate() -> pObject* { // -auto mIconViewItem::icon() const -> image { - return state.icon; +auto mIconViewItem::image() const -> Image { + return state.image; } auto mIconViewItem::remove() -> type& { @@ -19,9 +19,9 @@ auto mIconViewItem::selected() const -> bool { return state.selected; } -auto mIconViewItem::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mIconViewItem::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/icon-view.cpp b/hiro/core/widget/icon-view.cpp index 184601b3..9026c95d 100644 --- a/hiro/core/widget/icon-view.cpp +++ b/hiro/core/widget/icon-view.cpp @@ -22,6 +22,18 @@ auto mIconView::backgroundColor() const -> Color { return state.backgroundColor; } +auto mIconView::batchable() const -> bool { + return state.batchable; +} + +auto mIconView::batched() const -> vector { + vector items; + for(auto& item : state.items) { + if(item->selected()) items.append(item); + } + return items; +} + auto mIconView::doActivate() const -> void { if(state.onActivate) return state.onActivate(); } @@ -57,10 +69,6 @@ auto mIconView::items() const -> vector { return items; } -auto mIconView::multiSelect() const -> bool { - return state.multiSelect; -} - auto mIconView::onActivate(const function& callback) -> type& { state.onActivate = callback; return *this; @@ -97,19 +105,11 @@ auto mIconView::reset() -> type& { return *this; } -auto mIconView::selected() const -> maybe { +auto mIconView::selected() const -> IconViewItem { for(auto& item : state.items) { - if(item->selected()) return (unsigned)item->offset(); + if(item->selected()) return item; } - return nothing; -} - -auto mIconView::selectedItems() const -> vector { - vector result; - for(auto& item : state.items) { - if(item->selected()) result.append(item->offset()); - } - return result; + return {}; } auto mIconView::setBackgroundColor(Color color) -> type& { @@ -118,6 +118,12 @@ auto mIconView::setBackgroundColor(Color color) -> type& { return *this; } +auto mIconView::setBatchable(bool batchable) -> type& { + state.batchable = batchable; + signal(setBatchable, batchable); + return *this; +} + auto mIconView::setFlow(Orientation flow) -> type& { state.flow = flow; signal(setFlow, flow); @@ -130,18 +136,19 @@ auto mIconView::setForegroundColor(Color color) -> type& { return *this; } -auto mIconView::setMultiSelect(bool multiSelect) -> type& { - state.multiSelect = multiSelect; - signal(setMultiSelect, multiSelect); - return *this; -} - auto mIconView::setOrientation(Orientation orientation) -> type& { state.orientation = orientation; signal(setOrientation, orientation); return *this; } +auto mIconView::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); + return *this; +} + auto mIconView::setSelected(const vector& selections) -> type& { bool selectAll = selections(0, 0) == ~0; for(auto& item : state.items) item->state.selected = selectAll; diff --git a/hiro/core/widget/list-view-cell.cpp b/hiro/core/widget/list-view-cell.cpp index bcfc6483..bd4b699f 100644 --- a/hiro/core/widget/list-view-cell.cpp +++ b/hiro/core/widget/list-view-cell.cpp @@ -54,7 +54,7 @@ auto mListViewCell::checked() const -> bool { return state.checkable && state.checked; } -auto mListViewCell::font(bool recursive) const -> string { +auto mListViewCell::font(bool recursive) const -> Font { if(auto font = mObject::font()) return font; if(recursive) { if(auto parent = parentListViewItem()) { @@ -94,8 +94,8 @@ auto mListViewCell::foregroundColor(bool recursive) const -> Color { return state.foregroundColor; } -auto mListViewCell::icon() const -> image { - return state.icon; +auto mListViewCell::image() const -> Image { + return state.image; } auto mListViewCell::setAlignment(Alignment alignment) -> type& { @@ -129,9 +129,9 @@ auto mListViewCell::setForegroundColor(Color color) -> type& { return *this; } -auto mListViewCell::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mListViewCell::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/list-view-column.cpp b/hiro/core/widget/list-view-column.cpp index e23e67df..a9223da9 100644 --- a/hiro/core/widget/list-view-column.cpp +++ b/hiro/core/widget/list-view-column.cpp @@ -35,8 +35,8 @@ auto mListViewColumn::horizontalAlignment() const -> double { return state.horizontalAlignment; } -auto mListViewColumn::icon() const -> image { - return state.icon; +auto mListViewColumn::image() const -> Image { + return state.image; } auto mListViewColumn::remove() -> type& { @@ -91,9 +91,9 @@ auto mListViewColumn::setHorizontalAlignment(double alignment) -> type& { return *this; } -auto mListViewColumn::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mListViewColumn::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/list-view.cpp b/hiro/core/widget/list-view.cpp index 2307449c..14a8ccb3 100644 --- a/hiro/core/widget/list-view.cpp +++ b/hiro/core/widget/list-view.cpp @@ -194,7 +194,7 @@ auto mListView::setForegroundColor(Color color) -> type& { } auto mListView::setParent(mObject* parent, signed offset) -> type& { - for(auto& item : state.items) item->destruct(); + for(auto n : rrange(state.items)) state.items[n]->destruct(); if(auto& header = state.header) header->destruct(); mObject::setParent(parent, offset); if(auto& header = state.header) header->setParent(this, 0); diff --git a/hiro/core/widget/radio-button.cpp b/hiro/core/widget/radio-button.cpp index e504972a..b95e7066 100644 --- a/hiro/core/widget/radio-button.cpp +++ b/hiro/core/widget/radio-button.cpp @@ -22,8 +22,8 @@ auto mRadioButton::group() const -> Group { return state.group; } -auto mRadioButton::icon() const -> image { - return state.icon; +auto mRadioButton::image() const -> Image { + return state.image; } auto mRadioButton::onActivate(const function& callback) -> type& { @@ -57,15 +57,14 @@ auto mRadioButton::setChecked() -> type& { } auto mRadioButton::setGroup(sGroup group) -> type& { - state.group = group; + state.group = group ? group : Group{&instance}; signal(setGroup, group); - if(group && group->objectCount() == 1) setChecked(); return *this; } -auto mRadioButton::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mRadioButton::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/radio-label.cpp b/hiro/core/widget/radio-label.cpp index a4f45ac2..6961ba72 100644 --- a/hiro/core/widget/radio-label.cpp +++ b/hiro/core/widget/radio-label.cpp @@ -39,9 +39,8 @@ auto mRadioLabel::setChecked() -> type& { } auto mRadioLabel::setGroup(sGroup group) -> type& { - state.group = group; + state.group = group ? group : Group{&instance}; signal(setGroup, group); - if(group && group->objectCount() == 1) setChecked(); return *this; } diff --git a/hiro/core/widget/source-edit.cpp b/hiro/core/widget/source-edit.cpp index ec100116..5ef494a5 100644 --- a/hiro/core/widget/source-edit.cpp +++ b/hiro/core/widget/source-edit.cpp @@ -6,6 +6,10 @@ auto mSourceEdit::allocate() -> pObject* { // +auto mSourceEdit::cursor() const -> Cursor { + return state.cursor; +} + auto mSourceEdit::doChange() const -> void { if(state.onChange) return state.onChange(); } @@ -24,22 +28,9 @@ auto mSourceEdit::onMove(const function& callback) -> type& { return *this; } -auto mSourceEdit::position() const -> unsigned { - return state.position; -} - -auto mSourceEdit::setPosition(signed position) -> type& { - state.position = position; - signal(setPosition, position); - return *this; -} - -auto mSourceEdit::setSelected(Position selected) -> type& { - if(selected.x() < 0) return *this; - if(selected.y() < 0) selected.setY(-1); - else if(selected.x() > selected.y()) return *this; - state.selected = selected; - signal(setSelected, selected); +auto mSourceEdit::setCursor(Cursor cursor) -> type& { + state.cursor = cursor; + signal(setCursor, cursor); return *this; } diff --git a/hiro/core/widget/tab-frame-item.cpp b/hiro/core/widget/tab-frame-item.cpp index 2c6998f4..3a7d1cff 100644 --- a/hiro/core/widget/tab-frame-item.cpp +++ b/hiro/core/widget/tab-frame-item.cpp @@ -23,8 +23,8 @@ auto mTabFrameItem::closable() const -> bool { return state.closable; } -auto mTabFrameItem::icon() const -> image { - return state.icon; +auto mTabFrameItem::image() const -> Image { + return state.image; } auto mTabFrameItem::layout() const -> Layout { @@ -62,9 +62,9 @@ auto mTabFrameItem::setClosable(bool closable) -> type& { return *this; } -auto mTabFrameItem::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mTabFrameItem::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); return *this; } diff --git a/hiro/core/widget/tab-frame.cpp b/hiro/core/widget/tab-frame.cpp index d344a629..1ac78bf5 100644 --- a/hiro/core/widget/tab-frame.cpp +++ b/hiro/core/widget/tab-frame.cpp @@ -12,6 +12,7 @@ auto mTabFrame::destruct() -> void { // auto mTabFrame::append(sTabFrameItem item) -> type& { + if(!state.items) item->state.selected = true; state.items.append(item); item->setParent(this, itemCount() - 1); signal(append, item); @@ -30,10 +31,6 @@ auto mTabFrame::doMove(sTabFrameItem from, sTabFrameItem to) const -> void { if(state.onMove) return state.onMove(from, to); } -auto mTabFrame::edge() const -> Edge { - return state.edge; -} - auto mTabFrame::item(unsigned position) const -> TabFrameItem { if(position < itemCount()) return state.items[position]; return {}; @@ -49,6 +46,10 @@ auto mTabFrame::items() const -> vector { return items; } +auto mTabFrame::navigation() const -> Navigation { + return state.navigation; +} + auto mTabFrame::onChange(const function& callback) -> type& { state.onChange = callback; return *this; @@ -87,14 +88,14 @@ auto mTabFrame::selected() const -> TabFrameItem { return {}; } -auto mTabFrame::setEdge(Edge edge) -> type& { - state.edge = edge; - signal(setEdge, edge); +auto mTabFrame::setNavigation(Navigation navigation) -> type& { + state.navigation = navigation; + signal(setNavigation, navigation); return *this; } auto mTabFrame::setParent(mObject* parent, signed offset) -> type& { - for(auto& item : state.items) item->destruct(); + for(auto n : rrange(state.items)) state.items[n]->destruct(); mObject::setParent(parent, offset); for(auto& item : state.items) item->setParent(this, item->offset()); return *this; diff --git a/hiro/core/widget/text-edit.cpp b/hiro/core/widget/text-edit.cpp index 909d7440..14211900 100644 --- a/hiro/core/widget/text-edit.cpp +++ b/hiro/core/widget/text-edit.cpp @@ -10,8 +10,8 @@ auto mTextEdit::backgroundColor() const -> Color { return state.backgroundColor; } -auto mTextEdit::cursorPosition() const -> unsigned { - return state.cursorPosition; +auto mTextEdit::cursor() const -> Cursor { + return state.cursor; } auto mTextEdit::doChange() const -> void { @@ -46,9 +46,9 @@ auto mTextEdit::setBackgroundColor(Color color) -> type& { return *this; } -auto mTextEdit::setCursorPosition(unsigned position) -> type& { - state.cursorPosition = position; - signal(setCursorPosition, position); +auto mTextEdit::setCursor(Cursor cursor) -> type& { + state.cursor = cursor; + signal(setCursor, cursor); return *this; } diff --git a/hiro/core/widget/tree-view-item.cpp b/hiro/core/widget/tree-view-item.cpp index e3f720a1..798282d1 100644 --- a/hiro/core/widget/tree-view-item.cpp +++ b/hiro/core/widget/tree-view-item.cpp @@ -18,12 +18,42 @@ auto mTreeViewItem::append(sTreeViewItem item) -> type& { return *this; } +auto mTreeViewItem::backgroundColor(bool recursive) const -> Color { + if(auto color = state.backgroundColor) return color; + if(recursive) { + if(auto parent = parentTreeViewItem()) { + if(auto color = parent->backgroundColor(true)) return color; + } + if(auto parent = parentTreeView()) { + if(auto color = parent->backgroundColor()) return color; + } + } + return {}; +} + +auto mTreeViewItem::checkable() const -> bool { + return state.checkable; +} + auto mTreeViewItem::checked() const -> bool { return state.checked; } -auto mTreeViewItem::icon() const -> image { - return state.icon; +auto mTreeViewItem::foregroundColor(bool recursive) const -> Color { + if(auto color = state.foregroundColor) return color; + if(recursive) { + if(auto parent = parentTreeViewItem()) { + if(auto color = parent->foregroundColor(true)) return color; + } + if(auto parent = parentTreeView()) { + if(auto color = parent->foregroundColor()) return color; + } + } + return {}; +} + +auto mTreeViewItem::image() const -> Image { + return state.image; } auto mTreeViewItem::item(const string& path) const -> TreeViewItem { @@ -73,23 +103,52 @@ auto mTreeViewItem::selected() const -> bool { return false; } +auto mTreeViewItem::setBackgroundColor(Color color) -> type& { + state.backgroundColor = color; + signal(setBackgroundColor, color); + return *this; +} + +auto mTreeViewItem::setCheckable(bool checkable) -> type& { + state.checkable = checkable; + signal(setCheckable, checkable); + return *this; +} + auto mTreeViewItem::setChecked(bool checked) -> type& { state.checked = checked; signal(setChecked, checked); return *this; } +auto mTreeViewItem::setExpanded(bool expanded) -> type& { + signal(setExpanded, expanded); + return *this; +} + auto mTreeViewItem::setFocused() -> type& { signal(setFocused); return *this; } -auto mTreeViewItem::setIcon(const image& icon) -> type& { - state.icon = icon; - signal(setIcon, icon); +auto mTreeViewItem::setForegroundColor(Color color) -> type& { + state.foregroundColor = color; + signal(setForegroundColor, color); return *this; } +auto mTreeViewItem::setImage(const Image& image) -> type& { + state.image = image; + signal(setImage, image); + return *this; +} + +auto mTreeViewItem::setParent(mObject* parent, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(parent, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); +} + auto mTreeViewItem::setSelected() -> type& { signal(setSelected); return *this; diff --git a/hiro/core/widget/tree-view.cpp b/hiro/core/widget/tree-view.cpp index d93351e0..a3cc3cd6 100644 --- a/hiro/core/widget/tree-view.cpp +++ b/hiro/core/widget/tree-view.cpp @@ -22,15 +22,6 @@ auto mTreeView::backgroundColor() const -> Color { return state.backgroundColor; } -auto mTreeView::checkable() const -> bool { - return state.checkable; -} - -auto mTreeView::collapse() -> type& { - signal(collapse); - return *this; -} - auto mTreeView::doActivate() const -> void { if(state.onActivate) return state.onActivate(); } @@ -47,11 +38,6 @@ auto mTreeView::doToggle(sTreeViewItem item) const -> void { if(state.onToggle) return state.onToggle(item); } -auto mTreeView::expand() -> type& { - signal(expand); - return *this; -} - auto mTreeView::foregroundColor() const -> Color { return state.foregroundColor; } @@ -107,9 +93,7 @@ auto mTreeView::remove(sTreeViewItem item) -> type& { auto mTreeView::reset() -> type& { state.selectedPath.reset(); - signal(reset); - for(auto& item : state.items) item->setParent(); - state.items.reset(); + for(auto n : rrange(state.items)) remove(state.items[n]); return *this; } @@ -123,16 +107,17 @@ auto mTreeView::setBackgroundColor(Color color) -> type& { return *this; } -auto mTreeView::setCheckable(bool checkable) -> type& { - state.checkable = checkable; - signal(setCheckable, checkable); - return *this; -} - auto mTreeView::setForegroundColor(Color color) -> type& { state.foregroundColor = color; signal(setForegroundColor, color); return *this; } +auto mTreeView::setParent(mObject* object, signed offset) -> type& { + for(auto n : rrange(state.items)) state.items[n]->destruct(); + mObject::setParent(object, offset); + for(auto& item : state.items) item->setParent(this, item->offset()); + return *this; +} + #endif diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 2de7b70a..89551ad8 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -15,8 +15,8 @@ private: VerticalLayout layout{&window}; HorizontalLayout pathLayout{&layout, Size{~0, 0}, 5}; LineEdit pathName{&pathLayout, Size{~0, 0}, 0}; - Button pathHome{&pathLayout, Size{0, 0}, 0}; Button pathRefresh{&pathLayout, Size{0, 0}, 0}; + Button pathHome{&pathLayout, Size{0, 0}, 0}; Button pathUp{&pathLayout, Size{0, 0}, 0}; ListView view{&layout, Size{~0, ~0}, 5}; HorizontalLayout controlLayout{&layout, Size{~0, 0}}; @@ -118,9 +118,9 @@ auto BrowserDialogWindow::run() -> lstring { layout.setMargin(5); pathName.onActivate([&] { setPath(pathName.text()); }); - pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); }); - pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); }); - pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); }); + pathRefresh.setBordered(false).setImage(Icon::Action::Refresh).onActivate([&] { setPath(state.path); }); + pathHome.setBordered(false).setImage(Icon::Go::Home).onActivate([&] { setPath(userpath()); }); + pathUp.setBordered(false).setImage(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); }); view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); }); filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); }); for(auto& filter : state.filters) { @@ -175,7 +175,7 @@ auto BrowserDialogWindow::setPath(string path) -> void { if(folderMode && isMatch(content)) continue; view.append(ListViewItem() - .append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder)) + .append(ListViewCell().setText(content).setImage(Icon::Emblem::Folder)) ); } @@ -185,7 +185,7 @@ auto BrowserDialogWindow::setPath(string path) -> void { if(!isMatch(content)) continue; view.append(ListViewItem() - .append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File)) + .append(ListViewCell().setText(content).setImage(folderMode ? Icon::Action::Open : Icon::Emblem::File)) ); } diff --git a/hiro/extension/fixed-layout.cpp b/hiro/extension/fixed-layout.cpp index cbabcbd0..8fe302f9 100644 --- a/hiro/extension/fixed-layout.cpp +++ b/hiro/extension/fixed-layout.cpp @@ -7,6 +7,14 @@ auto mFixedLayout::append(sSizable sizable, Geometry geometry) -> type& { return *this; } +auto mFixedLayout::modify(sSizable sizable, Geometry geometry) -> type& { + if(sizable && this->sizable(sizable->offset()) == sizable) { + auto& properties = this->properties[sizable->offset()]; + properties.geometry = geometry; + } + return *this; +} + auto mFixedLayout::minimumSize() const -> Size { signed width = Size::Minimum, height = Size::Minimum; for(auto n : range(sizableCount())) { @@ -36,7 +44,7 @@ auto mFixedLayout::setEnabled(bool enabled) -> type& { return *this; } -auto mFixedLayout::setFont(const string& font) -> type& { +auto mFixedLayout::setFont(const Font& font) -> type& { mLayout::setFont(font); for(auto n : range(sizableCount())) { sizable(n)->setFont(sizable(n)->font()); diff --git a/hiro/extension/fixed-layout.hpp b/hiro/extension/fixed-layout.hpp index 3d4c94f8..bcfb2e6c 100644 --- a/hiro/extension/fixed-layout.hpp +++ b/hiro/extension/fixed-layout.hpp @@ -6,11 +6,12 @@ struct mFixedLayout : mLayout { using mLayout::remove; auto append(sSizable sizable, Geometry geometry) -> type&; + auto modify(sSizable sizable, Geometry geometry) -> type&; auto minimumSize() const -> Size override; auto remove(sSizable sizable) -> type& override; auto reset() -> type& override; auto setEnabled(bool enabled = true) -> type& override; - auto setFont(const string& font = "") -> type& override; + auto setFont(const Font& font = {}) -> type& override; auto setVisible(bool visible = true) ->type& override; struct Properties { diff --git a/hiro/extension/horizontal-layout.cpp b/hiro/extension/horizontal-layout.cpp index a3fe9344..35f11ca6 100644 --- a/hiro/extension/horizontal-layout.cpp +++ b/hiro/extension/horizontal-layout.cpp @@ -6,6 +6,16 @@ auto mHorizontalLayout::append(sSizable sizable, Size size, signed spacing) -> t return *this; } +auto mHorizontalLayout::modify(sSizable sizable, Size size, signed spacing) -> type& { + if(sizable && this->sizable(sizable->offset()) == sizable) { + auto& properties = this->properties[sizable->offset()]; + properties.width = size.width(); + properties.height = size.height(); + properties.spacing = spacing; + } + return *this; +} + auto mHorizontalLayout::minimumSize() const -> Size { signed width = 0, height = 0; @@ -56,7 +66,7 @@ auto mHorizontalLayout::setEnabled(bool enabled) -> type& { return *this; } -auto mHorizontalLayout::setFont(const string& font) -> type& { +auto mHorizontalLayout::setFont(const Font& font) -> type& { mLayout::setFont(font); for(auto n : range(sizableCount())) { sizable(n)->setFont(sizable(n)->font()); diff --git a/hiro/extension/horizontal-layout.hpp b/hiro/extension/horizontal-layout.hpp index 783a2768..13a4d95a 100644 --- a/hiro/extension/horizontal-layout.hpp +++ b/hiro/extension/horizontal-layout.hpp @@ -7,11 +7,12 @@ struct mHorizontalLayout : mLayout { auto append(sSizable sizable, Size size, signed spacing = 5) -> type&; auto minimumSize() const -> Size override; + auto modify(sSizable sizable, Size size, signed spacing = 5) -> type&; auto remove(sSizable sizable) -> type& override; auto reset() -> type& override; auto setAlignment(double alignment = 0.5) -> type&; auto setEnabled(bool enabled = true) -> type& override; - auto setFont(const string& font = "") -> type& override; + auto setFont(const Font& font = {}) -> type& override; auto setGeometry(Geometry geometry) -> type& override; auto setMargin(signed margin = 0) -> type&; auto setSpacing(signed spacing = 5) -> type&; diff --git a/hiro/extension/message-dialog.cpp b/hiro/extension/message-dialog.cpp index 2f1b5bde..31a4c894 100644 --- a/hiro/extension/message-dialog.cpp +++ b/hiro/extension/message-dialog.cpp @@ -6,19 +6,19 @@ MessageDialog::MessageDialog(const string& text) { auto MessageDialog::error(const lstring& buttons) -> string { state.buttons = buttons; - state.icon = Icon::Prompt::Error; + state.image = Icon::Prompt::Error; return _run(); } auto MessageDialog::information(const lstring& buttons) -> string { state.buttons = buttons; - state.icon = Icon::Prompt::Information; + state.image = Icon::Prompt::Information; return _run(); } auto MessageDialog::question(const lstring& buttons) -> string { state.buttons = buttons; - state.icon = Icon::Prompt::Question; + state.image = Icon::Prompt::Question; return _run(); } @@ -39,7 +39,7 @@ auto MessageDialog::setTitle(const string& title) -> type& { auto MessageDialog::warning(const lstring& buttons) -> string { state.buttons = buttons; - state.icon = Icon::Prompt::Warning; + state.image = Icon::Prompt::Warning; return _run(); } @@ -53,7 +53,7 @@ auto MessageDialog::_run() -> string { Widget controlSpacer{&controlLayout, Size{~0, 0}}; layout.setMargin(5); - messageIcon.setIcon(state.icon); + messageIcon.setImage(state.image); messageText.setText(state.text); for(auto n : range(state.buttons)) { Button button{&controlLayout, Size{80, 0}, 5}; @@ -62,7 +62,7 @@ auto MessageDialog::_run() -> string { button.setFocused(); //the last button will have effective focus } - signed widthMessage = 5 + 16 + 5 + Font::size(Font::sans(), state.text).width() + 5; + signed widthMessage = 5 + 16 + 5 + Font().size(state.text).width() + 5; signed widthButtons = 5 + state.buttons.size() * 85; signed width = max(320, widthMessage, widthButtons); diff --git a/hiro/extension/message-dialog.hpp b/hiro/extension/message-dialog.hpp index 64f845a1..480beedb 100644 --- a/hiro/extension/message-dialog.hpp +++ b/hiro/extension/message-dialog.hpp @@ -15,7 +15,7 @@ struct MessageDialog { private: struct State { lstring buttons; - vector icon; + vector image; sWindow parent; string response; string text; diff --git a/hiro/extension/shared.hpp b/hiro/extension/shared.hpp index b432b451..de05c1c9 100644 --- a/hiro/extension/shared.hpp +++ b/hiro/extension/shared.hpp @@ -4,6 +4,7 @@ struct FixedLayout : sFixedLayout { DeclareSharedLayout(FixedLayout) auto append(sSizable sizable, Geometry geometry) { return self().append(sizable, geometry), *this; } + auto modify(sSizable sizable, Geometry geometry) { return self().modify(sizable, geometry), *this; } }; #endif @@ -13,6 +14,7 @@ struct HorizontalLayout : sHorizontalLayout { DeclareSharedLayout(HorizontalLayout) auto append(sSizable sizable, Size size, signed spacing = 5) { return self().append(sizable, size, spacing), *this; } + auto modify(sSizable sizable, Size size, signed spacing = 5) { return self().modify(sizable, size, spacing), *this; } auto setAlignment(double alignment = 0.5) { return self().setAlignment(alignment), *this; } auto setMargin(signed margin = 0) { return self().setMargin(margin), *this; } auto setSpacing(signed spacing = 5) { return self().setSpacing(spacing), *this; } @@ -25,6 +27,7 @@ struct VerticalLayout : sVerticalLayout { DeclareSharedLayout(VerticalLayout) auto append(sSizable sizable, Size size, signed spacing = 5) { return self().append(sizable, size, spacing), *this; } + auto modify(sSizable sizable, Size size, signed spacing = 5) { return self().modify(sizable, size, spacing), *this; } auto setAlignment(double alignment = 0.0) { return self().setAlignment(alignment), *this; } auto setMargin(signed margin = 0) { return self().setMargin(margin), *this; } auto setSpacing(signed spacing = 5) { return self().setSpacing(spacing), *this; } diff --git a/hiro/extension/vertical-layout.cpp b/hiro/extension/vertical-layout.cpp index 1c799a02..d5a2867a 100644 --- a/hiro/extension/vertical-layout.cpp +++ b/hiro/extension/vertical-layout.cpp @@ -6,6 +6,16 @@ auto mVerticalLayout::append(sSizable sizable, Size size, signed spacing) -> typ return *this; } +auto mVerticalLayout::modify(sSizable sizable, Size size, signed spacing) -> type& { + if(sizable && this->sizable(sizable->offset()) == sizable) { + auto& properties = this->properties[sizable->offset()]; + properties.width = size.width(); + properties.height = size.height(); + properties.spacing = spacing; + } + return *this; +} + auto mVerticalLayout::minimumSize() const -> Size { signed width = 0, height = 0; @@ -56,7 +66,7 @@ auto mVerticalLayout::setEnabled(bool enabled) -> type& { return *this; } -auto mVerticalLayout::setFont(const string& font) -> type& { +auto mVerticalLayout::setFont(const Font& font) -> type& { mLayout::setFont(font); for(auto n : range(sizableCount())) { sizable(n)->setFont(sizable(n)->font()); diff --git a/hiro/extension/vertical-layout.hpp b/hiro/extension/vertical-layout.hpp index f8dc968d..c208fc23 100644 --- a/hiro/extension/vertical-layout.hpp +++ b/hiro/extension/vertical-layout.hpp @@ -6,12 +6,13 @@ struct mVerticalLayout : mLayout { using mLayout::remove; auto append(sSizable sizable, Size size, signed spacing = 5) -> type&; + auto modify(sSizable sizable, Size size, signed spacing = 5) -> type&; auto minimumSize() const -> Size override; auto remove(sSizable sizable) -> type& override; auto reset() -> type& override; auto setAlignment(double alignment = 0.0) -> type&; auto setEnabled(bool enabled = true) -> type& override; - auto setFont(const string& font = "") -> type& override; + auto setFont(const Font& font = {}) -> type& override; auto setGeometry(Geometry geometry) -> type& override; auto setMargin(signed margin = 0) -> type&; auto setSpacing(signed spacing = 5) -> type&; diff --git a/hiro/gtk/action/action.cpp b/hiro/gtk/action/action.cpp index 9b0cd10a..010125bd 100644 --- a/hiro/gtk/action/action.cpp +++ b/hiro/gtk/action/action.cpp @@ -12,7 +12,7 @@ auto pAction::setEnabled(bool enabled) -> void { gtk_widget_set_sensitive(widget, enabled); } -auto pAction::setFont(const string& font) -> void { +auto pAction::setFont(const Font& font) -> void { pFont::setFont(widget, font); } diff --git a/hiro/gtk/action/action.hpp b/hiro/gtk/action/action.hpp index 2117d49a..62fe99fb 100644 --- a/hiro/gtk/action/action.hpp +++ b/hiro/gtk/action/action.hpp @@ -6,7 +6,7 @@ struct pAction : pObject { Declare(Action, Object) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; auto _mnemonic(string text) -> string; diff --git a/hiro/gtk/action/menu-item.cpp b/hiro/gtk/action/menu-item.cpp index 383775e9..92ae2b92 100644 --- a/hiro/gtk/action/menu-item.cpp +++ b/hiro/gtk/action/menu-item.cpp @@ -9,6 +9,7 @@ static auto MenuItem_activate(GtkMenuItem*, pMenuItem* p) -> void { auto pMenuItem::construct() -> void { widget = gtk_image_menu_item_new_with_mnemonic(""); g_signal_connect(G_OBJECT(widget), "activate", G_CALLBACK(MenuItem_activate), (gpointer)this); + setImage(state().image); setText(state().text); } @@ -16,9 +17,9 @@ auto pMenuItem::destruct() -> void { if(widget) gtk_widget_destroy(widget), widget = nullptr; } -auto pMenuItem::setIcon(const image& icon) -> void { - if(icon) { - GtkImage* gtkImage = CreateImage(icon, true); +auto pMenuItem::setImage(const Image& image) -> void { + if(image) { + GtkImage* gtkImage = CreateImage(image, true); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); } else { gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); diff --git a/hiro/gtk/action/menu-item.hpp b/hiro/gtk/action/menu-item.hpp index 8d980c34..263b3bb4 100644 --- a/hiro/gtk/action/menu-item.hpp +++ b/hiro/gtk/action/menu-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pMenuItem : pAction { Declare(MenuItem, Action) - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; }; diff --git a/hiro/gtk/action/menu-radio-item.cpp b/hiro/gtk/action/menu-radio-item.cpp index 8dc75941..f1e28e71 100644 --- a/hiro/gtk/action/menu-radio-item.cpp +++ b/hiro/gtk/action/menu-radio-item.cpp @@ -27,8 +27,6 @@ auto pMenuRadioItem::setChecked() -> void { } auto pMenuRadioItem::setGroup(sGroup group) -> void { - if(!group) return; - maybe gtkRadioMenuItem; for(auto& weak : group->state.objects) { if(auto object = weak.acquire()) { @@ -36,9 +34,13 @@ auto pMenuRadioItem::setGroup(sGroup group) -> void { if(auto self = menuRadioItem->self()) { self->lock(); gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, nullptr); - if(!gtkRadioMenuItem) gtkRadioMenuItem = self->gtkRadioMenuItem; - else gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, gtk_radio_menu_item_get_group(*gtkRadioMenuItem)); - gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->checked()); + if(!gtkRadioMenuItem) { + gtkRadioMenuItem = self->gtkRadioMenuItem; + gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->state.checked = true); + } else { + gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, gtk_radio_menu_item_get_group(*gtkRadioMenuItem)); + gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->state.checked = false); + } self->unlock(); } } diff --git a/hiro/gtk/action/menu.cpp b/hiro/gtk/action/menu.cpp index 574ac7ea..34c95572 100644 --- a/hiro/gtk/action/menu.cpp +++ b/hiro/gtk/action/menu.cpp @@ -6,6 +6,7 @@ auto pMenu::construct() -> void { gtkMenu = gtk_menu_new(); widget = gtk_image_menu_item_new_with_mnemonic(""); gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), gtkMenu); + setImage(state().image); setText(state().text); for(auto& action : state().actions) append(*action); @@ -27,16 +28,16 @@ auto pMenu::append(sAction action) -> void { auto pMenu::remove(sAction action) -> void { } -auto pMenu::setFont(const string& font) -> void { +auto pMenu::setFont(const Font& font) -> void { pAction::setFont(font); for(auto& action : state().actions) { if(action->self()) action->self()->setFont(action->font(true)); } } -auto pMenu::setIcon(const image& icon) -> void { - if(icon) { - GtkImage* gtkImage = CreateImage(icon, true); +auto pMenu::setImage(const Image& image) -> void { + if(image) { + GtkImage* gtkImage = CreateImage(image, true); gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); } else { gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr); diff --git a/hiro/gtk/action/menu.hpp b/hiro/gtk/action/menu.hpp index a198cf09..34f0b8de 100644 --- a/hiro/gtk/action/menu.hpp +++ b/hiro/gtk/action/menu.hpp @@ -7,8 +7,8 @@ struct pMenu : pAction { auto append(sAction action) -> void; auto remove(sAction action) -> void; - auto setFont(const string& font) -> void override; - auto setIcon(const image& icon) -> void; + auto setFont(const Font& font) -> void override; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; GtkWidget* gtkMenu = nullptr; diff --git a/hiro/gtk/font.cpp b/hiro/gtk/font.cpp index 5addb5c6..1a85e97f 100644 --- a/hiro/gtk/font.cpp +++ b/hiro/gtk/font.cpp @@ -2,67 +2,54 @@ namespace hiro { -auto pFont::serif(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Serif, ", size, ", ", style}; -} - -auto pFont::sans(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Sans, ", size, ", ", style}; -} - -auto pFont::monospace(unsigned size, string style) -> string { - if(size == 0) size = 8; - return {"Liberation Mono, ", size, ", ", style}; -} - -auto pFont::size(string font, string text) -> Size { +auto pFont::size(const Font& font, const string& text) -> Size { PangoFontDescription* description = create(font); Size size = pFont::size(description, text); free(description); return size; } -auto pFont::create(string description) -> PangoFontDescription* { - lstring part = description.split(",", 2L).strip(); +auto pFont::size(PangoFontDescription* font, const string& text) -> Size { + PangoContext* context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); + PangoLayout* layout = pango_layout_new(context); + pango_layout_set_font_description(layout, font); + pango_layout_set_text(layout, text, -1); + signed width = 0, height = 0; + pango_layout_get_pixel_size(layout, &width, &height); + g_object_unref((gpointer)layout); + return {width, height}; +} - string family = "Sans"; - unsigned size = 8u; - bool bold = false; - bool italic = false; +auto pFont::family(const string& family) -> string { + #if defined(DISPLAY_WINDOWS) + if(family == Font::Sans ) return "Tahoma"; + if(family == Font::Serif) return "Georgia"; + if(family == Font::Mono ) return "Lucida Console"; + return family ? family : "Tahoma"; + #elif defined(DISPLAY_XORG) + if(family == Font::Sans ) return "Sans"; + if(family == Font::Serif) return "Serif"; + if(family == Font::Mono ) return "Liberation Mono"; + return family ? family : "Sans"; + #else + return family; + #endif +} - if(part[0] != "") family = part[0]; - if(part.size() >= 2) size = decimal(part[1]); - if(part.size() >= 3) bold = (bool)part[2].find("Bold"); - if(part.size() >= 3) italic = (bool)part[2].find("Italic"); - - PangoFontDescription* font = pango_font_description_new(); - pango_font_description_set_family(font, family); - pango_font_description_set_size(font, size * PANGO_SCALE); - pango_font_description_set_weight(font, !bold ? PANGO_WEIGHT_NORMAL : PANGO_WEIGHT_BOLD); - pango_font_description_set_style(font, !italic ? PANGO_STYLE_NORMAL : PANGO_STYLE_OBLIQUE); - return font; +auto pFont::create(const Font& font) -> PangoFontDescription* { + auto p = pango_font_description_new(); + pango_font_description_set_family(p, family(font.family())); + pango_font_description_set_size(p, (font.size() ? font.size() : 8) * PANGO_SCALE); + pango_font_description_set_weight(p, font.bold() ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); + pango_font_description_set_style(p, font.italic() ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL); + return p; } auto pFont::free(PangoFontDescription* font) -> void { pango_font_description_free(font); } -auto pFont::size(PangoFontDescription* font, string text) -> Size { - PangoContext* context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); - PangoLayout* layout = pango_layout_new(context); - pango_layout_set_font_description(layout, font); - pango_layout_set_text(layout, text, -1); - int width = 0, height = 0; - pango_layout_get_pixel_size(layout, &width, &height); - g_object_unref((gpointer)layout); - return {width, height}; -} - -auto pFont::setFont(GtkWidget* widget, string font) -> void { +auto pFont::setFont(GtkWidget* widget, const Font& font) -> void { auto gtkFont = pFont::create(font); pFont::setFont(widget, (gpointer)gtkFont); pFont::free(gtkFont); diff --git a/hiro/gtk/font.hpp b/hiro/gtk/font.hpp index 71101ddc..3ad59dd1 100644 --- a/hiro/gtk/font.hpp +++ b/hiro/gtk/font.hpp @@ -3,15 +3,12 @@ namespace hiro { struct pFont { - static auto serif(unsigned size, string style) -> string; - static auto sans(unsigned size, string style) -> string; - static auto monospace(unsigned size, string style) -> string; - static auto size(string font, string text) -> Size; - - static auto create(string description) -> PangoFontDescription*; + static auto size(const Font& font, const string& text) -> Size; + static auto size(PangoFontDescription* font, const string& text) -> Size; + static auto family(const string& family) -> string; + static auto create(const Font& font) -> PangoFontDescription*; static auto free(PangoFontDescription* font) -> void; - static auto size(PangoFontDescription* font, string text) -> Size; - static auto setFont(GtkWidget* widget, string font) -> void; + static auto setFont(GtkWidget* widget, const Font& font) -> void; static auto setFont(GtkWidget* widget, gpointer font) -> void; }; diff --git a/hiro/gtk/hotkey.cpp b/hiro/gtk/hotkey.cpp deleted file mode 100644 index 608ba7bb..00000000 --- a/hiro/gtk/hotkey.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#if defined(Hiro_Hotkey) - -namespace hiro { - -auto pHotkey::construct() -> void { -} - -auto pHotkey::destruct() -> void { -} - -} - -#endif diff --git a/hiro/gtk/hotkey.hpp b/hiro/gtk/hotkey.hpp deleted file mode 100644 index b1caa7bc..00000000 --- a/hiro/gtk/hotkey.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#if defined(Hiro_Hotkey) - -namespace hiro { - -struct pHotkey : pObject { - Declare(Hotkey, Object) -}; - -} - -#endif diff --git a/hiro/gtk/layout.cpp b/hiro/gtk/layout.cpp index 4872f933..6420d2fe 100644 --- a/hiro/gtk/layout.cpp +++ b/hiro/gtk/layout.cpp @@ -13,7 +13,7 @@ auto pLayout::destruct() -> void { auto pLayout::setEnabled(bool enabled) -> void { } -auto pLayout::setFont(const string& font) -> void { +auto pLayout::setFont(const Font& font) -> void { } auto pLayout::setVisible(bool visible) -> void { diff --git a/hiro/gtk/layout.hpp b/hiro/gtk/layout.hpp index 3895710c..dba11836 100644 --- a/hiro/gtk/layout.hpp +++ b/hiro/gtk/layout.hpp @@ -6,7 +6,7 @@ struct pLayout : pSizable { Declare(Layout, Sizable) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; }; diff --git a/hiro/gtk/menu-bar.cpp b/hiro/gtk/menu-bar.cpp index eb7b2e37..d1522dd3 100644 --- a/hiro/gtk/menu-bar.cpp +++ b/hiro/gtk/menu-bar.cpp @@ -27,7 +27,7 @@ auto pMenuBar::setEnabled(bool enabled) -> void { } } -auto pMenuBar::setFont(const string& font) -> void { +auto pMenuBar::setFont(const Font& font) -> void { if(auto parent = _parent()) { parent->_setMenuFont(font); } diff --git a/hiro/gtk/menu-bar.hpp b/hiro/gtk/menu-bar.hpp index 6fd9801b..25ffbda0 100644 --- a/hiro/gtk/menu-bar.hpp +++ b/hiro/gtk/menu-bar.hpp @@ -8,7 +8,7 @@ struct pMenuBar : pObject { auto append(sMenu menu) -> void; auto remove(sMenu menu) -> void; auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; auto _parent() -> pWindow*; diff --git a/hiro/gtk/object.cpp b/hiro/gtk/object.cpp index fae97d8c..3c6ac442 100644 --- a/hiro/gtk/object.cpp +++ b/hiro/gtk/object.cpp @@ -24,7 +24,7 @@ auto pObject::setEnabled(bool enabled) -> void { auto pObject::setFocused() -> void { } -auto pObject::setFont(const string& font) -> void { +auto pObject::setFont(const Font& font) -> void { } auto pObject::setVisible(bool visible) -> void { diff --git a/hiro/gtk/object.hpp b/hiro/gtk/object.hpp index 84469aa5..056ed0b7 100644 --- a/hiro/gtk/object.hpp +++ b/hiro/gtk/object.hpp @@ -15,7 +15,7 @@ struct pObject { virtual auto reset() -> void; virtual auto setEnabled(bool enabled) -> void; virtual auto setFocused() -> void; - virtual auto setFont(const string& font) -> void; + virtual auto setFont(const Font& font) -> void; virtual auto setVisible(bool visible) -> void; auto locked() const -> bool { return locks != 0; } diff --git a/hiro/gtk/platform.cpp b/hiro/gtk/platform.cpp index 3253c49d..72a42b4a 100644 --- a/hiro/gtk/platform.cpp +++ b/hiro/gtk/platform.cpp @@ -12,7 +12,6 @@ #include "object.cpp" #include "group.cpp" -#include "hotkey.cpp" #include "timer.cpp" #include "window.cpp" #include "status-bar.cpp" diff --git a/hiro/gtk/platform.hpp b/hiro/gtk/platform.hpp index c572eab1..828959ed 100644 --- a/hiro/gtk/platform.hpp +++ b/hiro/gtk/platform.hpp @@ -23,7 +23,6 @@ namespace hiro { #include "object.hpp" #include "group.hpp" -#include "hotkey.hpp" #include "timer.hpp" #include "window.hpp" #include "status-bar.hpp" diff --git a/hiro/gtk/popup-menu.cpp b/hiro/gtk/popup-menu.cpp index 2f0f9d91..65fa6a3f 100644 --- a/hiro/gtk/popup-menu.cpp +++ b/hiro/gtk/popup-menu.cpp @@ -21,7 +21,7 @@ auto pPopupMenu::append(sAction action) -> void { auto pPopupMenu::remove(sAction action) -> void { } -auto pPopupMenu::setFont(const string& font) -> void { +auto pPopupMenu::setFont(const Font& font) -> void { for(auto& action : state().actions) { if(action->self()) action->self()->setFont(action->font(true)); } diff --git a/hiro/gtk/popup-menu.hpp b/hiro/gtk/popup-menu.hpp index 631ac17b..2c44cf7f 100644 --- a/hiro/gtk/popup-menu.hpp +++ b/hiro/gtk/popup-menu.hpp @@ -7,7 +7,7 @@ struct pPopupMenu : pObject { auto append(sAction action) -> void; auto remove(sAction action) -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void; GtkWidget* gtkMenu = nullptr; diff --git a/hiro/gtk/status-bar.cpp b/hiro/gtk/status-bar.cpp index a58eae53..3d4d88d6 100644 --- a/hiro/gtk/status-bar.cpp +++ b/hiro/gtk/status-bar.cpp @@ -14,7 +14,7 @@ auto pStatusBar::setEnabled(bool enabled) -> void { } } -auto pStatusBar::setFont(const string& font) -> void { +auto pStatusBar::setFont(const Font& font) -> void { if(auto parent = _parent()) { parent->_setStatusFont(font); } diff --git a/hiro/gtk/status-bar.hpp b/hiro/gtk/status-bar.hpp index 61655437..7e2a9be6 100644 --- a/hiro/gtk/status-bar.hpp +++ b/hiro/gtk/status-bar.hpp @@ -6,7 +6,7 @@ struct pStatusBar : pObject { Declare(StatusBar, Object) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setText(const string& text) -> void; auto setVisible(bool visible) -> void override; diff --git a/hiro/gtk/utility.cpp b/hiro/gtk/utility.cpp index 8593481b..41d5db38 100644 --- a/hiro/gtk/utility.cpp +++ b/hiro/gtk/utility.cpp @@ -20,6 +20,34 @@ static auto CreatePixbuf(image icon, bool scale = false) -> GdkPixbuf* { auto pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, icon.width(), icon.height()); memory::copy(gdk_pixbuf_get_pixels(pixbuf), icon.data(), icon.size()); + if(scale) { + auto scaled = gdk_pixbuf_scale_simple(pixbuf, 15, 15, GDK_INTERP_BILINEAR); + g_object_unref(pixbuf); + pixbuf = scaled; + } + + return pixbuf; +} + +static auto CreatePixbuf(const Image& image, bool scale = false) -> GdkPixbuf* { + if(!image.state.data) return nullptr; + + auto pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, image.width(), image.height()); + + //ARGB -> ABGR conversion + const uint32_t* source = image.data(); + uint32_t* target = (uint32_t*)gdk_pixbuf_get_pixels(pixbuf); + for(auto n : range(image.width() * image.height())) { + uint32_t pixel = *source++; + *target++ = (pixel & 0x00ff0000) >> 16 | (pixel & 0xff00ff00) | (pixel & 0x000000ff) << 16; + } + + if(scale) { + auto scaled = gdk_pixbuf_scale_simple(pixbuf, 15, 15, GDK_INTERP_BILINEAR); + g_object_unref(pixbuf); + pixbuf = scaled; + } + return pixbuf; } @@ -30,6 +58,13 @@ static auto CreateImage(const nall::image& image, bool scale = false) -> GtkImag return gtkImage; } +static auto CreateImage(const Image& image, bool scale = false) -> GtkImage* { + auto pixbuf = CreatePixbuf(image, scale); + auto gtkImage = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + return gtkImage; +} + static auto DropPaths(GtkSelectionData* data) -> lstring { gchar** uris = gtk_selection_data_get_uris(data); if(uris == nullptr) return {}; diff --git a/hiro/gtk/widget/button.cpp b/hiro/gtk/widget/button.cpp index 764af857..63a28c6e 100644 --- a/hiro/gtk/widget/button.cpp +++ b/hiro/gtk/widget/button.cpp @@ -9,7 +9,7 @@ auto pButton::construct() -> void { gtkButton = GTK_BUTTON(gtkWidget); setBordered(state().bordered); - setIcon(state().icon); + setImage(state().image); setOrientation(state().orientation); setText(state().text); @@ -26,13 +26,13 @@ auto pButton::minimumSize() const -> Size { Size size = pFont::size(self().font(true), state().text); if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(size.height(), state().icon.height())); + size.setWidth(size.width() + state().image.width()); + size.setHeight(max(size.height(), state().image.height())); } if(state().orientation == Orientation::Vertical) { - size.setWidth(max(size.width(), state().icon.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(size.width(), state().image.width())); + size.setHeight(size.height() + state().image.height()); } return {size.width() + (state().text ? 24 : 12), size.height() + 12}; @@ -42,9 +42,9 @@ auto pButton::setBordered(bool bordered) -> void { gtk_button_set_relief(gtkButton, bordered ? GTK_RELIEF_NORMAL : GTK_RELIEF_NONE); } -auto pButton::setIcon(const image& icon) -> void { - if(icon) { - auto gtkImage = CreateImage(icon); +auto pButton::setImage(const Image& image) -> void { + if(image) { + auto gtkImage = CreateImage(image); gtk_button_set_image(gtkButton, (GtkWidget*)gtkImage); } else { gtk_button_set_image(gtkButton, nullptr); diff --git a/hiro/gtk/widget/button.hpp b/hiro/gtk/widget/button.hpp index 76108e67..3a769248 100644 --- a/hiro/gtk/widget/button.hpp +++ b/hiro/gtk/widget/button.hpp @@ -7,7 +7,7 @@ struct pButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/canvas.cpp b/hiro/gtk/widget/canvas.cpp index 2761c1c2..d92beb73 100644 --- a/hiro/gtk/widget/canvas.cpp +++ b/hiro/gtk/widget/canvas.cpp @@ -73,16 +73,11 @@ auto pCanvas::destruct() -> void { } auto pCanvas::minimumSize() const -> Size { - return {max(0, state().size.width()), max(0, state().size.height())}; + if(auto& image = state().image) return image.size(); + return {0, 0}; } auto pCanvas::setColor(Color color) -> void { - mode = Mode::Color; - update(); -} - -auto pCanvas::setData(Size size) -> void { - mode = Mode::Data; update(); } @@ -98,13 +93,11 @@ auto pCanvas::setGeometry(Geometry geometry) -> void { pWidget::setGeometry(geometry); } -auto pCanvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void { - mode = Mode::Gradient; +auto pCanvas::setGradient(Gradient gradient) -> void { update(); } -auto pCanvas::setIcon(const image& icon) -> void { - mode = Mode::Icon; +auto pCanvas::setImage(const Image& image) -> void { update(); } @@ -146,14 +139,13 @@ auto pCanvas::_rasterize() -> void { signed width = 0; signed height = 0; - if(mode == Mode::Color || mode == Mode::Gradient) { + if(auto& image = state().image) { + width = image.width(); + height = image.height(); + } else { width = pSizable::state().geometry.width(); height = pSizable::state().geometry.height(); - } else { - width = state().size.width(); - height = state().size.height(); } - if(width <= 0 || height <= 0) return; if(width != surfaceWidth || height != surfaceHeight) _release(); @@ -161,33 +153,21 @@ auto pCanvas::_rasterize() -> void { surfaceHeight = height; if(!surface) surface = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, width, height); - uint32_t* buffer = (uint32_t*)gdk_pixbuf_get_pixels(surface); + auto buffer = (uint32_t*)gdk_pixbuf_get_pixels(surface); - if(mode == Mode::Color) { + if(auto& image = state().image) { + memory::copy(buffer, state().image.data(), width * height * sizeof(uint32_t)); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + nall::image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(buffer, fill.data(), fill.size()); + } else { uint32_t color = state().color.value(); for(auto n : range(width * height)) buffer[n] = color; } - if(mode == Mode::Gradient) { - image fill; - fill.allocate(width, height); - fill.gradient( - state().gradient[0].value(), state().gradient[1].value(), state().gradient[2].value(), state().gradient[3].value() - ); - memory::copy(buffer, fill.data(), fill.size()); - } - - if(mode == Mode::Icon) { - auto icon = state().icon; - icon.scale(width, height); - icon.transform(); - memory::copy(buffer, icon.data(), icon.size()); - } - - if(mode == Mode::Data) { - memory::copy(buffer, state().data.data(), state().data.size() * sizeof(uint32_t)); - } - //ARGB -> ABGR conversion for(auto n : range(width * height)) { uint32_t color = *buffer; diff --git a/hiro/gtk/widget/canvas.hpp b/hiro/gtk/widget/canvas.hpp index 5a2a79b3..9b6a93ad 100644 --- a/hiro/gtk/widget/canvas.hpp +++ b/hiro/gtk/widget/canvas.hpp @@ -7,15 +7,12 @@ struct pCanvas : pWidget { auto minimumSize() const -> Size; auto setColor(Color color) -> void; - auto setData(Size size) -> void; auto setDroppable(bool droppable) -> void; auto setGeometry(Geometry geometry) -> void override; - auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void; - auto setIcon(const image& icon) -> void; + auto setGradient(Gradient gradient) -> void; + auto setImage(const Image& image) -> void; auto update() -> void; - enum class Mode : unsigned { Color, Data, Gradient, Icon }; - auto _onExpose(GdkEventExpose* event) -> void; auto _rasterize() -> void; auto _redraw() -> void; @@ -24,7 +21,6 @@ struct pCanvas : pWidget { GdkPixbuf* surface = nullptr; unsigned surfaceWidth = 0; unsigned surfaceHeight = 0; - Mode mode = Mode::Color; }; } diff --git a/hiro/gtk/widget/check-button.cpp b/hiro/gtk/widget/check-button.cpp index 3ff37aa9..903b3c21 100644 --- a/hiro/gtk/widget/check-button.cpp +++ b/hiro/gtk/widget/check-button.cpp @@ -12,7 +12,7 @@ auto pCheckButton::construct() -> void { setBordered(state().bordered); setChecked(state().checked); - setIcon(state().icon); + setImage(state().image); setOrientation(state().orientation); setText(state().text); @@ -29,13 +29,13 @@ auto pCheckButton::minimumSize() const -> Size { Size size = pFont::size(self().font(true), state().text); if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(size.height(), state().icon.height())); + size.setWidth(size.width() + state().image.width()); + size.setHeight(max(size.height(), state().image.height())); } if(state().orientation == Orientation::Vertical) { - size.setWidth(max(size.width(), state().icon.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(size.width(), state().image.width())); + size.setHeight(size.height() + state().image.height()); } return {size.width() + 24, size.height() + 12}; @@ -51,9 +51,9 @@ auto pCheckButton::setChecked(bool checked) -> void { unlock(); } -auto pCheckButton::setIcon(const image& icon) -> void { - if(icon) { - GtkImage* gtkImage = CreateImage(icon); +auto pCheckButton::setImage(const Image& image) -> void { + if(image) { + GtkImage* gtkImage = CreateImage(image); gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); } else { gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); diff --git a/hiro/gtk/widget/check-button.hpp b/hiro/gtk/widget/check-button.hpp index 886f4e56..1b6cdf7b 100644 --- a/hiro/gtk/widget/check-button.hpp +++ b/hiro/gtk/widget/check-button.hpp @@ -8,7 +8,7 @@ struct pCheckButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; auto setChecked(bool checked) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; }; diff --git a/hiro/gtk/widget/combo-button-item.cpp b/hiro/gtk/widget/combo-button-item.cpp index 3a54544f..b475be36 100644 --- a/hiro/gtk/widget/combo-button-item.cpp +++ b/hiro/gtk/widget/combo-button-item.cpp @@ -8,11 +8,10 @@ auto pComboButtonItem::construct() -> void { auto pComboButtonItem::destruct() -> void { } -auto pComboButtonItem::setIcon(image icon) -> void { +auto pComboButtonItem::setImage(const Image& image) -> void { if(auto parent = _parent()) { auto size = pFont::size(self().font(true), " ").height(); - if(icon) icon.scale(size, size); - auto pixbuf = CreatePixbuf(icon); + auto pixbuf = CreatePixbuf(image, true); gtk_list_store_set(parent->gtkListStore, >kIter, 0, pixbuf, -1); } } diff --git a/hiro/gtk/widget/combo-button-item.hpp b/hiro/gtk/widget/combo-button-item.hpp index 0ed29bd9..f0c3c5d0 100644 --- a/hiro/gtk/widget/combo-button-item.hpp +++ b/hiro/gtk/widget/combo-button-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pComboButtonItem : pObject { Declare(ComboButtonItem, Object) - auto setIcon(image icon) -> void; + auto setImage(const Image& icon) -> void; auto setSelected() -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/combo-button.cpp b/hiro/gtk/widget/combo-button.cpp index 08eebddd..1a93f2be 100644 --- a/hiro/gtk/widget/combo-button.cpp +++ b/hiro/gtk/widget/combo-button.cpp @@ -32,7 +32,7 @@ auto pComboButton::append(sComboButtonItem item) -> void { lock(); if(auto self = item->self()) { gtk_list_store_append(gtkListStore, &self->gtkIter); - self->setIcon(item->state.icon); + self->setImage(item->state.image); if(item->state.selected) self->setSelected(); self->setText(item->state.text); } @@ -41,11 +41,11 @@ auto pComboButton::append(sComboButtonItem item) -> void { } auto pComboButton::minimumSize() const -> Size { - string font = self().font(true); + auto font = self().font(true); signed maximumWidth = 0; for(auto& item : state().items) { maximumWidth = max(maximumWidth, - (item->state.icon ? pFont::size(font, " ").height() + 2 : 0) + (item->state.image ? pFont::size(font, " ").height() + 2 : 0) + pFont::size(font, item->state.text).width() ); } @@ -69,7 +69,7 @@ auto pComboButton::reset() -> void { unlock(); } -auto pComboButton::setFont(const string& font) -> void { +auto pComboButton::setFont(const Font& font) -> void { pWidget::setFont(font); auto fontDescription = pFont::create(font); g_object_set(G_OBJECT(gtkCellText), "font-desc", fontDescription, nullptr); diff --git a/hiro/gtk/widget/combo-button.hpp b/hiro/gtk/widget/combo-button.hpp index ae36b7f4..a81470e6 100644 --- a/hiro/gtk/widget/combo-button.hpp +++ b/hiro/gtk/widget/combo-button.hpp @@ -9,7 +9,7 @@ struct pComboButton : pWidget { auto minimumSize() const -> Size override; auto remove(sComboButtonItem item) -> void; auto reset() -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto _updateSelected() -> void; diff --git a/hiro/gtk/widget/frame.cpp b/hiro/gtk/widget/frame.cpp index 2d8c603c..e07f2a67 100644 --- a/hiro/gtk/widget/frame.cpp +++ b/hiro/gtk/widget/frame.cpp @@ -33,7 +33,7 @@ auto pFrame::setEnabled(bool enabled) -> void { pWidget::setEnabled(enabled); } -auto pFrame::setFont(const string& font) -> void { +auto pFrame::setFont(const Font& font) -> void { if(auto layout = _layout()) layout->setFont(layout->self().font(true)); pFont::setFont(gtkLabel, font); } diff --git a/hiro/gtk/widget/frame.hpp b/hiro/gtk/widget/frame.hpp index bdc09626..71f49004 100644 --- a/hiro/gtk/widget/frame.hpp +++ b/hiro/gtk/widget/frame.hpp @@ -9,7 +9,7 @@ struct pFrame : pWidget { auto container(mWidget& widget) -> GtkWidget* override; auto remove(shared_pointer layout) -> void; auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setGeometry(Geometry geometry) -> void override; auto setText(const string& text) -> void; auto setVisible(bool visible) -> void override; diff --git a/hiro/gtk/widget/icon-view-item.cpp b/hiro/gtk/widget/icon-view-item.cpp index 48081e86..2b766efc 100644 --- a/hiro/gtk/widget/icon-view-item.cpp +++ b/hiro/gtk/widget/icon-view-item.cpp @@ -8,9 +8,9 @@ auto pIconViewItem::construct() -> void { auto pIconViewItem::destruct() -> void { } -auto pIconViewItem::setIcon(const image& icon) -> void { +auto pIconViewItem::setImage(const Image& image) -> void { if(auto parent = _parent()) { - parent->setItemIcon(self().offset(), icon); + parent->setItemImage(self().offset(), image); } } diff --git a/hiro/gtk/widget/icon-view-item.hpp b/hiro/gtk/widget/icon-view-item.hpp index e4060110..a386069a 100644 --- a/hiro/gtk/widget/icon-view-item.hpp +++ b/hiro/gtk/widget/icon-view-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pIconViewItem : pObject { Declare(IconViewItem, Object) - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setSelected(bool selected) -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/icon-view.cpp b/hiro/gtk/widget/icon-view.cpp index f4d6bcdd..2fd3419f 100644 --- a/hiro/gtk/widget/icon-view.cpp +++ b/hiro/gtk/widget/icon-view.cpp @@ -39,9 +39,9 @@ auto pIconView::construct() -> void { gtk_widget_show(subWidget); setBackgroundColor(state().backgroundColor); + setBatchable(state().batchable); setFlow(state().flow); setForegroundColor(state().foregroundColor); - setMultiSelect(state().multiSelect); setOrientation(state().orientation); for(auto position : range(self().items())) { auto& item = state().items[position]; @@ -65,7 +65,7 @@ auto pIconView::destruct() -> void { auto pIconView::append(sIconViewItem item) -> void { GtkTreeIter iter; gtk_list_store_append(store, &iter); - setItemIcon(item->offset(), item->state.icon); + setItemImage(item->offset(), item->state.image); setItemSelected(item->offset(), item->state.selected); setItemText(item->offset(), item->state.text); } @@ -92,6 +92,12 @@ auto pIconView::setBackgroundColor(Color color) -> void { gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } +auto pIconView::setBatchable(bool batchable) -> void { + gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(subWidget), + batchable ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE + ); +} + auto pIconView::setFlow(Orientation flow) -> void { //GTK+ does not support vertical flow ... the closest we can get is a horizontal flow with only one column if(flow == Orientation::Horizontal) { @@ -115,12 +121,12 @@ auto pIconView::setGeometry(Geometry geometry) -> void { } } -auto pIconView::setItemIcon(unsigned position, const image& icon) -> void { +auto pIconView::setItemImage(unsigned position, const Image& image) -> void { if(position >= self().itemCount()) return; GtkTreeIter iter; if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) { - if(icon) { - GdkPixbuf* pixbuf = CreatePixbuf(icon); + if(image) { + GdkPixbuf* pixbuf = CreatePixbuf(image); gtk_list_store_set(store, &iter, 0, pixbuf, -1); } else { gtk_list_store_set(store, &iter, 0, nullptr, -1); @@ -172,12 +178,6 @@ auto pIconView::setItemText(unsigned position, const string& text) -> void { } } -auto pIconView::setMultiSelect(bool multiSelect) -> void { - gtk_icon_view_set_selection_mode(GTK_ICON_VIEW(subWidget), - multiSelect ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE - ); -} - auto pIconView::setOrientation(Orientation orientation) -> void { gtk_icon_view_set_item_orientation(GTK_ICON_VIEW(subWidget), orientation == Orientation::Horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL diff --git a/hiro/gtk/widget/icon-view.hpp b/hiro/gtk/widget/icon-view.hpp index 0be21b83..58923c21 100644 --- a/hiro/gtk/widget/icon-view.hpp +++ b/hiro/gtk/widget/icon-view.hpp @@ -9,16 +9,16 @@ struct pIconView : pWidget { auto remove(sIconViewItem item) -> void; auto reset() -> void; auto setBackgroundColor(Color color) -> void; + auto setBatchable(bool batchable) -> void; auto setFlow(Orientation flow) -> void; auto setForegroundColor(Color color) -> void; auto setGeometry(Geometry geometry) -> void; - auto setItemIcon(unsigned position, const image& icon) -> void; + auto setItemImage(unsigned position, const Image& image) -> void; auto setItemSelected(unsigned position, bool selected) -> void; auto setItemSelected(const vector& selections) -> void; auto setItemSelectedAll() -> void; auto setItemSelectedNone() -> void; auto setItemText(unsigned position, const string& text) -> void; - auto setMultiSelect(bool multiSelect) -> void; auto setOrientation(Orientation orientation) -> void; auto _updateSelected() -> void; diff --git a/hiro/gtk/widget/list-view-cell.cpp b/hiro/gtk/widget/list-view-cell.cpp index 94e22bcc..507d0341 100644 --- a/hiro/gtk/widget/list-view-cell.cpp +++ b/hiro/gtk/widget/list-view-cell.cpp @@ -25,7 +25,7 @@ auto pListViewCell::setChecked(bool checked) -> void { auto pListViewCell::setForegroundColor(Color color) -> void { } -auto pListViewCell::setIcon(const image& icon) -> void { +auto pListViewCell::setImage(const Image& image) -> void { _setState(); } @@ -50,7 +50,7 @@ auto pListViewCell::_setState() -> void { if(auto grandparent = _grandparent()) { grandparent->lock(); gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 0, state().checked, -1); - gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 1, CreatePixbuf(state().icon), -1); + gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 1, CreatePixbuf(state().image), -1); gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 2, state().text.data(), -1); grandparent->unlock(); } diff --git a/hiro/gtk/widget/list-view-cell.hpp b/hiro/gtk/widget/list-view-cell.hpp index 2fd00821..3587d44f 100644 --- a/hiro/gtk/widget/list-view-cell.hpp +++ b/hiro/gtk/widget/list-view-cell.hpp @@ -10,7 +10,7 @@ struct pListViewCell : pObject { auto setCheckable(bool checkable) -> void; auto setChecked(bool checked) -> void; auto setForegroundColor(Color color) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto _grandparent() -> maybe; diff --git a/hiro/gtk/widget/list-view-column.cpp b/hiro/gtk/widget/list-view-column.cpp index 4ea0436f..8a984495 100644 --- a/hiro/gtk/widget/list-view-column.cpp +++ b/hiro/gtk/widget/list-view-column.cpp @@ -75,15 +75,15 @@ auto pListViewColumn::setExpandable(bool expandable) -> void { } } -auto pListViewColumn::setFont(const string& font) -> void { +auto pListViewColumn::setFont(const Font& font) -> void { } auto pListViewColumn::setForegroundColor(Color color) -> void { } -auto pListViewColumn::setIcon(const image& icon) -> void { - if(icon) { - gtk_image_set_from_pixbuf(GTK_IMAGE(gtkHeaderIcon), CreatePixbuf(icon)); +auto pListViewColumn::setImage(const Image& image) -> void { + if(image) { + gtk_image_set_from_pixbuf(GTK_IMAGE(gtkHeaderIcon), CreatePixbuf(image)); } else { gtk_image_clear(GTK_IMAGE(gtkHeaderIcon)); } diff --git a/hiro/gtk/widget/list-view-column.hpp b/hiro/gtk/widget/list-view-column.hpp index 2e2d37ee..1c58fb85 100644 --- a/hiro/gtk/widget/list-view-column.hpp +++ b/hiro/gtk/widget/list-view-column.hpp @@ -10,10 +10,10 @@ struct pListViewColumn : pObject { auto setBackgroundColor(Color color) -> void; auto setEditable(bool editable) -> void; auto setExpandable(bool expandable) -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setForegroundColor(Color color) -> void; auto setHorizontalAlignment(double) -> void {} - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setResizable(bool resizable) -> void; auto setSortable(bool sortable) -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/list-view.cpp b/hiro/gtk/widget/list-view.cpp index f2bd8ec3..9bc1b5e5 100644 --- a/hiro/gtk/widget/list-view.cpp +++ b/hiro/gtk/widget/list-view.cpp @@ -122,7 +122,7 @@ auto pListView::setFocused() -> void { gtk_widget_grab_focus(gtkWidgetChild); } -auto pListView::setFont(const string& font) -> void { +auto pListView::setFont(const Font& font) -> void { if(auto& header = state().header) { if(auto self = header->self()) self->_setState(); } @@ -149,11 +149,11 @@ auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned { if(cell->state.checkable) { width += 24; } - if(auto& icon = cell->state.icon) { - width += icon.width() + 2; + if(auto& image = cell->state.image) { + width += image.width() + 2; } if(auto& text = cell->state.text) { - width += Font::size(cell->font(true), text).width(); + width += pFont::size(cell->font(true), text).width(); } } } @@ -164,11 +164,11 @@ auto pListView::_columnWidth(unsigned _column) -> unsigned { unsigned width = 8; if(auto& header = state().header) { if(auto column = header->column(_column)) { - if(auto& icon = column->state.icon) { - width += icon.width() + 2; + if(auto& image = column->state.image) { + width += image.width() + 2; } if(auto& text = column->state.text) { - width += Font::size(column->font(true), text).width(); + width += pFont::size(column->font(true), text).width(); } } } diff --git a/hiro/gtk/widget/list-view.hpp b/hiro/gtk/widget/list-view.hpp index d87cc3bd..1df15dfb 100644 --- a/hiro/gtk/widget/list-view.hpp +++ b/hiro/gtk/widget/list-view.hpp @@ -16,7 +16,7 @@ struct pListView : pWidget { auto setBatchable(bool batchable) -> void; auto setBordered(bool bordered) -> void; auto setFocused() -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setForegroundColor(Color color) -> void; auto setGeometry(Geometry geometry) -> void override; diff --git a/hiro/gtk/widget/radio-button.cpp b/hiro/gtk/widget/radio-button.cpp index 74a5d0f8..9cdd8063 100644 --- a/hiro/gtk/widget/radio-button.cpp +++ b/hiro/gtk/widget/radio-button.cpp @@ -5,7 +5,7 @@ namespace hiro { static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void { if(p->groupLocked()) return; bool wasChecked = p->state().checked; - p->setChecked(); + p->self().setChecked(); if(!wasChecked) p->self().doActivate(); } @@ -13,7 +13,7 @@ auto pRadioButton::construct() -> void { gtkWidget = gtk_toggle_button_new(); setBordered(state().bordered); - setIcon(state().icon); + setImage(state().image); setOrientation(state().orientation); setText(state().text); @@ -30,13 +30,13 @@ auto pRadioButton::minimumSize() const -> Size { Size size = pFont::size(self().font(true), state().text); if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(size.height(), state().icon.height())); + size.setWidth(size.width() + state().image.width()); + size.setHeight(max(size.height(), state().image.height())); } if(state().orientation == Orientation::Vertical) { - size.setWidth(max(size.width(), state().icon.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(size.width(), state().image.width())); + size.setHeight(size.height() + state().image.height()); } return {size.width() + 24, size.height() + 12}; @@ -47,14 +47,12 @@ auto pRadioButton::setBordered(bool bordered) -> void { } auto pRadioButton::setChecked() -> void { - if(!self().group()) return; for(auto& weak : self().group()->state.objects) { if(auto object = weak.acquire()) { if(auto radioButton = dynamic_cast(object.data())) { if(auto self = radioButton->self()) { self->lock(); - bool checked = self == this; - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked = checked); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked); self->unlock(); } } @@ -63,13 +61,14 @@ auto pRadioButton::setChecked() -> void { } auto pRadioButton::setGroup(sGroup group) -> void { - if(!group) return; + bool first = true; for(auto& weak : group->state.objects) { if(auto object = weak.acquire()) { if(auto radioButton = dynamic_cast(object.data())) { if(auto self = radioButton->self()) { self->lock(); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->checked()); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked = first); + first = false; self->unlock(); } } @@ -77,9 +76,9 @@ auto pRadioButton::setGroup(sGroup group) -> void { } } -auto pRadioButton::setIcon(const image& icon) -> void { - if(icon) { - GtkImage* gtkImage = CreateImage(icon); +auto pRadioButton::setImage(const Image& image) -> void { + if(image) { + GtkImage* gtkImage = CreateImage(image); gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); } else { gtk_button_set_image(GTK_BUTTON(gtkWidget), nullptr); diff --git a/hiro/gtk/widget/radio-button.hpp b/hiro/gtk/widget/radio-button.hpp index 2be014dd..f1e77ead 100644 --- a/hiro/gtk/widget/radio-button.hpp +++ b/hiro/gtk/widget/radio-button.hpp @@ -9,7 +9,7 @@ struct pRadioButton : pWidget { auto setBordered(bool bordered) -> void; auto setChecked() -> void; auto setGroup(sGroup group) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/radio-label.cpp b/hiro/gtk/widget/radio-label.cpp index 9681cd29..89d6b6cd 100644 --- a/hiro/gtk/widget/radio-label.cpp +++ b/hiro/gtk/widget/radio-label.cpp @@ -5,7 +5,7 @@ namespace hiro { static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void { if(p->groupLocked()) return; bool wasChecked = p->state().checked; - p->setChecked(); + p->self().setChecked(); if(!wasChecked) p->self().doActivate(); } @@ -37,8 +37,6 @@ auto pRadioLabel::setChecked() -> void { } auto pRadioLabel::setGroup(sGroup group) -> void { - if(!group) return; - maybe gtkRadioButton; for(auto& weak : group->state.objects) { if(auto object = weak.acquire()) { @@ -46,9 +44,13 @@ auto pRadioLabel::setGroup(sGroup group) -> void { if(auto self = radioLabel->self()) { self->lock(); gtk_radio_button_set_group(self->gtkRadioButton, nullptr); - if(!gtkRadioButton) gtkRadioButton = self->gtkRadioButton; - else gtk_radio_button_set_group(self->gtkRadioButton, gtk_radio_button_get_group(*gtkRadioButton)); - gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->checked()); + if(!gtkRadioButton) { + gtkRadioButton = self->gtkRadioButton; + gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->state.checked = true); + } else { + gtk_radio_button_set_group(self->gtkRadioButton, gtk_radio_button_get_group(*gtkRadioButton)); + gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->state.checked = false); + } self->unlock(); } } diff --git a/hiro/gtk/widget/source-edit.cpp b/hiro/gtk/widget/source-edit.cpp index 186c2e12..b1a6fd0d 100644 --- a/hiro/gtk/widget/source-edit.cpp +++ b/hiro/gtk/widget/source-edit.cpp @@ -7,11 +7,11 @@ static auto SourceEdit_change(GtkTextBuffer*, pSourceEdit* p) -> void { } static auto SourceEdit_move(GObject*, GParamSpec*, pSourceEdit* p) -> void { - signed position = 0; - g_object_get(G_OBJECT(p->gtkSourceBuffer), "cursor-position", &position, nullptr); + signed offset = 0; + g_object_get(G_OBJECT(p->gtkSourceBuffer), "cursor-position", &offset, nullptr); - if(p->state().position != position) { - p->state().position = position; + if(p->state().cursor.offset() != offset) { + p->state().cursor.setOffset(offset); if(!p->locked()) p->self().doMove(); } } @@ -68,10 +68,25 @@ auto pSourceEdit::destruct() -> void { gtk_widget_destroy(gtkWidget); } +auto pSourceEdit::setCursor(Cursor cursor) -> void { + lock(); + GtkTextIter offset, length; + gtk_text_buffer_get_end_iter(gtkTextBuffer, &offset); + gtk_text_buffer_get_end_iter(gtkTextBuffer, &length); + signed end = gtk_text_iter_get_offset(&offset); + gtk_text_iter_set_offset(&offset, max(0, min(end, cursor.offset()))); + gtk_text_iter_set_offset(&length, max(0, min(end, cursor.offset() + cursor.length()))); + gtk_text_buffer_select_range(gtkTextBuffer, &offset, &length); + auto mark = gtk_text_buffer_get_mark(gtkTextBuffer, "insert"); + gtk_text_view_scroll_mark_onscreen(gtkTextView, mark); + unlock(); +} + auto pSourceEdit::setFocused() -> void { gtk_widget_grab_focus(gtkWidgetSourceView); } +/* auto pSourceEdit::setPosition(signed position) -> void { lock(); GtkTextIter iter; @@ -105,6 +120,7 @@ auto pSourceEdit::setSelected(Position selected) -> void { gtk_text_buffer_select_range(gtkTextBuffer, &startIter, &endIter); unlock(); } +*/ auto pSourceEdit::setText(const string& text) -> void { lock(); diff --git a/hiro/gtk/widget/source-edit.hpp b/hiro/gtk/widget/source-edit.hpp index 2caf3cd1..f8923187 100644 --- a/hiro/gtk/widget/source-edit.hpp +++ b/hiro/gtk/widget/source-edit.hpp @@ -5,9 +5,8 @@ namespace hiro { struct pSourceEdit : pWidget { Declare(SourceEdit, Widget) + auto setCursor(Cursor cursor) -> void; auto setFocused() -> void override; - auto setPosition(signed position) -> void; - auto setSelected(Position selected) -> void; auto setText(const string& text) -> void; auto text() const -> string; diff --git a/hiro/gtk/widget/tab-frame-item.cpp b/hiro/gtk/widget/tab-frame-item.cpp index 3b8f548b..f9ae429b 100644 --- a/hiro/gtk/widget/tab-frame-item.cpp +++ b/hiro/gtk/widget/tab-frame-item.cpp @@ -22,9 +22,9 @@ auto pTabFrameItem::setClosable(bool closable) -> void { } } -auto pTabFrameItem::setIcon(const image& icon) -> void { +auto pTabFrameItem::setImage(const Image& image) -> void { if(auto parent = _parent()) { - parent->setItemIcon(self().offset(), icon); + parent->setItemImage(self().offset(), image); } } diff --git a/hiro/gtk/widget/tab-frame-item.hpp b/hiro/gtk/widget/tab-frame-item.hpp index 495555b0..b2cb4417 100644 --- a/hiro/gtk/widget/tab-frame-item.hpp +++ b/hiro/gtk/widget/tab-frame-item.hpp @@ -8,7 +8,7 @@ struct pTabFrameItem : pObject { auto append(sLayout layout) -> void; auto remove(sLayout layout) -> void; auto setClosable(bool closable) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setMovable(bool movable) -> void; auto setSelected() -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/tab-frame.cpp b/hiro/gtk/widget/tab-frame.cpp index ffc12a9d..2cdbfd0b 100644 --- a/hiro/gtk/widget/tab-frame.cpp +++ b/hiro/gtk/widget/tab-frame.cpp @@ -49,7 +49,7 @@ auto pTabFrame::construct() -> void { tabs.reset(); //todo: memory leak, need to release each tab for(auto& item : state().items) append(item); - setEdge(state().edge); + setNavigation(state().navigation); g_signal_connect(G_OBJECT(gtkWidget), "page-reordered", G_CALLBACK(TabFrame_move), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "switch-page", G_CALLBACK(TabFrame_change), (gpointer)this); @@ -72,7 +72,7 @@ auto pTabFrame::append(sTabFrameItem item) -> void { tab.close = gtk_button_new_with_label("\u00d7"); //Unicode multiplication sign (looks better than 'X') gtk_button_set_focus_on_click(GTK_BUTTON(tab.close), false); gtk_button_set_relief(GTK_BUTTON(tab.close), GTK_RELIEF_NONE); - pFont::setFont(tab.close, Font::sans(9, "Bold")); + pFont::setFont(tab.close, Font("sans", 9).setBold()); auto color = CreateColor({255, 0, 0}); gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(tab.close)), GTK_STATE_PRELIGHT, &color); tabs.append(tab); @@ -140,18 +140,6 @@ auto pTabFrame::remove(sTabFrameItem item) -> void { unlock(); } -auto pTabFrame::setEdge(Edge edge) -> void { - GtkPositionType type; - switch(edge) { default: - case Edge::Top: type = GTK_POS_TOP; break; - case Edge::Bottom: type = GTK_POS_BOTTOM; break; - case Edge::Left: type = GTK_POS_LEFT; break; - case Edge::Right: type = GTK_POS_RIGHT; break; - } - gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkWidget), type); - setGeometry(self().geometry()); -} - auto pTabFrame::setEnabled(bool enabled) -> void { for(auto& item : state().items) { if(auto layout = item->state.layout) { @@ -161,7 +149,7 @@ auto pTabFrame::setEnabled(bool enabled) -> void { pWidget::setEnabled(enabled); } -auto pTabFrame::setFont(const string& font) -> void { +auto pTabFrame::setFont(const Font& font) -> void { for(auto n : range(tabs.size())) { pFont::setFont(tabs[n].title, font); if(auto layout = state().items[n]->state.layout) { @@ -174,7 +162,7 @@ auto pTabFrame::setGeometry(Geometry geometry) -> void { pWidget::setGeometry(geometry); geometry.setPosition(0, 0); - if(state().edge == Edge::Top || state().edge == Edge::Bottom) { + if(state().navigation == Navigation::Top || state().navigation == Navigation::Bottom) { geometry.setWidth(geometry.width() - 6); geometry.setHeight(geometry.height() - (15 + _tabHeight())); } else { @@ -190,7 +178,7 @@ auto pTabFrame::setItemClosable(unsigned position, bool closable) -> void { _synchronizeTab(position); } -auto pTabFrame::setItemIcon(unsigned position, const image& icon) -> void { +auto pTabFrame::setItemImage(unsigned position, const Image& image) -> void { _synchronizeTab(position); } @@ -214,6 +202,18 @@ auto pTabFrame::setItemText(unsigned position, const string& text) -> void { _synchronizeTab(position); } +auto pTabFrame::setNavigation(Navigation navigation) -> void { + GtkPositionType type; + switch(navigation) { default: + case Navigation::Top: type = GTK_POS_TOP; break; + case Navigation::Bottom: type = GTK_POS_BOTTOM; break; + case Navigation::Left: type = GTK_POS_LEFT; break; + case Navigation::Right: type = GTK_POS_RIGHT; break; + } + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkWidget), type); + setGeometry(self().geometry()); +} + auto pTabFrame::setVisible(bool visible) -> void { for(auto& item : state().items) { if(auto layout = item->state.layout) { @@ -239,16 +239,15 @@ auto pTabFrame::_synchronizeTab(unsigned position) -> void { auto& item = state().items[position]; auto& tab = tabs[position]; gtk_widget_set_visible(tab.close, item->closable()); - if(auto copy = item->state.icon) { + if(auto& image = item->state.image) { unsigned size = pFont::size(self().font(true), " ").height(); - copy.scale(size, size); - auto pixbuf = CreatePixbuf(copy); + auto pixbuf = CreatePixbuf(image, true); gtk_image_set_from_pixbuf(GTK_IMAGE(tab.image), pixbuf); } else { gtk_image_clear(GTK_IMAGE(tab.image)); } string text = { - item->state.icon && item->state.text ? " " : "", + item->state.image && item->state.text ? " " : "", item->state.text, item->state.text && item->state.closable ? " " : "" }; diff --git a/hiro/gtk/widget/tab-frame.hpp b/hiro/gtk/widget/tab-frame.hpp index f6392033..07d41d3f 100644 --- a/hiro/gtk/widget/tab-frame.hpp +++ b/hiro/gtk/widget/tab-frame.hpp @@ -8,16 +8,16 @@ struct pTabFrame : pWidget { auto append(sTabFrameItem item) -> void; auto container(mWidget& widget) -> GtkWidget* override; auto remove(sTabFrameItem item) -> void; - auto setEdge(Edge edge) -> void; auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setGeometry(Geometry geometry) -> void override; auto setItemClosable(unsigned position, bool closable) -> void; - auto setItemIcon(unsigned position, const image& icon) -> void; + auto setItemImage(unsigned position, const Image& image) -> void; auto setItemLayout(unsigned position, sLayout layout) -> void; auto setItemMovable(unsigned position, bool movable) -> void; auto setItemSelected(unsigned position) -> void; auto setItemText(unsigned position, const string& text) -> void; + auto setNavigation(Navigation navigation) -> void; auto setVisible(bool visible) -> void override; auto _append(shared_pointer item) -> void; diff --git a/hiro/gtk/widget/text-edit.cpp b/hiro/gtk/widget/text-edit.cpp index 46c0fd11..7e6c4e38 100644 --- a/hiro/gtk/widget/text-edit.cpp +++ b/hiro/gtk/widget/text-edit.cpp @@ -7,11 +7,11 @@ static auto TextEdit_change(GtkTextBuffer* textBuffer, pTextEdit* p) -> void { } static auto TextEdit_move(GObject* object, GParamSpec* spec, pTextEdit* p) -> void { - int position = 0; - g_object_get(p->textBuffer, "cursor-position", &position, nullptr); + signed offset = 0; + g_object_get(p->textBuffer, "cursor-position", &offset, nullptr); - if(p->state().cursorPosition != position) { - p->state().cursorPosition = position; + if(p->state().cursor.offset() != offset) { + p->state().cursor.setOffset(offset); if(!p->locked()) p->self().doMove(); } } @@ -33,6 +33,7 @@ auto pTextEdit::construct() -> void { setForegroundColor(state().foregroundColor); setText(state().text); setWordWrap(state().wordWrap); + setCursor(state().cursor); g_signal_connect(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)this); g_signal_connect(G_OBJECT(textBuffer), "notify::cursor-position", G_CALLBACK(TextEdit_move), (gpointer)this); @@ -55,13 +56,16 @@ auto pTextEdit::setBackgroundColor(Color color) -> void { gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } -auto pTextEdit::setCursorPosition(unsigned position) -> void { +auto pTextEdit::setCursor(Cursor cursor) -> void { lock(); - GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); - GtkTextIter iter; - gtk_text_buffer_get_end_iter(textBuffer, &iter); - gtk_text_iter_set_offset(&iter, min(position, gtk_text_iter_get_offset(&iter))); - gtk_text_buffer_place_cursor(textBuffer, &iter); + GtkTextIter offset, length; + gtk_text_buffer_get_end_iter(textBuffer, &offset); + gtk_text_buffer_get_end_iter(textBuffer, &length); + signed end = gtk_text_iter_get_offset(&offset); + gtk_text_iter_set_offset(&offset, max(0, min(end, cursor.offset()))); + gtk_text_iter_set_offset(&length, max(0, min(end, cursor.offset() + cursor.length()))); + gtk_text_buffer_select_range(textBuffer, &offset, &length); + auto mark = gtk_text_buffer_get_mark(textBuffer, "insert"); gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); unlock(); } @@ -70,6 +74,10 @@ auto pTextEdit::setEditable(bool editable) -> void { gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), editable); } +auto pTextEdit::setFocused() -> void { + gtk_widget_grab_focus(subWidget); +} + auto pTextEdit::setForegroundColor(Color color) -> void { GdkColor gdkColor = CreateColor(color); gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); diff --git a/hiro/gtk/widget/text-edit.hpp b/hiro/gtk/widget/text-edit.hpp index 92a22dc6..4bb7e1fe 100644 --- a/hiro/gtk/widget/text-edit.hpp +++ b/hiro/gtk/widget/text-edit.hpp @@ -7,8 +7,9 @@ struct pTextEdit : pWidget { auto focused() const -> bool override; auto setBackgroundColor(Color color) -> void; - auto setCursorPosition(unsigned position) -> void; + auto setCursor(Cursor cursor) -> void; auto setEditable(bool editable) -> void; + auto setFocused() -> void override; auto setForegroundColor(Color color) -> void; auto setText(const string& text) -> void; auto setWordWrap(bool wordWrap) -> void; diff --git a/hiro/gtk/widget/tree-view-item.cpp b/hiro/gtk/widget/tree-view-item.cpp index f66912a4..00042970 100644 --- a/hiro/gtk/widget/tree-view-item.cpp +++ b/hiro/gtk/widget/tree-view-item.cpp @@ -3,26 +3,36 @@ namespace hiro { auto pTreeViewItem::construct() -> void { + if(auto parentWidget = _parentWidget()) { + if(auto parentItem = _parentItem()) { + gtk_tree_store_append(parentWidget->gtkTreeStore, >kIter, &parentItem->gtkIter); + } else { + gtk_tree_store_append(parentWidget->gtkTreeStore, >kIter, nullptr); + } + setChecked(state().checked); + setImage(state().image); + setText(state().text); + } } auto pTreeViewItem::destruct() -> void { + if(auto parent = _parentWidget()) { + gtk_tree_store_remove(parent->gtkTreeStore, >kIter); + } } // auto pTreeViewItem::append(sTreeViewItem item) -> void { - if(auto parentWidget = _parentWidget()) { - gtk_tree_store_append(parentWidget->gtkTreeStore, &item->self()->gtkIter, >kIter); - item->setChecked(item->checked()); - item->setIcon(item->icon()); - item->setText(item->text()); - } } auto pTreeViewItem::remove(sTreeViewItem item) -> void { - if(auto parentWidget = _parentWidget()) { - gtk_tree_store_remove(parentWidget->gtkTreeStore, &item->self()->gtkIter); - } +} + +auto pTreeViewItem::setBackgroundColor(Color color) -> void { +} + +auto pTreeViewItem::setCheckable(bool checkable) -> void { } auto pTreeViewItem::setChecked(bool checked) -> void { @@ -31,6 +41,18 @@ auto pTreeViewItem::setChecked(bool checked) -> void { } } +auto pTreeViewItem::setExpanded(bool expanded) -> void { + if(auto parentWidget = _parentWidget()) { + auto path = gtk_tree_model_get_path(parentWidget->gtkTreeModel, >kIter); + if(expanded) { + gtk_tree_view_expand_row(parentWidget->gtkTreeView, path, false); + } else { + gtk_tree_view_collapse_row(parentWidget->gtkTreeView, path); + } + gtk_tree_path_free(path); + } +} + auto pTreeViewItem::setFocused() -> void { if(auto parentWidget = _parentWidget()) { GtkTreePath* path = gtk_tree_path_new_from_string(self().path().transform("/", ":")); @@ -40,10 +62,13 @@ auto pTreeViewItem::setFocused() -> void { } } -auto pTreeViewItem::setIcon(const image& icon) -> void { +auto pTreeViewItem::setForegroundColor(Color color) -> void { +} + +auto pTreeViewItem::setImage(const Image& image) -> void { if(auto parentWidget = _parentWidget()) { - if(icon) { - auto pixbuf = CreatePixbuf(icon, true); + if(image) { + auto pixbuf = CreatePixbuf(image); gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 1, pixbuf, -1); } else { gtk_tree_store_set(parentWidget->gtkTreeStore, >kIter, 1, nullptr, -1); diff --git a/hiro/gtk/widget/tree-view-item.hpp b/hiro/gtk/widget/tree-view-item.hpp index a6a08b64..775f4bc5 100644 --- a/hiro/gtk/widget/tree-view-item.hpp +++ b/hiro/gtk/widget/tree-view-item.hpp @@ -7,9 +7,13 @@ struct pTreeViewItem : pObject { auto append(sTreeViewItem item) -> void; auto remove(sTreeViewItem item) -> void; + auto setBackgroundColor(Color color) -> void; + auto setCheckable(bool checkable) -> void; auto setChecked(bool checked) -> void; + auto setExpanded(bool expanded) -> void; auto setFocused() -> void; - auto setIcon(const image& icon) -> void; + auto setForegroundColor(Color color) -> void; + auto setImage(const Image& image) -> void; auto setSelected() -> void; auto setText(const string& text) -> void; diff --git a/hiro/gtk/widget/tree-view.cpp b/hiro/gtk/widget/tree-view.cpp index f1cc2f0b..7649e482 100644 --- a/hiro/gtk/widget/tree-view.cpp +++ b/hiro/gtk/widget/tree-view.cpp @@ -2,10 +2,14 @@ namespace hiro { +//gtk_tree_view_collapse_all(gtkTreeView); +//gtk_tree_view_expand_all(gtkTreeView); + static auto TreeView_activate(GtkTreeView*, GtkTreePath* gtkPath, GtkTreeViewColumn*, pTreeView* p) -> void { p->_activatePath(gtkPath); } static auto TreeView_buttonEvent(GtkTreeView*, GdkEventButton* gdkEvent, pTreeView* p) -> signed { return p->_buttonEvent(gdkEvent); } static auto TreeView_change(GtkTreeSelection*, pTreeView* p) -> void { p->_updateSelected(); } static auto TreeView_context(GtkTreeView*, pTreeView* p) -> void { p->self().doContext(); } +static auto TreeView_dataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pTreeView* p) -> void { return p->_doDataFunc(column, renderer, iter); } static auto TreeView_toggle(GtkCellRendererToggle*, char* path, pTreeView* p) -> void { p->_togglePath(path); } auto pTreeView::construct() -> void { @@ -29,15 +33,17 @@ auto pTreeView::construct() -> void { gtkCellToggle = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(gtkTreeViewColumn, gtkCellToggle, false); gtk_tree_view_column_set_attributes(gtkTreeViewColumn, gtkCellToggle, "active", 0, nullptr); - gtk_cell_renderer_set_visible(gtkCellToggle, state().checkable); + gtk_tree_view_column_set_cell_data_func(gtkTreeViewColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)TreeView_dataFunc, (gpointer)this, nullptr); gtkCellPixbuf = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(gtkTreeViewColumn, gtkCellPixbuf, false); gtk_tree_view_column_set_attributes(gtkTreeViewColumn, gtkCellPixbuf, "pixbuf", 1, nullptr); + gtk_tree_view_column_set_cell_data_func(gtkTreeViewColumn, GTK_CELL_RENDERER(gtkCellPixbuf), (GtkTreeCellDataFunc)TreeView_dataFunc, (gpointer)this, nullptr); gtkCellText = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(gtkTreeViewColumn, gtkCellText, true); gtk_tree_view_column_set_attributes(gtkTreeViewColumn, gtkCellText, "text", 2, nullptr); + gtk_tree_view_column_set_cell_data_func(gtkTreeViewColumn, GTK_CELL_RENDERER(gtkCellText), (GtkTreeCellDataFunc)TreeView_dataFunc, (gpointer)this, nullptr); gtk_tree_view_append_column(gtkTreeView, gtkTreeViewColumn); gtk_tree_view_set_search_column(gtkTreeView, 2); @@ -63,29 +69,9 @@ auto pTreeView::destruct() -> void { // auto pTreeView::append(sTreeViewItem item) -> void { - gtk_tree_store_append(gtkTreeStore, &item->self()->gtkIter, nullptr); - item->setChecked(item->checked()); - item->setIcon(item->icon()); - item->setText(item->text()); -} - -auto pTreeView::collapse() -> void { - gtk_tree_view_collapse_all(gtkTreeView); -} - -auto pTreeView::expand() -> void { - gtk_tree_view_expand_all(gtkTreeView); } auto pTreeView::remove(sTreeViewItem item) -> void { - gtk_tree_store_remove(gtkTreeStore, &item->self()->gtkIter); -} - -auto pTreeView::reset() -> void { - gtk_tree_view_set_model(gtkTreeView, nullptr); - gtkTreeStore = gtk_tree_store_new(3, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING); - gtkTreeModel = GTK_TREE_MODEL(gtkTreeStore); - gtk_tree_view_set_model(gtkTreeView, gtkTreeModel); } auto pTreeView::setBackgroundColor(Color color) -> void { @@ -93,10 +79,6 @@ auto pTreeView::setBackgroundColor(Color color) -> void { gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } -auto pTreeView::setCheckable(bool checkable) -> void { - gtk_cell_renderer_set_visible(gtkCellToggle, checkable); -} - auto pTreeView::setForegroundColor(Color color) -> void { auto gdkColor = CreateColor(color); gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); @@ -136,6 +118,41 @@ auto pTreeView::_buttonEvent(GdkEventButton* gdkEvent) -> signed { return false; } +auto pTreeView::_doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void { + auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter); + auto parts = string{path}.split(":"); + g_free(path); + + auto item = self().item(decimal(parts.takeFirst())); + if(!item) return; + while(parts) { + item = item.item(decimal(parts.takeFirst())); + if(!item) return; + } + + if(renderer == GTK_CELL_RENDERER(gtkCellToggle)) { + gtk_cell_renderer_set_visible(renderer, item->state.checkable); + } else if(renderer == GTK_CELL_RENDERER(gtkCellPixbuf)) { + gtk_cell_renderer_set_visible(renderer, (bool)item->state.image); + } else if(renderer == GTK_CELL_RENDERER(gtkCellText)) { + auto font = pFont::create(item->font(true)); + g_object_set(G_OBJECT(renderer), "font-desc", font, nullptr); + pango_font_description_free(font); + if(auto color = item->foregroundColor(true)) { + auto gdkColor = CreateColor(color); + g_object_set(G_OBJECT(renderer), "foreground-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(renderer), "foreground-set", false, nullptr); + } + } + if(auto color = item->backgroundColor(true)) { + auto gdkColor = CreateColor(color); + g_object_set(G_OBJECT(renderer), "cell-background-gdk", &gdkColor, nullptr); + } else { + g_object_set(G_OBJECT(renderer), "cell-background-set", false, nullptr); + } +} + auto pTreeView::_togglePath(string path) -> void { if(auto item = self().item(path.transform(":", "/"))) { bool checked = !item->checked(); diff --git a/hiro/gtk/widget/tree-view.hpp b/hiro/gtk/widget/tree-view.hpp index e73e66d9..23becafd 100644 --- a/hiro/gtk/widget/tree-view.hpp +++ b/hiro/gtk/widget/tree-view.hpp @@ -6,16 +6,13 @@ struct pTreeView : pWidget { Declare(TreeView, Widget) auto append(sTreeViewItem item) -> void; - auto collapse() -> void; - auto expand() -> void; auto remove(sTreeViewItem item) -> void; - auto reset() -> void; auto setBackgroundColor(Color color) -> void; - auto setCheckable(bool checkable) -> void; auto setForegroundColor(Color color) -> void; auto _activatePath(GtkTreePath* gtkPath) -> void; auto _buttonEvent(GdkEventButton* gdkEvent) -> signed; + auto _doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void; auto _togglePath(string path) -> void; auto _updateSelected() -> void; diff --git a/hiro/gtk/widget/widget.cpp b/hiro/gtk/widget/widget.cpp index 3729f5d2..8d7a783d 100644 --- a/hiro/gtk/widget/widget.cpp +++ b/hiro/gtk/widget/widget.cpp @@ -33,7 +33,7 @@ auto pWidget::setFocused() -> void { gtk_widget_grab_focus(gtkWidget); } -auto pWidget::setFont(const string& font) -> void { +auto pWidget::setFont(const Font& font) -> void { if(!gtkWidget) return; return pFont::setFont(gtkWidget, font); } diff --git a/hiro/gtk/widget/widget.hpp b/hiro/gtk/widget/widget.hpp index 453f045d..0a8ec0cb 100644 --- a/hiro/gtk/widget/widget.hpp +++ b/hiro/gtk/widget/widget.hpp @@ -9,7 +9,7 @@ struct pWidget : pSizable { virtual auto focused() const -> bool override; auto setEnabled(bool enabled) -> void override; virtual auto setFocused() -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setGeometry(Geometry geometry) -> void override; auto setVisible(bool visible) -> void override; diff --git a/hiro/gtk/window.cpp b/hiro/gtk/window.cpp index 20313733..009993bc 100644 --- a/hiro/gtk/window.cpp +++ b/hiro/gtk/window.cpp @@ -388,7 +388,7 @@ auto pWindow::_setMenuEnabled(bool enabled) -> void { gtk_widget_set_sensitive(gtkMenu, enabled); } -auto pWindow::_setMenuFont(const string& font) -> void { +auto pWindow::_setMenuFont(const Font& font) -> void { pFont::setFont(gtkMenu, font); } @@ -400,7 +400,7 @@ auto pWindow::_setStatusEnabled(bool enabled) -> void { gtk_widget_set_sensitive(gtkStatus, enabled); } -auto pWindow::_setStatusFont(const string& font) -> void { +auto pWindow::_setStatusFont(const Font& font) -> void { pFont::setFont(gtkStatus, font); } diff --git a/hiro/gtk/window.hpp b/hiro/gtk/window.hpp index c095c532..ac6fc841 100644 --- a/hiro/gtk/window.hpp +++ b/hiro/gtk/window.hpp @@ -29,10 +29,10 @@ struct pWindow : pObject { auto _menuHeight() const -> signed; auto _setIcon(const string& basename) -> bool; auto _setMenuEnabled(bool enabled) -> void; - auto _setMenuFont(const string& font) -> void; + auto _setMenuFont(const Font& font) -> void; auto _setMenuVisible(bool visible) -> void; auto _setStatusEnabled(bool enabled) -> void; - auto _setStatusFont(const string& font) -> void; + auto _setStatusFont(const Font& font) -> void; auto _setStatusText(const string& text) -> void; auto _setStatusVisible(bool visible) -> void; auto _statusHeight() const -> signed; diff --git a/hiro/qt/action/action.cpp b/hiro/qt/action/action.cpp index cf4541b8..37b27628 100644 --- a/hiro/qt/action/action.cpp +++ b/hiro/qt/action/action.cpp @@ -12,7 +12,7 @@ auto pAction::setEnabled(bool enabled) -> void { _setState(); } -auto pAction::setFont(const string& font) -> void { +auto pAction::setFont(const Font& font) -> void { _setState(); } diff --git a/hiro/qt/action/action.hpp b/hiro/qt/action/action.hpp index 8b9d302c..584d4a8e 100644 --- a/hiro/qt/action/action.hpp +++ b/hiro/qt/action/action.hpp @@ -6,7 +6,7 @@ struct pAction : pObject { Declare(Action, Object) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; auto _parentMenu() -> maybe; diff --git a/hiro/qt/action/menu-item.cpp b/hiro/qt/action/menu-item.cpp index 18dc5cfd..0323cb9d 100644 --- a/hiro/qt/action/menu-item.cpp +++ b/hiro/qt/action/menu-item.cpp @@ -22,7 +22,7 @@ auto pMenuItem::destruct() -> void { qtMenuItem = nullptr; } -auto pMenuItem::setIcon(const image& icon) -> void { +auto pMenuItem::setImage(const Image& icon) -> void { _setState(); } @@ -31,7 +31,7 @@ auto pMenuItem::setText(const string& text) -> void { } auto pMenuItem::_setState() -> void { - qtMenuItem->setIcon(CreateIcon(state().icon)); + qtMenuItem->setIcon(CreateImage(state().image)); qtMenuItem->setText(state().text); } diff --git a/hiro/qt/action/menu-item.hpp b/hiro/qt/action/menu-item.hpp index 35d815f7..4da61c42 100644 --- a/hiro/qt/action/menu-item.hpp +++ b/hiro/qt/action/menu-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pMenuItem : pAction { Declare(MenuItem, Action) - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto _setState() -> void override; diff --git a/hiro/qt/action/menu-radio-item.cpp b/hiro/qt/action/menu-radio-item.cpp index a3cf8f16..a8d1dcb6 100644 --- a/hiro/qt/action/menu-radio-item.cpp +++ b/hiro/qt/action/menu-radio-item.cpp @@ -18,6 +18,7 @@ auto pMenuRadioItem::construct() -> void { parent->qtPopupMenu->addAction(qtMenuRadioItem); } + setGroup(state().group); _setState(); } @@ -33,7 +34,19 @@ auto pMenuRadioItem::setChecked() -> void { } auto pMenuRadioItem::setGroup(sGroup group) -> void { - _setState(); + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + self->qtMenuRadioItem->setChecked(menuRadioItem->state.checked = first); + first = false; + } + } + } + } + } } auto pMenuRadioItem::setText(const string& text) -> void { @@ -41,7 +54,7 @@ auto pMenuRadioItem::setText(const string& text) -> void { } auto pMenuRadioItem::_setState() -> void { - if(auto group = state().group) { + if(auto& group = state().group) { if(auto object = group->object(0)) { if(auto menuRadioItem = dynamic_cast(object.data())) { if(auto self = menuRadioItem->self()) { @@ -56,7 +69,7 @@ auto pMenuRadioItem::_setState() -> void { auto QtMenuRadioItem::onActivate() -> void { if(p.state().checked) return; - p.state().checked = true; + p.self().setChecked(); p.self().doActivate(); } diff --git a/hiro/qt/action/menu.cpp b/hiro/qt/action/menu.cpp index 001444bd..eaf4c2a6 100644 --- a/hiro/qt/action/menu.cpp +++ b/hiro/qt/action/menu.cpp @@ -33,7 +33,7 @@ auto pMenu::append(sAction action) -> void { auto pMenu::remove(sAction action) -> void { } -auto pMenu::setIcon(const image& icon) -> void { +auto pMenu::setImage(const Image& image) -> void { _setState(); } @@ -44,7 +44,7 @@ auto pMenu::setText(const string& text) -> void { auto pMenu::_setState() -> void { qtMenu->setEnabled(self().enabled()); qtMenu->setFont(pFont::create(self().font(true))); - qtMenu->setIcon(CreateIcon(state().icon)); + qtMenu->setIcon(CreateImage(state().image)); qtMenu->setTitle(QString::fromUtf8(state().text)); qtMenu->menuAction()->setVisible(self().visible()); diff --git a/hiro/qt/action/menu.hpp b/hiro/qt/action/menu.hpp index f09ca43d..44cf3d05 100644 --- a/hiro/qt/action/menu.hpp +++ b/hiro/qt/action/menu.hpp @@ -7,7 +7,7 @@ struct pMenu : public pAction { auto append(sAction action) -> void; auto remove(sAction action) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto _setState() -> void override; diff --git a/hiro/qt/font.cpp b/hiro/qt/font.cpp index b839328a..3a6dc1ae 100644 --- a/hiro/qt/font.cpp +++ b/hiro/qt/font.cpp @@ -2,61 +2,34 @@ namespace hiro { -auto pFont::serif(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Serif, ", size, ", ", style}; -} - -auto pFont::sans(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Sans, ", size, ", ", style}; -} - -auto pFont::monospace(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Liberation Mono, ", size, ", ", style}; -} - -auto pFont::size(string font, string text) -> Size { +auto pFont::size(const Font& font, const string& text) -> Size { return pFont::size(pFont::create(font), text); } -auto pFont::create(string description) -> QFont { - lstring part = description.split(",", 2L).strip(); - - string family = "Sans"; - unsigned size = 8u; - bool bold = false; - bool italic = false; - - if(part[0] != "") family = part[0]; - if(part.size() >= 2) size = decimal(part[1]); - if(part.size() >= 3) bold = (bool)part[2].find("Bold"); - if(part.size() >= 3) italic = (bool)part[2].find("Italic"); - - QFont qtFont; - qtFont.setFamily(family); - qtFont.setPointSize(size); - if(bold) qtFont.setBold(true); - if(italic) qtFont.setItalic(true); - return qtFont; -} - auto pFont::size(const QFont& qtFont, const string& text) -> Size { QFontMetrics metrics(qtFont); - - lstring lines; - lines.split(text ? text : " ", "\n"); - - unsigned maxWidth = 0; + signed maxWidth = 0; + auto lines = text.split("\n"); for(auto& line : lines) { maxWidth = max(maxWidth, metrics.width(line)); } + return {maxWidth, metrics.height() * (signed)lines.size()}; +} - return Size().setWidth(maxWidth).setHeight(metrics.height() * lines.size()); +auto pFont::family(const string& family) -> string { + if(family == Font::Sans ) return "Sans"; + if(family == Font::Serif) return "Serif"; + if(family == Font::Mono ) return "Liberation Mono"; + return family ? family : "Sans"; +} + +auto pFont::create(const Font& font) -> QFont { + QFont qtFont; + qtFont.setFamily(family(font.family())); + qtFont.setPointSize(font.size() ? font.size() : 8); + qtFont.setBold(font.bold()); + qtFont.setItalic(font.italic()); + return qtFont; } } diff --git a/hiro/qt/font.hpp b/hiro/qt/font.hpp index 7928d775..3b7fe79c 100644 --- a/hiro/qt/font.hpp +++ b/hiro/qt/font.hpp @@ -3,13 +3,10 @@ namespace hiro { struct pFont { - static auto serif(unsigned size, string style) -> string; - static auto sans(unsigned size, string style) -> string; - static auto monospace(unsigned size, string style) -> string; - static auto size(string font, string text) -> Size; - - static auto create(string description) -> QFont; + static auto size(const Font& font, const string& text) -> Size; static auto size(const QFont& qtFont, const string& text) -> Size; + static auto family(const string& family) -> string; + static auto create(const Font& font) -> QFont; }; } diff --git a/hiro/qt/hotkey.cpp b/hiro/qt/hotkey.cpp deleted file mode 100644 index 608ba7bb..00000000 --- a/hiro/qt/hotkey.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#if defined(Hiro_Hotkey) - -namespace hiro { - -auto pHotkey::construct() -> void { -} - -auto pHotkey::destruct() -> void { -} - -} - -#endif diff --git a/hiro/qt/hotkey.hpp b/hiro/qt/hotkey.hpp deleted file mode 100644 index b1caa7bc..00000000 --- a/hiro/qt/hotkey.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#if defined(Hiro_Hotkey) - -namespace hiro { - -struct pHotkey : pObject { - Declare(Hotkey, Object) -}; - -} - -#endif diff --git a/hiro/qt/menu-bar.cpp b/hiro/qt/menu-bar.cpp index 979ff305..a2432c0a 100644 --- a/hiro/qt/menu-bar.cpp +++ b/hiro/qt/menu-bar.cpp @@ -19,7 +19,7 @@ auto pMenuBar::setEnabled(bool enabled) -> void { _setState(); } -auto pMenuBar::setFont(const string& font) -> void { +auto pMenuBar::setFont(const Font& font) -> void { _setState(); } diff --git a/hiro/qt/menu-bar.hpp b/hiro/qt/menu-bar.hpp index ddf8bf05..e1fed335 100644 --- a/hiro/qt/menu-bar.hpp +++ b/hiro/qt/menu-bar.hpp @@ -8,7 +8,7 @@ struct pMenuBar : pObject { auto append(sMenu menu) -> void; auto remove(sMenu menu) -> void; auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; auto _parent() -> maybe; diff --git a/hiro/qt/object.cpp b/hiro/qt/object.cpp index fae97d8c..3c6ac442 100644 --- a/hiro/qt/object.cpp +++ b/hiro/qt/object.cpp @@ -24,7 +24,7 @@ auto pObject::setEnabled(bool enabled) -> void { auto pObject::setFocused() -> void { } -auto pObject::setFont(const string& font) -> void { +auto pObject::setFont(const Font& font) -> void { } auto pObject::setVisible(bool visible) -> void { diff --git a/hiro/qt/object.hpp b/hiro/qt/object.hpp index 5e198d81..ec5b878a 100644 --- a/hiro/qt/object.hpp +++ b/hiro/qt/object.hpp @@ -15,7 +15,7 @@ struct pObject { virtual auto reset() -> void; virtual auto setEnabled(bool enabled) -> void; virtual auto setFocused() -> void; - virtual auto setFont(const string& font) -> void; + virtual auto setFont(const Font& font) -> void; virtual auto setVisible(bool visible) -> void; auto locked() const -> bool { return locks != 0; } diff --git a/hiro/qt/platform.cpp b/hiro/qt/platform.cpp index 91b09819..e529b916 100644 --- a/hiro/qt/platform.cpp +++ b/hiro/qt/platform.cpp @@ -16,7 +16,6 @@ #include "object.cpp" #include "group.cpp" -#include "hotkey.cpp" #include "timer.cpp" #include "window.cpp" #include "status-bar.cpp" diff --git a/hiro/qt/platform.hpp b/hiro/qt/platform.hpp index d4454121..2f223cdf 100644 --- a/hiro/qt/platform.hpp +++ b/hiro/qt/platform.hpp @@ -19,7 +19,6 @@ #include "object.hpp" #include "group.hpp" -#include "hotkey.hpp" #include "timer.hpp" #include "window.hpp" #include "status-bar.hpp" diff --git a/hiro/qt/popup-menu.cpp b/hiro/qt/popup-menu.cpp index cc74a027..dcaef0e4 100644 --- a/hiro/qt/popup-menu.cpp +++ b/hiro/qt/popup-menu.cpp @@ -20,7 +20,7 @@ auto pPopupMenu::remove(sAction action) -> void { _setState(); } -auto pPopupMenu::setFont(const string& font) -> void { +auto pPopupMenu::setFont(const Font& font) -> void { _setState(); } diff --git a/hiro/qt/popup-menu.hpp b/hiro/qt/popup-menu.hpp index 04bf4d76..707d81d7 100644 --- a/hiro/qt/popup-menu.hpp +++ b/hiro/qt/popup-menu.hpp @@ -7,7 +7,7 @@ struct pPopupMenu : pObject { auto append(sAction action) -> void; auto remove(sAction action) -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; auto _setState() -> void; diff --git a/hiro/qt/status-bar.cpp b/hiro/qt/status-bar.cpp index bf8e3faf..17b0d81a 100644 --- a/hiro/qt/status-bar.cpp +++ b/hiro/qt/status-bar.cpp @@ -13,7 +13,7 @@ auto pStatusBar::setEnabled(bool enabled) -> void { _setState(); } -auto pStatusBar::setFont(const string& font) -> void { +auto pStatusBar::setFont(const Font& font) -> void { _setState(); } diff --git a/hiro/qt/status-bar.hpp b/hiro/qt/status-bar.hpp index 7d0f9bec..309e6c7c 100644 --- a/hiro/qt/status-bar.hpp +++ b/hiro/qt/status-bar.hpp @@ -6,7 +6,7 @@ struct pStatusBar : pObject { Declare(StatusBar, Object) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setText(const string& text) -> void; auto setVisible(bool visible) -> void override; diff --git a/hiro/qt/utility.cpp b/hiro/qt/utility.cpp index 86eeeef1..d8739c0e 100644 --- a/hiro/qt/utility.cpp +++ b/hiro/qt/utility.cpp @@ -24,6 +24,12 @@ static auto CreateIcon(const nall::image& icon, bool scale = false) -> QIcon { return QIcon(QPixmap::fromImage(qtImage)); } +static auto CreateImage(const Image& image, bool scale = false) -> QIcon { + if(!image) return QIcon(); + QImage qtImage((const uint8_t*)image.data(), image.width(), image.height(), QImage::Format_ARGB32); + return QIcon(QPixmap::fromImage(qtImage)); +} + static auto DropPaths(QDropEvent* event) -> lstring { QList urls = event->mimeData()->urls(); if(urls.size() == 0) return {}; diff --git a/hiro/qt/widget/button.cpp b/hiro/qt/widget/button.cpp index e0593c04..168292ad 100644 --- a/hiro/qt/widget/button.cpp +++ b/hiro/qt/widget/button.cpp @@ -8,7 +8,7 @@ auto pButton::construct() -> void { qtButton->connect(qtButton, SIGNAL(released()), SLOT(onActivate())); setBordered(state().bordered); - setIcon(state().icon); + setImage(state().image); setOrientation(state().orientation); setText(state().text); @@ -21,16 +21,16 @@ auto pButton::destruct() -> void { } auto pButton::minimumSize() const -> Size { - auto size = pFont::size(qtWidget->font(), state().text); + auto size = pFont::size(qtWidget->font(), state().text ? state().text : " "); if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(state().icon.height(), size.height())); + size.setWidth(size.width() + state().image.width()); + size.setHeight(max(state().image.height(), size.height())); } if(state().orientation == Orientation::Vertical) { - size.setWidth(max(state().icon.width(), size.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(state().image.width(), size.width())); + size.setHeight(size.height() + state().image.height()); } return {size.width() + (state().text ? 20 : 12), size.height() + 12}; @@ -40,9 +40,9 @@ auto pButton::setBordered(bool bordered) -> void { qtButton->setAutoRaise(!bordered); } -auto pButton::setIcon(const image& icon) -> void { - qtButton->setIconSize(QSize(icon.width(), icon.height())); - qtButton->setIcon(CreateIcon(icon)); +auto pButton::setImage(const Image& image) -> void { + qtButton->setIconSize(QSize(image.width(), image.height())); + qtButton->setIcon(CreateImage(image)); qtButton->setStyleSheet("text-align: top;"); } diff --git a/hiro/qt/widget/button.hpp b/hiro/qt/widget/button.hpp index 2cc25b0d..215383e6 100644 --- a/hiro/qt/widget/button.hpp +++ b/hiro/qt/widget/button.hpp @@ -7,7 +7,7 @@ struct pButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; diff --git a/hiro/qt/widget/canvas.cpp b/hiro/qt/widget/canvas.cpp index 37181a1b..0dcd1995 100644 --- a/hiro/qt/widget/canvas.cpp +++ b/hiro/qt/widget/canvas.cpp @@ -18,16 +18,11 @@ auto pCanvas::destruct() -> void { } auto pCanvas::minimumSize() const -> Size { - return {max(0, state().size.width()), max(0, state().size.height())}; + if(auto& image = state().image) return image.size(); + return {0, 0}; } auto pCanvas::setColor(Color color) -> void { - mode = Mode::Color; - update(); -} - -auto pCanvas::setData(Size size) -> void { - mode = Mode::Data; update(); } @@ -40,13 +35,11 @@ auto pCanvas::setGeometry(Geometry geometry) -> void { pWidget::setGeometry(geometry); } -auto pCanvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void { - mode = Mode::Gradient; +auto pCanvas::setGradient(Gradient gradient) -> void { update(); } -auto pCanvas::setIcon(const image& icon) -> void { - mode = Mode::Icon; +auto pCanvas::setImage(const Image& image) -> void { update(); } @@ -59,14 +52,13 @@ auto pCanvas::_rasterize() -> void { signed width = 0; signed height = 0; - if(mode == Mode::Color || mode == Mode::Gradient) { + if(auto& image = state().image) { + width = image.width(); + height = image.height(); + } else { width = pSizable::state().geometry.width(); height = pSizable::state().geometry.height(); - } else { - width = state().size.width(); - height = state().size.height(); } - if(width <= 0 || height <= 0) return; if(width != qtImageWidth || height != qtImageHeight) _release(); @@ -76,30 +68,18 @@ auto pCanvas::_rasterize() -> void { if(!qtImage) qtImage = new QImage(width, height, QImage::Format_ARGB32); auto buffer = (uint32_t*)qtImage->bits(); - if(mode == Mode::Color) { + if(auto& image = state().image) { + memory::copy(buffer, state().image.data(), width * height * sizeof(uint32_t)); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + nall::image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(buffer, fill.data(), fill.size()); + } else { uint32_t color = state().color.value(); for(auto n : range(width * height)) buffer[n] = color; } - - if(mode == Mode::Gradient) { - image fill; - fill.allocate(width, height); - fill.gradient( - state().gradient[0].value(), state().gradient[1].value(), state().gradient[2].value(), state().gradient[3].value() - ); - memory::copy(buffer, fill.data(), fill.size()); - } - - if(mode == Mode::Icon) { - auto icon = state().icon; - icon.scale(width, height); - icon.transform(); - memory::copy(buffer, icon.data(), icon.size()); - } - - if(mode == Mode::Data) { - memory::copy(buffer, state().data.data(), state().data.size() * sizeof(uint32_t)); - } } auto pCanvas::_release() -> void { diff --git a/hiro/qt/widget/canvas.hpp b/hiro/qt/widget/canvas.hpp index 91682f43..de30b602 100644 --- a/hiro/qt/widget/canvas.hpp +++ b/hiro/qt/widget/canvas.hpp @@ -7,15 +7,12 @@ struct pCanvas : pWidget { auto minimumSize() const -> Size; auto setColor(Color color) -> void; - auto setData(Size size) -> void; auto setDroppable(bool droppable) -> void; auto setGeometry(Geometry geometry) -> void; - auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void; - auto setIcon(const image& icon) -> void; + auto setGradient(Gradient gradient) -> void; + auto setImage(const Image& image) -> void; auto update() -> void; - enum class Mode : unsigned { Color, Data, Gradient, Icon }; - auto _rasterize() -> void; auto _release() -> void; @@ -23,7 +20,6 @@ struct pCanvas : pWidget { QImage* qtImage = nullptr; unsigned qtImageWidth = 0; unsigned qtImageHeight = 0; - Mode mode = Mode::Color; }; } diff --git a/hiro/qt/widget/check-button.cpp b/hiro/qt/widget/check-button.cpp index 4e71ef8b..9cf20fbd 100644 --- a/hiro/qt/widget/check-button.cpp +++ b/hiro/qt/widget/check-button.cpp @@ -21,13 +21,13 @@ auto pCheckButton::minimumSize() const -> Size { auto size = pFont::size(qtWidget->font(), state().text); if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(state().icon.height(), size.height())); + size.setWidth(size.width() + state().image.width()); + size.setHeight(max(state().image.height(), size.height())); } if(state().orientation == Orientation::Vertical) { - size.setWidth(max(state().icon.width(), size.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(state().image.width(), size.width())); + size.setHeight(size.height() + state().image.height()); } return {size.width() + 20, size.height() + 12}; @@ -41,7 +41,7 @@ auto pCheckButton::setChecked(bool checked) -> void { _setState(); } -auto pCheckButton::setIcon(const image& icon) -> void { +auto pCheckButton::setImage(const Image& image) -> void { _setState(); } @@ -57,8 +57,8 @@ auto pCheckButton::_setState() -> void { lock(); qtCheckButton->setAutoRaise(!state().bordered); qtCheckButton->setChecked(state().checked); - qtCheckButton->setIconSize(QSize(state().icon.width(), state().icon.height())); - qtCheckButton->setIcon(CreateIcon(state().icon)); + qtCheckButton->setIconSize(QSize(state().image.width(), state().image.height())); + qtCheckButton->setIcon(CreateImage(state().image)); qtCheckButton->setStyleSheet("text-align: top;"); switch(state().orientation) { case Orientation::Horizontal: qtCheckButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; diff --git a/hiro/qt/widget/check-button.hpp b/hiro/qt/widget/check-button.hpp index 092c8024..49493a6e 100644 --- a/hiro/qt/widget/check-button.hpp +++ b/hiro/qt/widget/check-button.hpp @@ -8,7 +8,7 @@ struct pCheckButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; auto setChecked(bool checked) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; diff --git a/hiro/qt/widget/combo-button-item.cpp b/hiro/qt/widget/combo-button-item.cpp index a38266a4..64cf12a6 100644 --- a/hiro/qt/widget/combo-button-item.cpp +++ b/hiro/qt/widget/combo-button-item.cpp @@ -19,7 +19,7 @@ auto pComboButtonItem::destruct() -> void { } } -auto pComboButtonItem::setIcon(const image& icon) -> void { +auto pComboButtonItem::setImage(const Image& image) -> void { _setState(); } @@ -40,7 +40,7 @@ auto pComboButtonItem::_parent() -> maybe { auto pComboButtonItem::_setState() -> void { if(auto parent = _parent()) { - parent->qtComboButton->setItemIcon(self().offset(), CreateIcon(state().icon)); + parent->qtComboButton->setItemIcon(self().offset(), CreateImage(state().image)); if(state().selected) parent->qtComboButton->setCurrentIndex(self().offset()); parent->qtComboButton->setItemText(self().offset(), QString::fromUtf8(state().text)); } diff --git a/hiro/qt/widget/combo-button-item.hpp b/hiro/qt/widget/combo-button-item.hpp index 11e65a4e..5918b19a 100644 --- a/hiro/qt/widget/combo-button-item.hpp +++ b/hiro/qt/widget/combo-button-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pComboButtonItem : pObject { Declare(ComboButtonItem, Object) - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setSelected() -> void; auto setText(const string& text) -> void; diff --git a/hiro/qt/widget/list-view-cell.cpp b/hiro/qt/widget/list-view-cell.cpp index 6469ca64..d9125044 100644 --- a/hiro/qt/widget/list-view-cell.cpp +++ b/hiro/qt/widget/list-view-cell.cpp @@ -32,7 +32,7 @@ auto pListViewCell::setForegroundColor(Color color) -> void { _setState(); } -auto pListViewCell::setIcon(const image& icon) -> void { +auto pListViewCell::setImage(const Image& image) -> void { _setState(); } @@ -60,7 +60,7 @@ auto pListViewCell::_setState() -> void { } parent->qtItem->setFont(self().offset(), pFont::create(self().font(true))); parent->qtItem->setForeground(self().offset(), CreateBrush(self().foregroundColor(true))); - parent->qtItem->setIcon(self().offset(), CreateIcon(state().icon)); + parent->qtItem->setIcon(self().offset(), CreateImage(state().image)); parent->qtItem->setText(self().offset(), QString::fromUtf8(state().text)); parent->qtItem->setTextAlignment(self().offset(), CalculateAlignment(self().alignment(true))); grandparent->unlock(); diff --git a/hiro/qt/widget/list-view-cell.hpp b/hiro/qt/widget/list-view-cell.hpp index 4eddcc5e..14f89ee2 100644 --- a/hiro/qt/widget/list-view-cell.hpp +++ b/hiro/qt/widget/list-view-cell.hpp @@ -11,7 +11,7 @@ struct pListViewCell : pObject { auto setChecked(bool checked) -> void; auto setFont(const string& font) -> void; auto setForegroundColor(Color color) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto _parent() -> maybe; diff --git a/hiro/qt/widget/list-view-column.cpp b/hiro/qt/widget/list-view-column.cpp index 48b5cc41..aac67854 100644 --- a/hiro/qt/widget/list-view-column.cpp +++ b/hiro/qt/widget/list-view-column.cpp @@ -28,7 +28,7 @@ auto pListViewColumn::setExpandable(bool expandable) -> void { _setState(); } -auto pListViewColumn::setFont(const string& font) -> void { +auto pListViewColumn::setFont(const Font& font) -> void { _setState(); } @@ -40,7 +40,7 @@ auto pListViewColumn::setHorizontalAlignment(double alignment) -> void { _setState(); } -auto pListViewColumn::setIcon(const image& icon) -> void { +auto pListViewColumn::setImage(const Image& image) -> void { //unsupported } diff --git a/hiro/qt/widget/list-view-column.hpp b/hiro/qt/widget/list-view-column.hpp index a3e450a4..b5d1eec5 100644 --- a/hiro/qt/widget/list-view-column.hpp +++ b/hiro/qt/widget/list-view-column.hpp @@ -10,10 +10,10 @@ struct pListViewColumn : pObject { auto setBackgroundColor(Color color) -> void; auto setEditable(bool editable) -> void; auto setExpandable(bool expandable) -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setForegroundColor(Color color) -> void; auto setHorizontalAlignment(double alignment) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setResizable(bool resizable) -> void; auto setSortable(bool sortable) -> void; auto setText(const string& text) -> void; diff --git a/hiro/qt/widget/list-view-item.cpp b/hiro/qt/widget/list-view-item.cpp index 7bd9d922..b3e71064 100644 --- a/hiro/qt/widget/list-view-item.cpp +++ b/hiro/qt/widget/list-view-item.cpp @@ -28,7 +28,7 @@ auto pListViewItem::setBackgroundColor(Color color) -> void { _setState(); } -auto pListViewItem::setFont(const string& font) -> void { +auto pListViewItem::setFont(const Font& font) -> void { _setState(); } diff --git a/hiro/qt/widget/list-view-item.hpp b/hiro/qt/widget/list-view-item.hpp index ed20122b..eb51d302 100644 --- a/hiro/qt/widget/list-view-item.hpp +++ b/hiro/qt/widget/list-view-item.hpp @@ -9,7 +9,7 @@ struct pListViewItem : pObject { auto remove(sListViewCell cell) -> void; auto setAlignment(Alignment alignment) -> void; auto setBackgroundColor(Color color) -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setForegroundColor(Color color) -> void; auto setSelected(bool selected) -> void; diff --git a/hiro/qt/widget/list-view.cpp b/hiro/qt/widget/list-view.cpp index 2c2e87c6..1a51d5cb 100644 --- a/hiro/qt/widget/list-view.cpp +++ b/hiro/qt/widget/list-view.cpp @@ -154,11 +154,11 @@ auto pListView::_widthOfColumn(unsigned _column) -> unsigned { unsigned width = 8; if(auto& header = state().header) { if(auto column = header->column(_column)) { - if(auto& icon = column->state.icon) { - width += icon.width() + 2; + if(auto& image = column->state.image) { + width += image.width() + 2; } if(auto& text = column->state.text) { - width += Font::size(column->font(true), text).width(); + width += pFont::size(column->font(true), text).width(); } } } @@ -172,11 +172,11 @@ auto pListView::_widthOfCell(unsigned _row, unsigned _column) -> unsigned { if(cell->state.checkable) { width += 16 + 2; } - if(auto& icon = cell->state.icon) { - width += icon.width() + 2; + if(auto& image = cell->state.image) { + width += image.width() + 2; } if(auto& text = cell->state.text) { - width += Font::size(cell->font(true), text).width(); + width += pFont::size(cell->font(true), text).width(); } } } diff --git a/hiro/qt/widget/radio-button.cpp b/hiro/qt/widget/radio-button.cpp index be24041e..0e7a9f55 100644 --- a/hiro/qt/widget/radio-button.cpp +++ b/hiro/qt/widget/radio-button.cpp @@ -9,6 +9,7 @@ auto pRadioButton::construct() -> void { qtRadioButton->connect(qtRadioButton, SIGNAL(toggled(bool)), SLOT(onActivate())); pWidget::construct(); + setGroup(state().group); _setState(); } @@ -21,13 +22,13 @@ auto pRadioButton::minimumSize() const -> Size { auto size = pFont::size(qtWidget->font(), state().text); if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(state().icon.height(), size.height())); + size.setWidth(size.width() + state().image.width()); + size.setHeight(max(state().image.height(), size.height())); } if(state().orientation == Orientation::Vertical) { - size.setWidth(max(state().icon.width(), size.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(state().image.width(), size.width())); + size.setHeight(size.height() + state().image.height()); } return {size.width() + 20, size.height() + 12}; @@ -41,10 +42,24 @@ auto pRadioButton::setChecked() -> void { } auto pRadioButton::setGroup(sGroup group) -> void { - _setState(); + bool first = true; + if(auto& group = state().group) { + group->self()->lock(); + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + self->qtRadioButton->setChecked(radioButton->state.checked = first); + first = false; + } + } + } + } + group->self()->unlock(); + } } -auto pRadioButton::setIcon(const image& icon) -> void { +auto pRadioButton::setImage(const Image& image) -> void { _setState(); } @@ -70,8 +85,8 @@ auto pRadioButton::_setState() -> void { } group->self()->unlock(); } - qtRadioButton->setIconSize(QSize(state().icon.width(), state().icon.height())); - qtRadioButton->setIcon(CreateIcon(state().icon)); + qtRadioButton->setIconSize(QSize(state().image.width(), state().image.height())); + qtRadioButton->setIcon(CreateImage(state().image)); qtRadioButton->setStyleSheet("text-align: top;"); switch(state().orientation) { case Orientation::Horizontal: qtRadioButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; diff --git a/hiro/qt/widget/radio-button.hpp b/hiro/qt/widget/radio-button.hpp index 2aec616b..1ebe7a7e 100644 --- a/hiro/qt/widget/radio-button.hpp +++ b/hiro/qt/widget/radio-button.hpp @@ -9,7 +9,7 @@ struct pRadioButton : pWidget { auto setBordered(bool bordered) -> void; auto setChecked() -> void; auto setGroup(sGroup group) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; diff --git a/hiro/qt/widget/radio-label.cpp b/hiro/qt/widget/radio-label.cpp index 81a7d6f6..4fb310f5 100644 --- a/hiro/qt/widget/radio-label.cpp +++ b/hiro/qt/widget/radio-label.cpp @@ -8,6 +8,7 @@ auto pRadioLabel::construct() -> void { qtRadioLabel->connect(qtRadioLabel, SIGNAL(toggled(bool)), SLOT(onActivate())); pWidget::construct(); + setGroup(state().group); _setState(); } @@ -26,7 +27,21 @@ auto pRadioLabel::setChecked() -> void { } auto pRadioLabel::setGroup(sGroup group) -> void { - _setState(); + bool first = true; + if(auto& group = state().group) { + group->self()->lock(); + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + self->qtRadioLabel->setChecked(radioLabel->state.checked = first); + first = false; + } + } + } + } + group->self()->unlock(); + } } auto pRadioLabel::setText(const string& text) -> void { diff --git a/hiro/qt/widget/tab-frame-item.cpp b/hiro/qt/widget/tab-frame-item.cpp index 72d8ca73..fa0b4f54 100644 --- a/hiro/qt/widget/tab-frame-item.cpp +++ b/hiro/qt/widget/tab-frame-item.cpp @@ -34,7 +34,7 @@ auto pTabFrameItem::setGeometry(Geometry geometry) -> void { } } -auto pTabFrameItem::setIcon(const image& icon) -> void { +auto pTabFrameItem::setImage(const Image& image) -> void { _setState(); } @@ -62,7 +62,7 @@ auto pTabFrameItem::_parent() -> maybe { auto pTabFrameItem::_setState() -> void { if(auto parent = _parent()) { - parent->qtTabFrame->setTabIcon(self().offset(), CreateIcon(state().icon)); + parent->qtTabFrame->setTabIcon(self().offset(), CreateImage(state().image)); if(state().selected) parent->qtTabFrame->setCurrentIndex(self().offset()); parent->qtTabFrame->setTabText(self().offset(), QString::fromUtf8(state().text)); if(auto layout = state().layout) { diff --git a/hiro/qt/widget/tab-frame-item.hpp b/hiro/qt/widget/tab-frame-item.hpp index 4b8d59c8..cb383b6e 100644 --- a/hiro/qt/widget/tab-frame-item.hpp +++ b/hiro/qt/widget/tab-frame-item.hpp @@ -8,7 +8,7 @@ struct pTabFrameItem : pObject { auto append(sLayout layout) -> void; auto remove(sLayout layout) -> void; auto setClosable(bool closable) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setGeometry(Geometry geometry) -> void; auto setMovable(bool movable) -> void; auto setSelected() -> void; diff --git a/hiro/qt/widget/tab-frame.cpp b/hiro/qt/widget/tab-frame.cpp index d1fb1a5d..89670136 100644 --- a/hiro/qt/widget/tab-frame.cpp +++ b/hiro/qt/widget/tab-frame.cpp @@ -22,9 +22,6 @@ auto pTabFrame::append(sTabFrameItem item) -> void { auto pTabFrame::remove(sTabFrameItem item) -> void { } -auto pTabFrame::setEdge(Edge edge) -> void { -} - auto pTabFrame::setGeometry(Geometry geometry) -> void { pWidget::setGeometry(geometry); @@ -33,7 +30,18 @@ auto pTabFrame::setGeometry(Geometry geometry) -> void { } } +auto pTabFrame::setNavigation(Navigation navigation) -> void { + _setState(); +} + auto pTabFrame::_setState() -> void { + switch(state().navigation) { default: + case Navigation::Top: qtTabFrame->setTabPosition(QTabWidget::TabPosition::North); break; + case Navigation::Bottom: qtTabFrame->setTabPosition(QTabWidget::TabPosition::South); break; + case Navigation::Left: qtTabFrame->setTabPosition(QTabWidget::TabPosition::West); break; + case Navigation::Right: qtTabFrame->setTabPosition(QTabWidget::TabPosition::East); break; + } + for(auto& item : state().items) { if(auto self = item->self()) self->_setState(); } diff --git a/hiro/qt/widget/tab-frame.hpp b/hiro/qt/widget/tab-frame.hpp index 4345e748..e87cdc36 100644 --- a/hiro/qt/widget/tab-frame.hpp +++ b/hiro/qt/widget/tab-frame.hpp @@ -7,8 +7,8 @@ struct pTabFrame : pWidget { auto append(sTabFrameItem item) -> void; auto remove(sTabFrameItem item) -> void; - auto setEdge(Edge edge) -> void; auto setGeometry(Geometry geometry) -> void override; + auto setNavigation(Navigation navigation) -> void; auto _setState() -> void; diff --git a/hiro/qt/widget/text-edit.cpp b/hiro/qt/widget/text-edit.cpp index ab3e5ae4..f5d55313 100644 --- a/hiro/qt/widget/text-edit.cpp +++ b/hiro/qt/widget/text-edit.cpp @@ -19,7 +19,7 @@ auto pTextEdit::setBackgroundColor(Color color) -> void { _setState(); } -auto pTextEdit::setCursorPosition(unsigned position) -> void { +auto pTextEdit::setCursor(Cursor cursor) -> void { _setState(); } @@ -53,8 +53,9 @@ auto pTextEdit::_setState() -> void { //todo } QTextCursor cursor = qtTextEdit->textCursor(); - unsigned lastCharacter = strlen(qtTextEdit->toPlainText().toUtf8().constData()); - cursor.setPosition(min(state().cursorPosition, lastCharacter)); + signed lastCharacter = strlen(qtTextEdit->toPlainText().toUtf8().constData()); + cursor.setPosition(max(0, min(lastCharacter, state().cursor.offset()))); + cursor.setPosition(max(0, min(lastCharacter, state().cursor.offset() + state().cursor.length())), QTextCursor::KeepAnchor); qtTextEdit->setTextCursor(cursor); qtTextEdit->setTextInteractionFlags(state().editable ? Qt::TextEditorInteraction diff --git a/hiro/qt/widget/text-edit.hpp b/hiro/qt/widget/text-edit.hpp index 882d2881..a810a3ed 100644 --- a/hiro/qt/widget/text-edit.hpp +++ b/hiro/qt/widget/text-edit.hpp @@ -6,7 +6,7 @@ struct pTextEdit : pWidget { Declare(TextEdit, Widget) auto setBackgroundColor(Color color) -> void; - auto setCursorPosition(unsigned position) -> void; + auto setCursor(Cursor cursor) -> void; auto setEditable(bool editable) -> void; auto setForegroundColor(Color color) -> void; auto setText(const string& text) -> void; diff --git a/hiro/qt/widget/widget.cpp b/hiro/qt/widget/widget.cpp index 95335701..03666911 100644 --- a/hiro/qt/widget/widget.cpp +++ b/hiro/qt/widget/widget.cpp @@ -47,7 +47,7 @@ auto pWidget::setFocused() -> void { qtWidget->setFocus(Qt::OtherFocusReason); } -auto pWidget::setFont(const string& font) -> void { +auto pWidget::setFont(const Font& font) -> void { if(!qtWidget) return; qtWidget->setFont(pFont::create(font)); } diff --git a/hiro/qt/widget/widget.hpp b/hiro/qt/widget/widget.hpp index dc714610..080c2a14 100644 --- a/hiro/qt/widget/widget.hpp +++ b/hiro/qt/widget/widget.hpp @@ -8,7 +8,7 @@ struct pWidget : pSizable { auto focused() const -> bool override; auto setEnabled(bool enabled) -> void override; auto setFocused() -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setGeometry(Geometry geometry) -> void override; auto setVisible(bool visible) -> void override; diff --git a/hiro/windows/action/menu-item.cpp b/hiro/windows/action/menu-item.cpp index fa67aefc..df2bbeb5 100644 --- a/hiro/windows/action/menu-item.cpp +++ b/hiro/windows/action/menu-item.cpp @@ -10,7 +10,7 @@ auto pMenuItem::destruct() -> void { if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } } -auto pMenuItem::setIcon(const image& icon) -> void { +auto pMenuItem::setImage(const Image& image) -> void { _createBitmap(); _synchronize(); } @@ -26,8 +26,10 @@ auto pMenuItem::onActivate() -> void { auto pMenuItem::_createBitmap() -> void { if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } - if(auto icon = state().icon) { - icon.transform(); + if(auto& image = state().image) { + nall::image icon; + icon.allocate(image.width(), image.height()); + memory::copy(icon.data(), image.data(), icon.size()); icon.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) icon.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); hbitmap = CreateBitmap(icon); diff --git a/hiro/windows/action/menu-item.hpp b/hiro/windows/action/menu-item.hpp index 636eef4a..8f94950a 100644 --- a/hiro/windows/action/menu-item.hpp +++ b/hiro/windows/action/menu-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pMenuItem : pAction { Declare(MenuItem, Action) - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto onActivate() -> void; diff --git a/hiro/windows/action/menu-radio-item.cpp b/hiro/windows/action/menu-radio-item.cpp index 56de8b3d..04f12e7c 100644 --- a/hiro/windows/action/menu-radio-item.cpp +++ b/hiro/windows/action/menu-radio-item.cpp @@ -3,13 +3,14 @@ namespace hiro { auto pMenuRadioItem::construct() -> void { + setGroup(state().group); } auto pMenuRadioItem::destruct() -> void { } auto pMenuRadioItem::setChecked() -> void { - if(auto group = self().group()) { + if(auto& group = state().group) { for(auto& weak : group->state.objects) { if(auto object = weak.acquire()) { if(auto menuRadioItem = dynamic_cast(object.data())) { @@ -32,6 +33,20 @@ auto pMenuRadioItem::setChecked() -> void { } auto pMenuRadioItem::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto menuRadioItem = dynamic_cast(object.data())) { + if(auto self = menuRadioItem->self()) { + menuRadioItem->state.checked = first; + first = false; + } + } + } + } + } + setChecked(); } auto pMenuRadioItem::setText(const string& text) -> void { diff --git a/hiro/windows/action/menu.cpp b/hiro/windows/action/menu.cpp index 778e8dcd..56f2e03b 100644 --- a/hiro/windows/action/menu.cpp +++ b/hiro/windows/action/menu.cpp @@ -19,7 +19,7 @@ auto pMenu::remove(sAction action) -> void { _synchronize(); } -auto pMenu::setIcon(const image& icon) -> void { +auto pMenu::setImage(const Image& image) -> void { _createBitmap(); _synchronize(); } @@ -31,8 +31,10 @@ auto pMenu::setText(const string& text) -> void { auto pMenu::_createBitmap() -> void { if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } - if(auto icon = state().icon) { - icon.transform(); + if(auto& image = state().image) { + nall::image icon; + icon.allocate(image.width(), image.height()); + memory::copy(icon.data(), image.data(), icon.size()); icon.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) icon.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); hbitmap = CreateBitmap(icon); diff --git a/hiro/windows/action/menu.hpp b/hiro/windows/action/menu.hpp index b8caee56..63aea704 100644 --- a/hiro/windows/action/menu.hpp +++ b/hiro/windows/action/menu.hpp @@ -7,7 +7,7 @@ struct pMenu : pAction { auto append(sAction action) -> void; auto remove(sAction action) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto _createBitmap() -> void; diff --git a/hiro/windows/font.cpp b/hiro/windows/font.cpp index 80d240be..f3c87851 100644 --- a/hiro/windows/font.cpp +++ b/hiro/windows/font.cpp @@ -2,59 +2,14 @@ namespace hiro { -auto pFont::serif(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Georgia, ", size, ", ", style}; -} - -auto pFont::sans(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Tahoma, ", size, ", ", style}; -} - -auto pFont::monospace(unsigned size, string style) -> string { - if(size == 0) size = 8; - if(style == "") style = "Normal"; - return {"Lucida Console, ", size, ", ", style}; -} - -auto pFont::size(const string& font, const string& text) -> Size { - HFONT hfont = pFont::create(font); - Size size = pFont::size(hfont, text); +auto pFont::size(const Font& font, const string& text) -> Size { + auto hfont = pFont::create(font); + auto size = pFont::size(hfont, text); pFont::free(hfont); return size; } -auto pFont::create(const string& description) -> HFONT { - lstring part = description.split(",", 2L).strip(); - - string family = "Tahoma"; - unsigned size = 8u; - bool bold = false; - bool italic = false; - - if(part[0] != "") family = part[0]; - if(part.size() >= 2) size = decimal(part[1]); - if(part.size() >= 3) bold = (bool)part[2].find("Bold"); - if(part.size() >= 3) italic = (bool)part[2].find("Italic"); - - return CreateFont( - -(size * 96.0 / 72.0 + 0.5), - 0, 0, 0, bold ? FW_BOLD : FW_NORMAL, italic, 0, 0, 0, 0, 0, 0, 0, - utf16_t(family) - ); -} - -auto pFont::free(HFONT hfont) -> void { - DeleteObject(hfont); -} - -auto pFont::size(HFONT hfont, string text) -> Size { - //temporary fix: empty text string returns height of zero; bad for eg Button height - if(text.empty()) text = " "; - +auto pFont::size(HFONT hfont, const string& text) -> Size { HDC hdc = GetDC(0); SelectObject(hdc, hfont); RECT rc = {0, 0, 0, 0}; @@ -63,6 +18,25 @@ auto pFont::size(HFONT hfont, string text) -> Size { return {rc.right, rc.bottom}; } +auto pFont::family(const string& family) -> string { + if(family == Font::Sans ) return "Tahoma"; + if(family == Font::Serif) return "Georgia"; + if(family == Font::Mono ) return "Lucida Console"; + return family ? family : "Tahoma"; +} + +auto pFont::create(const Font& font) -> HFONT { + return CreateFont( + -((font.size() ? font.size() : 8) * 96.0 / 72.0 + 0.5), + 0, 0, 0, font.bold() ? FW_BOLD : FW_NORMAL, font.italic(), 0, 0, 0, 0, 0, 0, 0, + utf16_t(family(font.family())) + ); +} + +auto pFont::free(HFONT hfont) -> void { + DeleteObject(hfont); +} + } #endif diff --git a/hiro/windows/font.hpp b/hiro/windows/font.hpp index c899e31f..1882d550 100644 --- a/hiro/windows/font.hpp +++ b/hiro/windows/font.hpp @@ -3,14 +3,11 @@ namespace hiro { struct pFont { - static auto serif(unsigned size, string style) -> string; - static auto sans(unsigned size, string style) -> string; - static auto monospace(unsigned size, string style) -> string; - static auto size(const string& font, const string& text) -> Size; - - static auto create(const string& description) -> HFONT; + static auto size(const Font& font, const string& text) -> Size; + static auto size(HFONT hfont, const string& text) -> Size; + static auto family(const string& family) -> string; + static auto create(const Font& font) -> HFONT; static auto free(HFONT hfont) -> void; - static auto size(HFONT hfont, string text) -> Size; }; } diff --git a/hiro/windows/header.hpp b/hiro/windows/header.hpp index 6314c8eb..e260678e 100644 --- a/hiro/windows/header.hpp +++ b/hiro/windows/header.hpp @@ -35,6 +35,30 @@ #define Button_SetImageList(hwnd, pbuttonImagelist) (WINBOOL)SNDMSG((hwnd),BCM_SETIMAGELIST,0,(LPARAM)(pbuttonImagelist)) #endif +#if !defined(BP_PUSHBUTTON) + #define BP_PUSHBUTTON 1 +#endif + +#if !defined(PBS_NORMAL) + #define PBS_NORMAL 1 +#endif + +#if !defined(PBS_HOT) + #define PBS_HOT 2 +#endif + +#if !defined(PBS_PRESSED) + #define PBS_PRESSED 3 +#endif + +#if !defined(PBS_DISABLED) + #define PBS_DISABLED 4 +#endif + +#if !defined(PBS_DEFAULTED) + #define PBS_DEFAULTED 5 +#endif + #if !defined(BP_CHECKBOX) #define BP_CHECKBOX 3 #endif diff --git a/hiro/windows/hotkey.cpp b/hiro/windows/hotkey.cpp deleted file mode 100644 index 608ba7bb..00000000 --- a/hiro/windows/hotkey.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#if defined(Hiro_Hotkey) - -namespace hiro { - -auto pHotkey::construct() -> void { -} - -auto pHotkey::destruct() -> void { -} - -} - -#endif diff --git a/hiro/windows/hotkey.hpp b/hiro/windows/hotkey.hpp deleted file mode 100644 index b1caa7bc..00000000 --- a/hiro/windows/hotkey.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#if defined(Hiro_Hotkey) - -namespace hiro { - -struct pHotkey : pObject { - Declare(Hotkey, Object) -}; - -} - -#endif diff --git a/hiro/windows/layout.cpp b/hiro/windows/layout.cpp index caec0182..fbd3dcd4 100644 --- a/hiro/windows/layout.cpp +++ b/hiro/windows/layout.cpp @@ -14,7 +14,7 @@ auto pLayout::setEnabled(bool enabled) -> void { } } -auto pLayout::setFont(const string& font) -> void { +auto pLayout::setFont(const Font& font) -> void { for(auto& sizable : state().sizables) { if(auto self = sizable->self()) self->setFont(sizable->font(true)); } diff --git a/hiro/windows/layout.hpp b/hiro/windows/layout.hpp index 3895710c..dba11836 100644 --- a/hiro/windows/layout.hpp +++ b/hiro/windows/layout.hpp @@ -6,7 +6,7 @@ struct pLayout : pSizable { Declare(Layout, Sizable) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; }; diff --git a/hiro/windows/menu-bar.cpp b/hiro/windows/menu-bar.cpp index bc98b95c..fc2c5bc5 100644 --- a/hiro/windows/menu-bar.cpp +++ b/hiro/windows/menu-bar.cpp @@ -25,7 +25,7 @@ auto pMenuBar::setEnabled(bool enabled) -> void { _update(); } -auto pMenuBar::setFont(const string& font) -> void { +auto pMenuBar::setFont(const Font& font) -> void { //unsupported } diff --git a/hiro/windows/menu-bar.hpp b/hiro/windows/menu-bar.hpp index 13d4b2af..b804f256 100644 --- a/hiro/windows/menu-bar.hpp +++ b/hiro/windows/menu-bar.hpp @@ -8,7 +8,7 @@ struct pMenuBar : pObject { auto append(sMenu menu) -> void; auto remove(sMenu menu) -> void; auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; auto _parent() -> maybe; diff --git a/hiro/windows/object.cpp b/hiro/windows/object.cpp index bc074c4a..4cf170d7 100644 --- a/hiro/windows/object.cpp +++ b/hiro/windows/object.cpp @@ -27,7 +27,7 @@ auto pObject::setEnabled(bool enabled) -> void { auto pObject::setFocused() -> void { } -auto pObject::setFont(const string& font) -> void { +auto pObject::setFont(const Font& font) -> void { } auto pObject::setGroup(sGroup group) -> void { diff --git a/hiro/windows/object.hpp b/hiro/windows/object.hpp index 4951650e..c30c8ade 100644 --- a/hiro/windows/object.hpp +++ b/hiro/windows/object.hpp @@ -14,7 +14,7 @@ struct pObject { virtual auto reset() -> void; virtual auto setEnabled(bool enabled) -> void; virtual auto setFocused() -> void; - virtual auto setFont(const string& font) -> void; + virtual auto setFont(const Font& font) -> void; virtual auto setGroup(sGroup group) -> void; virtual auto setVisible(bool visible) -> void; diff --git a/hiro/windows/platform.cpp b/hiro/windows/platform.cpp index 36fc5196..42dac191 100644 --- a/hiro/windows/platform.cpp +++ b/hiro/windows/platform.cpp @@ -11,7 +11,6 @@ #include "object.cpp" #include "group.cpp" -#include "hotkey.cpp" #include "font.cpp" #include "timer.cpp" #include "window.cpp" diff --git a/hiro/windows/platform.hpp b/hiro/windows/platform.hpp index 954c2bc0..7c6be74c 100644 --- a/hiro/windows/platform.hpp +++ b/hiro/windows/platform.hpp @@ -41,7 +41,6 @@ static vector windows; #include "object.hpp" #include "group.hpp" -#include "hotkey.hpp" #include "timer.hpp" #include "window.hpp" #include "status-bar.hpp" diff --git a/hiro/windows/popup-menu.cpp b/hiro/windows/popup-menu.cpp index 3ef1058d..001fbfb7 100644 --- a/hiro/windows/popup-menu.cpp +++ b/hiro/windows/popup-menu.cpp @@ -17,7 +17,7 @@ auto pPopupMenu::append(sAction action) -> void { auto pPopupMenu::remove(sAction action) -> void { } -auto pPopupMenu::setFont(const string& font) -> void { +auto pPopupMenu::setFont(const Font& font) -> void { } auto pPopupMenu::setVisible(bool visible) -> void { diff --git a/hiro/windows/popup-menu.hpp b/hiro/windows/popup-menu.hpp index 34fe094a..a51cedfa 100644 --- a/hiro/windows/popup-menu.hpp +++ b/hiro/windows/popup-menu.hpp @@ -7,7 +7,7 @@ struct pPopupMenu : pObject { auto append(sAction action) -> void; auto remove(sAction action) -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setVisible(bool visible) -> void override; HWND hwnd = nullptr; diff --git a/hiro/windows/status-bar.cpp b/hiro/windows/status-bar.cpp index 19b22f8a..68ef63c4 100644 --- a/hiro/windows/status-bar.cpp +++ b/hiro/windows/status-bar.cpp @@ -25,7 +25,7 @@ auto pStatusBar::setEnabled(bool enabled) -> void { //unsupported } -auto pStatusBar::setFont(const string& font) -> void { +auto pStatusBar::setFont(const Font& font) -> void { if(hfont) DeleteObject(hfont); hfont = pFont::create(font); if(hwnd) SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); diff --git a/hiro/windows/status-bar.hpp b/hiro/windows/status-bar.hpp index 75df1012..618e0268 100644 --- a/hiro/windows/status-bar.hpp +++ b/hiro/windows/status-bar.hpp @@ -6,7 +6,7 @@ struct pStatusBar : pObject { Declare(StatusBar, Object) auto setEnabled(bool enabled) -> void override; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setText(const string& text) -> void; auto setVisible(bool visible) -> void override; diff --git a/hiro/windows/utility.cpp b/hiro/windows/utility.cpp index e4b023fe..21700816 100644 --- a/hiro/windows/utility.cpp +++ b/hiro/windows/utility.cpp @@ -5,6 +5,8 @@ static const unsigned WindowsXP = 0x0501; static const unsigned WindowsVista = 0x0600; static const unsigned Windows7 = 0x0601; +static auto Button_CustomDraw(HWND, PAINTSTRUCT&, unsigned, const Font&, const Image&, Orientation, const string&) -> void; + static auto OsVersion() -> unsigned { OSVERSIONINFO versionInfo{0}; versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); @@ -12,7 +14,9 @@ static auto OsVersion() -> unsigned { return (versionInfo.dwMajorVersion << 8) + (versionInfo.dwMajorVersion << 0); } -static auto CreateBitmap(const image& icon) -> HBITMAP { +static auto CreateBitmap(image icon) -> HBITMAP { + icon.alphaMultiply(); //Windows AlphaBlend() requires premultiplied image data + icon.transform(); HDC hdc = GetDC(0); BITMAPINFO bitmapInfo; memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); @@ -30,6 +34,33 @@ static auto CreateBitmap(const image& icon) -> HBITMAP { return hbitmap; } +static auto CreateBitmap(const Image& image) -> HBITMAP { + HDC hdc = GetDC(0); + BITMAPINFO bitmapInfo{0}; + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = image.width(); + bitmapInfo.bmiHeader.biHeight = -image.height(); //bitmaps are stored upside down unless we negate height + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = image.width() * image.height() * sizeof(uint32_t); + void* bits = nullptr; + HBITMAP hbitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, nullptr, 0); + if(bits) { + auto source = (const uint8_t*)image.data(); + auto target = (uint8_t*)bits; + for(auto n : range(image.width() * image.height())) { + target[0] = (source[0] * source[3]) / 255; + target[1] = (source[1] * source[3]) / 255; + target[2] = (source[2] * source[3]) / 255; + target[3] = (source[3]); + source += 4, target += 4; + } + } + ReleaseDC(0, hdc); + return hbitmap; +} + static auto CreateRGB(const Color& color) -> COLORREF { return RGB(color.red(), color.green(), color.blue()); } @@ -62,16 +93,18 @@ static auto GetWindowZOrder(HWND hwnd) -> unsigned { return z; } -static auto ImageList_Append(HIMAGELIST imageList, const image& source, unsigned scale) -> void { - auto image = source; - if(image.empty()) { - image.allocate(scale, scale); - image.fill(GetSysColor(COLOR_WINDOW)); +static auto ImageList_Append(HIMAGELIST imageList, const Image& image, unsigned scale) -> void { + nall::image icon; + if(image) { + icon.allocate(image.width(), image.height()); + memory::copy(icon.data(), image.data(), icon.size()); + icon.scale(scale, scale); + } else { + icon.allocate(scale, scale); + icon.fill(GetSysColor(COLOR_WINDOW)); } - image.transform(); - image.scale(scale, scale); - HBITMAP bitmap = CreateBitmap(image); - ImageList_Add(imageList, bitmap, NULL); + HBITMAP bitmap = CreateBitmap(icon); + ImageList_Add(imageList, bitmap, nullptr); DeleteObject(bitmap); } diff --git a/hiro/windows/widget/button.cpp b/hiro/windows/widget/button.cpp index 76bc6b1e..eabd2b77 100644 --- a/hiro/windows/widget/button.cpp +++ b/hiro/windows/widget/button.cpp @@ -2,44 +2,92 @@ namespace hiro { +static auto Button_paintProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, + bool bordered, bool checked, bool enabled, const Font& font, const Image& image, Orientation orientation, const string& text +) -> LRESULT { + if(msg == WM_PAINT) { + PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + auto state = Button_GetState(hwnd); + Button_CustomDraw(hwnd, ps, + (state & BST_PUSHED || checked) ? PBS_PRESSED + : (state & BST_HOT) ? PBS_HOT + : bordered ? (enabled ? PBS_NORMAL : PBS_DISABLED) + : 0, font, image, orientation, text + ); + EndPaint(hwnd, &ps); + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + +//BUTTON cannot draw borderless buttons on its own +//BS_OWNERDRAW will send WM_DRAWITEM; but will disable hot-tracking notifications +//to gain hot-tracking plus borderless buttons; BUTTON is superclassed and WM_PAINT is hijacked +//note: letting hiro paint bordered buttons will lose the fade animations on Vista+; +//however, it will allow placing icons immediately next to text (original forces icon left alignment) +static auto CALLBACK Button_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto button = dynamic_cast(object)) { + if(auto self = button->self()) { + if(msg == WM_ERASEBKGND) return DefWindowProc(hwnd, msg, wparam, lparam); + if(msg == WM_PAINT) return Button_paintProc(hwnd, msg, wparam, lparam, + button->state.bordered, false, button->enabled(true), button->font(true), + button->state.image, button->state.orientation, button->state.text + ); + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + auto pButton::construct() -> void { hwnd = CreateWindow( - L"BUTTON", L"", - WS_CHILD | WS_TABSTOP, + L"BUTTON", L"", WS_CHILD | WS_TABSTOP, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)Button_windowProc); pWidget::_setState(); _setState(); - setBordered(state().bordered); } auto pButton::destruct() -> void { - if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } - if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } DestroyWindow(hwnd); } auto pButton::minimumSize() const -> Size { - auto size = pFont::size(hfont, state().text); - + Size image = state().image.size(); + Size text = state().text ? pFont::size(self().font(true), state().text) : Size{}; + Size size; if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(size.height(), state().icon.height())); + size.setWidth(image.width() + (image && text ? 5 : 0) + text.width()); + size.setHeight(max(image.height(), text.height())); } - if(state().orientation == Orientation::Vertical) { - size.setWidth(max(size.width(), state().icon.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(image.width(), text.width())); + size.setHeight(image.height() + (image && text ? 5 : 0) + text.height()); } - - return {size.width() + (state().text ? 20 : 13), size.height() + 10}; + size.setHeight(max(size.height(), pFont::size(self().font(true), " ").height())); + return {size.width() + (state().bordered && text ? 20 : 10), size.height() + 10}; } auto pButton::setBordered(bool bordered) -> void { + _setState(); } -auto pButton::setIcon(const image& icon) -> void { +auto pButton::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + _setState(); +} + +auto pButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + _setState(); +} + +auto pButton::setImage(const Image& image) -> void { _setState(); } @@ -51,42 +99,84 @@ auto pButton::setText(const string& text) -> void { _setState(); } +auto pButton::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + _setState(); +} + auto pButton::onActivate() -> void { self().doActivate(); } -//performs setIcon, setOrientation, setText auto pButton::_setState() -> void { - image icon = state().icon; - icon.transform(); + InvalidateRect(hwnd, 0, false); +} - if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } - if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } +//this function is designed to be used with Button, CheckButton, and RadioButton +auto Button_CustomDraw(HWND hwnd, PAINTSTRUCT& ps, unsigned state, const Font& font, const Image& image, Orientation orientation, const string& text) -> void { + RECT rc; + GetClientRect(hwnd, &rc); + Geometry geometry{rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}, imageGeometry, textGeometry; + if(image) imageGeometry.setSize(image.size()); + if(text) textGeometry.setSize(pFont::size(font, text)); - //Windows XP and earlier do not support translucent images - //so we must blend with the button background color (which does not look great with XP gradient-button themes) - if(OsVersion() < WindowsVista) icon.alphaBlend(GetSysColor(COLOR_BTNFACE)); + Position position; + Size size; - hbitmap = CreateBitmap(icon); - himagelist = ImageList_Create(icon.width(), icon.height(), ILC_COLOR32, 1, 0); - ImageList_Add(himagelist, hbitmap, NULL); - BUTTON_IMAGELIST list; - list.himl = himagelist; - switch(state().orientation) { - case Orientation::Horizontal: SetRect(&list.margin, 5, 0, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; break; - case Orientation::Vertical: SetRect(&list.margin, 0, 5, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_TOP; break; + switch(orientation) { + case Orientation::Horizontal: + size = {imageGeometry.width() + (image && text ? 5 : 0) + textGeometry.width(), max(imageGeometry.height(), textGeometry.height())}; + position = {(geometry.width() - size.width()) / 2, (geometry.height() - size.height()) / 2}; + imageGeometry.setPosition({position.x(), position.y() + (size.height() - imageGeometry.height()) / 2}); + textGeometry.setPosition({position.x() + size.width() - textGeometry.width(), position.y() + (size.height() - textGeometry.height()) / 2}); + break; + case Orientation::Vertical: + size = {max(imageGeometry.width(), textGeometry.width()), imageGeometry.height() + (image && text ? 5 : 0) + textGeometry.height()}; + position = {(geometry.width() - size.width()) / 2, (geometry.height() - size.height()) / 2}; + imageGeometry.setPosition({position.x() + (size.width() - imageGeometry.width()) / 2, position.y()}); + textGeometry.setPosition({position.x() + (size.width() - textGeometry.width()) / 2, position.y() + size.height() - textGeometry.height()}); + break; } - Button_SetImageList(hwnd, &list); - if(auto text = state().text) { - //text will not show up if BS_BITMAP is set - SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) &~ BS_BITMAP); - SetWindowText(hwnd, utf16_t(text)); - } else { - //bitmaps will not show up if text is empty - SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | BS_BITMAP); - SetWindowText(hwnd, L""); + HDC hdcSource = CreateCompatibleDC(ps.hdc); + DrawThemeParentBackground(hwnd, ps.hdc, &rc); + + if(state) { + if(auto theme = OpenThemeData(hwnd, L"BUTTON")) { + DrawThemeBackground(theme, ps.hdc, BP_PUSHBUTTON, state, &rc, &ps.rcPaint); + CloseThemeData(theme); + } } + + if(GetFocus() == hwnd) { + signed offset = state ? 4 : 1; + RECT rcFocus{rc.left + offset, rc.top + offset, rc.right - offset, rc.bottom - offset}; + if(!state || state == PBS_NORMAL) DrawFocusRect(ps.hdc, &rcFocus); + } + + if(image) { + auto bitmap = CreateBitmap(image); + SelectBitmap(hdcSource, bitmap); + BLENDFUNCTION blend{AC_SRC_OVER, 0, (BYTE)(IsWindowEnabled(hwnd) ? 255 : 128), AC_SRC_ALPHA}; + AlphaBlend( + ps.hdc, imageGeometry.x(), imageGeometry.y(), image.width(), image.height(), + hdcSource, 0, 0, image.width(), image.height(), blend + ); + DeleteObject(bitmap); + } + + if(text) { + utf16_t wText(text); + SetBkMode(ps.hdc, TRANSPARENT); + SetTextColor(ps.hdc, GetSysColor(IsWindowEnabled(hwnd) ? COLOR_BTNTEXT : COLOR_GRAYTEXT)); + auto hFont = pFont::create(font); + SelectObject(ps.hdc, hFont); + RECT rcText{textGeometry.x(), textGeometry.y(), textGeometry.x() + textGeometry.width(), textGeometry.y() + textGeometry.height()}; + DrawText(ps.hdc, wText, -1, &rcText, DT_NOPREFIX | DT_END_ELLIPSIS); + DeleteObject(hFont); + } + + DeleteDC(hdcSource); } } diff --git a/hiro/windows/widget/button.hpp b/hiro/windows/widget/button.hpp index 12ee854f..3ff16470 100644 --- a/hiro/windows/widget/button.hpp +++ b/hiro/windows/widget/button.hpp @@ -7,16 +7,18 @@ struct pButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; - auto setIcon(const image& icon) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; auto onActivate() -> void; auto _setState() -> void; - HBITMAP hbitmap; - HIMAGELIST himagelist; + WindowProc windowProc = nullptr; }; } diff --git a/hiro/windows/widget/canvas.cpp b/hiro/windows/widget/canvas.cpp index b30dd9f9..6118e6e4 100644 --- a/hiro/windows/widget/canvas.cpp +++ b/hiro/windows/widget/canvas.cpp @@ -69,16 +69,11 @@ auto pCanvas::destruct() -> void { } auto pCanvas::minimumSize() const -> Size { - return {max(0, state().size.width()), max(0, state().size.height())}; + if(auto& image = state().image) return image.size(); + return {0, 0}; } auto pCanvas::setColor(Color color) -> void { - mode = Mode::Color; - update(); -} - -auto pCanvas::setData(Size size) -> void { - mode = Mode::Data; update(); } @@ -91,13 +86,11 @@ auto pCanvas::setGeometry(Geometry geometry) -> void { update(); } -auto pCanvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void { - mode = Mode::Gradient; +auto pCanvas::setGradient(Gradient gradient) -> void { update(); } -auto pCanvas::setIcon(const image& icon) -> void { - mode = Mode::Icon; +auto pCanvas::setImage(const Image& image) -> void { update(); } @@ -121,8 +114,18 @@ auto pCanvas::_paint() -> void { bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside now; negative height flips bitmap bmi.bmiHeader.biSizeImage = pixels.size() * sizeof(uint32_t); void* bits = nullptr; - HBITMAP bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); - if(bits) memory::copy(bits, pixels.data(), pixels.size() * sizeof(uint32_t)); + HBITMAP bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0); + if(bits) { + auto source = (const uint8_t*)pixels.data(); + auto target = (uint8_t*)bits; + for(auto n : range(width * height)) { + target[0] = (source[0] * source[3]) / 255; + target[1] = (source[1] * source[3]) / 255; + target[2] = (source[2] * source[3]) / 255; + target[3] = (source[3]); + source += 4, target += 4; + } + } SelectObject(hdc, bitmap); RECT rc; @@ -139,45 +142,29 @@ auto pCanvas::_paint() -> void { } auto pCanvas::_rasterize() -> void { - if(mode == Mode::Color || mode == Mode::Gradient) { + if(auto& image = state().image) { + width = image.width(); + height = image.height(); + } else { width = self().geometry().width(); height = self().geometry().height(); - } else { - width = state().size.width(); - height = state().size.height(); } if(width <= 0 || height <= 0) return; pixels.reallocate(width * height); - if(mode == Mode::Color) { + if(auto& image = state().image) { + memory::copy(pixels.data(), image.data(), width * height * sizeof(uint32_t)); + } else if(auto& gradient = state().gradient) { + auto& colors = gradient.state.colors; + nall::image fill; + fill.allocate(width, height); + fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value()); + memory::copy(pixels.data(), fill.data(), fill.size()); + } else { uint32_t color = state().color.value(); for(auto& pixel : pixels) pixel = color; } - - if(mode == Mode::Gradient) { - image fill; - fill.allocate(width, height); - fill.gradient( - state().gradient[0].value(), state().gradient[1].value(), - state().gradient[2].value(), state().gradient[3].value() - ); - memory::copy(pixels.data(), fill.data(), fill.size()); - } - - if(mode == Mode::Icon) { - auto icon = state().icon; - icon.scale(width, height); - icon.transform(); - memory::copy(pixels.data(), icon.data(), icon.size()); - } - - if(mode == Mode::Data) { - memory::copy( - pixels.data(), pixels.size() * sizeof(uint32_t), - state().data.data(), state().data.size() * sizeof(uint32_t) - ); - } } auto pCanvas::_redraw() -> void { diff --git a/hiro/windows/widget/canvas.hpp b/hiro/windows/widget/canvas.hpp index f66bb8be..a76f5cfb 100644 --- a/hiro/windows/widget/canvas.hpp +++ b/hiro/windows/widget/canvas.hpp @@ -7,20 +7,16 @@ struct pCanvas : pWidget { auto minimumSize() const -> Size override; auto setColor(Color color) -> void; - auto setData(Size size) -> void; auto setDroppable(bool droppable) -> void; auto setGeometry(Geometry geometry) -> void override; - auto setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) -> void; - auto setIcon(const image& icon) -> void; + auto setGradient(Gradient gradient) -> void; + auto setImage(const Image& image) -> void; auto update() -> void; - enum class Mode : unsigned { Color, Data, Gradient, Icon }; - auto _paint() -> void; auto _rasterize() -> void; auto _redraw() -> void; - Mode mode = Mode::Color; vector pixels; signed width = 0; signed height = 0; diff --git a/hiro/windows/widget/check-button.cpp b/hiro/windows/widget/check-button.cpp index badd781e..7da36753 100644 --- a/hiro/windows/widget/check-button.cpp +++ b/hiro/windows/widget/check-button.cpp @@ -2,47 +2,73 @@ namespace hiro { +static auto CALLBACK CheckButton_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto button = dynamic_cast(object)) { + if(auto self = button->self()) { + if(msg == WM_ERASEBKGND) return DefWindowProc(hwnd, msg, wparam, lparam); + if(msg == WM_PAINT) return Button_paintProc(hwnd, msg, wparam, lparam, + button->state.bordered, button->state.checked, button->enabled(true), button->font(true), + button->state.image, button->state.orientation, button->state.text + ); + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + auto pCheckButton::construct() -> void { hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP | BS_CHECKBOX | BS_PUSHLIKE, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)CheckButton_windowProc); pWidget::_setState(); _setState(); - setBordered(state().bordered); setChecked(state().checked); } auto pCheckButton::destruct() -> void { - if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } - if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } DestroyWindow(hwnd); } auto pCheckButton::minimumSize() const -> Size { - auto size = pFont::size(hfont, state().text); - + Size image = state().image.size(); + Size text = state().text ? pFont::size(self().font(true), state().text) : Size{}; + Size size; if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(size.height(), state().icon.height())); + size.setWidth(image.width() + (image && text ? 5 : 0) + text.width()); + size.setHeight(max(image.height(), text.height())); } - if(state().orientation == Orientation::Vertical) { - size.setWidth(max(size.width(), state().icon.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(image.width(), text.width())); + size.setHeight(image.height() + (image && text ? 5 : 0) + text.height()); } - - return {size.width() + (state().text ? 20 : 10), size.height() + 10}; + size.setHeight(max(size.height(), pFont::size(self().font(true), " ").height())); + return {size.width() + (state().bordered && text ? 20 : 10), size.height() + 10}; } auto pCheckButton::setBordered(bool bordered) -> void { + _setState(); } auto pCheckButton::setChecked(bool checked) -> void { SendMessage(hwnd, BM_SETCHECK, (WPARAM)checked, 0); } -auto pCheckButton::setIcon(const image& icon) -> void { +auto pCheckButton::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + _setState(); +} + +auto pCheckButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + _setState(); +} + +auto pCheckButton::setImage(const Image& image) -> void { _setState(); } @@ -54,6 +80,11 @@ auto pCheckButton::setText(const string& text) -> void { _setState(); } +auto pCheckButton::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + _setState(); +} + auto pCheckButton::onToggle() -> void { state().checked = !state().checked; setChecked(state().checked); @@ -61,32 +92,7 @@ auto pCheckButton::onToggle() -> void { } auto pCheckButton::_setState() -> void { - image icon = state().icon; - icon.transform(); - - if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } - if(himagelist) { ImageList_Destroy(himagelist); himagelist = nullptr; } - - if(OsVersion() < WindowsVista) icon.alphaBlend(GetSysColor(COLOR_BTNFACE)); - - hbitmap = CreateBitmap(icon); - himagelist = ImageList_Create(icon.width(), icon.height(), ILC_COLOR32, 1, 0); - ImageList_Add(himagelist, hbitmap, nullptr); - BUTTON_IMAGELIST list; - list.himl = himagelist; - switch(state().orientation) { - case Orientation::Horizontal: SetRect(&list.margin, 5, 0, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; break; - case Orientation::Vertical: SetRect(&list.margin, 0, 5, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_TOP; break; - } - Button_SetImageList(hwnd, &list); - - if(auto text = state().text) { - SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) &~ BS_BITMAP); - SetWindowText(hwnd, utf16_t(text)); - } else { - SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | BS_BITMAP); - SetWindowText(hwnd, L""); - } + InvalidateRect(hwnd, 0, false); } } diff --git a/hiro/windows/widget/check-button.hpp b/hiro/windows/widget/check-button.hpp index 3083cb2d..62ab9a82 100644 --- a/hiro/windows/widget/check-button.hpp +++ b/hiro/windows/widget/check-button.hpp @@ -7,17 +7,19 @@ struct pCheckButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; auto setChecked(bool checked) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; auto onToggle() -> void; auto _setState() -> void; - HBITMAP hbitmap = 0; - HIMAGELIST himagelist = 0; + WindowProc windowProc = nullptr; }; } diff --git a/hiro/windows/widget/check-label.cpp b/hiro/windows/widget/check-label.cpp index d263c7bb..7aa12508 100644 --- a/hiro/windows/widget/check-label.cpp +++ b/hiro/windows/widget/check-label.cpp @@ -19,7 +19,7 @@ auto pCheckLabel::destruct() -> void { } auto pCheckLabel::minimumSize() const -> Size { - auto size = pFont::size(hfont, state().text); + auto size = pFont::size(self().font(true), state().text ? state().text : " "); return {size.width() + 20, size.height() + 4}; } diff --git a/hiro/windows/widget/combo-button-item.cpp b/hiro/windows/widget/combo-button-item.cpp index 0b8b1a0e..dc802202 100644 --- a/hiro/windows/widget/combo-button-item.cpp +++ b/hiro/windows/widget/combo-button-item.cpp @@ -8,7 +8,7 @@ auto pComboButtonItem::construct() -> void { auto pComboButtonItem::destruct() -> void { } -auto pComboButtonItem::setIcon(const image& icon) -> void { +auto pComboButtonItem::setImage(const Image& image) -> void { //unsupported } diff --git a/hiro/windows/widget/combo-button-item.hpp b/hiro/windows/widget/combo-button-item.hpp index 335e489a..045996ab 100644 --- a/hiro/windows/widget/combo-button-item.hpp +++ b/hiro/windows/widget/combo-button-item.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pComboButtonItem : pObject { Declare(ComboButtonItem, Object) - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setSelected() -> void; auto setText(const string& text) -> void; diff --git a/hiro/windows/widget/line-edit.cpp b/hiro/windows/widget/line-edit.cpp index 5dd03e13..81311ee0 100644 --- a/hiro/windows/widget/line-edit.cpp +++ b/hiro/windows/widget/line-edit.cpp @@ -21,7 +21,7 @@ auto pLineEdit::destruct() -> void { } auto pLineEdit::minimumSize() const -> Size { - auto size = pFont::size(hfont, state().text); + auto size = pFont::size(hfont, state().text ? state().text : " "); return {size.width() + 12, size.height() + 10}; } diff --git a/hiro/windows/widget/list-view-cell.cpp b/hiro/windows/widget/list-view-cell.cpp index 0b912aae..f37b62b6 100644 --- a/hiro/windows/widget/list-view-cell.cpp +++ b/hiro/windows/widget/list-view-cell.cpp @@ -27,7 +27,7 @@ auto pListViewCell::setForegroundColor(Color color) -> void { _repaint(); } -auto pListViewCell::setIcon(const image& icon) -> void { +auto pListViewCell::setImage(const Image& icon) -> void { _repaint(); } diff --git a/hiro/windows/widget/list-view-cell.hpp b/hiro/windows/widget/list-view-cell.hpp index d5c62923..4cc0e0d0 100644 --- a/hiro/windows/widget/list-view-cell.hpp +++ b/hiro/windows/widget/list-view-cell.hpp @@ -10,7 +10,7 @@ struct pListViewCell : pObject { auto setCheckable(bool checkable) -> void; auto setChecked(bool checked) -> void; auto setForegroundColor(Color color) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setText(const string& text) -> void; auto _parent() -> maybe; diff --git a/hiro/windows/widget/list-view-column.cpp b/hiro/windows/widget/list-view-column.cpp index ef2871b3..06a1b26c 100644 --- a/hiro/windows/widget/list-view-column.cpp +++ b/hiro/windows/widget/list-view-column.cpp @@ -49,7 +49,7 @@ auto pListViewColumn::setHorizontalAlignment(double alignment) -> void { _setState(); } -auto pListViewColumn::setIcon(const image& icon) -> void { +auto pListViewColumn::setImage(const Image& image) -> void { _setState(); } @@ -97,7 +97,7 @@ auto pListViewColumn::_setState() -> void { lvColumn.cx = _width; if(state().horizontalAlignment < 0.333) lvColumn.fmt = LVCFMT_LEFT; if(state().horizontalAlignment > 0.666) lvColumn.fmt = LVCFMT_RIGHT; - if(state().icon) lvColumn.mask |= LVCF_IMAGE; + if(state().image) lvColumn.mask |= LVCF_IMAGE; if(!state().resizable) lvColumn.fmt |= LVCFMT_FIXED_WIDTH; ListView_SetColumn(grandparent->hwnd, self().offset(), &lvColumn); grandparent->unlock(); diff --git a/hiro/windows/widget/list-view-column.hpp b/hiro/windows/widget/list-view-column.hpp index 2c00c654..bf13aeac 100644 --- a/hiro/windows/widget/list-view-column.hpp +++ b/hiro/windows/widget/list-view-column.hpp @@ -12,7 +12,7 @@ struct pListViewColumn : pObject { auto setExpandable(bool expandable) -> void; auto setForegroundColor(Color color) -> void; auto setHorizontalAlignment(double alignment) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setResizable(bool resizable) -> void; auto setSortable(bool sortable) -> void; auto setText(const string& text) -> void; diff --git a/hiro/windows/widget/list-view.cpp b/hiro/windows/widget/list-view.cpp index a9bc6de3..4d573bed 100644 --- a/hiro/windows/widget/list-view.cpp +++ b/hiro/windows/widget/list-view.cpp @@ -219,13 +219,11 @@ auto pListView::onCustomDraw(LPARAM lparam) -> LRESULT { rc.left += 2; } - if(auto icon = cell->state.icon) { - icon.scale(iconSize, iconSize); - icon.transform(); - auto bitmap = CreateBitmap(icon); + if(auto& image = cell->state.image) { + auto bitmap = CreateBitmap(image); SelectBitmap(hdcSource, bitmap); BLENDFUNCTION blend{AC_SRC_OVER, 0, (BYTE)(selected ? 128 : 255), AC_SRC_ALPHA}; - AlphaBlend(hdc, rc.left, rc.top, iconSize, iconSize, hdcSource, 0, 0, iconSize, iconSize, blend); + AlphaBlend(hdc, rc.left, rc.top, iconSize, iconSize, hdcSource, 0, 0, image.width(), image.height(), blend); DeleteObject(bitmap); rc.left += iconSize + 2; } @@ -325,11 +323,11 @@ auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned { if(cell->state.checkable) { width += 16 + 2; } - if(auto& icon = cell->state.icon) { + if(auto& image = cell->state.image) { width += 16 + 2; } if(auto& text = cell->state.text) { - width += Font::size(_font(_row, _column), text).width(); + width += pFont::size(_font(_row, _column), text).width(); } } } @@ -340,18 +338,18 @@ auto pListView::_columnWidth(unsigned _column) -> unsigned { unsigned width = 12; if(auto header = state().header) { if(auto column = header->column(_column)) { - if(auto& icon = column->state.icon) { + if(auto& image = column->state.image) { width += 16 + 12; //yes; icon spacing in column headers is excessive } if(auto& text = column->state.text) { - width += Font::size(self().font(true), text).width(); + width += pFont::size(self().font(true), text).width(); } } } return width; } -auto pListView::_font(unsigned _row, unsigned _column) -> string { +auto pListView::_font(unsigned _row, unsigned _column) -> Font { if(auto item = self().item(_row)) { if(auto cell = item->cell(_column)) { if(auto font = cell->font()) return font; @@ -362,7 +360,7 @@ auto pListView::_font(unsigned _row, unsigned _column) -> string { // if(auto font = column->font()) return font; // } if(auto font = self().font(true)) return font; - return Font::sans(8); + return {}; } auto pListView::_foregroundColor(unsigned _row, unsigned _column) -> Color { @@ -387,10 +385,11 @@ auto pListView::_setIcons() -> void { if(auto& header = state().header) { for(auto column : range(header->columnCount())) { - auto icon = header->state.columns[column]->state.icon; - if(icon) { + nall::image icon; + if(auto& image = header->state.columns[column]->state.image) { + icon.allocate(image.width(), image.height()); + memory::copy(icon.data(), image.data(), icon.size()); icon.scale(16, 16); - icon.transform(); } else { icon.allocate(16, 16); icon.fill(0x00ffffff); @@ -402,7 +401,7 @@ auto pListView::_setIcons() -> void { } //empty icon used for ListViewItems (drawn manually via onCustomDraw) - image icon; + nall::image icon; icon.allocate(16, 16); icon.fill(0x00ffffff); auto bitmap = CreateBitmap(icon); diff --git a/hiro/windows/widget/list-view.hpp b/hiro/windows/widget/list-view.hpp index 4aff0796..3e3af014 100644 --- a/hiro/windows/widget/list-view.hpp +++ b/hiro/windows/widget/list-view.hpp @@ -27,7 +27,7 @@ struct pListView : pWidget { auto _backgroundColor(unsigned row, unsigned column) -> Color; auto _cellWidth(unsigned row, unsigned column) -> unsigned; auto _columnWidth(unsigned column) -> unsigned; - auto _font(unsigned row, unsigned column) -> string; + auto _font(unsigned row, unsigned column) -> Font; auto _foregroundColor(unsigned row, unsigned column) -> Color; auto _setIcons() -> void; auto _setSortable() -> void; diff --git a/hiro/windows/widget/radio-button.cpp b/hiro/windows/widget/radio-button.cpp index 06751286..fabba761 100644 --- a/hiro/windows/widget/radio-button.cpp +++ b/hiro/windows/widget/radio-button.cpp @@ -2,44 +2,60 @@ namespace hiro { +static auto CALLBACK RadioButton_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT { + if(auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA)) { + if(auto button = dynamic_cast(object)) { + if(auto self = button->self()) { + if(msg == WM_ERASEBKGND) return DefWindowProc(hwnd, msg, wparam, lparam); + if(msg == WM_PAINT) return Button_paintProc(hwnd, msg, wparam, lparam, + button->state.bordered, button->state.checked, button->enabled(true), button->font(true), + button->state.image, button->state.orientation, button->state.text + ); + return self->windowProc(hwnd, msg, wparam, lparam); + } + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); +} + auto pRadioButton::construct() -> void { hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP | BS_CHECKBOX | BS_PUSHLIKE, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); + windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)RadioButton_windowProc); pWidget::_setState(); + setGroup(state().group); _setState(); - setBordered(state().bordered); - if(state().checked) setChecked(); } auto pRadioButton::destruct() -> void { - if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } - if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } DestroyWindow(hwnd); } auto pRadioButton::minimumSize() const -> Size { - auto size = pFont::size(hfont, state().text); - + Size image = state().image.size(); + Size text = state().text ? pFont::size(self().font(true), state().text) : Size{}; + Size size; if(state().orientation == Orientation::Horizontal) { - size.setWidth(size.width() + state().icon.width()); - size.setHeight(max(size.height(), state().icon.height())); + size.setWidth(image.width() + (image && text ? 5 : 0) + text.width()); + size.setHeight(max(image.height(), text.height())); } - if(state().orientation == Orientation::Vertical) { - size.setWidth(max(size.width(), state().icon.width())); - size.setHeight(size.height() + state().icon.height()); + size.setWidth(max(image.width(), text.width())); + size.setHeight(image.height() + (image && text ? 5 : 0) + text.height()); } - - return {size.width() + (state().text ? 20 : 10), size.height() + 10}; + size.setHeight(max(size.height(), pFont::size(self().font(true), " ").height())); + return {size.width() + (state().bordered && text ? 20 : 10), size.height() + 10}; } auto pRadioButton::setBordered(bool bordered) -> void { + _setState(); } auto pRadioButton::setChecked() -> void { - if(auto group = self().group()) { + if(auto& group = state().group) { for(auto& weak : group->state.objects) { if(auto object = weak.acquire()) { if(auto radioButton = dynamic_cast(object.data())) { @@ -52,10 +68,33 @@ auto pRadioButton::setChecked() -> void { } } -auto pRadioButton::setGroup(sGroup group) -> void { +auto pRadioButton::setEnabled(bool enabled) -> void { + pWidget::setEnabled(enabled); + _setState(); } -auto pRadioButton::setIcon(const image& icon) -> void { +auto pRadioButton::setFont(const Font& font) -> void { + pWidget::setFont(font); + _setState(); +} + +auto pRadioButton::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioButton = dynamic_cast(object.data())) { + if(auto self = radioButton->self()) { + SendMessage(self->hwnd, BM_SETCHECK, (WPARAM)(radioButton->state.checked = first), 0); + first = false; + } + } + } + } + } +} + +auto pRadioButton::setImage(const Image& image) -> void { _setState(); } @@ -63,43 +102,23 @@ auto pRadioButton::setOrientation(Orientation orientation) -> void { _setState(); } -void pRadioButton::setText(const string& text) { +auto pRadioButton::setText(const string& text) -> void { _setState(); } -void pRadioButton::onActivate() { +auto pRadioButton::setVisible(bool visible) -> void { + pWidget::setVisible(visible); + _setState(); +} + +auto pRadioButton::onActivate() -> void { if(state().checked) return; self().setChecked(); self().doActivate(); } auto pRadioButton::_setState() -> void { - image icon = state().icon; - icon.transform(); - - if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; } - if(himagelist) { ImageList_Destroy(himagelist); himagelist = nullptr; } - - if(OsVersion() < WindowsVista) icon.alphaBlend(GetSysColor(COLOR_BTNFACE)); - - hbitmap = CreateBitmap(icon); - himagelist = ImageList_Create(icon.width(), icon.height(), ILC_COLOR32, 1, 0); - ImageList_Add(himagelist, hbitmap, nullptr); - BUTTON_IMAGELIST list; - list.himl = himagelist; - switch(state().orientation) { - case Orientation::Horizontal: SetRect(&list.margin, 5, 0, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; break; - case Orientation::Vertical: SetRect(&list.margin, 0, 5, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_TOP; break; - } - Button_SetImageList(hwnd, &list); - - if(auto text = state().text) { - SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) &~ BS_BITMAP); - SetWindowText(hwnd, utf16_t(text)); - } else { - SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | BS_BITMAP); - SetWindowText(hwnd, L""); - } + InvalidateRect(hwnd, 0, false); } } diff --git a/hiro/windows/widget/radio-button.hpp b/hiro/windows/widget/radio-button.hpp index 31f4d917..2a94db2f 100644 --- a/hiro/windows/widget/radio-button.hpp +++ b/hiro/windows/widget/radio-button.hpp @@ -8,17 +8,19 @@ struct pRadioButton : pWidget { auto minimumSize() const -> Size override; auto setBordered(bool bordered) -> void; auto setChecked() -> void; + auto setEnabled(bool enabled) -> void override; + auto setFont(const Font& font) -> void override; auto setGroup(sGroup group) -> void override; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setOrientation(Orientation orientation) -> void; auto setText(const string& text) -> void; + auto setVisible(bool visible) -> void override; auto onActivate() -> void; auto _setState() -> void; - HBITMAP hbitmap = 0; - HIMAGELIST himagelist = 0; + WindowProc windowProc = nullptr; }; } diff --git a/hiro/windows/widget/radio-label.cpp b/hiro/windows/widget/radio-label.cpp index 01231102..90db50b7 100644 --- a/hiro/windows/widget/radio-label.cpp +++ b/hiro/windows/widget/radio-label.cpp @@ -4,13 +4,12 @@ namespace hiro { auto pRadioLabel::construct() -> void { hwnd = CreateWindow( - L"BUTTON", L"", - WS_CHILD | WS_TABSTOP | BS_RADIOBUTTON, + L"BUTTON", L"", WS_CHILD | WS_TABSTOP | BS_RADIOBUTTON, 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); pWidget::_setState(); - if(state().checked) setChecked(); + setGroup(state().group); setText(state().text); } @@ -18,13 +17,13 @@ auto pRadioLabel::destruct() -> void { DestroyWindow(hwnd); } -auto pRadioLabel::minimumSize() -> Size { - auto size = pFont::size(hfont, state().text); +auto pRadioLabel::minimumSize() const -> Size { + auto size = pFont::size(self().font(true), state().text ? state().text : " "); return {size.width() + 20, size.height() + 4}; } auto pRadioLabel::setChecked() -> void { - if(auto group = self().group()) { + if(auto& group = state().group) { for(auto& weak : group->state.objects) { if(auto object = weak.acquire()) { if(auto radioLabel = dynamic_cast(object.data())) { @@ -38,6 +37,19 @@ auto pRadioLabel::setChecked() -> void { } auto pRadioLabel::setGroup(sGroup group) -> void { + bool first = true; + if(auto& group = state().group) { + for(auto& weak : group->state.objects) { + if(auto object = weak.acquire()) { + if(auto radioLabel = dynamic_cast(object.data())) { + if(auto self = radioLabel->self()) { + SendMessage(self->hwnd, BM_SETCHECK, (WPARAM)(radioLabel->state.checked = first), 0); + first = false; + } + } + } + } + } } auto pRadioLabel::setText(const string& text) -> void { diff --git a/hiro/windows/widget/radio-label.hpp b/hiro/windows/widget/radio-label.hpp index 38b5b6f7..28f1b29d 100644 --- a/hiro/windows/widget/radio-label.hpp +++ b/hiro/windows/widget/radio-label.hpp @@ -5,7 +5,7 @@ namespace hiro { struct pRadioLabel : pWidget { Declare(RadioLabel, Widget) - auto minimumSize() -> Size; + auto minimumSize() const -> Size override; auto setChecked() -> void; auto setGroup(sGroup group) -> void override; auto setText(const string& text) -> void; diff --git a/hiro/windows/widget/tab-frame-item.cpp b/hiro/windows/widget/tab-frame-item.cpp index 2583d648..e9615d50 100644 --- a/hiro/windows/widget/tab-frame-item.cpp +++ b/hiro/windows/widget/tab-frame-item.cpp @@ -24,7 +24,7 @@ auto pTabFrameItem::setClosable(bool closable) -> void { //unsupported } -auto pTabFrameItem::setIcon(const image& icon) -> void { +auto pTabFrameItem::setImage(const Image& image) -> void { if(auto parent = _parent()) { parent->_buildImageList(); } diff --git a/hiro/windows/widget/tab-frame-item.hpp b/hiro/windows/widget/tab-frame-item.hpp index d08a2696..37bef59d 100644 --- a/hiro/windows/widget/tab-frame-item.hpp +++ b/hiro/windows/widget/tab-frame-item.hpp @@ -8,7 +8,7 @@ struct pTabFrameItem : pObject { auto append(sLayout layout) -> void; auto remove(sLayout layout) -> void; auto setClosable(bool closable) -> void; - auto setIcon(const image& icon) -> void; + auto setImage(const Image& image) -> void; auto setMovable(bool movable) -> void; auto setSelected() -> void; auto setText(const string& text) -> void; diff --git a/hiro/windows/widget/tab-frame.cpp b/hiro/windows/widget/tab-frame.cpp index 22efbc66..3c320e71 100644 --- a/hiro/windows/widget/tab-frame.cpp +++ b/hiro/windows/widget/tab-frame.cpp @@ -15,9 +15,10 @@ static auto CALLBACK TabFrame_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPA } auto pTabFrame::construct() -> void { - hwnd = CreateWindow(WC_TABCONTROL, L"", - WS_CHILD | WS_TABSTOP, - 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0); + hwnd = CreateWindow( + WC_TABCONTROL, L"", WS_CHILD | WS_TABSTOP, + 0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0 + ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); windowProc = (WindowProc)GetWindowLongPtr(hwnd, GWLP_WNDPROC); SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)TabFrame_windowProc); @@ -38,7 +39,7 @@ auto pTabFrame::append(sTabFrameItem item) -> void { TabCtrl_InsertItem(hwnd, item->offset(), &tcItem); if(auto self = item->self()) { self->setClosable(item->state.closable); - self->setIcon(item->state.icon); + self->setImage(item->state.image); self->setMovable(item->state.movable); self->setText(item->state.text); if(item->selected()) self->setSelected(); @@ -52,10 +53,6 @@ auto pTabFrame::remove(sTabFrameItem item) -> void { _buildImageList(); } -auto pTabFrame::setEdge(Edge edge) -> void { - //unsupported -} - auto pTabFrame::setEnabled(bool enabled) -> void { pWidget::setEnabled(enabled); for(auto& item : state().items) { @@ -78,6 +75,10 @@ auto pTabFrame::setGeometry(Geometry geometry) -> void { } } +auto pTabFrame::setNavigation(Navigation navigation) -> void { + //unsupported +} + auto pTabFrame::setVisible(bool visible) -> void { pWidget::setVisible(visible); for(auto& item : state().items) { @@ -93,13 +94,13 @@ auto pTabFrame::_buildImageList() -> void { if(imageList) { ImageList_Destroy(imageList); imageList = nullptr; } imageList = ImageList_Create(size, size, ILC_COLOR32, 1, 0); for(auto& item : state().items) { - ImageList_Append(imageList, item->state.icon, size); + ImageList_Append(imageList, item->state.image, size); } TabCtrl_SetImageList(hwnd, imageList); for(auto offset : range(state().items)) { TCITEM tcItem; tcItem.mask = TCIF_IMAGE; - tcItem.iImage = state().items[offset]->state.icon ? offset : -1; + tcItem.iImage = state().items[offset]->state.image ? offset : -1; TabCtrl_SetItem(hwnd, offset, &tcItem); } } diff --git a/hiro/windows/widget/tab-frame.hpp b/hiro/windows/widget/tab-frame.hpp index cfbd0d8a..e2356a6b 100644 --- a/hiro/windows/widget/tab-frame.hpp +++ b/hiro/windows/widget/tab-frame.hpp @@ -7,9 +7,9 @@ struct pTabFrame : pWidget { auto append(sTabFrameItem item) -> void; auto remove(sTabFrameItem item) -> void; - auto setEdge(Edge edge) -> void; auto setEnabled(bool enabled) -> void override; auto setGeometry(Geometry geometry) -> void override; + auto setNavigation(Navigation navigation) -> void; auto setVisible(bool visible) -> void override; auto onChange() -> void; diff --git a/hiro/windows/widget/text-edit.cpp b/hiro/windows/widget/text-edit.cpp index 81255b06..2ddb830d 100644 --- a/hiro/windows/widget/text-edit.cpp +++ b/hiro/windows/widget/text-edit.cpp @@ -11,9 +11,9 @@ auto pTextEdit::construct() -> void { SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference); pWidget::_setState(); setBackgroundColor(state().backgroundColor); - setCursorPosition(state().cursorPosition); setEditable(state().editable); setText(state().text); + setCursor(state().cursor); } auto pTextEdit::destruct() -> void { @@ -27,9 +27,11 @@ auto pTextEdit::setBackgroundColor(Color color) -> void { backgroundBrush = CreateSolidBrush(color ? CreateRGB(color) : GetSysColor(COLOR_WINDOW)); } -auto pTextEdit::setCursorPosition(unsigned position) -> void { - if(position == ~0) position >>= 1; //Edit_SetSel takes signed type - Edit_SetSel(hwnd, position, position); +auto pTextEdit::setCursor(Cursor cursor) -> void { + signed end = GetWindowTextLength(hwnd); + signed offset = max(0, min(end, cursor.offset())); + signed length = max(0, min(end, cursor.offset() + cursor.length())); + Edit_SetSel(hwnd, offset, length); Edit_ScrollCaret(hwnd); } diff --git a/hiro/windows/widget/text-edit.hpp b/hiro/windows/widget/text-edit.hpp index 061d12af..e3605475 100644 --- a/hiro/windows/widget/text-edit.hpp +++ b/hiro/windows/widget/text-edit.hpp @@ -6,7 +6,7 @@ struct pTextEdit : pWidget { Declare(TextEdit, Widget) auto setBackgroundColor(Color color) -> void; - auto setCursorPosition(unsigned position) -> void; + auto setCursor(Cursor cursor) -> void; auto setEditable(bool editable) -> void; auto setForegroundColor(Color color) -> void; auto setText(string text) -> void; diff --git a/hiro/windows/widget/widget.cpp b/hiro/windows/widget/widget.cpp index 2d2a8afb..5edde98b 100644 --- a/hiro/windows/widget/widget.cpp +++ b/hiro/windows/widget/widget.cpp @@ -35,11 +35,9 @@ auto pWidget::setFocused() -> void { SetFocus(hwnd); } -auto pWidget::setFont(const string&) -> void { - auto font = self().font(true); - if(!font) font = Font::sans(8); +auto pWidget::setFont(const Font&) -> void { if(hfont) DeleteObject(hfont); - hfont = pFont::create(font); + hfont = pFont::create(self().font(true)); SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); } diff --git a/hiro/windows/widget/widget.hpp b/hiro/windows/widget/widget.hpp index e8350116..2f2926a0 100644 --- a/hiro/windows/widget/widget.hpp +++ b/hiro/windows/widget/widget.hpp @@ -9,7 +9,7 @@ struct pWidget : pSizable { virtual auto minimumSize() -> Size; auto setEnabled(bool enabled) -> void override; auto setFocused() -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; virtual auto setGeometry(Geometry geometry) -> void; auto setVisible(bool visible) -> void override; diff --git a/hiro/windows/window.cpp b/hiro/windows/window.cpp index 92d49c2e..675c5385 100644 --- a/hiro/windows/window.cpp +++ b/hiro/windows/window.cpp @@ -82,7 +82,7 @@ auto pWindow::setFocused() -> void { SetFocus(hwnd); } -auto pWindow::setFont(const string& font) -> void { +auto pWindow::setFont(const Font& font) -> void { if(auto layout = state().layout) { if(auto self = layout->self()) self->setFont(layout->font(true)); } diff --git a/hiro/windows/window.hpp b/hiro/windows/window.hpp index 11f0dd39..e42397ad 100644 --- a/hiro/windows/window.hpp +++ b/hiro/windows/window.hpp @@ -17,7 +17,7 @@ struct pWindow : pObject { auto setDroppable(bool droppable) -> void; auto setEnabled(bool enabled) -> void; auto setFocused() -> void; - auto setFont(const string& font) -> void override; + auto setFont(const Font& font) -> void override; auto setFullScreen(bool fullScreen) -> void; auto setGeometry(Geometry geometry) -> void; auto setModal(bool modal) -> void; diff --git a/nall/image/base.hpp b/nall/image/base.hpp index e7c4c059..42244ee9 100644 --- a/nall/image/base.hpp +++ b/nall/image/base.hpp @@ -80,6 +80,7 @@ struct image { //utility.hpp inline auto crop(unsigned x, unsigned y, unsigned width, unsigned height) -> bool; inline auto alphaBlend(uint64_t alphaColor) -> void; + inline auto alphaMultiply() -> void; inline auto transform(const image& source = {}) -> void; inline auto transform(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) -> void; diff --git a/nall/image/utility.hpp b/nall/image/utility.hpp index e70bda2a..bb6e7454 100644 --- a/nall/image/utility.hpp +++ b/nall/image/utility.hpp @@ -56,6 +56,30 @@ auto image::alphaBlend(uint64_t alphaColor) -> void { } } +auto image::alphaMultiply() -> void { + unsigned divisor = (1 << _alpha.depth()) - 1; + + #pragma omp parallel for + for(unsigned y = 0; y < _height; y++) { + uint8_t* dp = _data + pitch() * y; + for(unsigned x = 0; x < _width; x++) { + uint64_t color = read(dp); + + uint64_t colorA = (color & _alpha.mask()) >> _alpha.shift(); + uint64_t colorR = (color & _red.mask() ) >> _red.shift(); + uint64_t colorG = (color & _green.mask()) >> _green.shift(); + uint64_t colorB = (color & _blue.mask() ) >> _blue.shift(); + + colorR = (colorR * colorA) / divisor; + colorG = (colorG * colorA) / divisor; + colorB = (colorB * colorA) / divisor; + + write(dp, (colorA << _alpha.shift()) | (colorR << _red.shift()) | (colorG << _green.shift()) | (colorB << _blue.shift())); + dp += stride(); + } + } +} + auto image::transform(const image& source) -> void { return transform(source._endian, source._depth, source._alpha.mask(), source._red.mask(), source._green.mask(), source._blue.mask()); } diff --git a/target-tomoko/presentation/presentation.cpp b/target-tomoko/presentation/presentation.cpp index 54e5312f..36b80d9d 100644 --- a/target-tomoko/presentation/presentation.cpp +++ b/target-tomoko/presentation/presentation.cpp @@ -97,7 +97,7 @@ Presentation::Presentation() { cheatEditor.setText("Cheat Editor").onActivate([&] { toolsManager->show(0); }); stateManager.setText("State Manager").onActivate([&] { toolsManager->show(1); }); - statusBar.setFont(Font::sans(8, "Bold")); + statusBar.setFont(Font().setBold()); statusBar.setVisible(config->userInterface.showStatusBar); onClose([&] { program->quit(); }); diff --git a/target-tomoko/program/program.cpp b/target-tomoko/program/program.cpp index 3d21d0ba..9617c496 100644 --- a/target-tomoko/program/program.cpp +++ b/target-tomoko/program/program.cpp @@ -68,8 +68,15 @@ Program::Program(lstring args) { updateVideoFilter(); - if(args.size() == 2 && directory::exists(args[1])) { - loadMedia(args[1]); + args.takeFirst(); //ignore program location in argument parsing + for(auto& argument : args) { + if(argument == "--fullscreen") { + presentation->toggleFullScreen(); + } else { + auto location = argument; + if(file::exists(location)) location = dirname(location); + if(directory::exists(location)) loadMedia(location); + } } } diff --git a/target-tomoko/settings/advanced.cpp b/target-tomoko/settings/advanced.cpp index 1a1a385f..1261d0db 100644 --- a/target-tomoko/settings/advanced.cpp +++ b/target-tomoko/settings/advanced.cpp @@ -1,10 +1,10 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Action::Settings); + setImage(Icon::Action::Settings); setText("Advanced"); layout.setMargin(5); - driverLabel.setText("Driver Selection").setFont(Font::sans(8, "Bold")); + driverLabel.setText("Driver Selection").setFont(Font().setBold()); videoLabel.setText("Video:"); videoDriver.onChange([&] { config->video.driver = videoDriver.selected()->text(); }); for(auto& driver : Video::availableDrivers()) { @@ -30,7 +30,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) { if(config->input.driver == driver) item.setSelected(); } - libraryLabel.setText("Game Library").setFont(Font::sans(8, "Bold")); + libraryLabel.setText("Game Library").setFont(Font().setBold()); libraryPrefix.setText("Location:"); libraryLocation.setEditable(false).setText(config->library.location); libraryChange.setText("Change ...").onActivate([&] { diff --git a/target-tomoko/settings/audio.cpp b/target-tomoko/settings/audio.cpp index fcb4989b..c75be097 100644 --- a/target-tomoko/settings/audio.cpp +++ b/target-tomoko/settings/audio.cpp @@ -1,5 +1,5 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Device::Speaker); + setImage(Icon::Device::Speaker); setText("Audio"); layout.setMargin(5); diff --git a/target-tomoko/settings/hotkeys.cpp b/target-tomoko/settings/hotkeys.cpp index 0e087bb5..0d809879 100644 --- a/target-tomoko/settings/hotkeys.cpp +++ b/target-tomoko/settings/hotkeys.cpp @@ -1,5 +1,5 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Device::Keyboard); + setImage(Icon::Device::Keyboard); setText("Hotkeys"); layout.setMargin(5); diff --git a/target-tomoko/settings/input.cpp b/target-tomoko/settings/input.cpp index df168b71..8c4a7f8a 100644 --- a/target-tomoko/settings/input.cpp +++ b/target-tomoko/settings/input.cpp @@ -1,5 +1,5 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Device::Joypad); + setImage(Icon::Device::Joypad); setText("Input"); layout.setMargin(5); diff --git a/target-tomoko/settings/settings.cpp b/target-tomoko/settings/settings.cpp index ad55c400..de987341 100644 --- a/target-tomoko/settings/settings.cpp +++ b/target-tomoko/settings/settings.cpp @@ -11,7 +11,7 @@ SettingsManager::SettingsManager() { settingsManager = this; layout.setMargin(5); - statusBar.setFont(Font::sans(8, "Bold")); + statusBar.setFont(Font().setBold()); setTitle("Configuration Settings"); setSize({600, 400}); diff --git a/target-tomoko/settings/timing.cpp b/target-tomoko/settings/timing.cpp index b46c49b1..3ef1e8e2 100644 --- a/target-tomoko/settings/timing.cpp +++ b/target-tomoko/settings/timing.cpp @@ -1,5 +1,5 @@ TimingSettings::TimingSettings(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Device::Clock); + setImage(Icon::Device::Clock); setText("Timing"); layout.setMargin(5); diff --git a/target-tomoko/settings/video.cpp b/target-tomoko/settings/video.cpp index 13491a00..3c12b46e 100644 --- a/target-tomoko/settings/video.cpp +++ b/target-tomoko/settings/video.cpp @@ -1,10 +1,10 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Device::Display); + setImage(Icon::Device::Display); setText("Video"); layout.setMargin(5); - colorAdjustmentLabel.setFont(Font::sans(8, "Bold")).setText("Color Adjustment"); + colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment"); saturationLabel.setText("Saturation:"); saturationSlider.setLength(201).setPosition(config->video.saturation).onChange([&] { update(); }); gammaLabel.setText("Gamma:"); @@ -12,7 +12,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { luminanceLabel.setText("Luminance:"); luminanceSlider.setLength(101).setPosition(config->video.luminance).onChange([&] { update(); }); - overscanMaskLabel.setFont(Font::sans(8, "Bold")).setText("Overscan Mask"); + overscanMaskLabel.setFont(Font().setBold()).setText("Overscan Mask"); horizontalMaskLabel.setText("Horizontal:"); horizontalMaskSlider.setLength(17).setPosition(config->video.overscan.horizontal).onChange([&] { update(); }); verticalMaskLabel.setText("Vertical:"); diff --git a/target-tomoko/tools/cheat-editor.cpp b/target-tomoko/tools/cheat-editor.cpp index f1b5cb86..4f26d72c 100644 --- a/target-tomoko/tools/cheat-editor.cpp +++ b/target-tomoko/tools/cheat-editor.cpp @@ -1,5 +1,5 @@ CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Edit::Replace); + setImage(Icon::Edit::Replace); setText("Cheat Editor"); layout.setMargin(5); diff --git a/target-tomoko/tools/state-manager.cpp b/target-tomoko/tools/state-manager.cpp index 0c8912f8..87b12627 100644 --- a/target-tomoko/tools/state-manager.cpp +++ b/target-tomoko/tools/state-manager.cpp @@ -1,5 +1,5 @@ StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) { - setIcon(Icon::Application::FileManager); + setImage(Icon::Application::FileManager); setText("State Manager"); layout.setMargin(5);