Update to v094r24 release.

byuu says:

Finally!! Compilation works once again on Windows.

However, it's pretty buggy. Modality isn't really working right, you can
still poke at other windows, but when you select ListView items, they
redraw as empty boxes (need to process WM_DRAWITEM before checking
modality.)

The program crashes when you close it (probably a ruby driver's term()
function, that's what it usually is.)

The Layout::setEnabled(false) call isn't working right, so you get that
annoying chiming sound and cursor movement when mapping keyboard keys to
game inputs.

The column sizing seems off a bit on first display for the Hotkeys tab.

And probably lots more.
This commit is contained in:
Tim Allen 2015-06-12 23:14:38 +10:00
parent 314aee8c5c
commit f0c17ffc0d
188 changed files with 5474 additions and 3834 deletions

View File

@ -12,8 +12,7 @@ target := tomoko
# console := true # console := true
# compiler # compiler
flags += -I. -O3 -fopenmp flags += -I. -O3
link += -fopenmp
objects := libco objects := libco
# profile-guided optimization mode # profile-guided optimization mode
@ -44,11 +43,13 @@ ifeq ($(platform),windows)
else ifeq ($(platform),macosx) else ifeq ($(platform),macosx)
flags += -march=native flags += -march=native
else ifeq ($(platform),linux) else ifeq ($(platform),linux)
flags += -march=native flags += -march=native -fopenmp
link += -fopenmp
link += -Wl,-export-dynamic link += -Wl,-export-dynamic
link += -lX11 -lXext -ldl link += -lX11 -lXext -ldl
else ifeq ($(platform),bsd) else ifeq ($(platform),bsd)
flags += -march=native flags += -march=native -fopenmp
link += -fopenmp
link += -Wl,-export-dynamic link += -Wl,-export-dynamic
link += -lX11 -lXext link += -lX11 -lXext
else else

2
data/resource.rc Normal file
View File

@ -0,0 +1,2 @@
1 24 "higan.Manifest"
2 ICON DISCARDABLE "higan.ico"

View File

@ -3,7 +3,7 @@
namespace Emulator { namespace Emulator {
static const char Name[] = "higan"; static const char Name[] = "higan";
static const char Version[] = "094.23"; static const char Version[] = "094.24";
static const char Author[] = "byuu"; static const char Author[] = "byuu";
static const char License[] = "GPLv3"; static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/"; static const char Website[] = "http://byuu.org/";

View File

@ -25,6 +25,8 @@
#define Hiro_MessageWindow #define Hiro_MessageWindow
#define Hiro_Object #define Hiro_Object
#define Hiro_Group
#define Hiro_Hotkey #define Hiro_Hotkey
#define Hiro_Timer #define Hiro_Timer
@ -48,22 +50,22 @@
#define Hiro_CheckButton #define Hiro_CheckButton
#define Hiro_CheckLabel #define Hiro_CheckLabel
#define Hiro_ComboButton #define Hiro_ComboButton
#define Hiro_Console //#define Hiro_Console
#define Hiro_Frame #define Hiro_Frame
#define Hiro_HexEdit #define Hiro_HexEdit
#define Hiro_HorizontalScroller #define Hiro_HorizontalScroller
#define Hiro_HorizontalSlider #define Hiro_HorizontalSlider
#define Hiro_IconView //#define Hiro_IconView
#define Hiro_Label #define Hiro_Label
#define Hiro_LineEdit #define Hiro_LineEdit
#define Hiro_ListView #define Hiro_ListView
#define Hiro_ProgressBar #define Hiro_ProgressBar
#define Hiro_RadioButton #define Hiro_RadioButton
#define Hiro_RadioLabel #define Hiro_RadioLabel
#define Hiro_SourceView //#define Hiro_SourceView
#define Hiro_TabFrame #define Hiro_TabFrame
#define Hiro_TextEdit #define Hiro_TextEdit
#define Hiro_TreeView //#define Hiro_TreeView
#define Hiro_VerticalScroller #define Hiro_VerticalScroller
#define Hiro_VerticalSlider #define Hiro_VerticalSlider
#define Hiro_Viewport #define Hiro_Viewport

View File

@ -6,20 +6,6 @@ auto mMenuRadioItem::allocate() -> pObject* {
// //
auto mMenuRadioItem::group(const vector<wMenuRadioItem>& group) -> void {
for(auto& weak : group) {
if(auto item = weak.acquire()) item->state.group = group;
}
for(auto& weak : group) {
if(auto item = weak.acquire()) {
if(item->self()) item->self()->setGroup(group);
}
}
if(group.size()) {
if(auto item = group.first().acquire()) item->setChecked();
}
}
auto mMenuRadioItem::checked() const -> bool { auto mMenuRadioItem::checked() const -> bool {
return state.checked; return state.checked;
} }
@ -28,20 +14,36 @@ auto mMenuRadioItem::doActivate() const -> void {
if(state.onActivate) return state.onActivate(); if(state.onActivate) return state.onActivate();
} }
auto mMenuRadioItem::group() const -> sGroup {
return state.group;
}
auto mMenuRadioItem::onActivate(const function<void ()>& function) -> type& { auto mMenuRadioItem::onActivate(const function<void ()>& function) -> type& {
state.onActivate = function; state.onActivate = function;
return *this; return *this;
} }
auto mMenuRadioItem::setChecked() -> type& { auto mMenuRadioItem::setChecked() -> type& {
for(auto& weak : state.group) { if(auto group = this->group()) {
if(auto item = weak.acquire()) item->state.checked = false; for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto menuRadioItem = dynamic_cast<mMenuRadioItem*>(object.data())) {
menuRadioItem->state.checked = false;
}
}
}
} }
state.checked = true; state.checked = true;
signal(setChecked); signal(setChecked);
return *this; return *this;
} }
auto mMenuRadioItem::setGroup(sGroup group) -> type& {
state.group = group;
signal(setGroup, group);
return *this;
}
auto mMenuRadioItem::setText(const string& text) -> type& { auto mMenuRadioItem::setText(const string& text) -> type& {
state.text = text; state.text = text;
signal(setText, text); signal(setText, text);

View File

@ -43,7 +43,10 @@ namespace hiro {
#include "mouse.cpp" #include "mouse.cpp"
#include "browser-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "object.cpp" #include "object.cpp"
#include "group.cpp"
#include "hotkey.cpp" #include "hotkey.cpp"
#include "timer.cpp" #include "timer.cpp"
#include "window.cpp" #include "window.cpp"
@ -80,6 +83,7 @@ namespace hiro {
#include "widget/list-view.cpp" #include "widget/list-view.cpp"
#include "widget/list-view-column.cpp" #include "widget/list-view-column.cpp"
#include "widget/list-view-item.cpp" #include "widget/list-view-item.cpp"
#include "widget/list-view-cell.cpp"
#include "widget/progress-bar.cpp" #include "widget/progress-bar.cpp"
#include "widget/radio-button.cpp" #include "widget/radio-button.cpp"
#include "widget/radio-label.cpp" #include "widget/radio-label.cpp"

View File

@ -31,6 +31,7 @@ namespace hiro {
Declare(Keyboard) Declare(Keyboard)
Declare(Object) Declare(Object)
Declare(Group)
Declare(Timer) Declare(Timer)
Declare(Hotkey) Declare(Hotkey)
Declare(Window) Declare(Window)
@ -64,6 +65,7 @@ Declare(LineEdit)
Declare(ListView) Declare(ListView)
Declare(ListViewColumn) Declare(ListViewColumn)
Declare(ListViewItem) Declare(ListViewItem)
Declare(ListViewCell)
Declare(ProgressBar) Declare(ProgressBar)
Declare(RadioButton) Declare(RadioButton)
Declare(RadioLabel) Declare(RadioLabel)
@ -409,6 +411,7 @@ struct mObject {
auto enabled(bool recursive = false) const -> bool; auto enabled(bool recursive = false) const -> bool;
virtual auto focused() const -> bool; virtual auto focused() const -> bool;
auto font(bool recursive = false) const -> string; auto font(bool recursive = false) const -> string;
virtual auto group() const -> sGroup;
auto offset() const -> signed; auto offset() const -> signed;
auto offset(signed displacement) -> type&; auto offset(signed displacement) -> type&;
auto parent() const -> mObject*; auto parent() const -> mObject*;
@ -417,6 +420,7 @@ struct mObject {
auto parentIconView(bool recursive = false) const -> mIconView*; auto parentIconView(bool recursive = false) const -> mIconView*;
auto parentLayout(bool recursive = false) const -> mLayout*; auto parentLayout(bool recursive = false) const -> mLayout*;
auto parentListView(bool recursive = false) const -> mListView*; auto parentListView(bool recursive = false) const -> mListView*;
auto parentListViewItem(bool recursive = false) const -> mListViewItem*;
auto parentMenu(bool recursive = false) const -> mMenu*; auto parentMenu(bool recursive = false) const -> mMenu*;
auto parentMenuBar(bool recursive = false) const -> mMenuBar*; auto parentMenuBar(bool recursive = false) const -> mMenuBar*;
auto parentPopupMenu(bool recursive = false) const -> mPopupMenu*; auto parentPopupMenu(bool recursive = false) const -> mPopupMenu*;
@ -432,6 +436,7 @@ struct mObject {
virtual auto setEnabled(bool enabled = true) -> type&; virtual auto setEnabled(bool enabled = true) -> type&;
virtual auto setFocused() -> type&; virtual auto setFocused() -> type&;
virtual auto setFont(const string& font = "") -> type&; virtual auto setFont(const string& font = "") -> type&;
virtual auto setGroup(sGroup group = {}) -> type&;
virtual auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&; virtual auto setParent(mObject* parent = nullptr, signed offset = -1) -> type&;
virtual auto setVisible(bool visible = true) -> type&; virtual auto setVisible(bool visible = true) -> type&;
auto visible(bool recursive = false) const -> bool; auto visible(bool recursive = false) const -> bool;
@ -453,6 +458,23 @@ struct mObject {
}; };
#endif #endif
#if defined(Hiro_Group)
struct mGroup : mObject {
Declare(Group)
using mObject::remove;
auto append(sObject object) -> type&;
auto object(unsigned offset) const -> sObject;
auto objects() const -> unsigned;
auto remove(sObject object) -> type&;
//private:
struct State {
vector<wObject> objects;
} state;
};
#endif
#if defined(Hiro_Hotkey) #if defined(Hiro_Hotkey)
struct mHotkey : mObject { struct mHotkey : mObject {
Declare(Hotkey) Declare(Hotkey)
@ -596,6 +618,7 @@ struct mMenuBar : mObject {
auto remove() -> type& override; auto remove() -> type& override;
auto remove(sMenu menu) -> type&; auto remove(sMenu menu) -> type&;
auto reset() -> type&; auto reset() -> type&;
//TODO setParent
//private: //private:
struct State { struct State {
@ -616,6 +639,7 @@ struct mPopupMenu : mObject {
auto append(sAction action) -> type&; auto append(sAction action) -> type&;
auto remove(sAction action) -> type&; auto remove(sAction action) -> type&;
auto reset() -> type&; auto reset() -> type&;
//TODO setParent
auto setVisible(bool visible = true) -> type& override; auto setVisible(bool visible = true) -> type& override;
//private: //private:
@ -651,6 +675,7 @@ struct mMenu : mAction {
auto remove(sAction action) -> type&; auto remove(sAction action) -> type&;
auto reset() -> type&; auto reset() -> type&;
auto setIcon(const image& icon = {}) -> type&; auto setIcon(const image& icon = {}) -> type&;
//TODO setParent
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto text() const -> string; auto text() const -> string;
@ -721,17 +746,17 @@ struct mMenuRadioItem : mAction {
auto checked() const -> bool; auto checked() const -> bool;
auto doActivate() const -> void; auto doActivate() const -> void;
auto group() const -> sGroup override;
auto onActivate(const function<void ()>& function = {}) -> type&; auto onActivate(const function<void ()>& function = {}) -> type&;
auto setChecked() -> type&; auto setChecked() -> type&;
auto setGroup(sGroup group = {}) -> type& override;
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto text() const -> string; auto text() const -> string;
static auto group(const vector<wMenuRadioItem>& group) -> void;
//private: //private:
struct State { struct State {
bool checked = true; bool checked = false;
vector<wMenuRadioItem> group; sGroup group;
function<void ()> onActivate; function<void ()> onActivate;
string text; string text;
} state; } state;
@ -923,12 +948,12 @@ struct mComboButton : mWidget {
auto remove(sComboButtonItem item) -> type&; auto remove(sComboButtonItem item) -> type&;
auto reset() -> type&; auto reset() -> type&;
auto selected() const -> sComboButtonItem; auto selected() const -> sComboButtonItem;
auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override;
//private: //private:
struct State { struct State {
vector<sComboButtonItem> items; vector<sComboButtonItem> items;
function<void ()> onChange; function<void ()> onChange;
signed selected = -1;
} state; } state;
auto destruct() -> void override; auto destruct() -> void override;
@ -950,6 +975,7 @@ struct mComboButtonItem : mObject {
//private: //private:
struct State { struct State {
image icon; image icon;
bool selected = false;
string text; string text;
} state; } state;
}; };
@ -989,6 +1015,7 @@ struct mFrame : mWidget {
auto layout() const -> sLayout; auto layout() const -> sLayout;
auto remove(sLayout layout) -> type&; auto remove(sLayout layout) -> type&;
auto reset() -> type&; auto reset() -> type&;
//TODO setParent()
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto text() const -> string; auto text() const -> string;
@ -1106,6 +1133,7 @@ struct mIconView : mWidget {
auto setForegroundColor(Color color = {}) -> type&; auto setForegroundColor(Color color = {}) -> type&;
auto setMultiSelect(bool multipleSelections = true) -> type&; auto setMultiSelect(bool multipleSelections = true) -> type&;
auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&;
//TODO setParent()
auto setSelected(const vector<signed>& selections) -> type&; auto setSelected(const vector<signed>& selections) -> type&;
//private: //private:
@ -1203,14 +1231,16 @@ struct mListView : mWidget {
auto append(sListViewColumn column) -> type&; auto append(sListViewColumn column) -> type&;
auto append(sListViewItem item) -> type&; auto append(sListViewItem item) -> type&;
auto backgroundColor() const -> Color; auto backgroundColor() const -> Color;
auto batchable() const -> bool;
auto checkable() const -> bool; auto checkable() const -> bool;
auto checkAll() -> type&;
auto checked() const -> vector<sListViewItem>; auto checked() const -> vector<sListViewItem>;
auto column(unsigned position) const -> sListViewColumn; auto column(unsigned position) const -> sListViewColumn;
auto columns() const -> unsigned; auto columns() const -> unsigned;
auto doActivate() const -> void; auto doActivate() const -> void;
auto doChange() const -> void; auto doChange() const -> void;
auto doContext() const -> void; auto doContext() const -> void;
auto doEdit(sListViewItem item, sListViewColumn column) const -> void; auto doEdit(sListViewCell cell) const -> void;
auto doSort(sListViewColumn column) const -> void; auto doSort(sListViewColumn column) const -> void;
auto doToggle(sListViewItem item) const -> void; auto doToggle(sListViewItem item) const -> void;
auto foregroundColor() const -> Color; auto foregroundColor() const -> Color;
@ -1218,45 +1248,49 @@ struct mListView : mWidget {
auto headerVisible() const -> bool; auto headerVisible() const -> bool;
auto item(unsigned position) const -> sListViewItem; auto item(unsigned position) const -> sListViewItem;
auto items() const -> unsigned; auto items() const -> unsigned;
auto multiSelect() const -> bool;
auto onActivate(const function<void ()>& function = {}) -> type&; auto onActivate(const function<void ()>& function = {}) -> type&;
auto onChange(const function<void ()>& function = {}) -> type&; auto onChange(const function<void ()>& function = {}) -> type&;
auto onContext(const function<void ()>& function = {}) -> type&; auto onContext(const function<void ()>& function = {}) -> type&;
auto onEdit(const function<void (sListViewItem, sListViewColumn)>& function = {}) -> type&; auto onEdit(const function<void (sListViewCell)>& function = {}) -> type&;
auto onSort(const function<void (sListViewColumn)>& function = {}) -> type&; auto onSort(const function<void (sListViewColumn)>& function = {}) -> type&;
auto onToggle(const function<void (sListViewItem)>& function = {}) -> type&; auto onToggle(const function<void (sListViewItem)>& function = {}) -> type&;
auto remove(sListViewColumn column) -> type&; auto remove(sListViewColumn column) -> type&;
auto remove(sListViewItem item) -> type&; auto remove(sListViewItem item) -> type&;
auto reset() -> type&; auto reset() -> type&;
auto resizeColumns() -> type&; auto resizeColumns() -> type&;
auto selectAll() -> type&;
auto selected() const -> sListViewItem; auto selected() const -> sListViewItem;
auto selectedItems() const -> vector<sListViewItem>; auto selectedItems() const -> vector<sListViewItem>;
auto setBackgroundColor(Color color = {}) -> type&; auto setBackgroundColor(Color color = {}) -> type&;
auto setBatchable(bool batchable = true) -> type&;
auto setCheckable(bool checkable = true) -> type&; auto setCheckable(bool checkable = true) -> type&;
auto setChecked(bool checked = true) -> type&;
auto setForegroundColor(Color color = {}) -> type&; auto setForegroundColor(Color color = {}) -> type&;
auto setGridVisible(bool visible = true) -> type&; auto setGridVisible(bool visible = true) -> type&;
auto setHeaderVisible(bool visible = true) -> type&; auto setHeaderVisible(bool visible = true) -> type&;
auto setMultiSelect(bool multiSelect = true) -> type&; auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override;
auto setSelected(bool selected = true) -> type&; auto setSortable(bool sortable = true) -> type&;
auto sortable() const -> bool;
auto uncheckAll() -> type&;
auto unselectAll() -> type&;
//private: //private:
struct State { struct State {
unsigned activeColumn = 0; unsigned activeColumn = 0;
Color backgroundColor; Color backgroundColor;
bool batchable = false;
bool checkable = false; bool checkable = false;
vector<sListViewColumn> columns; vector<sListViewColumn> columns;
Color foregroundColor; Color foregroundColor;
bool gridVisible = false; bool gridVisible = false;
bool headerVisible = false; bool headerVisible = false;
vector<sListViewItem> items; vector<sListViewItem> items;
bool multiSelect = false;
function<void ()> onActivate; function<void ()> onActivate;
function<void ()> onChange; function<void ()> onChange;
function<void ()> onContext; function<void ()> onContext;
function<void (sListViewItem, sListViewColumn)> onEdit; function<void (sListViewCell)> onEdit;
function<void (sListViewColumn)> onSort; function<void (sListViewColumn)> onSort;
function<void (sListViewItem)> onToggle; function<void (sListViewItem)> onToggle;
bool sortable = false;
} state; } state;
auto destruct() -> void override; auto destruct() -> void override;
@ -1270,6 +1304,7 @@ struct mListViewColumn : mObject {
auto active() const -> bool; auto active() const -> bool;
auto backgroundColor() const -> Color; auto backgroundColor() const -> Color;
auto editable() const -> bool; auto editable() const -> bool;
auto expandable() const -> bool;
auto foregroundColor() const -> Color; auto foregroundColor() const -> Color;
auto horizontalAlignment() const -> double; auto horizontalAlignment() const -> double;
auto icon() const -> image; auto icon() const -> image;
@ -1278,17 +1313,16 @@ struct mListViewColumn : mObject {
auto setActive() -> type&; auto setActive() -> type&;
auto setBackgroundColor(Color color = {}) -> type&; auto setBackgroundColor(Color color = {}) -> type&;
auto setEditable(bool editable = true) -> type&; auto setEditable(bool editable = true) -> type&;
auto setExpandable(bool expandable = true) -> type&;
auto setFont(const string& font = "") -> type&; auto setFont(const string& font = "") -> type&;
auto setForegroundColor(Color color = {}) -> type&; auto setForegroundColor(Color color = {}) -> type&;
auto setHorizontalAlignment(double alignment = 0.0) -> type&; auto setHorizontalAlignment(double alignment = 0.0) -> type&;
auto setIcon(const image& icon = {}) -> type&; auto setIcon(const image& icon = {}) -> type&;
auto setResizable(bool resizable = true) -> type&; auto setResizable(bool resizable = true) -> type&;
auto setSortable(bool sortable = true) -> type&;
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto setVerticalAlignment(double alignment = 0.5) -> type&; auto setVerticalAlignment(double alignment = 0.5) -> type&;
auto setVisible(bool visible = true) -> type&; auto setVisible(bool visible = true) -> type&;
auto setWidth(signed width = 0) -> type&; auto setWidth(signed width = 0) -> type&;
auto sortable() const -> bool;
auto text() const -> string; auto text() const -> string;
auto verticalAlignment() const -> double; auto verticalAlignment() const -> double;
auto width() const -> signed; auto width() const -> signed;
@ -1297,12 +1331,12 @@ struct mListViewColumn : mObject {
struct State { struct State {
Color backgroundColor; Color backgroundColor;
bool editable = false; bool editable = false;
bool expandable = false;
string font; string font;
Color foregroundColor; Color foregroundColor;
double horizontalAlignment = 0.0; double horizontalAlignment = 0.0;
image icon; image icon;
bool resizable = true; bool resizable = true;
bool sortable = false;
string text; string text;
double verticalAlignment = 0.5; double verticalAlignment = 0.5;
bool visible = true; bool visible = true;
@ -1315,24 +1349,52 @@ struct mListViewColumn : mObject {
struct mListViewItem : mObject { struct mListViewItem : mObject {
Declare(ListViewItem) Declare(ListViewItem)
auto append(sListViewCell cell) -> type&;
auto backgroundColor() const -> Color;
auto cell(unsigned position) const -> sListViewCell;
auto cells() const -> unsigned;
auto checked() const -> bool; auto checked() const -> bool;
auto icon(unsigned column = 0) const -> image; auto foregroundColor() const -> Color;
auto remove() -> type& override; auto remove() -> type& override;
auto remove(sListViewCell cell) -> type&;
auto selected() const -> bool; auto selected() const -> bool;
auto setBackgroundColor(Color color = {}) -> type&;
auto setChecked(bool checked = true) -> type&; auto setChecked(bool checked = true) -> type&;
auto setFocused() -> type& override; auto setFocused() -> type& override;
auto setIcon(unsigned column, const image& icon = {}) -> type&; auto setForegroundColor(Color color = {}) -> type&;
auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override;
auto setSelected(bool selected = true) -> type&; auto setSelected(bool selected = true) -> type&;
auto setText(const lstring& text) -> type&;
auto setText(unsigned column, const string& text = "") -> type&;
auto text(unsigned column = 0) const -> string;
//private: //private:
struct State { struct State {
Color backgroundColor;
vector<sListViewCell> cells;
bool checked = false; bool checked = false;
vector<image> icon; Color foregroundColor;
bool selected = false; bool selected = false;
lstring text; } state;
};
#endif
#if defined(Hiro_ListView)
struct mListViewCell : mObject {
Declare(ListViewCell)
auto backgroundColor() const -> Color;
auto foregroundColor() const -> Color;
auto icon() const -> image;
auto setBackgroundColor(Color color = {}) -> type&;
auto setForegroundColor(Color color = {}) -> type&;
auto setIcon(const image& icon = {}) -> type&;
auto setText(const string& text = "") -> type&;
auto text() const -> string;
//private:
struct State {
Color backgroundColor;
Color foregroundColor;
image icon;
string text;
} state; } state;
}; };
#endif #endif
@ -1358,23 +1420,23 @@ struct mRadioButton : mWidget {
auto bordered() const -> bool; auto bordered() const -> bool;
auto checked() const -> bool; auto checked() const -> bool;
auto doActivate() const -> void; auto doActivate() const -> void;
auto group() const -> sGroup override;
auto icon() const -> image; auto icon() const -> image;
auto onActivate(const function<void ()>& function = {}) -> type&; auto onActivate(const function<void ()>& function = {}) -> type&;
auto orientation() const -> Orientation; auto orientation() const -> Orientation;
auto setBordered(bool bordered = true) -> type&; auto setBordered(bool bordered = true) -> type&;
auto setChecked() -> type&; auto setChecked() -> type&;
auto setGroup(sGroup group = {}) -> type& override;
auto setIcon(const image& icon = {}) -> type&; auto setIcon(const image& icon = {}) -> type&;
auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&; auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&;
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto text() const -> string; auto text() const -> string;
static auto group(const vector<wRadioButton>& group) -> void;
//private: //private:
struct State { struct State {
bool bordered = true; bool bordered = true;
bool checked = true; bool checked = false;
vector<wRadioButton> group; sGroup group;
image icon; image icon;
function<void ()> onActivate; function<void ()> onActivate;
Orientation orientation = Orientation::Horizontal; Orientation orientation = Orientation::Horizontal;
@ -1389,17 +1451,17 @@ struct mRadioLabel : mWidget {
auto checked() const -> bool; auto checked() const -> bool;
auto doActivate() const -> void; auto doActivate() const -> void;
auto group() const -> sGroup override;
auto onActivate(const function<void ()>& function = {}) -> type&; auto onActivate(const function<void ()>& function = {}) -> type&;
auto setChecked() -> type&; auto setChecked() -> type&;
auto setGroup(sGroup group = {}) -> type& override;
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto text() const -> string; auto text() const -> string;
static auto group(const vector<wRadioLabel>& group) -> void;
//private: //private:
struct State { struct State {
bool checked = true; bool checked = false;
vector<wRadioLabel> group; sGroup group;
function<void ()> onActivate; function<void ()> onActivate;
string text; string text;
} state; } state;
@ -1460,7 +1522,6 @@ struct mTabFrame : mWidget {
function<void ()> onChange; function<void ()> onChange;
function<void (sTabFrameItem)> onClose; function<void (sTabFrameItem)> onClose;
function<void (sTabFrameItem, sTabFrameItem)> onMove; function<void (sTabFrameItem, sTabFrameItem)> onMove;
unsigned selected = 0;
} state; } state;
auto destruct() -> void override; auto destruct() -> void override;
@ -1494,6 +1555,7 @@ struct mTabFrameItem : mObject {
image icon; image icon;
sLayout layout; sLayout layout;
bool movable = false; bool movable = false;
bool selected = false;
string text; string text;
} state; } state;
@ -1563,6 +1625,7 @@ struct mTreeView : mWidget {
auto setBackgroundColor(Color color = {}) -> type&; auto setBackgroundColor(Color color = {}) -> type&;
auto setCheckable(bool checkable = true) -> type&; auto setCheckable(bool checkable = true) -> type&;
auto setForegroundColor(Color color = {}) -> type&; auto setForegroundColor(Color color = {}) -> type&;
//TODO setParent
//private: //private:
struct State { struct State {
@ -1597,6 +1660,7 @@ struct mTreeViewItem : mObject {
auto setChecked(bool checked = true) -> type&; auto setChecked(bool checked = true) -> type&;
auto setFocused() -> type& override; auto setFocused() -> type& override;
auto setIcon(const image& icon = {}) -> type&; auto setIcon(const image& icon = {}) -> type&;
//TODO setParent
auto setSelected() -> type&; auto setSelected() -> type&;
auto setText(const string& text = "") -> type&; auto setText(const string& text = "") -> type&;
auto text() const -> string; auto text() const -> string;

39
hiro/core/group.cpp Normal file
View File

@ -0,0 +1,39 @@
#if defined(Hiro_Group)
auto mGroup::allocate() -> pObject* {
return new pGroup(*this);
}
//
auto mGroup::append(sObject object) -> type& {
if(auto group = instance.acquire()) {
state.objects.append(object);
object->setGroup(group);
}
return *this;
}
auto mGroup::object(unsigned position) const -> sObject {
if(position < state.objects.size()) return state.objects[position];
return {};
}
auto mGroup::objects() const -> unsigned {
return state.objects.size();
}
auto mGroup::remove(sObject object) -> type& {
object->setGroup();
for(auto offset : range(state.objects)) {
if(auto shared = state.objects[offset].acquire()) {
if(object == shared) {
state.objects.remove(offset);
break;
}
}
}
return *this;
}
#endif

View File

@ -31,10 +31,18 @@ auto mObject::destruct() -> void {
//if the mObject is not abstract, the pObject delegate is allocated immediately //if the mObject is not abstract, the pObject delegate is allocated immediately
//otherwise, the pObject is not allocated until it is attached to a non-abstract parent //otherwise, the pObject is not allocated until it is attached to a non-abstract parent
auto mObject::abstract() const -> bool { auto mObject::abstract() const -> bool {
#if defined(Hiro_Group)
if(dynamic_cast<const mGroup*>(this)) return false;
#endif
#if defined(Hiro_Window)
if(dynamic_cast<const mWindow*>(this)) return false; if(dynamic_cast<const mWindow*>(this)) return false;
#endif
#if defined(Hiro_PopupMenu) #if defined(Hiro_PopupMenu)
if(dynamic_cast<const mPopupMenu*>(this)) return false; if(dynamic_cast<const mPopupMenu*>(this)) return false;
#endif #endif
if(auto object = parent()) return object->abstract(); if(auto object = parent()) return object->abstract();
return true; return true;
} }
@ -56,6 +64,10 @@ auto mObject::font(bool recursive) const -> string {
return Application::font(); return Application::font();
} }
auto mObject::group() const -> sGroup {
return {};
}
auto mObject::offset() const -> signed { auto mObject::offset() const -> signed {
return state.offset; return state.offset;
} }
@ -119,6 +131,16 @@ auto mObject::parentListView(bool recursive) const -> mListView* {
} }
#endif #endif
#if defined(Hiro_ListView)
auto mObject::parentListViewItem(bool recursive) const -> mListViewItem* {
if(auto listViewItem = dynamic_cast<mListViewItem*>(parent())) return listViewItem;
if(recursive) {
if(auto object = parent()) return object->parentListViewItem(true);
}
return nullptr;
}
#endif
#if defined(Hiro_Menu) #if defined(Hiro_Menu)
auto mObject::parentMenu(bool recursive) const -> mMenu* { auto mObject::parentMenu(bool recursive) const -> mMenu* {
if(auto menu = dynamic_cast<mMenu*>(parent())) return menu; if(auto menu = dynamic_cast<mMenu*>(parent())) return menu;
@ -246,6 +268,10 @@ auto mObject::setFont(const string& font) -> type& {
return *this; return *this;
} }
auto mObject::setGroup(sGroup group) -> type& {
return *this;
}
auto mObject::setParent(mObject* parent, signed offset) -> type& { auto mObject::setParent(mObject* parent, signed offset) -> type& {
destruct(); destruct();
state.parent = parent; state.parent = parent;

View File

@ -16,8 +16,7 @@ auto mComboButtonItem::remove() -> type& {
} }
auto mComboButtonItem::selected() const -> bool { auto mComboButtonItem::selected() const -> bool {
if(auto comboButton = parentComboButton()) return comboButton->state.selected == offset(); return state.selected;
return false;
} }
auto mComboButtonItem::setIcon(const image& icon) -> type& { auto mComboButtonItem::setIcon(const image& icon) -> type& {
@ -28,9 +27,10 @@ auto mComboButtonItem::setIcon(const image& icon) -> type& {
auto mComboButtonItem::setSelected() -> type& { auto mComboButtonItem::setSelected() -> type& {
if(auto parent = parentComboButton()) { if(auto parent = parentComboButton()) {
parent->state.selected = offset(); for(auto& item : parent->state.items) item->state.selected = false;
signal(setSelected);
} }
state.selected = true;
signal(setSelected);
return *this; return *this;
} }

View File

@ -15,7 +15,6 @@ auto mComboButton::append(sComboButtonItem item) -> type& {
state.items.append(item); state.items.append(item);
item->setParent(this, items() - 1); item->setParent(this, items() - 1);
signal(append, item); signal(append, item);
if(state.selected < 0) item->setSelected();
return *this; return *this;
} }
@ -49,17 +48,23 @@ auto mComboButton::remove(sComboButtonItem item) -> type& {
auto mComboButton::reset() -> type& { auto mComboButton::reset() -> type& {
signal(reset); signal(reset);
for(auto& item : state.items) { for(auto& item : state.items) item->setParent();
item->setParent();
}
state.items.reset(); state.items.reset();
state.selected = -1;
return *this; return *this;
} }
auto mComboButton::selected() const -> sComboButtonItem { auto mComboButton::selected() const -> sComboButtonItem {
if(state.selected >= 0) return state.items[state.selected]; for(auto& item : state.items) {
if(item->selected()) return item;
}
return {}; return {};
} }
auto mComboButton::setParent(mObject* parent, signed offset) -> type& {
for(auto& item : state.items) item->destruct();
mObject::setParent(parent, offset);
for(auto& item : state.items) item->setParent(this, item->offset());
return *this;
}
#endif #endif

View File

@ -0,0 +1,49 @@
#if defined(Hiro_ListView)
auto mListViewCell::allocate() -> pObject* {
return new pListViewCell(*this);
}
//
auto mListViewCell::backgroundColor() const -> Color {
return state.backgroundColor;
}
auto mListViewCell::foregroundColor() const -> Color {
return state.foregroundColor;
}
auto mListViewCell::icon() const -> image {
return state.icon;
}
auto mListViewCell::setBackgroundColor(Color color) -> type& {
state.backgroundColor = color;
signal(setBackgroundColor, color);
return *this;
}
auto mListViewCell::setForegroundColor(Color color) -> type& {
state.foregroundColor = color;
signal(setForegroundColor, color);
return *this;
}
auto mListViewCell::setIcon(const image& icon) -> type& {
state.icon = icon;
signal(setIcon, icon);
return *this;
}
auto mListViewCell::setText(const string& text) -> type& {
state.text = text;
signal(setText, text);
return *this;
}
auto mListViewCell::text() const -> string {
return state.text;
}
#endif

View File

@ -19,6 +19,10 @@ auto mListViewColumn::editable() const -> bool {
return state.editable; return state.editable;
} }
auto mListViewColumn::expandable() const -> bool {
return state.expandable;
}
auto mListViewColumn::foregroundColor() const -> Color { auto mListViewColumn::foregroundColor() const -> Color {
return state.foregroundColor; return state.foregroundColor;
} }
@ -58,6 +62,12 @@ auto mListViewColumn::setEditable(bool editable) -> type& {
return *this; return *this;
} }
auto mListViewColumn::setExpandable(bool expandable) -> type& {
state.expandable = expandable;
signal(setExpandable, expandable);
return *this;
}
auto mListViewColumn::setFont(const string& font) -> type& { auto mListViewColumn::setFont(const string& font) -> type& {
state.font = font; state.font = font;
signal(setFont, this->font(true)); signal(setFont, this->font(true));
@ -89,12 +99,6 @@ auto mListViewColumn::setResizable(bool resizable) -> type& {
return *this; return *this;
} }
auto mListViewColumn::setSortable(bool sortable) -> type& {
state.sortable = sortable;
signal(setSortable, sortable);
return *this;
}
auto mListViewColumn::setText(const string& text) -> type& { auto mListViewColumn::setText(const string& text) -> type& {
state.text = text; state.text = text;
signal(setText, text); signal(setText, text);
@ -115,15 +119,11 @@ auto mListViewColumn::setVisible(bool visible) -> type& {
} }
auto mListViewColumn::setWidth(signed width) -> type& { auto mListViewColumn::setWidth(signed width) -> type& {
state.width = width; state.width = max(0, width);
signal(setWidth, width); signal(setWidth, width);
return *this; return *this;
} }
auto mListViewColumn::sortable() const -> bool {
return state.sortable;
}
auto mListViewColumn::text() const -> string { auto mListViewColumn::text() const -> string {
return state.text; return state.text;
} }

View File

@ -6,12 +6,32 @@ auto mListViewItem::allocate() -> pObject* {
// //
auto mListViewItem::append(sListViewCell cell) -> type& {
state.cells.append(cell);
cell->setParent(this, cells() - 1);
signal(append, cell);
return *this;
}
auto mListViewItem::backgroundColor() const -> Color {
return state.backgroundColor;
}
auto mListViewItem::cell(unsigned position) const -> sListViewCell {
if(position < cells()) return state.cells[position];
return {};
}
auto mListViewItem::cells() const -> unsigned {
return state.cells.size();
}
auto mListViewItem::checked() const -> bool { auto mListViewItem::checked() const -> bool {
return state.checked; return state.checked;
} }
auto mListViewItem::icon(unsigned column) const -> image { auto mListViewItem::foregroundColor() const -> Color {
return state.icon(column, {}); return state.foregroundColor;
} }
auto mListViewItem::remove() -> type& { auto mListViewItem::remove() -> type& {
@ -19,10 +39,26 @@ auto mListViewItem::remove() -> type& {
return *this; return *this;
} }
auto mListViewItem::remove(sListViewCell cell) -> type& {
signal(remove, cell);
state.cells.remove(cell->offset());
for(auto n : range(cell->offset(), cells())) {
state.cells[n]->offset(-1);
}
cell->setParent();
return *this;
}
auto mListViewItem::selected() const -> bool { auto mListViewItem::selected() const -> bool {
return state.selected; return state.selected;
} }
auto mListViewItem::setBackgroundColor(Color color) -> type& {
state.backgroundColor = color;
signal(setBackgroundColor, color);
return *this;
}
auto mListViewItem::setChecked(bool checked) -> type& { auto mListViewItem::setChecked(bool checked) -> type& {
state.checked = checked; state.checked = checked;
signal(setChecked, checked); signal(setChecked, checked);
@ -34,9 +70,16 @@ auto mListViewItem::setFocused() -> type& {
return *this; return *this;
} }
auto mListViewItem::setIcon(unsigned column, const image& icon) -> type& { auto mListViewItem::setForegroundColor(Color color) -> type& {
state.icon(column) = icon; state.foregroundColor = color;
signal(setIcon, column, icon); signal(setForegroundColor, color);
return *this;
}
auto mListViewItem::setParent(mObject* parent, signed offset) -> type& {
for(auto& cell : state.cells) cell->destruct();
mObject::setParent(parent, offset);
for(auto& cell : state.cells) cell->setParent(this, cell->offset());
return *this; return *this;
} }
@ -46,24 +89,4 @@ auto mListViewItem::setSelected(bool selected) -> type& {
return *this; return *this;
} }
auto mListViewItem::setText(const lstring& text) -> type& {
state.text = text;
if(auto listView = parentListView()) {
for(auto column : range(listView->columns())) {
setText(column, text(column, ""));
}
}
return *this;
}
auto mListViewItem::setText(unsigned column, const string& text) -> type& {
state.text(column) = text;
signal(setText, column, text);
return *this;
}
auto mListViewItem::text(unsigned column) const -> string {
return state.text(column, "");
}
#endif #endif

View File

@ -30,10 +30,20 @@ auto mListView::backgroundColor() const -> Color {
return state.backgroundColor; return state.backgroundColor;
} }
auto mListView::batchable() const -> bool {
return state.batchable;
}
auto mListView::checkable() const -> bool { auto mListView::checkable() const -> bool {
return state.checkable; return state.checkable;
} }
auto mListView::checkAll() -> type& {
for(auto& item : state.items) item->state.checked = true;
signal(checkAll);
return *this;
}
auto mListView::checked() const -> vector<sListViewItem> { auto mListView::checked() const -> vector<sListViewItem> {
vector<sListViewItem> items; vector<sListViewItem> items;
for(auto& item : state.items) { for(auto& item : state.items) {
@ -63,8 +73,8 @@ auto mListView::doContext() const -> void {
if(state.onContext) return state.onContext(); if(state.onContext) return state.onContext();
} }
auto mListView::doEdit(sListViewItem item, sListViewColumn column) const -> void { auto mListView::doEdit(sListViewCell cell) const -> void {
if(state.onEdit) return state.onEdit(item, column); if(state.onEdit) return state.onEdit(cell);
} }
auto mListView::doSort(sListViewColumn column) const -> void { auto mListView::doSort(sListViewColumn column) const -> void {
@ -96,10 +106,6 @@ auto mListView::items() const -> unsigned {
return state.items.size(); return state.items.size();
} }
auto mListView::multiSelect() const -> bool {
return state.multiSelect;
}
auto mListView::onActivate(const function<void ()>& function) -> type& { auto mListView::onActivate(const function<void ()>& function) -> type& {
state.onActivate = function; state.onActivate = function;
return *this; return *this;
@ -115,7 +121,7 @@ auto mListView::onContext(const function<void ()>& function) -> type& {
return *this; return *this;
} }
auto mListView::onEdit(const function<void (sListViewItem, sListViewColumn)>& function) -> type& { auto mListView::onEdit(const function<void (sListViewCell)>& function) -> type& {
state.onEdit = function; state.onEdit = function;
return *this; return *this;
} }
@ -154,10 +160,10 @@ auto mListView::remove(sListViewItem item) -> type& {
auto mListView::reset() -> type& { auto mListView::reset() -> type& {
signal(reset); signal(reset);
for(auto& column : state.columns) column->setParent();
state.columns.reset();
for(auto& item : state.items) item->setParent(); for(auto& item : state.items) item->setParent();
state.items.reset(); state.items.reset();
for(auto& column : state.columns) column->setParent();
state.columns.reset();
return *this; return *this;
} }
@ -166,6 +172,12 @@ auto mListView::resizeColumns() -> type& {
return *this; return *this;
} }
auto mListView::selectAll() -> type& {
for(auto& item : state.items) item->state.selected = true;
signal(selectAll);
return *this;
}
auto mListView::selected() const -> sListViewItem { auto mListView::selected() const -> sListViewItem {
for(auto& item : state.items) { for(auto& item : state.items) {
if(item->selected()) return item; if(item->selected()) return item;
@ -187,15 +199,15 @@ auto mListView::setBackgroundColor(Color color) -> type& {
return *this; return *this;
} }
auto mListView::setCheckable(bool checkable) -> type& { auto mListView::setBatchable(bool batchable) -> type& {
state.checkable = checkable; state.batchable = batchable;
signal(setCheckable, checkable); signal(setBatchable, batchable);
return *this; return *this;
} }
auto mListView::setChecked(bool checked) -> type& { auto mListView::setCheckable(bool checkable) -> type& {
for(auto& item : state.items) item->state.checked = checked; state.checkable = checkable;
signal(setChecked, checked); signal(setCheckable, checkable);
return *this; return *this;
} }
@ -217,15 +229,34 @@ auto mListView::setHeaderVisible(bool visible) -> type& {
return *this; return *this;
} }
auto mListView::setMultiSelect(bool multiSelect) -> type& { auto mListView::setParent(mObject* parent, signed offset) -> type& {
state.multiSelect = multiSelect; for(auto& item : state.items) item->destruct();
signal(setMultiSelect, multiSelect); for(auto& column : state.columns) column->destruct();
mObject::setParent(parent, offset);
for(auto& column : state.columns) column->setParent(this, column->offset());
for(auto& item : state.items) item->setParent(this, item->offset());
return *this; return *this;
} }
auto mListView::setSelected(bool selected) -> type& { auto mListView::setSortable(bool sortable) -> type& {
for(auto& item : state.items) item->state.selected = selected; state.sortable = sortable;
signal(setSelected, selected); signal(setSortable, sortable);
return *this;
}
auto mListView::sortable() const -> bool {
return state.sortable;
}
auto mListView::uncheckAll() -> type& {
for(auto& item : state.items) item->state.checked = false;
signal(uncheckAll);
return *this;
}
auto mListView::unselectAll() -> type& {
for(auto& item : state.items) item->state.selected = false;
signal(unselectAll);
return *this; return *this;
} }

View File

@ -6,20 +6,6 @@ auto mRadioButton::allocate() -> pObject* {
// //
auto mRadioButton::group(const vector<shared_pointer_weak<mRadioButton>>& group) -> void {
for(auto& weak : group) {
if(auto item = weak.acquire()) item->state.group = group;
}
for(auto& weak : group) {
if(auto item = weak.acquire()) {
if(item->self()) item->self()->setGroup(group);
}
}
if(group.size()) {
if(auto item = group.first().acquire()) item->setChecked();
}
}
auto mRadioButton::bordered() const -> bool { auto mRadioButton::bordered() const -> bool {
return state.bordered; return state.bordered;
} }
@ -32,6 +18,10 @@ auto mRadioButton::doActivate() const -> void {
if(state.onActivate) return state.onActivate(); if(state.onActivate) return state.onActivate();
} }
auto mRadioButton::group() const -> sGroup {
return state.group;
}
auto mRadioButton::icon() const -> image { auto mRadioButton::icon() const -> image {
return state.icon; return state.icon;
} }
@ -52,14 +42,26 @@ auto mRadioButton::setBordered(bool bordered) -> type& {
} }
auto mRadioButton::setChecked() -> type& { auto mRadioButton::setChecked() -> type& {
for(auto& weak : state.group) { if(auto group = this->group()) {
if(auto item = weak.acquire()) item->state.checked = false; for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto radioButton = dynamic_cast<mRadioButton*>(object.data())) {
radioButton->state.checked = false;
}
}
}
} }
state.checked = true; state.checked = true;
signal(setChecked); signal(setChecked);
return *this; return *this;
} }
auto mRadioButton::setGroup(sGroup group) -> type& {
state.group = group;
signal(setGroup, group);
return *this;
}
auto mRadioButton::setIcon(const image& icon) -> type& { auto mRadioButton::setIcon(const image& icon) -> type& {
state.icon = icon; state.icon = icon;
signal(setIcon, icon); signal(setIcon, icon);

View File

@ -6,20 +6,6 @@ auto mRadioLabel::allocate() -> pObject* {
// //
auto mRadioLabel::group(const vector<shared_pointer_weak<mRadioLabel>>& group) -> void {
for(auto& weak : group) {
if(auto item = weak.acquire()) item->state.group = group;
}
for(auto& weak : group) {
if(auto item = weak.acquire()) {
if(item->self()) item->self()->setGroup(group);
}
}
if(group.size()) {
if(auto item = group.first().acquire()) item->setChecked();
}
}
auto mRadioLabel::checked() const -> bool { auto mRadioLabel::checked() const -> bool {
return state.checked; return state.checked;
} }
@ -28,20 +14,36 @@ auto mRadioLabel::doActivate() const -> void {
if(state.onActivate) return state.onActivate(); if(state.onActivate) return state.onActivate();
} }
auto mRadioLabel::group() const -> sGroup {
return state.group;
}
auto mRadioLabel::onActivate(const function<void ()>& function) -> type& { auto mRadioLabel::onActivate(const function<void ()>& function) -> type& {
state.onActivate = function; state.onActivate = function;
return *this; return *this;
} }
auto mRadioLabel::setChecked() -> type& { auto mRadioLabel::setChecked() -> type& {
for(auto& weak : state.group) { if(auto group = this->group()) {
if(auto item = weak.acquire()) item->state.checked = false; for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto radioLabel = dynamic_cast<mRadioLabel*>(object.data())) {
radioLabel->state.checked = false;
}
}
}
} }
state.checked = true; state.checked = true;
signal(setChecked); signal(setChecked);
return *this; return *this;
} }
auto mRadioLabel::setGroup(sGroup group) -> type& {
state.group = group;
signal(setGroup, group);
return *this;
}
auto mRadioLabel::setText(const string& text) -> type& { auto mRadioLabel::setText(const string& text) -> type& {
state.text = text; state.text = text;
signal(setText, text); signal(setText, text);

View File

@ -15,6 +15,7 @@ auto mTabFrameItem::append(sLayout layout) -> type& {
if(auto& layout = state.layout) remove(layout); if(auto& layout = state.layout) remove(layout);
state.layout = layout; state.layout = layout;
layout->setParent(this, 0); layout->setParent(this, 0);
signal(append, layout);
return *this; return *this;
} }
@ -40,8 +41,9 @@ auto mTabFrameItem::remove() -> type& {
} }
auto mTabFrameItem::remove(sLayout layout) -> type& { auto mTabFrameItem::remove(sLayout layout) -> type& {
layout->setParent(); signal(remove, layout);
state.layout.reset(); state.layout.reset();
layout->setParent();
return *this; return *this;
} }
@ -51,8 +53,7 @@ auto mTabFrameItem::reset() -> type& {
} }
auto mTabFrameItem::selected() const -> bool { auto mTabFrameItem::selected() const -> bool {
if(auto tabFrame = parentTabFrame()) return offset() == tabFrame->state.selected; return state.selected;
return false;
} }
auto mTabFrameItem::setClosable(bool closable) -> type& { auto mTabFrameItem::setClosable(bool closable) -> type& {
@ -81,7 +82,10 @@ auto mTabFrameItem::setParent(mObject* parent, signed offset) -> type& {
} }
auto mTabFrameItem::setSelected() -> type& { auto mTabFrameItem::setSelected() -> type& {
if(auto tabFrame = parentTabFrame()) tabFrame->state.selected = offset(); if(auto parent = parentTabFrame()) {
for(auto& item : parent->state.items) item->state.selected = false;
}
state.selected = true;
signal(setSelected); signal(setSelected);
return *this; return *this;
} }

View File

@ -75,7 +75,10 @@ auto mTabFrame::reset() -> type& {
} }
auto mTabFrame::selected() const -> sTabFrameItem { auto mTabFrame::selected() const -> sTabFrameItem {
return state.items[state.selected]; for(auto& item : state.items) {
if(item->selected()) return item;
}
return {};
} }
auto mTabFrame::setEdge(Edge edge) -> type& { auto mTabFrame::setEdge(Edge edge) -> type& {

View File

@ -19,6 +19,7 @@ auto mWindow::append(shared_pointer<mLayout> layout) -> type& {
layout->setGeometry(geometry().setPosition(0, 0)); layout->setGeometry(geometry().setPosition(0, 0));
layout->setParent(this, 0); layout->setParent(this, 0);
layout->setGeometry(geometry().setPosition(0, 0)); layout->setGeometry(geometry().setPosition(0, 0));
signal(append, layout);
return *this; return *this;
} }
@ -129,6 +130,7 @@ auto mWindow::onSize(const function<void ()>& function) -> type& {
} }
auto mWindow::remove(shared_pointer<mLayout> layout) -> type& { auto mWindow::remove(shared_pointer<mLayout> layout) -> type& {
signal(remove, layout);
layout->setParent(); layout->setParent();
state.layout.reset(); state.layout.reset();
return *this; return *this;

View File

@ -35,27 +35,27 @@ auto BrowserDialogWindow::accept() -> void {
auto selectedItems = view.selectedItems(); auto selectedItems = view.selectedItems();
if(state.action == "openFile" && selectedItems) { if(state.action == "openFile" && selectedItems) {
string name = selectedItems.first()->text(0); string name = selectedItems.first()->cell(0)->text();
if(isFolder(name)) return setPath({state.path, name}); if(isFolder(name)) return setPath({state.path, name});
state.response.append(string{state.path, name}); state.response.append(string{state.path, name});
} }
if(state.action == "openFiles") { if(state.action == "openFiles") {
for(auto selectedItem : selectedItems) { for(auto selectedItem : selectedItems) {
string name = selectedItem->text(0); string name = selectedItem->cell(0)->text();
state.response.append(string{state.path, name, isFolder(name) ? "/" : ""}); state.response.append(string{state.path, name, isFolder(name) ? "/" : ""});
} }
} }
if(state.action == "openFolder" && selectedItems) { if(state.action == "openFolder" && selectedItems) {
string name = selectedItems.first()->text(0); string name = selectedItems.first()->cell(0)->text();
if(!isMatch(name)) return setPath({state.path, name}); if(!isMatch(name)) return setPath({state.path, name});
state.response.append(string{state.path, name, "/"}); state.response.append(string{state.path, name, "/"});
} }
if(state.action == "saveFile") { if(state.action == "saveFile") {
string name = fileName.text(); string name = fileName.text();
if(!name && selectedItems) name = selectedItems.first()->text(0); if(!name && selectedItems) name = selectedItems.first()->cell(0)->text();
if(!name || isFolder(name)) return; if(!name || isFolder(name)) return;
if(file::exists({state.path, name})) { if(file::exists({state.path, name})) {
if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return; if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return;
@ -64,7 +64,7 @@ auto BrowserDialogWindow::accept() -> void {
} }
if(state.action == "selectFolder" && selectedItems) { if(state.action == "selectFolder" && selectedItems) {
string name = selectedItems.first()->text(0); string name = selectedItems.first()->cell(0)->text();
if(isFolder(name)) state.response.append(string{state.path, name, "/"}); if(isFolder(name)) state.response.append(string{state.path, name, "/"});
} }
@ -76,13 +76,13 @@ auto BrowserDialogWindow::activate() -> void {
auto selectedItem = view.selected(); auto selectedItem = view.selected();
if(state.action == "saveFile" && selectedItem) { if(state.action == "saveFile" && selectedItem) {
string name = selectedItem->text(0); string name = selectedItem->cell(0)->text();
if(isFolder(name)) return setPath({state.path, name}); if(isFolder(name)) return setPath({state.path, name});
fileName.setText(name); fileName.setText(name);
} }
if(state.action == "selectFolder" && selectedItem) { if(state.action == "selectFolder" && selectedItem) {
string name = selectedItem->text(0); string name = selectedItem->cell(0)->text();
if(isFolder(name)) return setPath({state.path, name}); if(isFolder(name)) return setPath({state.path, name});
} }
@ -94,7 +94,7 @@ auto BrowserDialogWindow::change() -> void {
fileName.setText(""); fileName.setText("");
if(state.action == "saveFile") { if(state.action == "saveFile") {
if(auto selectedItem = view.selected()) { if(auto selectedItem = view.selected()) {
string name = selectedItem->text(0); string name = selectedItem->cell(0)->text();
if(!isFolder(name)) fileName.setText(name); if(!isFolder(name)) fileName.setText(name);
} }
} }
@ -121,7 +121,7 @@ auto BrowserDialogWindow::run() -> lstring {
pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); }); pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); });
pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); }); pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); });
pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); }); pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); });
view.setMultiSelect(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); }); view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); });
filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); }); filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); });
for(auto& filter : state.filters) { for(auto& filter : state.filters) {
auto part = filter.split<1>("|"); auto part = filter.split<1>("|");
@ -161,8 +161,8 @@ auto BrowserDialogWindow::setPath(string path) -> void {
pathName.setText(state.path = path); pathName.setText(state.path = path);
view.reset(); view.reset();
view.append(ListViewColumn().setWidth(~0)); view.append(ListViewColumn().setExpandable());
view.append(ListViewColumn().setWidth( 0).setForegroundColor({192, 128, 128})); view.append(ListViewColumn().setForegroundColor({192, 128, 128}));
auto contents = directory::contents(path); auto contents = directory::contents(path);
bool folderMode = state.action == "openFolder"; bool folderMode = state.action == "openFolder";
@ -171,20 +171,20 @@ auto BrowserDialogWindow::setPath(string path) -> void {
if(!content.endsWith("/")) continue; if(!content.endsWith("/")) continue;
if(folderMode && isMatch(content.rtrim("/"))) continue; if(folderMode && isMatch(content.rtrim("/"))) continue;
ListViewItem item{&view}; view.append(ListViewItem()
item.setIcon(0, Icon::Emblem::Folder); .append(ListViewCell().setText(content.rtrim("/")).setIcon(Icon::Emblem::Folder))
item.setText(0, content.rtrim("/")); .append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777)))
item.setText(1, octal<3>(storage::mode({path, content}) & 0777)); );
} }
for(auto content : contents) { for(auto content : contents) {
if(content.endsWith("/") && !folderMode) continue; if(content.endsWith("/") && !folderMode) continue;
if(!isMatch(content.rtrim("/"))) continue; if(!isMatch(content.rtrim("/"))) continue;
ListViewItem item{&view}; view.append(ListViewItem()
item.setIcon(0, folderMode ? Icon::Action::Open : Icon::Emblem::File); .append(ListViewCell().setText(content.rtrim("/")).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File))
item.setText(0, content.rtrim("/")); .append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777)))
item.setText(1, octal<3>(storage::mode({path, content}) & 0777)); );
} }
if(view.items()) view.item(0)->setSelected(); if(view.items()) view.item(0)->setSelected();

View File

@ -1,6 +1,6 @@
#define Declare(Name) \ #define Declare(Name) \
using type = Name; \ using type = Name; \
Name() : s##Name(new m##Name, [](m##Name* p) { \ Name() : s##Name(new m##Name, [](auto p) { \
p->unbind(); \ p->unbind(); \
delete p; \ delete p; \
}) { \ }) { \
@ -51,6 +51,27 @@ struct Object : sObject {
}; };
#endif #endif
#if defined(Hiro_Group)
struct Group : sGroup {
using type = Group;
Group() : sGroup(new mGroup, [](auto p) { p->unbind(); delete p; }) { (*this)->bind(*this); }
template<typename... P> Group(P&&... p) : Group() { _append(std::forward<P>(p)...); }
auto self() const -> mGroup& { return (mGroup&)operator*(); }
auto append(sObject object) -> type& { return self().append(object), *this; }
auto object(unsigned position) const -> sObject { return self().object(position); }
auto objects() const -> unsigned { return self().objects(); }
auto remove(sObject object) -> type& { return self().remove(object), *this; }
private:
auto _append() -> void {}
template<typename T, typename... P> auto _append(T* object, P&&... p) -> void {
append(*object);
_append(std::forward<P>(p)...);
}
};
#endif
#if defined(Hiro_Hotkey) #if defined(Hiro_Hotkey)
struct Hotkey : sHotkey { struct Hotkey : sHotkey {
DeclareObject(Hotkey) DeclareObject(Hotkey)
@ -222,16 +243,11 @@ struct MenuRadioItem : sMenuRadioItem {
auto checked() const -> bool { return self().checked(); } auto checked() const -> bool { return self().checked(); }
auto doActivate() const -> void { return self().doActivate(); } auto doActivate() const -> void { return self().doActivate(); }
auto group() const -> sGroup { return self().group(); }
auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; } auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; }
auto setChecked() -> type& { return self().setChecked(), *this; } auto setChecked() -> type& { return self().setChecked(), *this; }
auto setText(const string& text = "") -> type& { return self().setText(text), *this; } auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
auto text() const -> string { return self().text(); } auto text() const -> string { return self().text(); }
static auto group(const vector<MenuRadioItem>& group) -> void {
vector<wMenuRadioItem> items;
for(auto& item : group) items.append(item);
return mMenuRadioItem::group(items);
}
}; };
#endif #endif
@ -345,6 +361,7 @@ struct ComboButton : sComboButton {
auto remove(sComboButtonItem item) -> type& { return self().remove(item), *this; } auto remove(sComboButtonItem item) -> type& { return self().remove(item), *this; }
auto reset() -> type& { return self().reset(), *this; } auto reset() -> type& { return self().reset(), *this; }
auto selected() const -> sComboButtonItem { return self().selected(); } auto selected() const -> sComboButtonItem { return self().selected(); }
auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& { return self().setParent(parent, offset), *this; }
}; };
#endif #endif
@ -524,14 +541,16 @@ struct ListView : sListView {
auto append(sListViewColumn column) -> type& { return self().append(column), *this; } auto append(sListViewColumn column) -> type& { return self().append(column), *this; }
auto append(sListViewItem item) -> type& { return self().append(item), *this; } auto append(sListViewItem item) -> type& { return self().append(item), *this; }
auto backgroundColor() const -> Color { return self().backgroundColor(); } auto backgroundColor() const -> Color { return self().backgroundColor(); }
auto batchable() const -> bool { return self().batchable(); }
auto checkable() const -> bool { return self().checkable(); } auto checkable() const -> bool { return self().checkable(); }
auto checkAll() -> type& { return self().checkAll(), *this; }
auto checked() const -> vector<sListViewItem> { return self().checked(); } auto checked() const -> vector<sListViewItem> { return self().checked(); }
auto column(unsigned position) -> sListViewColumn { return self().column(position); } auto column(unsigned position) -> sListViewColumn { return self().column(position); }
auto columns() const -> unsigned { return self().columns(); } auto columns() const -> unsigned { return self().columns(); }
auto doActivate() const -> void { return self().doActivate(); } auto doActivate() const -> void { return self().doActivate(); }
auto doChange() const -> void { return self().doChange(); } auto doChange() const -> void { return self().doChange(); }
auto doContext() const -> void { return self().doContext(); } auto doContext() const -> void { return self().doContext(); }
auto doEdit(sListViewItem item, sListViewColumn column) const -> void { return self().doEdit(item, column); } auto doEdit(sListViewCell cell) const -> void { return self().doEdit(cell); }
auto doSort(sListViewColumn column) const -> void { return self().doSort(column); } auto doSort(sListViewColumn column) const -> void { return self().doSort(column); }
auto doToggle(sListViewItem item) const -> void { return self().doToggle(item); } auto doToggle(sListViewItem item) const -> void { return self().doToggle(item); }
auto foregroundColor() const -> Color { return self().foregroundColor(); } auto foregroundColor() const -> Color { return self().foregroundColor(); }
@ -539,27 +558,29 @@ struct ListView : sListView {
auto headerVisible() const -> bool { return self().headerVisible(); } auto headerVisible() const -> bool { return self().headerVisible(); }
auto item(unsigned position) -> sListViewItem { return self().item(position); } auto item(unsigned position) -> sListViewItem { return self().item(position); }
auto items() const -> unsigned { return self().items(); } auto items() const -> unsigned { return self().items(); }
auto multiSelect() const -> bool { return self().multiSelect(); }
auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; } auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; }
auto onChange(const function<void ()>& function = {}) -> type& { return self().onChange(function), *this; } auto onChange(const function<void ()>& function = {}) -> type& { return self().onChange(function), *this; }
auto onContext(const function<void ()>& function = {}) -> type& { return self().onContext(function), *this; } auto onContext(const function<void ()>& function = {}) -> type& { return self().onContext(function), *this; }
auto onEdit(const function<void (sListViewItem, sListViewColumn)>& function = {}) -> type& { return self().onEdit(function), *this; } auto onEdit(const function<void (sListViewCell)>& function = {}) -> type& { return self().onEdit(function), *this; }
auto onSort(const function<void (sListViewColumn)>& function = {}) -> type& { return self().onSort(function), *this; } auto onSort(const function<void (sListViewColumn)>& function = {}) -> type& { return self().onSort(function), *this; }
auto onToggle(const function<void (sListViewItem)>& function = {}) -> type& { return self().onToggle(function), *this; } auto onToggle(const function<void (sListViewItem)>& function = {}) -> type& { return self().onToggle(function), *this; }
auto remove(sListViewColumn column) -> type& { return self().remove(column), *this; } auto remove(sListViewColumn column) -> type& { return self().remove(column), *this; }
auto remove(sListViewItem item) -> type& { return self().remove(item), *this; } auto remove(sListViewItem item) -> type& { return self().remove(item), *this; }
auto reset() -> type& { return self().reset(), *this; } auto reset() -> type& { return self().reset(), *this; }
auto resizeColumns() -> type& { return self().resizeColumns(), *this; } auto resizeColumns() -> type& { return self().resizeColumns(), *this; }
auto selectAll() -> type& { return self().selectAll(), *this; }
auto selected() const -> sListViewItem { return self().selected(); } auto selected() const -> sListViewItem { return self().selected(); }
auto selectedItems() const -> vector<sListViewItem> { return self().selectedItems(); } auto selectedItems() const -> vector<sListViewItem> { return self().selectedItems(); }
auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; }
auto setBatchable(bool batchable = true) -> type& { return self().setBatchable(batchable), *this; }
auto setCheckable(bool checkable = true) -> type& { return self().setCheckable(checkable), *this; } auto setCheckable(bool checkable = true) -> type& { return self().setCheckable(checkable), *this; }
auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; }
auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; }
auto setGridVisible(bool visible = true) -> type& { return self().setGridVisible(visible), *this; } auto setGridVisible(bool visible = true) -> type& { return self().setGridVisible(visible), *this; }
auto setHeaderVisible(bool visible = true) -> type& { return self().setHeaderVisible(visible), *this; } auto setHeaderVisible(bool visible = true) -> type& { return self().setHeaderVisible(visible), *this; }
auto setMultiSelect(bool multiSelect = true) -> type& { return self().setMultiSelect(multiSelect), *this; } auto setSortable(bool sortable = true) -> type& { return self().setSortable(sortable), *this; }
auto setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; } auto sortable() const -> bool { return self().sortable(); }
auto uncheckAll() -> type& { return self().uncheckAll(), *this; }
auto unselectAll() -> type& { return self().unselectAll(), *this; }
}; };
#endif #endif
@ -570,6 +591,7 @@ struct ListViewColumn : sListViewColumn {
auto active() const -> bool { return self().active(); } auto active() const -> bool { return self().active(); }
auto backgroundColor() const -> Color { return self().backgroundColor(); } auto backgroundColor() const -> Color { return self().backgroundColor(); }
auto editable() const -> bool { return self().editable(); } auto editable() const -> bool { return self().editable(); }
auto expandable() const -> bool { return self().expandable(); }
auto foregroundColor() const -> Color { return self().foregroundColor(); } auto foregroundColor() const -> Color { return self().foregroundColor(); }
auto horizontalAlignment() const -> double { return self().horizontalAlignment(); } auto horizontalAlignment() const -> double { return self().horizontalAlignment(); }
auto icon() const -> image { return self().icon(); } auto icon() const -> image { return self().icon(); }
@ -577,15 +599,14 @@ struct ListViewColumn : sListViewColumn {
auto setActive() -> type& { return self().setActive(), *this; } auto setActive() -> type& { return self().setActive(), *this; }
auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; } auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; }
auto setEditable(bool editable = true) -> type& { return self().setEditable(editable), *this; } auto setEditable(bool editable = true) -> type& { return self().setEditable(editable), *this; }
auto setExpandable(bool expandable = true) -> type& { return self().setExpandable(expandable), *this; }
auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; } auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; }
auto setHorizontalAlignment(double alignment = 0.0) -> type& { return self().setHorizontalAlignment(alignment), *this; } auto setHorizontalAlignment(double alignment = 0.0) -> type& { return self().setHorizontalAlignment(alignment), *this; }
auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; } auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; }
auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; } auto setResizable(bool resizable = true) -> type& { return self().setResizable(resizable), *this; }
auto setSortable(bool sortable = true) -> type& { return self().setSortable(sortable), *this; }
auto setText(const string& text = "") -> type& { return self().setText(text), *this; } auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
auto setVerticalAlignment(double alignment = 0.5) -> type& { return self().setVerticalAlignment(alignment), *this; } auto setVerticalAlignment(double alignment = 0.5) -> type& { return self().setVerticalAlignment(alignment), *this; }
auto setWidth(signed width = 0) -> type& { return self().setWidth(width), *this; } auto setWidth(signed width = 0) -> type& { return self().setWidth(width), *this; }
auto sortable() const -> bool { return self().sortable(); }
auto text() const -> string { return self().text(); } auto text() const -> string { return self().text(); }
auto verticalAlignment() const -> double { return self().verticalAlignment(); } auto verticalAlignment() const -> double { return self().verticalAlignment(); }
auto width() const -> signed { return self().width(); } auto width() const -> signed { return self().width(); }
@ -596,15 +617,33 @@ struct ListViewColumn : sListViewColumn {
struct ListViewItem : sListViewItem { struct ListViewItem : sListViewItem {
DeclareObject(ListViewItem) DeclareObject(ListViewItem)
auto append(sListViewCell cell) -> type& { return self().append(cell), *this; }
auto backgroundColor() const -> Color { return self().backgroundColor(); }
auto cell(unsigned position) const -> sListViewCell { return self().cell(position); }
auto cells() const -> unsigned { return self().cells(); }
auto checked() const -> bool { return self().checked(); } auto checked() const -> bool { return self().checked(); }
auto icon(unsigned column = 0) const -> image { return self().icon(column); } auto foregroundColor() const -> Color { return self().foregroundColor(); }
auto remove(sListViewCell cell) -> type& { return self().remove(cell), *this; }
auto selected() const -> bool { return self().selected(); } auto selected() const -> bool { return self().selected(); }
auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; }
auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; } auto setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; }
auto setIcon(unsigned column, const image& icon = {}) -> type& { return self().setIcon(column, icon), *this; } auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; }
auto setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; } auto setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; }
auto setText(const lstring& text) -> type& { return self().setText(text), *this; } };
auto setText(unsigned column, const string& text = "") -> type& { return self().setText(column, text), *this; } #endif
auto text(unsigned column = 0) const -> string { return self().text(column); }
#if defined(Hiro_ListView)
struct ListViewCell : sListViewCell {
DeclareObject(ListViewCell)
auto backgroundColor() const -> Color { return self().backgroundColor(); }
auto foregroundColor() const -> Color { return self().foregroundColor(); }
auto icon() const -> image { return self().icon(); }
auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *this; }
auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; }
auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *this; }
auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
auto text() const -> string { return self().text(); }
}; };
#endif #endif
@ -624,6 +663,7 @@ struct RadioButton : sRadioButton {
auto bordered() const -> bool { return self().bordered(); } auto bordered() const -> bool { return self().bordered(); }
auto checked() const -> bool { return self().checked(); } auto checked() const -> bool { return self().checked(); }
auto doActivate() const -> void { return self().doActivate(); } auto doActivate() const -> void { return self().doActivate(); }
auto group() const -> sGroup { return self().group(); }
auto icon() const -> image { return self().icon(); } auto icon() const -> image { return self().icon(); }
auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; } auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; }
auto orientation() const -> Orientation { return self().orientation(); } auto orientation() const -> Orientation { return self().orientation(); }
@ -633,12 +673,6 @@ struct RadioButton : sRadioButton {
auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type& { return self().setOrientation(orientation), *this; } auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type& { return self().setOrientation(orientation), *this; }
auto setText(const string& text = "") -> type& { return self().setText(text), *this; } auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
auto text() const -> string { return self().text(); } auto text() const -> string { return self().text(); }
static auto group(const vector<RadioButton>& group) -> void {
vector<wRadioButton> items;
for(auto& item : group) items.append(item);
return mRadioButton::group(items);
}
}; };
#endif #endif
@ -648,16 +682,11 @@ struct RadioLabel : sRadioLabel {
auto checked() const -> bool { return self().checked(); } auto checked() const -> bool { return self().checked(); }
auto doActivate() const -> void { return self().doActivate(); } auto doActivate() const -> void { return self().doActivate(); }
auto group() const -> sGroup { return self().group(); }
auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; } auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; }
auto setChecked() -> type& { return self().setChecked(), *this; } auto setChecked() -> type& { return self().setChecked(), *this; }
auto setText(const string& text = "") -> type& { return self().setText(text), *this; } auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
auto text() const -> string { return self().text(); } auto text() const -> string { return self().text(); }
static auto group(const vector<RadioLabel>& group) -> void {
vector<wRadioLabel> items;
for(auto& item : items) items.append(item);
return mRadioLabel::group(items);
}
}; };
#endif #endif

View File

@ -8,13 +8,11 @@ static auto MenuRadioItem_activate(GtkCheckMenuItem* gtkCheckMenuItem, pMenuRadi
auto pMenuRadioItem::construct() -> void { auto pMenuRadioItem::construct() -> void {
widget = gtk_radio_menu_item_new_with_mnemonic(0, ""); widget = gtk_radio_menu_item_new_with_mnemonic(0, "");
setGroup(state().group); gtkCheckMenuItem = GTK_CHECK_MENU_ITEM(widget);
gtkRadioMenuItem = GTK_RADIO_MENU_ITEM(widget);
setText(state().text); setText(state().text);
for(auto& weak : state().group) {
if(auto item = weak.acquire()) {
if(item->self()) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->self()->widget), item->checked());
}
}
g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(MenuRadioItem_activate), (gpointer)this); g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(MenuRadioItem_activate), (gpointer)this);
} }
@ -23,55 +21,54 @@ auto pMenuRadioItem::destruct() -> void {
} }
auto pMenuRadioItem::setChecked() -> void { auto pMenuRadioItem::setChecked() -> void {
_parent().lock(); lock();
for(auto& weak : state().group) { gtk_check_menu_item_set_active(gtkCheckMenuItem, true);
if(auto item = weak.acquire()) { unlock();
if(item->self()) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item->self()->widget), false);
}
}
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true);
_parent().unlock();
} }
auto pMenuRadioItem::setGroup(const vector<shared_pointer_weak<mMenuRadioItem>>& group) -> void { auto pMenuRadioItem::setGroup(sGroup group) -> void {
_parent().lock(); if(!group) return;
shared_pointer<mMenuRadioItem> first;
for(auto& weak : group) { maybe<GtkRadioMenuItem*> gtkRadioMenuItem;
if(!first) { for(auto& weak : group->state.objects) {
first = weak.acquire(); if(auto object = weak.acquire()) {
continue; if(auto menuRadioItem = dynamic_cast<mMenuRadioItem*>(object.data())) {
} if(auto self = menuRadioItem->self()) {
if(auto item = weak.acquire()) { self->lock();
if(item->self() && first->self()) { gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, nullptr);
GSList* currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(first->self()->widget)); if(!gtkRadioMenuItem) gtkRadioMenuItem = self->gtkRadioMenuItem;
if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item->self()->widget))) { else gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, gtk_radio_menu_item_get_group(*gtkRadioMenuItem));
gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(item->self()->widget), currentGroup); gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->checked());
self->unlock();
} }
} }
} }
} }
_parent().unlock();
} }
auto pMenuRadioItem::setText(const string& text) -> void { auto pMenuRadioItem::setText(const string& text) -> void {
gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text)); gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text));
} }
auto pMenuRadioItem::_doActivate() -> void { auto pMenuRadioItem::groupLocked() const -> bool {
if(!_parent().locked()) { if(auto group = state().group) {
bool wasChecked = state().checked; for(auto& weak : group->state.objects) {
self().setChecked(); if(auto object = weak.acquire()) {
if(!wasChecked) self().doActivate(); if(auto self = object->self()) {
if(self->locked()) return true;
}
}
}
return false;
} }
return locked();
} }
auto pMenuRadioItem::_parent() -> pMenuRadioItem& { auto pMenuRadioItem::_doActivate() -> void {
if(state().group.size()) { if(groupLocked()) return;
if(auto item = state().group.first().acquire()) { bool wasChecked = state().checked;
if(item->self()) return *item->self(); self().setChecked();
} if(!wasChecked) self().doActivate();
}
return *this;
} }
} }

View File

@ -6,11 +6,15 @@ struct pMenuRadioItem : pAction {
Declare(MenuRadioItem, Action) Declare(MenuRadioItem, Action)
auto setChecked() -> void; auto setChecked() -> void;
auto setGroup(const vector<shared_pointer_weak<mMenuRadioItem>>& group) -> void; auto setGroup(sGroup group) -> void;
auto setText(const string& text) -> void; auto setText(const string& text) -> void;
auto groupLocked() const -> bool;
auto _doActivate() -> void; auto _doActivate() -> void;
auto _parent() -> pMenuRadioItem&;
GtkCheckMenuItem* gtkCheckMenuItem = nullptr;
GtkRadioMenuItem* gtkRadioMenuItem = nullptr;
}; };
} }

View File

@ -2,31 +2,31 @@
namespace hiro { namespace hiro {
string pFont::serif(unsigned size, string style) { auto pFont::serif(unsigned size, string style) -> string {
if(size == 0) size = 8; if(size == 0) size = 8;
if(style == "") style = "Normal"; if(style == "") style = "Normal";
return {"Serif, ", size, ", ", style}; return {"Serif, ", size, ", ", style};
} }
string pFont::sans(unsigned size, string style) { auto pFont::sans(unsigned size, string style) -> string {
if(size == 0) size = 8; if(size == 0) size = 8;
if(style == "") style = "Normal"; if(style == "") style = "Normal";
return {"Sans, ", size, ", ", style}; return {"Sans, ", size, ", ", style};
} }
string pFont::monospace(unsigned size, string style) { auto pFont::monospace(unsigned size, string style) -> string {
if(size == 0) size = 8; if(size == 0) size = 8;
return {"Liberation Mono, ", size, ", ", style}; return {"Liberation Mono, ", size, ", ", style};
} }
Size pFont::size(string font, string text) { auto pFont::size(string font, string text) -> Size {
PangoFontDescription* description = create(font); PangoFontDescription* description = create(font);
Size size = pFont::size(description, text); Size size = pFont::size(description, text);
free(description); free(description);
return size; return size;
} }
PangoFontDescription* pFont::create(string description) { auto pFont::create(string description) -> PangoFontDescription* {
lstring part = description.split<2>(",").strip(); lstring part = description.split<2>(",").strip();
string family = "Sans"; string family = "Sans";
@ -47,11 +47,11 @@ PangoFontDescription* pFont::create(string description) {
return font; return font;
} }
void pFont::free(PangoFontDescription* font) { auto pFont::free(PangoFontDescription* font) -> void {
pango_font_description_free(font); pango_font_description_free(font);
} }
Size pFont::size(PangoFontDescription* font, string text) { auto pFont::size(PangoFontDescription* font, string text) -> Size {
PangoContext* context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); PangoContext* context = gdk_pango_context_get_for_screen(gdk_screen_get_default());
PangoLayout* layout = pango_layout_new(context); PangoLayout* layout = pango_layout_new(context);
pango_layout_set_font_description(layout, font); pango_layout_set_font_description(layout, font);
@ -62,13 +62,13 @@ Size pFont::size(PangoFontDescription* font, string text) {
return {width, height}; return {width, height};
} }
void pFont::setFont(GtkWidget* widget, string font) { auto pFont::setFont(GtkWidget* widget, string font) -> void {
auto gtkFont = pFont::create(font); auto gtkFont = pFont::create(font);
pFont::setFont(widget, (gpointer)gtkFont); pFont::setFont(widget, (gpointer)gtkFont);
pFont::free(gtkFont); pFont::free(gtkFont);
} }
void pFont::setFont(GtkWidget* widget, gpointer font) { auto pFont::setFont(GtkWidget* widget, gpointer font) -> void {
if(font == nullptr) return; if(font == nullptr) return;
gtk_widget_modify_font(widget, (PangoFontDescription*)font); gtk_widget_modify_font(widget, (PangoFontDescription*)font);
if(GTK_IS_CONTAINER(widget)) { if(GTK_IS_CONTAINER(widget)) {

View File

@ -3,16 +3,16 @@
namespace hiro { namespace hiro {
struct pFont { struct pFont {
static string serif(unsigned size, string style); static auto serif(unsigned size, string style) -> string;
static string sans(unsigned size, string style); static auto sans(unsigned size, string style) -> string;
static string monospace(unsigned size, string style); static auto monospace(unsigned size, string style) -> string;
static Size size(string font, string text); static auto size(string font, string text) -> Size;
static PangoFontDescription* create(string description); static auto create(string description) -> PangoFontDescription*;
static void free(PangoFontDescription* font); static auto free(PangoFontDescription* font) -> void;
static Size size(PangoFontDescription* font, string text); static auto size(PangoFontDescription* font, string text) -> Size;
static void setFont(GtkWidget* widget, string font); static auto setFont(GtkWidget* widget, string font) -> void;
static void setFont(GtkWidget* widget, gpointer font); static auto setFont(GtkWidget* widget, gpointer font) -> void;
}; };
} }

13
hiro/gtk/group.cpp Normal file
View File

@ -0,0 +1,13 @@
#if defined(Hiro_Group)
namespace hiro {
auto pGroup::construct() -> void {
}
auto pGroup::destruct() -> void {
}
}
#endif

11
hiro/gtk/group.hpp Normal file
View File

@ -0,0 +1,11 @@
#if defined(Hiro_Group)
namespace hiro {
struct pGroup : pObject {
Declare(Group, Object)
};
}
#endif

View File

@ -240,7 +240,7 @@ auto pKeyboard::initialize() -> void {
#include <hiro/platform/xorg/keyboard.hpp> #include <hiro/platform/xorg/keyboard.hpp>
#endif #endif
//print("[phoenix/gtk] warning: unhandled key: ", key, "\n"); //print("[hiro/gtk] warning: unhandled key: ", key, "\n");
append(0); append(0);
} }
#undef map #undef map

View File

@ -8,7 +8,10 @@
#include "mouse.cpp" #include "mouse.cpp"
#include "browser-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "object.cpp" #include "object.cpp"
#include "group.cpp"
#include "hotkey.cpp" #include "hotkey.cpp"
#include "timer.cpp" #include "timer.cpp"
#include "window.cpp" #include "window.cpp"
@ -45,6 +48,7 @@
#include "widget/list-view.cpp" #include "widget/list-view.cpp"
#include "widget/list-view-column.cpp" #include "widget/list-view-column.cpp"
#include "widget/list-view-item.cpp" #include "widget/list-view-item.cpp"
#include "widget/list-view-cell.cpp"
#include "widget/progress-bar.cpp" #include "widget/progress-bar.cpp"
#include "widget/radio-button.cpp" #include "widget/radio-button.cpp"
#include "widget/radio-label.cpp" #include "widget/radio-label.cpp"

View File

@ -3,7 +3,7 @@ namespace hiro {
struct pMenu; struct pMenu;
struct pLayout; struct pLayout;
struct pWidget; struct pWidget;
}; }
#define Declare(Name, Base) \ #define Declare(Name, Base) \
p##Name(m##Name& reference) : p##Base(reference) {} \ p##Name(m##Name& reference) : p##Base(reference) {} \
@ -19,7 +19,10 @@ namespace hiro {
#include "mouse.hpp" #include "mouse.hpp"
#include "browser-window.hpp" #include "browser-window.hpp"
#include "message-window.hpp" #include "message-window.hpp"
#include "object.hpp" #include "object.hpp"
#include "group.hpp"
#include "hotkey.hpp" #include "hotkey.hpp"
#include "timer.hpp" #include "timer.hpp"
#include "window.hpp" #include "window.hpp"
@ -56,6 +59,7 @@ namespace hiro {
#include "widget/list-view.hpp" #include "widget/list-view.hpp"
#include "widget/list-view-column.hpp" #include "widget/list-view-column.hpp"
#include "widget/list-view-item.hpp" #include "widget/list-view-item.hpp"
#include "widget/list-view-cell.hpp"
#include "widget/progress-bar.hpp" #include "widget/progress-bar.hpp"
#include "widget/radio-button.hpp" #include "widget/radio-button.hpp"
#include "widget/radio-label.hpp" #include "widget/radio-label.hpp"

View File

@ -12,6 +12,8 @@ static auto CreateColor(const Color& color) -> GdkColor {
#endif #endif
static auto CreatePixbuf(const nall::image& image, bool scale = false) -> GdkPixbuf* { static auto CreatePixbuf(const nall::image& image, bool scale = false) -> GdkPixbuf* {
if(!image) return nullptr;
nall::image gdkImage = image; nall::image gdkImage = image;
gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16);
if(scale) gdkImage.scale(15, 15); if(scale) gdkImage.scale(15, 15);

View File

@ -8,17 +8,12 @@ auto pComboButtonItem::construct() -> void {
auto pComboButtonItem::destruct() -> void { auto pComboButtonItem::destruct() -> void {
} }
auto pComboButtonItem::setIcon(const image& icon) -> void { auto pComboButtonItem::setIcon(image icon) -> void {
if(auto parent = _parent()) { if(auto parent = _parent()) {
if(icon) { auto size = pFont::size(self().font(true), " ").height();
auto copy = icon; if(icon) icon.scale(size, size);
auto size = pFont::size(self().font(true), " ").height(); auto pixbuf = CreatePixbuf(icon);
copy.scale(size, size); gtk_list_store_set(parent->gtkListStore, &gtkIter, 0, pixbuf, -1);
auto pixbuf = CreatePixbuf(copy);
gtk_list_store_set(parent->gtkListStore, &gtkIter, 0, pixbuf, -1);
} else {
gtk_list_store_set(parent->gtkListStore, &gtkIter, 0, nullptr, -1);
}
} }
} }

View File

@ -5,7 +5,7 @@ namespace hiro {
struct pComboButtonItem : pObject { struct pComboButtonItem : pObject {
Declare(ComboButtonItem, Object) Declare(ComboButtonItem, Object)
auto setIcon(const image& icon) -> void; auto setIcon(image icon) -> void;
auto setSelected() -> void; auto setSelected() -> void;
auto setText(const string& text) -> void; auto setText(const string& text) -> void;

View File

@ -17,10 +17,7 @@ auto pComboButton::construct() -> void {
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, true); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, true);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, "text", 1, nullptr); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, "text", 1, nullptr);
for(auto& item : state().items) { for(auto& item : state().items) append(item);
append(item);
if(item->selected()) item->setSelected();
}
g_signal_connect(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboButton_change), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboButton_change), (gpointer)this);
@ -33,11 +30,13 @@ auto pComboButton::destruct() -> void {
auto pComboButton::append(sComboButtonItem item) -> void { auto pComboButton::append(sComboButtonItem item) -> void {
lock(); lock();
if(auto delegate = item->self()) { if(auto self = item->self()) {
gtk_list_store_append(gtkListStore, &delegate->gtkIter); gtk_list_store_append(gtkListStore, &self->gtkIter);
item->setIcon(item->state.icon); self->setIcon(item->state.icon);
item->setText(item->state.text); if(item->state.selected) self->setSelected();
self->setText(item->state.text);
} }
if(gtk_combo_box_get_active(gtkComboBox) < 0) item->setSelected();
unlock(); unlock();
} }
@ -46,25 +45,19 @@ auto pComboButton::minimumSize() const -> Size {
signed maximumWidth = 0; signed maximumWidth = 0;
for(auto& item : state().items) { for(auto& item : state().items) {
maximumWidth = max(maximumWidth, maximumWidth = max(maximumWidth,
(item->state.icon ? 2 + pFont::size(font, " ").height() : 0) (item->state.icon ? pFont::size(font, " ").height() + 2 : 0)
+ pFont::size(font, item->state.text).width() + pFont::size(font, item->state.text).width()
); );
} }
Size size = pFont::size(font, " "); return {maximumWidth + 40, pFont::size(font, " ").height() + 12};
return {maximumWidth + 40, size.height() + 12};
} }
auto pComboButton::remove(sComboButtonItem item) -> void { auto pComboButton::remove(sComboButtonItem item) -> void {
lock(); lock();
if(auto delegate = item->self()) { if(auto delegate = item->self()) {
gtk_list_store_remove(gtkListStore, &delegate->gtkIter); gtk_list_store_remove(gtkListStore, &delegate->gtkIter);
//if the currently selected item is removed; GTK+ deselects everything if(gtk_combo_box_get_active(gtkComboBox) < 0) {
//detect this behavior and select the first item instead of nothing if(auto item = self().item(0)) item->setSelected();
if(gtk_combo_box_get_active(GTK_COMBO_BOX(gtkWidget)) < 0) {
if(gtk_tree_model_iter_n_children(gtkTreeModel, nullptr) > 0) {
gtk_combo_box_set_active(GTK_COMBO_BOX(gtkWidget), 0);
state().selected = 0;
}
} }
} }
unlock(); unlock();
@ -83,10 +76,13 @@ auto pComboButton::setFont(const string& font) -> void {
} }
auto pComboButton::_updateSelected() -> void { auto pComboButton::_updateSelected() -> void {
for(auto& item : state().items) item->state.selected = false;
signed selected = gtk_combo_box_get_active(gtkComboBox); signed selected = gtk_combo_box_get_active(gtkComboBox);
if(selected >= 0) { if(selected >= 0) {
state().selected = selected; if(auto item = self().item(selected)) {
if(!locked()) self().doChange(); item->state.selected = true;
if(!locked()) self().doChange();
}
} }
} }

View File

@ -0,0 +1,40 @@
#if defined(Hiro_ListView)
namespace hiro {
auto pListViewCell::construct() -> void {
}
auto pListViewCell::destruct() -> void {
}
auto pListViewCell::setBackgroundColor(Color color) -> void {
}
auto pListViewCell::setForegroundColor(Color color) -> void {
}
auto pListViewCell::setIcon(const image& icon) -> void {
if(auto item = _parent()) {
if(auto view = item->_parent()) {
gtk_list_store_set(view->gtkListStore, &item->gtkIter, 1 + self().offset() * 2, CreatePixbuf(icon), -1);
}
}
}
auto pListViewCell::setText(const string& text) -> void {
if(auto item = _parent()) {
if(auto view = item->_parent()) {
gtk_list_store_set(view->gtkListStore, &item->gtkIter, 1 + self().offset() * 2 + 1, text.data(), -1);
}
}
}
auto pListViewCell::_parent() -> pListViewItem* {
if(auto parent = self().parentListViewItem()) return parent->self();
return nullptr;
}
}
#endif

View File

@ -0,0 +1,18 @@
#if defined(Hiro_ListView)
namespace hiro {
struct pListViewCell : pObject {
Declare(ListViewCell, Object)
auto setBackgroundColor(Color color) -> void;
auto setForegroundColor(Color color) -> void;
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
auto _parent() -> pListViewItem*;
};
}
#endif

View File

@ -63,6 +63,12 @@ auto pListViewColumn::setEditable(bool editable) -> void {
g_object_set(G_OBJECT(gtkCellText), "editable", editable ? TRUE : FALSE, nullptr); g_object_set(G_OBJECT(gtkCellText), "editable", editable ? TRUE : FALSE, nullptr);
} }
auto pListViewColumn::setExpandable(bool expandable) -> void {
if(auto parent = _parent()) {
parent->resizeColumns();
}
}
auto pListViewColumn::setFont(const string& font) -> void { auto pListViewColumn::setFont(const string& font) -> void {
pFont::setFont(gtkHeaderText, font); pFont::setFont(gtkHeaderText, font);
auto fontDescription = pFont::create(font); auto fontDescription = pFont::create(font);
@ -95,10 +101,6 @@ auto pListViewColumn::setResizable(bool resizable) -> void {
gtk_tree_view_column_set_resizable(gtkColumn, resizable); gtk_tree_view_column_set_resizable(gtkColumn, resizable);
} }
auto pListViewColumn::setSortable(bool sortable) -> void {
gtk_tree_view_column_set_clickable(gtkColumn, sortable);
}
auto pListViewColumn::setText(const string& text) -> void { auto pListViewColumn::setText(const string& text) -> void {
gtk_label_set_text(GTK_LABEL(gtkHeaderText), text); gtk_label_set_text(GTK_LABEL(gtkHeaderText), text);
} }

View File

@ -8,12 +8,12 @@ struct pListViewColumn : pObject {
auto setActive() -> void; auto setActive() -> void;
auto setBackgroundColor(Color color) -> void; auto setBackgroundColor(Color color) -> void;
auto setEditable(bool editable) -> void; auto setEditable(bool editable) -> void;
auto setExpandable(bool expandable) -> void;
auto setFont(const string& font) -> void override; auto setFont(const string& font) -> void override;
auto setForegroundColor(Color color) -> void; auto setForegroundColor(Color color) -> void;
auto setHorizontalAlignment(double alignment) -> void; auto setHorizontalAlignment(double alignment) -> void;
auto setIcon(const image& icon) -> void; auto setIcon(const image& icon) -> void;
auto setResizable(bool resizable) -> void; auto setResizable(bool resizable) -> void;
auto setSortable(bool sortable) -> void;
auto setText(const string& text) -> void; auto setText(const string& text) -> void;
auto setVerticalAlignment(double alignment) -> void; auto setVerticalAlignment(double alignment) -> void;
auto setVisible(bool visible) -> void override; auto setVisible(bool visible) -> void override;

View File

@ -8,6 +8,15 @@ auto pListViewItem::construct() -> void {
auto pListViewItem::destruct() -> void { auto pListViewItem::destruct() -> void {
} }
auto pListViewItem::append(sListViewCell cell) -> void {
}
auto pListViewItem::remove(sListViewCell cell) -> void {
}
auto pListViewItem::setBackgroundColor(Color color) -> void {
}
auto pListViewItem::setChecked(bool checked) -> void { auto pListViewItem::setChecked(bool checked) -> void {
if(auto parent = _parent()) { if(auto parent = _parent()) {
gtk_list_store_set(parent->gtkListStore, &gtkIter, 0, checked, -1); gtk_list_store_set(parent->gtkListStore, &gtkIter, 0, checked, -1);
@ -23,15 +32,7 @@ auto pListViewItem::setFocused() -> void {
} }
} }
auto pListViewItem::setIcon(unsigned column, const image& icon) -> void { auto pListViewItem::setForegroundColor(Color color) -> void {
if(auto parent = _parent()) {
if(icon) {
auto pixbuf = CreatePixbuf(icon, true);
gtk_list_store_set(parent->gtkListStore, &gtkIter, 1 + column * 2, pixbuf, -1);
} else {
gtk_list_store_set(parent->gtkListStore, &gtkIter, 1 + column * 2, nullptr, -1);
}
}
} }
auto pListViewItem::setSelected(bool selected) -> void { auto pListViewItem::setSelected(bool selected) -> void {
@ -47,12 +48,6 @@ auto pListViewItem::setSelected(bool selected) -> void {
} }
} }
auto pListViewItem::setText(unsigned column, const string& text) -> void {
if(auto parent = _parent()) {
gtk_list_store_set(parent->gtkListStore, &gtkIter, 1 + column * 2 + 1, text.data(), -1);
}
}
auto pListViewItem::_parent() -> pListView* { auto pListViewItem::_parent() -> pListView* {
if(auto parent = self().parentListView()) return parent->self(); if(auto parent = self().parentListView()) return parent->self();
return nullptr; return nullptr;

View File

@ -5,11 +5,13 @@ namespace hiro {
struct pListViewItem : pObject { struct pListViewItem : pObject {
Declare(ListViewItem, Object) Declare(ListViewItem, Object)
auto append(sListViewCell cell) -> void;
auto remove(sListViewCell cell) -> void;
auto setBackgroundColor(Color color) -> void;
auto setChecked(bool checked) -> void; auto setChecked(bool checked) -> void;
auto setFocused() -> void; auto setFocused() -> void;
auto setIcon(unsigned column, const image& icon) -> void; auto setForegroundColor(Color color) -> void;
auto setSelected(bool selected) -> void; auto setSelected(bool selected) -> void;
auto setText(unsigned column, const string& text) -> void;
auto _parent() -> pListView*; auto _parent() -> pListView*;

View File

@ -26,12 +26,13 @@ auto pListView::construct() -> void {
gtk_widget_show(gtkWidgetChild); gtk_widget_show(gtkWidgetChild);
setBackgroundColor(state().backgroundColor); setBackgroundColor(state().backgroundColor);
setBatchable(state().batchable);
setCheckable(state().checkable); setCheckable(state().checkable);
setFont(self().font(true)); setFont(self().font(true));
setForegroundColor(state().foregroundColor); setForegroundColor(state().foregroundColor);
setGridVisible(state().gridVisible); setGridVisible(state().gridVisible);
setHeaderVisible(state().headerVisible); setHeaderVisible(state().headerVisible);
setMultiSelect(state().multiSelect); setSortable(state().sortable);
g_signal_connect(G_OBJECT(gtkTreeView), "button-press-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this); g_signal_connect(G_OBJECT(gtkTreeView), "button-press-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeView), "button-release-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this); g_signal_connect(G_OBJECT(gtkTreeView), "button-release-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this);
@ -56,9 +57,12 @@ auto pListView::append(sListViewColumn column) -> void {
column->setFont(column->font()); column->setFont(column->font());
column->setForegroundColor(column->foregroundColor()); column->setForegroundColor(column->foregroundColor());
column->setHorizontalAlignment(column->horizontalAlignment()); column->setHorizontalAlignment(column->horizontalAlignment());
column->setResizable(column->resizable());
column->setVerticalAlignment(column->verticalAlignment()); column->setVerticalAlignment(column->verticalAlignment());
setCheckable(state().checkable); setCheckable(state().checkable);
setSortable(state().sortable);
_createModel(); _createModel();
resizeColumns();
gtk_tree_view_set_rules_hint(gtkTreeView, self().columns() >= 2); //two or more columns + checkbutton column gtk_tree_view_set_rules_hint(gtkTreeView, self().columns() >= 2); //two or more columns + checkbutton column
} }
@ -68,8 +72,18 @@ auto pListView::append(sListViewItem item) -> void {
item->setChecked(item->checked()); item->setChecked(item->checked());
item->setSelected(item->selected()); item->setSelected(item->selected());
for(auto column : range(self().columns())) { for(auto column : range(self().columns())) {
item->setIcon(column, item->state.icon(column, {})); if(auto cell = item->cell(column)) {
item->setText(column, item->state.text(column, "")); if(auto self = cell->self()) {
self->setIcon(cell->state.icon);
self->setText(cell->state.text);
}
}
}
}
auto pListView::checkAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setChecked(true);
} }
} }
@ -106,83 +120,61 @@ auto pListView::reset() -> void {
gtk_tree_view_set_rules_hint(gtkTreeView, false); gtk_tree_view_set_rules_hint(gtkTreeView, false);
} }
//column widths:
//< 0 = expanding (consume all remaining space)
// 0 = auto (resize to contents
//> 0 = fixed width
auto pListView::resizeColumns() -> void { auto pListView::resizeColumns() -> void {
lock(); lock();
//compute the minimum width required for each column based upon the contents of all rows vector<signed> widths;
vector<signed> minimumWidths; signed minimumWidth = 0;
for(auto column : range(self().columns())) { signed expandable = 0;
signed maximumWidth = 1; for(auto column : range(state().columns)) {
if(self().headerVisible()) { signed width = _width(column);
maximumWidth = max(maximumWidth, 8 //margin widths.append(width);
+ state().columns[column]->state.icon.width minimumWidth += width;
+ Font::size(state().columns[column]->font(true), state().columns[column]->state.text).width() if(state().columns[column]->expandable()) expandable++;
); }
signed maximumWidth = self().geometry().width() - 6;
if(auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow)) {
if(gtk_widget_get_visible(scrollBar)) maximumWidth -= scrollBar->allocation.width;
}
signed expandWidth = 0;
if(expandable && maximumWidth > minimumWidth) {
expandWidth = (maximumWidth - minimumWidth) / expandable;
}
for(auto column : range(state().columns)) {
if(auto self = state().columns[column]->self()) {
signed width = widths[column];
if(self->state().expandable) width += expandWidth;
gtk_tree_view_column_set_fixed_width(self->gtkColumn, width);
} }
for(auto row : range(self().items())) {
maximumWidth = max(maximumWidth, 8 //margin
+ (row == 0 && state().checkable ? 32 : 0) //check box
+ state().items[row]->state.icon(column, {}).width
+ Font::size(state().columns[column]->font(true), state().items[row]->state.text(column, "")).width()
);
}
if(!state().columns[column]->visible()) maximumWidth = 1;
minimumWidths.append(maximumWidth);
}
//subtract the widths of all non-expanding columns from the available widget space
signed expansions = 0; //count the number of expanded columns
signed emptyWidth = pSizable::state().geometry.width() - 5; //margin
for(auto column : range(self().columns())) {
signed width = state().columns[column]->width();
if(!state().columns[column]->visible()) width = 1;
if(width < 0) { expansions++; continue; }
if(width == 0) width = minimumWidths[column];
emptyWidth -= width;
}
//the vertical scroll bar consumes header space when visible; subtract it from available space if needed
auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow);
if(scrollBar && gtk_widget_get_visible(scrollBar)) {
emptyWidth -= scrollBar->allocation.width;
}
//divide remaining space among all expanded columns
if(expansions && emptyWidth >= expansions) emptyWidth /= expansions;
else emptyWidth = 1;
for(auto column : range(self().columns())) {
signed width = state().columns[column]->width();
if(!state().columns[column]->visible()) width = 1;
if(width < 0) width = emptyWidth;
if(width == 0) width = minimumWidths[column];
gtk_tree_view_column_set_fixed_width(_column(column)->gtkColumn, width);
} }
unlock(); unlock();
} }
auto pListView::selectAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setSelected(true);
}
}
auto pListView::setBackgroundColor(Color color) -> void { auto pListView::setBackgroundColor(Color color) -> void {
GdkColor gdkColor = CreateColor(color); GdkColor gdkColor = CreateColor(color);
gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr); gtk_widget_modify_base(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
} }
auto pListView::setBatchable(bool batchable) -> void {
gtk_tree_selection_set_mode(gtkTreeSelection, batchable ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
}
auto pListView::setCheckable(bool checkable) -> void { auto pListView::setCheckable(bool checkable) -> void {
if(auto delegate = _column(0)) { if(auto delegate = _column(0)) {
gtk_cell_renderer_set_visible(delegate->gtkCellToggle, checkable); gtk_cell_renderer_set_visible(delegate->gtkCellToggle, checkable);
} }
} }
auto pListView::setChecked(bool checked) -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setChecked(checked);
}
}
auto pListView::setFocused() -> void { auto pListView::setFocused() -> void {
gtk_widget_grab_focus(gtkWidgetChild); gtk_widget_grab_focus(gtkWidgetChild);
} }
@ -206,21 +198,60 @@ auto pListView::setHeaderVisible(bool visible) -> void {
gtk_tree_view_set_headers_visible(gtkTreeView, visible); gtk_tree_view_set_headers_visible(gtkTreeView, visible);
} }
auto pListView::setMultiSelect(bool multiSelect) -> void { auto pListView::setSortable(bool sortable) -> void {
gtk_tree_selection_set_mode(gtkTreeSelection, multiSelect ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); for(auto& column : state().columns) {
if(auto delegate = column->self()) {
gtk_tree_view_column_set_clickable(delegate->gtkColumn, sortable);
}
}
} }
auto pListView::setSelected(bool selected) -> void { auto pListView::uncheckAll() -> void {
for(auto& item : state().items) { for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setSelected(selected); if(auto delegate = item->self()) delegate->setChecked(false);
} }
} }
auto pListView::unselectAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setSelected(false);
}
}
auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned {
unsigned width = 8; //margin
if(state().checkable && _column == 0) width += 32; //checkbox
if(auto item = self().item(_row)) {
if(auto cell = item->cell(_column)) {
if(auto& icon = cell->state.icon) {
width += icon.width + 2;
}
if(auto& text = cell->state.text) {
width += Font::size(cell->font(true), text).width();
}
}
}
return width;
}
auto pListView::_column(unsigned column) -> pListViewColumn* { auto pListView::_column(unsigned column) -> pListViewColumn* {
if(auto delegate = self().column(column)) return delegate->self(); if(auto delegate = self().column(column)) return delegate->self();
return nullptr; return nullptr;
} }
auto pListView::_columnWidth(unsigned _column) -> unsigned {
unsigned width = 8; //margin
if(auto column = self().column(_column)) {
if(auto& icon = column->state.icon) {
width += icon.width + 2;
}
if(auto& text = column->state.text) {
width += Font::size(column->font(true), text).width();
}
}
return width;
}
auto pListView::_createModel() -> void { auto pListView::_createModel() -> void {
gtk_tree_view_set_model(gtkTreeView, nullptr); gtk_tree_view_set_model(gtkTreeView, nullptr);
gtkListStore = nullptr; gtkListStore = nullptr;
@ -256,13 +287,16 @@ auto pListView::_doContext() -> void {
auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void { auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void {
for(auto& column : state().columns) { for(auto& column : state().columns) {
if(auto delegate = column->self()) { if(auto delegate = column->self()) {
if(gtkCellRendererText = GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) { if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
if(auto item = self().item(decimal(path))) { auto row = decimal(path);
if(string{text} != item->text(column->offset())) { if(auto item = self().item(row)) {
item->setText(column->offset(), text); if(auto cell = item->cell(column->offset())) {
if(!locked()) self().doEdit(item, column); if(string{text} != cell->state.text) {
cell->setText(text);
if(!locked()) self().doEdit(cell);
}
return;
} }
return;
} }
} }
} }
@ -277,7 +311,7 @@ auto pListView::_doEvent(GdkEventButton* event) -> signed {
//when clicking in empty space below the last list view item; GTK+ does not deselect all items; //when clicking in empty space below the last list view item; GTK+ does not deselect all items;
//below code enables this functionality, to match behavior with all other UI toolkits (and because it's very convenient to have) //below code enables this functionality, to match behavior with all other UI toolkits (and because it's very convenient to have)
if(path == nullptr && gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) { if(path == nullptr && gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) {
self().setSelected({}); self().unselectAll();
self().doChange(); self().doChange();
return true; return true;
} }
@ -373,6 +407,19 @@ auto pListView::_updateSelected() -> void {
if(!locked()) self().doChange(); if(!locked()) self().doChange();
} }
auto pListView::_width(unsigned column) -> unsigned {
if(auto width = state().columns[column]->width()) return width;
unsigned width = 1;
if(!state().columns[column]->visible()) return width;
if(state().headerVisible) {
width = max(width, _columnWidth(column));
}
for(auto row : range(state().items)) {
width = max(width, _cellWidth(row, column));
}
return width;
}
} }
#endif #endif

View File

@ -7,23 +7,28 @@ struct pListView : pWidget {
auto append(sListViewColumn column) -> void; auto append(sListViewColumn column) -> void;
auto append(sListViewItem item) -> void; auto append(sListViewItem item) -> void;
auto checkAll() -> void;
auto focused() -> bool; auto focused() -> bool;
auto remove(sListViewColumn column) -> void; auto remove(sListViewColumn column) -> void;
auto remove(sListViewItem item) -> void; auto remove(sListViewItem item) -> void;
auto reset() -> void; auto reset() -> void;
auto resizeColumns() -> void; auto resizeColumns() -> void;
auto selectAll() -> void;
auto setBackgroundColor(Color color) -> void; auto setBackgroundColor(Color color) -> void;
auto setBatchable(bool batchable) -> void;
auto setCheckable(bool checkable) -> void; auto setCheckable(bool checkable) -> void;
auto setChecked(bool checked) -> void;
auto setFocused() -> void override; auto setFocused() -> void override;
auto setFont(const string& font) -> void override; auto setFont(const string& font) -> void override;
auto setForegroundColor(Color color) -> void; auto setForegroundColor(Color color) -> void;
auto setGridVisible(bool visible) -> void; auto setGridVisible(bool visible) -> void;
auto setHeaderVisible(bool visible) -> void; auto setHeaderVisible(bool visible) -> void;
auto setMultiSelect(bool multiSelect) -> void; auto setSortable(bool sortable) -> void;
auto setSelected(bool selected) -> void; auto uncheckAll() -> void;
auto unselectAll() -> void;
auto _cellWidth(unsigned row, unsigned column) -> unsigned;
auto _column(unsigned column) -> pListViewColumn*; auto _column(unsigned column) -> pListViewColumn*;
auto _columnWidth(unsigned column) -> unsigned;
auto _createModel() -> void; auto _createModel() -> void;
auto _doActivate() -> void; auto _doActivate() -> void;
auto _doChange() -> void; auto _doChange() -> void;
@ -34,6 +39,7 @@ struct pListView : pWidget {
auto _doMouseMove() -> signed; auto _doMouseMove() -> signed;
auto _doToggle(const char* path) -> void; auto _doToggle(const char* path) -> void;
auto _updateSelected() -> void; auto _updateSelected() -> void;
auto _width(unsigned column) -> unsigned;
GtkScrolledWindow* gtkScrolledWindow = nullptr; GtkScrolledWindow* gtkScrolledWindow = nullptr;
GtkWidget* gtkWidgetChild = nullptr; GtkWidget* gtkWidgetChild = nullptr;

View File

@ -3,7 +3,7 @@
namespace hiro { namespace hiro {
static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void { static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void {
if(p->_parent().locked()) return; if(p->groupLocked()) return;
bool wasChecked = p->state().checked; bool wasChecked = p->state().checked;
p->setChecked(); p->setChecked();
if(!wasChecked) p->self().doActivate(); if(!wasChecked) p->self().doActivate();
@ -12,7 +12,6 @@ static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void {
auto pRadioButton::construct() -> void { auto pRadioButton::construct() -> void {
gtkWidget = gtk_toggle_button_new(); gtkWidget = gtk_toggle_button_new();
setGroup(state().group);
setBordered(state().bordered); setBordered(state().bordered);
setIcon(state().icon); setIcon(state().icon);
setOrientation(state().orientation); setOrientation(state().orientation);
@ -48,26 +47,34 @@ auto pRadioButton::setBordered(bool bordered) -> void {
} }
auto pRadioButton::setChecked() -> void { auto pRadioButton::setChecked() -> void {
_parent().lock(); if(!self().group()) return;
for(auto& weak : state().group) { for(auto& weak : self().group()->state.objects) {
if(auto item = weak.acquire()) { if(auto object = weak.acquire()) {
if(item->self()) { if(auto radioButton = dynamic_cast<mRadioButton*>(object.data())) {
bool checked = item->self() == this; if(auto self = radioButton->self()) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), item->state.checked = checked); self->lock();
bool checked = self == this;
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked = checked);
self->unlock();
}
} }
} }
} }
_parent().unlock();
} }
auto pRadioButton::setGroup(const vector<wRadioButton>& group) -> void { auto pRadioButton::setGroup(sGroup group) -> void {
_parent().lock(); if(!group) return;
for(auto& weak : state().group) { for(auto& weak : group->state.objects) {
if(auto item = weak.acquire()) { if(auto object = weak.acquire()) {
if(item->self()) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), item->checked()); if(auto radioButton = dynamic_cast<mRadioButton*>(object.data())) {
if(auto self = radioButton->self()) {
self->lock();
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->checked());
self->unlock();
}
}
} }
} }
_parent().unlock();
} }
auto pRadioButton::setIcon(const image& icon) -> void { auto pRadioButton::setIcon(const image& icon) -> void {
@ -91,13 +98,18 @@ auto pRadioButton::setText(const string& text) -> void {
setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font
} }
auto pRadioButton::_parent() -> pRadioButton& { auto pRadioButton::groupLocked() const -> bool {
if(state().group.size()) { if(auto group = state().group) {
if(auto item = state().group.first().acquire()) { for(auto& weak : group->state.objects) {
if(item->self()) return *item->self(); if(auto object = weak.acquire()) {
if(auto self = object->self()) {
if(self->locked()) return true;
}
}
} }
return false;
} }
return *this; return locked();
} }
} }

View File

@ -8,12 +8,12 @@ struct pRadioButton : pWidget {
auto minimumSize() const -> Size; auto minimumSize() const -> Size;
auto setBordered(bool bordered) -> void; auto setBordered(bool bordered) -> void;
auto setChecked() -> void; auto setChecked() -> void;
auto setGroup(const vector<wRadioButton>& group) -> void; auto setGroup(sGroup group) -> void;
auto setIcon(const image& icon) -> void; auto setIcon(const image& icon) -> void;
auto setOrientation(Orientation orientation) -> void; auto setOrientation(Orientation orientation) -> void;
auto setText(const string& text) -> void; auto setText(const string& text) -> void;
auto _parent() -> pRadioButton&; auto groupLocked() const -> bool;
}; };
} }

View File

@ -3,7 +3,7 @@
namespace hiro { namespace hiro {
static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void { static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void {
if(p->_parent().locked()) return; if(p->groupLocked()) return;
bool wasChecked = p->state().checked; bool wasChecked = p->state().checked;
p->setChecked(); p->setChecked();
if(!wasChecked) p->self().doActivate(); if(!wasChecked) p->self().doActivate();
@ -11,8 +11,9 @@ static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void {
auto pRadioLabel::construct() -> void { auto pRadioLabel::construct() -> void {
gtkWidget = gtk_radio_button_new_with_label(nullptr, ""); gtkWidget = gtk_radio_button_new_with_label(nullptr, "");
gtkToggleButton = GTK_TOGGLE_BUTTON(gtkWidget);
gtkRadioButton = GTK_RADIO_BUTTON(gtkWidget);
setGroup(state().group);
setText(state().text); setText(state().text);
g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioLabel_activate), (gpointer)this); g_signal_connect(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioLabel_activate), (gpointer)this);
@ -30,30 +31,29 @@ auto pRadioLabel::minimumSize() const -> Size {
} }
auto pRadioLabel::setChecked() -> void { auto pRadioLabel::setChecked() -> void {
_parent().lock(); lock();
for(auto& weak : state().group) { gtk_toggle_button_set_active(gtkToggleButton, true);
if(auto item = weak.acquire()) item->state.checked = false; unlock();
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), state().checked = true);
_parent().unlock();
} }
auto pRadioLabel::setGroup(const vector<shared_pointer_weak<mRadioLabel>>& group) -> void { auto pRadioLabel::setGroup(sGroup group) -> void {
if(&_parent() == this) return; if(!group) return;
_parent().lock();
gtk_radio_button_set_group( maybe<GtkRadioButton*> gtkRadioButton;
GTK_RADIO_BUTTON(gtkWidget), for(auto& weak : group->state.objects) {
gtk_radio_button_get_group(GTK_RADIO_BUTTON(_parent().gtkWidget)) if(auto object = weak.acquire()) {
); if(auto radioLabel = dynamic_cast<mRadioLabel*>(object.data())) {
for(auto& weak : state().group) { if(auto self = radioLabel->self()) {
if(auto item = weak.acquire()) { self->lock();
if(item->self() && item->checked()) { gtk_radio_button_set_group(self->gtkRadioButton, nullptr);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), true); if(!gtkRadioButton) gtkRadioButton = self->gtkRadioButton;
break; else gtk_radio_button_set_group(self->gtkRadioButton, gtk_radio_button_get_group(*gtkRadioButton));
gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->checked());
self->unlock();
}
} }
} }
} }
_parent().unlock();
} }
auto pRadioLabel::setText(const string& text) -> void { auto pRadioLabel::setText(const string& text) -> void {
@ -61,13 +61,18 @@ auto pRadioLabel::setText(const string& text) -> void {
setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font setFont(self().font(true)); //gtk_button_set_label() recreates label, which destroys currently assigned font
} }
auto pRadioLabel::_parent() -> pRadioLabel& { auto pRadioLabel::groupLocked() const -> bool {
if(state().group.size()) { if(auto group = state().group) {
if(auto item = state().group.first().acquire()) { for(auto& weak : group->state.objects) {
if(item->self()) return *item->self(); if(auto object = weak.acquire()) {
if(auto self = object->self()) {
if(self->locked()) return true;
}
}
} }
return false;
} }
return *this; return locked();
} }
} }

View File

@ -7,10 +7,13 @@ struct pRadioLabel : pWidget {
auto minimumSize() const -> Size; auto minimumSize() const -> Size;
auto setChecked() -> void; auto setChecked() -> void;
auto setGroup(const vector<shared_pointer_weak<mRadioLabel>>& group) -> void; auto setGroup(sGroup group) -> void;
auto setText(const string& text) -> void; auto setText(const string& text) -> void;
auto _parent() -> pRadioLabel&; auto groupLocked() const -> bool;
GtkToggleButton* gtkToggleButton = nullptr;
GtkRadioButton* gtkRadioButton = nullptr;
}; };
} }

View File

@ -10,6 +10,12 @@ auto pTabFrameItem::destruct() -> void {
if(auto layout = state().layout) layout->destruct(); if(auto layout = state().layout) layout->destruct();
} }
auto pTabFrameItem::append(sLayout layout) -> void {
}
auto pTabFrameItem::remove(sLayout layout) -> void {
}
auto pTabFrameItem::setClosable(bool closable) -> void { auto pTabFrameItem::setClosable(bool closable) -> void {
if(auto parent = _parent()) { if(auto parent = _parent()) {
parent->setItemClosable(self().offset(), closable); parent->setItemClosable(self().offset(), closable);

View File

@ -5,6 +5,8 @@ namespace hiro {
struct pTabFrameItem : pObject { struct pTabFrameItem : pObject {
Declare(TabFrameItem, Object) Declare(TabFrameItem, Object)
auto append(sLayout layout) -> void;
auto remove(sLayout layout) -> void;
auto setClosable(bool closable) -> void; auto setClosable(bool closable) -> void;
auto setIcon(const image& icon) -> void; auto setIcon(const image& icon) -> void;
auto setMovable(bool movable) -> void; auto setMovable(bool movable) -> void;

View File

@ -3,7 +3,9 @@
namespace hiro { namespace hiro {
static auto TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned position, pTabFrame* p) -> void { static auto TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned position, pTabFrame* p) -> void {
p->state().selected = position; for(auto& item : p->state().items) item->state.selected = false;
if(auto item = p->self().item(position)) item->state.selected = true;
p->_synchronizeLayout(); p->_synchronizeLayout();
if(!p->locked()) p->self().doChange(); if(!p->locked()) p->self().doChange();
} }
@ -22,7 +24,10 @@ static auto TabFrame_close(GtkButton* button, pTabFrame* p) -> void {
} }
static auto TabFrame_move(GtkNotebook* notebook, GtkWidget* page, unsigned moveTo, pTabFrame* p) -> void { static auto TabFrame_move(GtkNotebook* notebook, GtkWidget* page, unsigned moveTo, pTabFrame* p) -> void {
p->state().selected = gtk_notebook_get_current_page(notebook); unsigned position = gtk_notebook_get_current_page(notebook);
for(auto& item : p->state().items) item->state.selected = false;
if(auto item = p->self().item(position)) item->state.selected = true;
maybe<unsigned> moveFrom; maybe<unsigned> moveFrom;
for(auto n : range(p->tabs)) { for(auto n : range(p->tabs)) {
if(page == p->tabs[n].child) { if(page == p->tabs[n].child) {
@ -45,7 +50,6 @@ auto pTabFrame::construct() -> void {
tabs.reset(); //todo: memory leak, need to release each tab tabs.reset(); //todo: memory leak, need to release each tab
for(auto& item : state().items) append(item); for(auto& item : state().items) append(item);
setEdge(state().edge); setEdge(state().edge);
setItemSelected(state().selected);
g_signal_connect(G_OBJECT(gtkWidget), "page-reordered", G_CALLBACK(TabFrame_move), (gpointer)this); 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); g_signal_connect(G_OBJECT(gtkWidget), "switch-page", G_CALLBACK(TabFrame_change), (gpointer)this);
@ -87,6 +91,7 @@ auto pTabFrame::append(sTabFrameItem item) -> void {
setFont(self().font(true)); setFont(self().font(true));
setItemMovable(item->offset(), item->movable()); setItemMovable(item->offset(), item->movable());
if(item->selected()) setItemSelected(item->offset());
_synchronizeTab(tabs.size() - 1); _synchronizeTab(tabs.size() - 1);
setGeometry(self().geometry()); setGeometry(self().geometry());
unlock(); unlock();
@ -128,7 +133,10 @@ auto pTabFrame::remove(sTabFrameItem item) -> void {
} }
tabs.remove(item->offset()); tabs.remove(item->offset());
gtk_notebook_remove_page(GTK_NOTEBOOK(gtkWidget), item->offset()); gtk_notebook_remove_page(GTK_NOTEBOOK(gtkWidget), item->offset());
state().selected = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkWidget));
unsigned position = gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkWidget));
for(auto& item : state().items) item->state.selected = false;
if(auto item = self().item(position)) item->state.selected = true;
unlock(); unlock();
} }
@ -218,14 +226,12 @@ auto pTabFrame::setVisible(bool visible) -> void {
} }
auto pTabFrame::_synchronizeLayout() -> void { auto pTabFrame::_synchronizeLayout() -> void {
unsigned position = 0;
for(auto& item : state().items) { for(auto& item : state().items) {
if(auto layout = item->state.layout) { if(auto layout = item->state.layout) {
if(layout->self()) { if(auto self = layout->self()) {
layout->self()->setVisible(layout->visible(true) && position == state().selected); self->setVisible(layout->visible(true) && item->selected());
} }
} }
position++;
} }
} }

View File

@ -184,13 +184,16 @@ auto pWindow::construct() -> void {
auto pWindow::destruct() -> void { auto pWindow::destruct() -> void {
} }
auto pWindow::append(shared_pointer<mMenuBar> menuBar) -> void { auto pWindow::append(sLayout layout) -> void {
}
auto pWindow::append(sMenuBar menuBar) -> void {
_setMenuEnabled(menuBar->enabled(true)); _setMenuEnabled(menuBar->enabled(true));
_setMenuFont(menuBar->font(true)); _setMenuFont(menuBar->font(true));
_setMenuVisible(menuBar->visible(true)); _setMenuVisible(menuBar->visible(true));
} }
auto pWindow::append(shared_pointer<mStatusBar> statusBar) -> void { auto pWindow::append(sStatusBar statusBar) -> void {
_setStatusEnabled(statusBar->enabled(true)); _setStatusEnabled(statusBar->enabled(true));
_setStatusFont(statusBar->font(true)); _setStatusFont(statusBar->font(true));
_setStatusText(statusBar->text()); _setStatusText(statusBar->text());
@ -215,11 +218,14 @@ auto pWindow::frameMargin() const -> Geometry {
}; };
} }
auto pWindow::remove(shared_pointer<mMenuBar> menuBar) -> void { auto pWindow::remove(sLayout layout) -> void {
}
auto pWindow::remove(sMenuBar menuBar) -> void {
_setMenuVisible(false); _setMenuVisible(false);
} }
auto pWindow::remove(shared_pointer<mStatusBar> statusBar) -> void { auto pWindow::remove(sStatusBar statusBar) -> void {
_setStatusVisible(false); _setStatusVisible(false);
} }

View File

@ -14,12 +14,14 @@ struct pWindow : pObject {
GtkAllocation lastAllocation = {0}; GtkAllocation lastAllocation = {0};
bool onSizePending = false; bool onSizePending = false;
auto append(shared_pointer<mMenuBar> menuBar) -> void; auto append(sLayout layout) -> void;
auto append(shared_pointer<mStatusBar> statusBar) -> void; auto append(sMenuBar menuBar) -> void;
auto append(sStatusBar statusBar) -> void;
auto focused() const -> bool override; auto focused() const -> bool override;
auto frameMargin() const -> Geometry; auto frameMargin() const -> Geometry;
auto remove(shared_pointer<mMenuBar> menuBar) -> void; auto remove(sLayout layout) -> void;
auto remove(shared_pointer<mStatusBar> statusBar) -> void; auto remove(sMenuBar menuBar) -> void;
auto remove(sStatusBar statusBar) -> void;
auto setBackgroundColor(Color color) -> void; auto setBackgroundColor(Color color) -> void;
auto setDroppable(bool droppable) -> void; auto setDroppable(bool droppable) -> void;
auto setEnabled(bool enabled) -> void override; auto setEnabled(bool enabled) -> void override;

View File

@ -1,16 +1,46 @@
namespace phoenix { #if defined(Hiro_Action)
void pAction::setEnabled(bool enabled) { namespace hiro {
if(parentWindow) parentWindow->p.updateMenu();
auto pAction::construct() -> void {
} }
void pAction::setVisible(bool visible) { auto pAction::destruct() -> void {
if(parentWindow) parentWindow->p.updateMenu();
} }
void pAction::constructor() { auto pAction::setEnabled(bool enabled) -> void {
parentMenu = 0; _synchronize();
parentWindow = 0; }
auto pAction::setVisible(bool visible) -> void {
_synchronize();
}
auto pAction::_parentMenu() -> maybe<pMenu&> {
if(auto parent = self().parentMenu()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pAction::_parentMenuBar() -> maybe<pMenuBar&> {
if(auto parent = self().parentMenuBar(true)) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pAction::_parentPopupMenu() -> maybe<pPopupMenu&> {
if(auto parent = self().parentPopupMenu(true)) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pAction::_synchronize() -> void {
if(auto parent = _parentMenuBar()) parent->_update();
} }
} }
#endif

View File

@ -0,0 +1,21 @@
#if defined(Hiro_Action)
namespace hiro {
struct pAction : pObject {
Declare(Action, Object)
auto setEnabled(bool enabled) -> void;
auto setVisible(bool visible) -> void;
auto _parentMenu() -> maybe<pMenu&>;
auto _parentMenuBar() -> maybe<pMenuBar&>;
auto _parentPopupMenu() -> maybe<pPopupMenu&>;
auto _synchronize() -> void;
unsigned position = 0;
};
}
#endif

View File

@ -1,24 +0,0 @@
namespace phoenix {
void pCheckItem::setChecked(bool checked) {
if(parentMenu) CheckMenuItem(parentMenu->p.hmenu, id, checked ? MF_CHECKED : MF_UNCHECKED);
}
void pCheckItem::setText(string text) {
if(parentWindow) parentWindow->p.updateMenu();
}
void pCheckItem::constructor() {
}
void pCheckItem::destructor() {
if(parentMenu) parentMenu->remove(checkItem);
}
void pCheckItem::onToggle() {
checkItem.state.checked = !checkItem.state.checked;
setChecked(checkItem.state.checked);
if(checkItem.onToggle) checkItem.onToggle();
}
}

View File

@ -1,37 +0,0 @@
namespace phoenix {
void pItem::setImage(const image& image) {
createBitmap();
if(parentWindow) parentWindow->p.updateMenu();
}
void pItem::setText(string text) {
if(parentWindow) parentWindow->p.updateMenu();
}
void pItem::constructor() {
createBitmap();
}
void pItem::destructor() {
if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; }
if(parentMenu) parentMenu->remove(item);
}
void pItem::createBitmap() {
if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; }
if(item.state.image.width && item.state.image.height) {
nall::image nallImage = item.state.image;
nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
nallImage.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline)
nallImage.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear);
hbitmap = CreateBitmap(nallImage);
}
}
void pItem::onActivate() {
if(item.onActivate) item.onActivate();
}
}

View File

@ -0,0 +1,29 @@
#if defined(Hiro_MenuCheckItem)
namespace hiro {
auto pMenuCheckItem::construct() -> void {
}
auto pMenuCheckItem::destruct() -> void {
}
auto pMenuCheckItem::setChecked(bool checked) -> void {
if(auto menu = _parentMenu()) {
CheckMenuItem(menu->hmenu, position, MF_BYPOSITION | (checked ? MF_CHECKED : MF_UNCHECKED));
}
}
auto pMenuCheckItem::setText(const string& text) -> void {
_synchronize();
}
auto pMenuCheckItem::onToggle() -> void {
state().checked = !state().checked;
setChecked(state().checked);
self().doToggle();
}
}
#endif

View File

@ -0,0 +1,16 @@
#if defined(Hiro_MenuCheckItem)
namespace hiro {
struct pMenuCheckItem : pAction {
Declare(MenuCheckItem, Action)
auto setChecked(bool checked) -> void;
auto setText(const string& text) -> void;
auto onToggle() -> void;
};
}
#endif

View File

@ -0,0 +1,39 @@
#if defined(Hiro_MenuItem)
namespace hiro {
auto pMenuItem::construct() -> void {
_createBitmap();
}
auto pMenuItem::destruct() -> void {
if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; }
}
auto pMenuItem::setIcon(const image& icon) -> void {
_createBitmap();
_synchronize();
}
auto pMenuItem::setText(const string& text) -> void {
_synchronize();
}
auto pMenuItem::onActivate() -> void {
self().doActivate();
}
auto pMenuItem::_createBitmap() -> void {
if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; }
if(auto icon = state().icon) {
icon.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
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);
}
}
}
#endif

View File

@ -0,0 +1,20 @@
#if defined(Hiro_MenuItem)
namespace hiro {
struct pMenuItem : pAction {
Declare(MenuItem, Action)
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
auto onActivate() -> void;
auto _createBitmap() -> void;
HBITMAP hbitmap = 0;
};
}
#endif

View File

@ -0,0 +1,49 @@
#if defined(Hiro_MenuRadioItem)
namespace hiro {
auto pMenuRadioItem::construct() -> void {
}
auto pMenuRadioItem::destruct() -> void {
}
auto pMenuRadioItem::setChecked() -> void {
if(auto group = self().group()) {
for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto menuRadioItem = dynamic_cast<mMenuRadioItem*>(object.data())) {
if(auto self = menuRadioItem->self()) {
if(auto menu = self->_parentMenu()) {
//CheckMenuRadioItem takes: lo, hi, id; checking only id when lo <= id <= hi
//hiro does not force IDs to be linear, so to uncheck id, we use: lo == hi == id + 1 (out of range)
//to check id, we use: lo == hi == id (only ID, but in range)
CheckMenuRadioItem(
menu->hmenu,
self->position, self->position, self->position + (position != self->position),
MF_BYPOSITION
);
}
}
}
}
}
}
}
auto pMenuRadioItem::setGroup(sGroup group) -> void {
}
auto pMenuRadioItem::setText(const string& text) -> void {
_synchronize();
}
auto pMenuRadioItem::onActivate() -> void {
if(state().checked) return;
self().setChecked();
self().doActivate();
}
}
#endif

View File

@ -0,0 +1,17 @@
#if defined(Hiro_MenuRadioItem)
namespace hiro {
struct pMenuRadioItem : pAction {
Declare(MenuRadioItem, Action)
auto setChecked() -> void;
auto setGroup(sGroup group) -> void override;
auto setText(const string& text) -> void;
auto onActivate() -> void;
};
}
#endif

View File

@ -0,0 +1,13 @@
#if defined(Hiro_MenuSeparator)
namespace hiro {
auto pMenuSeparator::construct() -> void {
}
auto pMenuSeparator::destruct() -> void {
}
}
#endif

View File

@ -0,0 +1,11 @@
#if defined(Hiro_MenuSeparator)
namespace hiro {
struct pMenuSeparator : pAction {
Declare(MenuSeparator, Action)
};
}
#endif

View File

@ -1,113 +1,124 @@
namespace phoenix { #if defined(Hiro_Menu)
void pMenu::append(Action& action) { namespace hiro {
action.p.parentMenu = &menu;
if(parentWindow) parentWindow->p.updateMenu(); auto pMenu::construct() -> void {
_createBitmap();
} }
void pMenu::remove(Action& action) { auto pMenu::destruct() -> void {
if(parentWindow) parentWindow->p.updateMenu(); if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; }
action.p.parentMenu = 0; if(hmenu) { DestroyMenu(hmenu); hmenu = nullptr; }
} }
void pMenu::setImage(const image& image) { auto pMenu::append(sAction action) -> void {
createBitmap(); _synchronize();
if(parentWindow) parentWindow->p.updateMenu();
} }
void pMenu::setText(string text) { auto pMenu::remove(sAction action) -> void {
if(parentWindow) parentWindow->p.updateMenu(); _synchronize();
} }
void pMenu::constructor() { auto pMenu::setIcon(const image& icon) -> void {
hmenu = 0; _createBitmap();
createBitmap(); _synchronize();
} }
void pMenu::destructor() { auto pMenu::setText(const string& text) -> void {
if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } _synchronize();
if(parentMenu) {
parentMenu->remove(menu);
} else if(parentWindow) {
//belongs to window's main menubar
parentWindow->remove(menu);
}
} }
void pMenu::createBitmap() { auto pMenu::_createBitmap() -> void {
if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; }
if(menu.state.image.width && menu.state.image.height) { if(auto icon = state().icon) {
nall::image nallImage = menu.state.image; icon.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); icon.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline)
nallImage.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);
nallImage.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); hbitmap = CreateBitmap(icon);
hbitmap = CreateBitmap(nallImage);
} }
} }
//Windows actions lack the ability to toggle visibility. //Windows actions lack the ability to toggle visibility.
//To support this, menus must be destroyed and recreated when toggling any action's visibility. //To support this, menus must be destroyed and recreated when toggling any action's visibility.
void pMenu::update(Window& parentWindow, Menu* parentMenu) { auto pMenu::_update() -> void {
this->parentMenu = parentMenu;
this->parentWindow = &parentWindow;
if(hmenu) DestroyMenu(hmenu); if(hmenu) DestroyMenu(hmenu);
hmenu = CreatePopupMenu(); hmenu = CreatePopupMenu();
for(auto& action : menu.state.action) { MENUINFO mi{sizeof(MENUINFO)};
action.p.parentMenu = &menu; mi.fMask = MIM_STYLE;
action.p.parentWindow = &parentWindow; mi.dwStyle = MNS_NOTIFYBYPOS; //| MNS_MODELESS;
SetMenuInfo(hmenu, &mi);
unsigned enabled = action.state.enabled ? 0 : MF_GRAYED; unsigned position = 0;
if(dynamic_cast<Menu*>(&action)) {
Menu& item = (Menu&)action;
if(action.state.visible) {
item.p.update(parentWindow, &menu);
AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)item.p.hmenu, utf16_t(item.state.text));
if(item.state.image.width && item.state.image.height) { for(auto& action : state().actions) {
MENUITEMINFO mii = {sizeof(MENUITEMINFO)}; if(!action->self()) continue;
action->self()->position = position;
unsigned enabled = action->enabled() ? 0 : MF_GRAYED;
MENUITEMINFO mii{sizeof(MENUITEMINFO)};
mii.fMask = MIIM_DATA;
mii.dwItemData = (ULONG_PTR)action.data();
if(auto menu = dynamic_cast<mMenu*>(action.data())) {
if(menu->visible()) {
menu->self()->_update();
AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)menu->self()->hmenu, utf16_t(menu->text()));
if(auto bitmap = menu->self()->hbitmap) {
//Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks) //Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks)
//this causes too much spacing, so use a custom checkmark image instead //this causes too much spacing, so use a custom checkmark image instead
mii.fMask = MIIM_CHECKMARKS; mii.fMask |= MIIM_CHECKMARKS;
mii.hbmpUnchecked = item.p.hbitmap; mii.hbmpUnchecked = bitmap;
SetMenuItemInfo(hmenu, (UINT_PTR)item.p.hmenu, FALSE, &mii);
} }
SetMenuItemInfo(hmenu, position++, true, &mii);
} }
} else if(dynamic_cast<Separator*>(&action)) {
Separator& item = (Separator&)action;
if(action.state.visible) {
AppendMenu(hmenu, MF_SEPARATOR | enabled, item.p.id, L"");
}
} else if(dynamic_cast<Item*>(&action)) {
Item& item = (Item&)action;
if(action.state.visible) {
AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text));
if(item.state.image.width && item.state.image.height) {
MENUITEMINFO mii = { sizeof(MENUITEMINFO) };
//Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks)
//this causes too much spacing, so use a custom checkmark image instead
mii.fMask = MIIM_CHECKMARKS;
mii.hbmpUnchecked = item.p.hbitmap;
SetMenuItemInfo(hmenu, item.p.id, FALSE, &mii);
}
}
} else if(dynamic_cast<CheckItem*>(&action)) {
CheckItem& item = (CheckItem&)action;
if(action.state.visible) {
AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text));
}
if(item.state.checked) item.setChecked();
} else if(dynamic_cast<RadioItem*>(&action)) {
RadioItem& item = (RadioItem&)action;
if(action.state.visible) {
AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text));
}
if(item.state.checked) item.setChecked();
} }
#if defined(Hiro_MenuSeparator)
else if(auto menuSeparator = dynamic_cast<mMenuSeparator*>(action.data())) {
if(menuSeparator->visible()) {
AppendMenu(hmenu, MF_SEPARATOR | enabled, position, L"");
SetMenuItemInfo(hmenu, position++, true, &mii);
}
}
#endif
#if defined(Hiro_MenuItem)
else if(auto menuItem = dynamic_cast<mMenuItem*>(action.data())) {
if(menuItem->visible()) {
AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuItem->text()));
if(auto bitmap = menuItem->self()->hbitmap) {
mii.fMask |= MIIM_CHECKMARKS;
mii.hbmpUnchecked = bitmap;
}
SetMenuItemInfo(hmenu, position++, true, &mii);
}
}
#endif
#if defined(Hiro_MenuCheckItem)
else if(auto menuCheckItem = dynamic_cast<mMenuCheckItem*>(action.data())) {
if(menuCheckItem->visible()) {
AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuCheckItem->text()));
SetMenuItemInfo(hmenu, position++, true, &mii);
if(menuCheckItem->checked()) menuCheckItem->setChecked();
}
}
#endif
#if defined(Hiro_MenuRadioItem)
else if(auto menuRadioItem = dynamic_cast<mMenuRadioItem*>(action.data())) {
if(menuRadioItem->visible()) {
AppendMenu(hmenu, MF_STRING | enabled, position, utf16_t(menuRadioItem->text()));
SetMenuItemInfo(hmenu, position++, true, &mii);
if(menuRadioItem->checked()) menuRadioItem->setChecked();
}
}
#endif
} }
} }
} }
#endif

View File

@ -0,0 +1,22 @@
#if defined(Hiro_Menu)
namespace hiro {
struct pMenu : pAction {
Declare(Menu, Action)
auto append(sAction action) -> void;
auto remove(sAction action) -> void;
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
auto _createBitmap() -> void;
auto _update() -> void;
HMENU hmenu = 0;
HBITMAP hbitmap = 0;
};
}
#endif

View File

@ -1,32 +0,0 @@
namespace phoenix {
void pRadioItem::setChecked() {
for(auto &item : radioItem.state.group) {
//CheckMenuRadioItem takes: lo, hi, id; checking only id when lo <= id <= hi
//phoenix does not force IDs to be linear, so to uncheck id, we use: lo == hi == id + 1 (out of range)
//to check id, we use: lo == hi == id (only ID, but in range)
if(item.p.parentMenu) CheckMenuRadioItem(item.p.parentMenu->p.hmenu, item.p.id, item.p.id, item.p.id + (id != item.p.id), MF_BYCOMMAND);
}
}
void pRadioItem::setGroup(const group<RadioItem>& group) {
}
void pRadioItem::setText(string text) {
if(parentWindow) parentWindow->p.updateMenu();
}
void pRadioItem::constructor() {
}
void pRadioItem::destructor() {
if(parentMenu) parentMenu->remove(radioItem);
}
void pRadioItem::onActivate() {
if(radioItem.state.checked) return;
radioItem.setChecked();
if(radioItem.onActivate) radioItem.onActivate();
}
}

View File

@ -1,10 +0,0 @@
namespace phoenix {
void pSeparator::constructor() {
}
void pSeparator::destructor() {
if(parentMenu) parentMenu->remove(separator);
}
}

View File

@ -1,14 +1,16 @@
namespace phoenix { #if defined(Hiro_Application)
static bool Application_keyboardProc(HWND, UINT, WPARAM, LPARAM); namespace hiro {
static void Application_processDialogMessage(MSG&);
static LRESULT CALLBACK Application_windowProc(HWND, UINT, WPARAM, LPARAM);
void pApplication::run() { static auto Application_keyboardProc(HWND, UINT, WPARAM, LPARAM) -> bool;
static auto Application_processDialogMessage(MSG&) -> void;
static auto CALLBACK Application_windowProc(HWND, UINT, WPARAM, LPARAM) -> LRESULT;
auto pApplication::run() -> void {
MSG msg; MSG msg;
if(Application::main) { if(Application::state.onMain) {
while(applicationState.quit == false) { while(!Application::state.quit) {
Application::main(); Application::doMain();
processEvents(); processEvents();
} }
} else { } else {
@ -19,12 +21,12 @@ void pApplication::run() {
} }
} }
bool pApplication::pendingEvents() { auto pApplication::pendingEvents() -> bool {
MSG msg; MSG msg;
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE); return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
} }
void pApplication::processEvents() { auto pApplication::processEvents() -> void {
while(pendingEvents()) { while(pendingEvents()) {
MSG msg; MSG msg;
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
@ -33,7 +35,7 @@ void pApplication::processEvents() {
} }
} }
void Application_processDialogMessage(MSG& msg) { auto Application_processDialogMessage(MSG& msg) -> void {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP
|| msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) { || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) {
if(Application_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) { if(Application_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) {
@ -48,15 +50,17 @@ void Application_processDialogMessage(MSG& msg) {
} }
} }
void pApplication::quit() { auto pApplication::quit() -> void {
PostQuitMessage(0); PostQuitMessage(0);
} }
void pApplication::initialize() { auto pApplication::initialize() -> void {
CoInitialize(0); CoInitialize(0);
InitCommonControls(); InitCommonControls();
WNDCLASS wc; WNDCLASS wc;
#if defined(Hiro_Window)
wc.cbClsExtra = 0; wc.cbClsExtra = 0;
wc.cbWndExtra = 0; wc.cbWndExtra = 0;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
@ -64,11 +68,27 @@ void pApplication::initialize() {
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
wc.hInstance = GetModuleHandle(0); wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Application_windowProc; wc.lpfnWndProc = Application_windowProc;
wc.lpszClassName = L"phoenix_window"; wc.lpszClassName = L"hiroWindow";
wc.lpszMenuName = 0; wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); RegisterClass(&wc);
#endif
#if defined(Hiro_PopupMenu)
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Menu_windowProc;
wc.lpszClassName = L"hiroPopupMenu";
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc);
#endif
#if defined(Hiro_Canvas)
wc.cbClsExtra = 0; wc.cbClsExtra = 0;
wc.cbWndExtra = 0; wc.cbWndExtra = 0;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
@ -76,11 +96,13 @@ void pApplication::initialize() {
wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0); wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Canvas_windowProc; wc.lpfnWndProc = Canvas_windowProc;
wc.lpszClassName = L"phoenix_canvas"; wc.lpszClassName = L"hiroCanvas";
wc.lpszMenuName = 0; wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); RegisterClass(&wc);
#endif
#if defined(Hiro_Label)
wc.cbClsExtra = 0; wc.cbClsExtra = 0;
wc.cbWndExtra = 0; wc.cbWndExtra = 0;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
@ -88,11 +110,13 @@ void pApplication::initialize() {
wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0); wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Label_windowProc; wc.lpfnWndProc = Label_windowProc;
wc.lpszClassName = L"phoenix_label"; wc.lpszClassName = L"hiroLabel";
wc.lpszMenuName = 0; wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); RegisterClass(&wc);
#endif
#if defined(Hiro_Viewport)
wc.cbClsExtra = 0; wc.cbClsExtra = 0;
wc.cbWndExtra = 0; wc.cbWndExtra = 0;
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
@ -100,76 +124,80 @@ void pApplication::initialize() {
wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = GetModuleHandle(0); wc.hInstance = GetModuleHandle(0);
wc.lpfnWndProc = Viewport_windowProc; wc.lpfnWndProc = Viewport_windowProc;
wc.lpszClassName = L"phoenix_viewport"; wc.lpszClassName = L"hiroViewport";
wc.lpszMenuName = 0; wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW; wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wc); RegisterClass(&wc);
#endif
settings = new Settings;
pKeyboard::initialize(); pKeyboard::initialize();
} }
static bool Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static auto Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> bool {
if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false; if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false;
GUITHREADINFO info; GUITHREADINFO info;
memset(&info, 0, sizeof(GUITHREADINFO)); memset(&info, 0, sizeof(GUITHREADINFO));
info.cbSize = sizeof(GUITHREADINFO); info.cbSize = sizeof(GUITHREADINFO);
GetGUIThreadInfo(GetCurrentThreadId(), &info); GetGUIThreadInfo(GetCurrentThreadId(), &info);
Object* object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); auto object = (mObject*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
if(object == nullptr) return false; if(!object) return false;
if(dynamic_cast<Window*>(object)) { if(auto window = dynamic_cast<mWindow*>(object)) {
Window& window = (Window&)*object; if(pWindow::modal && !pWindow::modal.find(window->self())) return false;
if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) return false;
Keyboard::Keycode keysym = Keysym(wparam, lparam); if(auto code = pKeyboard::_translate(wparam, lparam)) {
if(keysym != Keyboard::Keycode::None) { if(msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) window->doKeyPress(code);
if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym); if(msg == WM_KEYUP || msg == WM_SYSKEYUP) window->doKeyRelease(code);
if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym);
} }
return false; return false;
} }
if(msg == WM_KEYDOWN) { if(msg == WM_KEYDOWN) {
if(dynamic_cast<ListView*>(object)) { if(0);
ListView& listView = (ListView&)*object;
#if defined(Hiro_ListView)
else if(auto listView = dynamic_cast<mListView*>(object)) {
if(wparam == VK_RETURN) { if(wparam == VK_RETURN) {
if(listView.selected()) return true; //returning true generates LVN_ITEMACTIVATE message if(listView->selected()) return true; //returning true generates LVN_ITEMACTIVATE message
} }
} else if(dynamic_cast<LineEdit*>(object)) { }
LineEdit& lineEdit = (LineEdit&)*object; #endif
#if defined(Hiro_LineEdit)
else if(auto lineEdit = dynamic_cast<mLineEdit*>(object)) {
if(wparam == VK_RETURN) { if(wparam == VK_RETURN) {
if(lineEdit.onActivate) lineEdit.onActivate(); lineEdit->doActivate();
} }
} else if(dynamic_cast<TextEdit*>(object)) { }
TextEdit& textEdit = (TextEdit&)*object; #endif
#if defined(Hiro_TextEdit)
else if(auto textEdit = dynamic_cast<mTextEdit*>(object)) {
if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) { if(wparam == 'A' && GetKeyState(VK_CONTROL) < 0) {
//Ctrl+A = select all text //Ctrl+A = select all text
//note: this is not a standard accelerator on Windows //note: this is not a standard accelerator on Windows
Edit_SetSel(textEdit.p.hwnd, 0, ~0); Edit_SetSel(textEdit->self()->hwnd, 0, ~0);
return true; return true;
} else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) { } else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) {
//Ctrl+V = paste text //Ctrl+V = paste text
//note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings //note: this formats Unix (LF) and OS9 (CR) line-endings to Windows (CR+LF) line-endings
//this is necessary as the EDIT control only supports Windows line-endings //this is necessary as the EDIT control only supports Windows line-endings
OpenClipboard(hwnd); OpenClipboard(hwnd);
HANDLE handle = GetClipboardData(CF_UNICODETEXT); if(auto handle = GetClipboardData(CF_UNICODETEXT)) {
if(handle) { if(auto text = (wchar_t*)GlobalLock(handle)) {
wchar_t* text = (wchar_t*)GlobalLock(handle);
if(text) {
string data = (const char*)utf8_t(text); string data = (const char*)utf8_t(text);
data.replace("\r\n", "\n"); data.replace("\r\n", "\n");
data.replace("\r", "\n"); data.replace("\r", "\n");
data.replace("\n", "\r\n"); data.replace("\n", "\r\n");
GlobalUnlock(handle); GlobalUnlock(handle);
utf16_t output(data); utf16_t output(data);
HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t)); if(auto resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t))) {
if(resource) { if(auto write = (wchar_t*)GlobalLock(resource)) {
wchar_t* write = (wchar_t*)GlobalLock(resource);
if(write) {
wcscpy(write, output); wcscpy(write, output);
GlobalUnlock(write); GlobalUnlock(write);
if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) { if(SetClipboardData(CF_UNICODETEXT, resource) == NULL) {
GlobalFree(resource); GlobalFree(resource);
} }
} }
@ -180,40 +208,45 @@ static bool Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
return false; return false;
} }
} }
#endif
} }
return false; return false;
} }
/*case WM_GETMINMAXINFO: { /*
MINMAXINFO* mmi = (MINMAXINFO*)lparam; case WM_GETMINMAXINFO: {
mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width; MINMAXINFO* mmi = (MINMAXINFO*)lparam;
mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height; mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width;
return TRUE; mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height;
break; return TRUE;
}*/ break;
}
*/
static LRESULT CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static auto CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT {
Object* object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA); auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(object == nullptr) return DefWindowProc(hwnd, msg, wparam, lparam); if(!object) return DefWindowProc(hwnd, msg, wparam, lparam);
Window& window = dynamic_cast<Window*>(object) ? (Window&)*object : *((Widget*)object)->Sizable::state.window; auto& window = dynamic_cast<mWindow*>(object) ? (mWindow&)*object : *object->parentWindow(true);
bool process = true; bool process = true;
if(!pWindow::modal.empty() && !pWindow::modal.find(&window.p)) process = false; if(pWindow::modal && !pWindow::modal.find(window.self())) process = false;
if(applicationState.quit) process = false; if(Application::state.quit) process = false;
if(process == false) return DefWindowProc(hwnd, msg, wparam, lparam); if(!process) return DefWindowProc(hwnd, msg, wparam, lparam);
switch(msg) { switch(msg) {
case WM_CLOSE: window.p.onClose(); return TRUE; case WM_CLOSE: window.self()->onClose(); return TRUE;
case WM_MOVE: window.p.onMove(); break; case WM_MOVE: window.self()->onMove(); break;
case WM_SIZE: window.p.onSize(); break; case WM_SIZE: window.self()->onSize(); break;
case WM_DROPFILES: window.p.onDrop(wparam); return FALSE; case WM_DROPFILES: window.self()->onDrop(wparam); return FALSE;
case WM_ERASEBKGND: if(window.p.onEraseBackground()) return true; break; case WM_ERASEBKGND: if(window.self()->onEraseBackground()) return true; break;
case WM_ENTERMENULOOP: case WM_ENTERSIZEMOVE: window.p.onModalBegin(); return FALSE; case WM_ENTERMENULOOP: case WM_ENTERSIZEMOVE: window.self()->onModalBegin(); return FALSE;
case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: window.p.onModalEnd(); return FALSE; case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: window.self()->onModalEnd(); return FALSE;
} }
return Shared_windowProc(DefWindowProc, hwnd, msg, wparam, lparam); return Shared_windowProc(DefWindowProc, hwnd, msg, wparam, lparam);
} }
} }
#endif

View File

@ -0,0 +1,16 @@
#if defined(Hiro_Application)
namespace hiro {
struct pApplication {
static auto run() -> void;
static auto pendingEvents() -> bool;
static auto processEvents() -> void;
static auto quit() -> void;
static auto initialize() -> void;
};
}
#endif

View File

@ -1,6 +1,8 @@
namespace phoenix { #if defined(Hiro_BrowserWindow)
static int CALLBACK BrowserWindowCallbackProc(HWND hwnd, UINT msg, LPARAM lparam, LPARAM lpdata) { namespace hiro {
static auto CALLBACK BrowserWindowCallbackProc(HWND hwnd, UINT msg, LPARAM lparam, LPARAM lpdata) -> signed {
if(msg == BFFM_INITIALIZED) { if(msg == BFFM_INITIALIZED) {
if(lpdata) { if(lpdata) {
auto state = (BrowserWindow::State*)lpdata; auto state = (BrowserWindow::State*)lpdata;
@ -12,7 +14,7 @@ static int CALLBACK BrowserWindowCallbackProc(HWND hwnd, UINT msg, LPARAM lparam
return 0; return 0;
} }
static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) { static auto BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) -> string {
string path = string{state.path}.replace("/", "\\"); string path = string{state.path}.replace("/", "\\");
string filters; string filters;
@ -46,7 +48,7 @@ static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) {
OPENFILENAME ofn; OPENFILENAME ofn;
memset(&ofn, 0, sizeof(OPENFILENAME)); memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME); ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = state.parent ? state.parent->p.hwnd : 0; ofn.hwndOwner = state.parent ? state.parent->self()->hwnd : 0;
ofn.lpstrFilter = wfilters; ofn.lpstrFilter = wfilters;
ofn.lpstrInitialDir = wpath; ofn.lpstrInitialDir = wpath;
ofn.lpstrFile = wname; ofn.lpstrFile = wname;
@ -62,11 +64,11 @@ static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) {
return name; return name;
} }
string pBrowserWindow::directory(BrowserWindow::State& state) { auto pBrowserWindow::directory(BrowserWindow::State& state) -> string {
wchar_t wname[PATH_MAX + 1] = L""; wchar_t wname[PATH_MAX + 1] = L"";
BROWSEINFO bi; BROWSEINFO bi;
bi.hwndOwner = state.parent ? state.parent->p.hwnd : 0; bi.hwndOwner = state.parent ? state.parent->self()->hwnd : 0;
bi.pidlRoot = NULL; bi.pidlRoot = NULL;
bi.pszDisplayName = wname; bi.pszDisplayName = wname;
bi.lpszTitle = L"\nChoose a directory:"; bi.lpszTitle = L"\nChoose a directory:";
@ -94,12 +96,14 @@ string pBrowserWindow::directory(BrowserWindow::State& state) {
return name; return name;
} }
string pBrowserWindow::open(BrowserWindow::State& state) { auto pBrowserWindow::open(BrowserWindow::State& state) -> string {
return BrowserWindow_fileDialog(0, state); return BrowserWindow_fileDialog(0, state);
} }
string pBrowserWindow::save(BrowserWindow::State& state) { auto pBrowserWindow::save(BrowserWindow::State& state) -> string {
return BrowserWindow_fileDialog(1, state); return BrowserWindow_fileDialog(1, state);
} }
} }
#endif

View File

@ -0,0 +1,13 @@
#if defined(Hiro_BrowserWindow)
namespace hiro {
struct pBrowserWindow {
static auto directory(BrowserWindow::State& state) -> string;
static auto open(BrowserWindow::State& state) -> string;
static auto save(BrowserWindow::State& state) -> string;
};
}
#endif

View File

@ -1,13 +1,17 @@
namespace phoenix { #if defined(Hiro_Desktop)
Size pDesktop::size() { namespace hiro {
auto pDesktop::size() -> Size {
return {GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)}; return {GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN)};
} }
Geometry pDesktop::workspace() { auto pDesktop::workspace() -> Geometry {
RECT rc; RECT rc;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top}; return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top};
} }
} }
#endif

12
hiro/windows/desktop.hpp Normal file
View File

@ -0,0 +1,12 @@
#if defined(Hiro_Desktop)
namespace hiro {
struct pDesktop {
static auto size() -> Size;
static auto workspace() -> Geometry;
};
}
#endif

View File

@ -1,34 +1,36 @@
namespace phoenix { #if defined(Hiro_Font)
string pFont::serif(unsigned size, string style) { namespace hiro {
auto pFont::serif(unsigned size, string style) -> string {
if(size == 0) size = 8; if(size == 0) size = 8;
if(style == "") style = "Normal"; if(style == "") style = "Normal";
return {"Georgia, ", size, ", ", style}; return {"Georgia, ", size, ", ", style};
} }
string pFont::sans(unsigned size, string style) { auto pFont::sans(unsigned size, string style) -> string {
if(size == 0) size = 8; if(size == 0) size = 8;
if(style == "") style = "Normal"; if(style == "") style = "Normal";
return {"Tahoma, ", size, ", ", style}; return {"Tahoma, ", size, ", ", style};
} }
string pFont::monospace(unsigned size, string style) { auto pFont::monospace(unsigned size, string style) -> string {
if(size == 0) size = 8; if(size == 0) size = 8;
if(style == "") style = "Normal"; if(style == "") style = "Normal";
return {"Lucida Console, ", size, ", ", style}; return {"Lucida Console, ", size, ", ", style};
} }
Size pFont::size(string font, string text) { auto pFont::size(const string& font, const string& text) -> Size {
HFONT hfont = pFont::create(font); HFONT hfont = pFont::create(font);
Size size = pFont::size(hfont, text); Size size = pFont::size(hfont, text);
pFont::free(hfont); pFont::free(hfont);
return size; return size;
} }
HFONT pFont::create(string description) { auto pFont::create(const string& description) -> HFONT {
lstring part = description.split<2>(",").strip(); lstring part = description.split<2>(",").strip();
string family = "Sans"; string family = "Tahoma";
unsigned size = 8u; unsigned size = 8u;
bool bold = false; bool bold = false;
bool italic = false; bool italic = false;
@ -40,16 +42,16 @@ HFONT pFont::create(string description) {
return CreateFont( return CreateFont(
-(size * 96.0 / 72.0 + 0.5), -(size * 96.0 / 72.0 + 0.5),
0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bold ? FW_BOLD : FW_NORMAL, italic, 0, 0, 0, 0, 0, 0, 0,
utf16_t(family) utf16_t(family)
); );
} }
void pFont::free(HFONT hfont) { auto pFont::free(HFONT hfont) -> void {
DeleteObject(hfont); DeleteObject(hfont);
} }
Size pFont::size(HFONT hfont, string text) { auto pFont::size(HFONT hfont, string text) -> Size {
//temporary fix: empty text string returns height of zero; bad for eg Button height //temporary fix: empty text string returns height of zero; bad for eg Button height
if(text.empty()) text = " "; if(text.empty()) text = " ";
@ -62,3 +64,5 @@ Size pFont::size(HFONT hfont, string text) {
} }
} }
#endif

18
hiro/windows/font.hpp Normal file
View File

@ -0,0 +1,18 @@
#if defined(Hiro_Font)
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 free(HFONT hfont) -> void;
static auto size(HFONT hfont, string text) -> Size;
};
}
#endif

13
hiro/windows/group.cpp Normal file
View File

@ -0,0 +1,13 @@
#if defined(Hiro_Group)
namespace hiro {
auto pGroup::construct() -> void {
}
auto pGroup::destruct() -> void {
}
}
#endif

11
hiro/windows/group.hpp Normal file
View File

@ -0,0 +1,11 @@
#if defined(Hiro_Group)
namespace hiro {
struct pGroup : pObject {
Declare(Group, Object)
};
}
#endif

View File

@ -15,4 +15,42 @@
#include <nall/windows/registry.hpp> #include <nall/windows/registry.hpp>
#include <nall/windows/utf8.hpp> #include <nall/windows/utf8.hpp>
#define TBS_TRANSPARENTBKGND 0x1000 //MinGW/32-bit has painfully outdated platform headers ...
#if !defined(Button_SetImageList)
typedef struct {
HIMAGELIST himl;
RECT margin;
UINT uAlign;
} BUTTON_IMAGELIST, *PBUTTON_IMAGELIST;
#define BUTTON_IMAGELIST_ALIGN_LEFT 0
#define BUTTON_IMAGELIST_ALIGN_RIGHT 1
#define BUTTON_IMAGELIST_ALIGN_TOP 2
#define BUTTON_IMAGELIST_ALIGN_BOTTOM 3
#define BUTTON_IMAGELIST_ALIGN_CENTER 4
#define BCM_FIRST 0x1600
#define BCM_SETIMAGELIST (BCM_FIRST+2)
#define Button_SetImageList(hwnd, pbuttonImagelist) (WINBOOL)SNDMSG((hwnd),BCM_SETIMAGELIST,0,(LPARAM)(pbuttonImagelist))
#endif
#if !defined(BP_CHECKBOX)
#define BP_CHECKBOX 3
#endif
#if !defined(CBS_UNCHECKEDNORMAL)
#define CBS_UNCHECKEDNORMAL 1
#endif
#if !defined(CBS_CHECKEDNORMAL)
#define CBS_CHECKEDNORMAL 5
#endif
#if !defined(LVCFMT_FIXED_WIDTH)
#define LVCFMT_FIXED_WIDTH 0x0100
#endif
#if !defined(TBS_TRANSPARENTBKGND)
#define TBS_TRANSPARENTBKGND 0x1000
#endif

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="phoenix" version="1.0.0.0" processorArchitecture="*"/> <assemblyIdentity type="win32" name="hiro" version="1.0.0.0" processorArchitecture="*"/>
<dependency> <dependency>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>

1
hiro/windows/hiro.rc Normal file
View File

@ -0,0 +1 @@
1 24 "hiro.Manifest"

13
hiro/windows/hotkey.cpp Normal file
View File

@ -0,0 +1,13 @@
#if defined(Hiro_Hotkey)
namespace hiro {
auto pHotkey::construct() -> void {
}
auto pHotkey::destruct() -> void {
}
}
#endif

11
hiro/windows/hotkey.hpp Normal file
View File

@ -0,0 +1,11 @@
#if defined(Hiro_Hotkey)
namespace hiro {
struct pHotkey : pObject {
Declare(Hotkey, Object)
};
}
#endif

View File

@ -1,144 +1,99 @@
namespace phoenix { #if defined(Hiro_Keyboard)
void pKeyboard::initialize() { namespace hiro {
auto append = [](Keyboard::Scancode scancode, unsigned keysym) {
settings->keymap.insert(scancode, keysym);
};
append(Keyboard::Scancode::Escape, VK_ESCAPE); vector<uint16_t> pKeyboard::keycodes;
append(Keyboard::Scancode::F1, VK_F1);
append(Keyboard::Scancode::F2, VK_F2);
append(Keyboard::Scancode::F3, VK_F3);
append(Keyboard::Scancode::F4, VK_F4);
append(Keyboard::Scancode::F5, VK_F5);
append(Keyboard::Scancode::F6, VK_F6);
append(Keyboard::Scancode::F7, VK_F7);
append(Keyboard::Scancode::F8, VK_F8);
append(Keyboard::Scancode::F9, VK_F9);
append(Keyboard::Scancode::F10, VK_F10);
append(Keyboard::Scancode::F11, VK_F11);
append(Keyboard::Scancode::F12, VK_F12);
append(Keyboard::Scancode::PrintScreen, VK_SNAPSHOT); auto pKeyboard::poll() -> vector<bool> {
append(Keyboard::Scancode::ScrollLock, VK_SCROLL); vector<bool> result;
append(Keyboard::Scancode::Pause, VK_PAUSE); for(auto& code : keycodes) result.append(pressed(code));
return result;
append(Keyboard::Scancode::Insert, VK_INSERT);
append(Keyboard::Scancode::Delete, VK_DELETE);
append(Keyboard::Scancode::Home, VK_HOME);
append(Keyboard::Scancode::End, VK_END);
append(Keyboard::Scancode::PageUp, VK_PRIOR);
append(Keyboard::Scancode::PageDown, VK_NEXT);
append(Keyboard::Scancode::Up, VK_UP);
append(Keyboard::Scancode::Down, VK_DOWN);
append(Keyboard::Scancode::Left, VK_LEFT);
append(Keyboard::Scancode::Right, VK_RIGHT);
append(Keyboard::Scancode::Grave, VK_OEM_3);
append(Keyboard::Scancode::Number1, '1');
append(Keyboard::Scancode::Number2, '2');
append(Keyboard::Scancode::Number3, '3');
append(Keyboard::Scancode::Number4, '4');
append(Keyboard::Scancode::Number5, '5');
append(Keyboard::Scancode::Number6, '6');
append(Keyboard::Scancode::Number7, '7');
append(Keyboard::Scancode::Number8, '8');
append(Keyboard::Scancode::Number9, '9');
append(Keyboard::Scancode::Number0, '0');
append(Keyboard::Scancode::Minus, VK_OEM_MINUS);
append(Keyboard::Scancode::Equal, VK_OEM_PLUS);
append(Keyboard::Scancode::Backspace, VK_BACK);
append(Keyboard::Scancode::BracketLeft, VK_OEM_4);
append(Keyboard::Scancode::BracketRight, VK_OEM_6);
append(Keyboard::Scancode::Backslash, VK_OEM_5);
append(Keyboard::Scancode::Semicolon, VK_OEM_1);
append(Keyboard::Scancode::Apostrophe, VK_OEM_7);
append(Keyboard::Scancode::Comma, VK_OEM_COMMA);
append(Keyboard::Scancode::Period, VK_OEM_PERIOD);
append(Keyboard::Scancode::Slash, VK_OEM_2);
append(Keyboard::Scancode::Tab, VK_TAB);
append(Keyboard::Scancode::CapsLock, VK_CAPITAL);
append(Keyboard::Scancode::Return, VK_RETURN);
append(Keyboard::Scancode::ShiftLeft, VK_LSHIFT);
append(Keyboard::Scancode::ShiftRight, VK_RSHIFT);
append(Keyboard::Scancode::ControlLeft, VK_LCONTROL);
append(Keyboard::Scancode::ControlRight, VK_RCONTROL);
append(Keyboard::Scancode::SuperLeft, VK_LWIN);
append(Keyboard::Scancode::SuperRight, VK_RWIN);
append(Keyboard::Scancode::AltLeft, VK_LMENU);
append(Keyboard::Scancode::AltRight, VK_RMENU);
append(Keyboard::Scancode::Space, VK_SPACE);
append(Keyboard::Scancode::Menu, VK_APPS);
append(Keyboard::Scancode::A, 'A');
append(Keyboard::Scancode::B, 'B');
append(Keyboard::Scancode::C, 'C');
append(Keyboard::Scancode::D, 'D');
append(Keyboard::Scancode::E, 'E');
append(Keyboard::Scancode::F, 'F');
append(Keyboard::Scancode::G, 'G');
append(Keyboard::Scancode::H, 'H');
append(Keyboard::Scancode::I, 'I');
append(Keyboard::Scancode::J, 'J');
append(Keyboard::Scancode::K, 'K');
append(Keyboard::Scancode::L, 'L');
append(Keyboard::Scancode::M, 'M');
append(Keyboard::Scancode::N, 'N');
append(Keyboard::Scancode::O, 'O');
append(Keyboard::Scancode::P, 'P');
append(Keyboard::Scancode::Q, 'Q');
append(Keyboard::Scancode::R, 'R');
append(Keyboard::Scancode::S, 'S');
append(Keyboard::Scancode::T, 'T');
append(Keyboard::Scancode::U, 'U');
append(Keyboard::Scancode::V, 'V');
append(Keyboard::Scancode::W, 'W');
append(Keyboard::Scancode::X, 'X');
append(Keyboard::Scancode::Y, 'Y');
append(Keyboard::Scancode::Z, 'Z');
append(Keyboard::Scancode::NumLock, VK_NUMLOCK);
append(Keyboard::Scancode::Divide, VK_DIVIDE);
append(Keyboard::Scancode::Multiply, VK_MULTIPLY);
append(Keyboard::Scancode::Subtract, VK_SUBTRACT);
append(Keyboard::Scancode::Add, VK_ADD);
//append(Keyboard::Scancode::Enter, ...);
append(Keyboard::Scancode::Point, VK_DECIMAL);
append(Keyboard::Scancode::Keypad1, VK_NUMPAD1);
append(Keyboard::Scancode::Keypad2, VK_NUMPAD2);
append(Keyboard::Scancode::Keypad3, VK_NUMPAD3);
append(Keyboard::Scancode::Keypad4, VK_NUMPAD4);
append(Keyboard::Scancode::Keypad5, VK_NUMPAD5);
append(Keyboard::Scancode::Keypad6, VK_NUMPAD6);
append(Keyboard::Scancode::Keypad7, VK_NUMPAD7);
append(Keyboard::Scancode::Keypad8, VK_NUMPAD8);
append(Keyboard::Scancode::Keypad9, VK_NUMPAD9);
append(Keyboard::Scancode::Keypad0, VK_NUMPAD0);
} }
bool pKeyboard::pressed(Keyboard::Scancode scancode) { auto pKeyboard::pressed(unsigned code) -> bool {
if(auto result = settings->keymap.find(scancode)) { uint8_t lo = code >> 0;
return GetAsyncKeyState(result()) & 0x8000; uint8_t hi = code >> 8;
} if(lo && GetAsyncKeyState(lo) & 0x8000) return true;
if(hi && GetAsyncKeyState(hi) & 0x8000) return true;
return false; return false;
} }
vector<bool> pKeyboard::state() { auto pKeyboard::initialize() -> void {
vector<bool> output; auto append = [](unsigned lo, unsigned hi = 0) {
output.resize((unsigned)Keyboard::Scancode::Limit); keycodes.append(lo << 0 | hi << 8);
for(auto& n : output) n = false; };
for(auto node : settings->keymap) { #define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; }
if(GetAsyncKeyState(node.value) & 0x8000) { for(auto& key : Keyboard::keys) {
output[(unsigned)node.key] = true; #include <hiro/platform/windows/keyboard.hpp>
} //print("[hiro/windows] warning: unhandled key: ", key, "\n");
append(0);
}
#undef map
}
auto pKeyboard::_translate(unsigned code, unsigned flags) -> signed {
bool numLock = GetKeyState(VK_NUMLOCK);
bool capsLock = GetKeyState(VK_CAPITAL);
bool shifted = (GetAsyncKeyState(VK_LSHIFT) & 0x8000) || (GetAsyncKeyState(VK_RSHIFT) & 0x8000);
bool pressed = GetAsyncKeyState(code) & 0x8000;
bool extended = flags & (1 << 24);
switch(code) {
case VK_OEM_3: return !shifted ? '`' : '~';
case '1': return !shifted ? '1' : '!';
case '2': return !shifted ? '2' : '@';
case '3': return !shifted ? '3' : '#';
case '4': return !shifted ? '4' : '$';
case '5': return !shifted ? '5' : '%';
case '6': return !shifted ? '6' : '^';
case '7': return !shifted ? '7' : '&';
case '8': return !shifted ? '8' : '*';
case '9': return !shifted ? '9' : '(';
case '0': return !shifted ? '0' : ')';
case VK_OEM_MINUS: return !shifted ? '-' : '_';
case VK_OEM_PLUS: return !shifted ? '=' : '+';
case VK_BACK: return '\b';
case VK_TAB: return '\t';
case VK_RETURN: return '\n';
case VK_SPACE: return ' ';
case VK_OEM_4: return !shifted ? '[' : '{';
case VK_OEM_6: return !shifted ? ']' : '}';
case VK_OEM_5: return !shifted ? '\\' : '|';
case VK_OEM_1: return !shifted ? ';' : ':';
case VK_OEM_7: return !shifted ? '\'' : '\"';
case VK_OEM_COMMA: return !shifted ? ',' : '<';
case VK_OEM_PERIOD: return !shifted ? '.' : '>';
case VK_OEM_2: return !shifted ? '/' : '?';
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M':
case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
if(capsLock) return !shifted ? code : code + 32;
else return !shifted ? code + 32 : code;
case VK_DIVIDE: return '/';
case VK_MULTIPLY: return '*';
case VK_SUBTRACT: return '-';
case VK_ADD: return '+';
case VK_DECIMAL: return '.';
case VK_NUMPAD1: return numLock ? '1' : 0;
case VK_NUMPAD2: return numLock ? '2' : 0;
case VK_NUMPAD3: return numLock ? '3' : 0;
case VK_NUMPAD4: return numLock ? '4' : 0;
case VK_NUMPAD5: return numLock ? '5' : 0;
case VK_NUMPAD6: return numLock ? '6' : 0;
case VK_NUMPAD7: return numLock ? '7' : 0;
case VK_NUMPAD8: return numLock ? '8' : 0;
case VK_NUMPAD9: return numLock ? '9' : 0;
case VK_NUMPAD0: return numLock ? '0' : 0;
} }
return output; return 0;
} }
} }
#endif

18
hiro/windows/keyboard.hpp Normal file
View File

@ -0,0 +1,18 @@
#if defined(Hiro_Keyboard)
namespace hiro {
struct pKeyboard {
static auto poll() -> vector<bool>;
static auto pressed(unsigned code) -> bool;
static auto initialize() -> void;
static auto _translate(unsigned code, unsigned flags) -> signed;
static vector<uint16_t> keycodes;
};
}
#endif

22
hiro/windows/layout.cpp Normal file
View File

@ -0,0 +1,22 @@
#if defined(Hiro_Layout)
namespace hiro {
auto pLayout::construct() -> void {
}
auto pLayout::destruct() -> void {
}
auto pLayout::setEnabled(bool enabled) -> void {
}
auto pLayout::setFont(const string& font) -> void {
}
auto pLayout::setVisible(bool visible) -> void {
}
}
#endif

15
hiro/windows/layout.hpp Normal file
View File

@ -0,0 +1,15 @@
#if defined(Hiro_Layout)
namespace hiro {
struct pLayout : pSizable {
Declare(Layout, Sizable)
auto setEnabled(bool enabled) -> void override;
auto setFont(const string& font) -> void override;
auto setVisible(bool visible) -> void override;
};
}
#endif

83
hiro/windows/menu-bar.cpp Normal file
View File

@ -0,0 +1,83 @@
#if defined(Hiro_MenuBar)
namespace hiro {
auto pMenuBar::construct() -> void {
_update();
}
auto pMenuBar::destruct() -> void {
if(hmenu) { DestroyMenu(hmenu); hmenu = nullptr; }
if(auto parent = _parent()) {
SetMenu(parent->hwnd, nullptr);
}
}
auto pMenuBar::append(sMenu) -> void {
_update();
}
auto pMenuBar::remove(sMenu) -> void {
_update();
}
auto pMenuBar::setEnabled(bool enabled) -> void {
_update();
}
auto pMenuBar::setFont(const string& font) -> void {
//unsupported
}
auto pMenuBar::setVisible(bool visible) -> void {
if(auto parent = _parent()) {
SetMenu(parent->hwnd, visible ? hmenu : nullptr);
parent->setGeometry(parent->state().geometry);
}
}
auto pMenuBar::_parent() -> maybe<pWindow&> {
if(auto parent = self().parentWindow(true)) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pMenuBar::_update() -> void {
if(hmenu) DestroyMenu(hmenu);
hmenu = CreateMenu();
MENUINFO mi{sizeof(MENUINFO)};
mi.fMask = MIM_STYLE;
mi.dwStyle = MNS_NOTIFYBYPOS; //| MNS_MODELESS;
SetMenuInfo(hmenu, &mi);
unsigned position = 0;
#if defined(Hiro_Menu)
for(auto& menu : state().menus) {
unsigned enabled = menu->enabled() ? 0 : MF_GRAYED;
MENUITEMINFO mii{sizeof(MENUITEMINFO)};
mii.fMask = MIIM_DATA;
mii.dwItemData = (ULONG_PTR)menu.data();
if(menu->visible()) {
if(auto self = menu->self()) {
self->_update();
AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)self->hmenu, utf16_t(menu->text()));
SetMenuItemInfo(hmenu, position++, true, &mii);
}
}
}
#endif
if(auto parent = _parent()) {
SetMenu(parent->hwnd, self().visible(true) ? hmenu : nullptr);
parent->setGeometry(parent->state().geometry);
}
}
}
#endif

23
hiro/windows/menu-bar.hpp Normal file
View File

@ -0,0 +1,23 @@
#if defined(Hiro_MenuBar)
namespace hiro {
struct pMenuBar : pObject {
Declare(MenuBar, Object)
auto append(sMenu menu) -> void;
auto remove(sMenu menu) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const string& font) -> void override;
auto setVisible(bool visible) -> void override;
auto _parent() -> maybe<pWindow&>;
auto _update() -> void;
HMENU hmenu = 0;
vector<wObject> objects;
};
}
#endif

View File

@ -1,6 +1,8 @@
namespace phoenix { #if defined(Hiro_MessageWindow)
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, UINT response) { namespace hiro {
static auto MessageWindow_response(MessageWindow::Buttons buttons, UINT response) -> MessageWindow::Response {
if(response == IDOK) return MessageWindow::Response::Ok; if(response == IDOK) return MessageWindow::Response::Ok;
if(response == IDCANCEL) return MessageWindow::Response::Cancel; if(response == IDCANCEL) return MessageWindow::Response::Cancel;
if(response == IDYES) return MessageWindow::Response::Yes; if(response == IDYES) return MessageWindow::Response::Yes;
@ -15,7 +17,7 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
throw; throw;
} }
static UINT MessageWindow_buttons(MessageWindow::Buttons buttons) { static auto MessageWindow_buttons(MessageWindow::Buttons buttons) -> UINT {
if(buttons == MessageWindow::Buttons::Ok) return MB_OK; if(buttons == MessageWindow::Buttons::Ok) return MB_OK;
if(buttons == MessageWindow::Buttons::OkCancel) return MB_OKCANCEL; if(buttons == MessageWindow::Buttons::OkCancel) return MB_OKCANCEL;
if(buttons == MessageWindow::Buttons::YesNo) return MB_YESNO; if(buttons == MessageWindow::Buttons::YesNo) return MB_YESNO;
@ -23,32 +25,34 @@ static UINT MessageWindow_buttons(MessageWindow::Buttons buttons) {
throw; throw;
} }
MessageWindow::Response pMessageWindow::error(MessageWindow::State& state) { auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response {
UINT flags = MB_ICONERROR | MessageWindow_buttons(state.buttons); UINT flags = MB_ICONERROR | MessageWindow_buttons(state.buttons);
return MessageWindow_response(state.buttons, MessageBox( return MessageWindow_response(state.buttons, MessageBox(
state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
)); ));
} }
MessageWindow::Response pMessageWindow::information(MessageWindow::State& state) { auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response {
UINT flags = MB_ICONINFORMATION | MessageWindow_buttons(state.buttons); UINT flags = MB_ICONINFORMATION | MessageWindow_buttons(state.buttons);
return MessageWindow_response(state.buttons, MessageBox( return MessageWindow_response(state.buttons, MessageBox(
state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
)); ));
} }
MessageWindow::Response pMessageWindow::question(MessageWindow::State& state) { auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response {
UINT flags = MB_ICONQUESTION | MessageWindow_buttons(state.buttons); UINT flags = MB_ICONQUESTION | MessageWindow_buttons(state.buttons);
return MessageWindow_response(state.buttons, MessageBox( return MessageWindow_response(state.buttons, MessageBox(
state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
)); ));
} }
MessageWindow::Response pMessageWindow::warning(MessageWindow::State& state) { auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response {
UINT flags = MB_ICONWARNING | MessageWindow_buttons(state.buttons); UINT flags = MB_ICONWARNING | MessageWindow_buttons(state.buttons);
return MessageWindow_response(state.buttons, MessageBox( return MessageWindow_response(state.buttons, MessageBox(
state.parent ? state.parent->p.hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags state.parent ? state.parent->self()->hwnd : 0, utf16_t(state.text), utf16_t(state.title), flags
)); ));
} }
} }
#endif

View File

@ -0,0 +1,14 @@
#if defined(Hiro_MessageWindow)
namespace hiro {
struct pMessageWindow {
static auto error(MessageWindow::State& state) -> MessageWindow::Response;
static auto information(MessageWindow::State& state) -> MessageWindow::Response;
static auto question(MessageWindow::State& state) -> MessageWindow::Response;
static auto warning(MessageWindow::State& state) -> MessageWindow::Response;
};
}
#endif

View File

@ -1,4 +1,6 @@
namespace phoenix { #if defined(Hiro_Monitor)
namespace hiro {
struct MonitorInfo { struct MonitorInfo {
unsigned monitor = 0; unsigned monitor = 0;
@ -7,7 +9,7 @@ struct MonitorInfo {
Geometry geometry; Geometry geometry;
}; };
static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { static auto CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
MonitorInfo& info = *(MonitorInfo*)dwData; MonitorInfo& info = *(MonitorInfo*)dwData;
MONITORINFOEX mi; MONITORINFOEX mi;
memset(&mi, 0, sizeof(MONITORINFOEX)); memset(&mi, 0, sizeof(MONITORINFOEX));
@ -23,21 +25,23 @@ static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT l
return TRUE; return TRUE;
} }
unsigned pMonitor::count() { auto pMonitor::count() -> unsigned {
return GetSystemMetrics(SM_CMONITORS); return GetSystemMetrics(SM_CMONITORS);
} }
Geometry pMonitor::geometry(unsigned monitor) { auto pMonitor::geometry(unsigned monitor) -> Geometry {
MonitorInfo info; MonitorInfo info;
info.monitor = monitor; info.monitor = monitor;
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info); EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info);
return info.geometry; return info.geometry;
} }
unsigned pMonitor::primary() { auto pMonitor::primary() -> unsigned {
MonitorInfo info; MonitorInfo info;
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info); EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info);
return info.primary; return info.primary;
} }
} }
#endif

13
hiro/windows/monitor.hpp Normal file
View File

@ -0,0 +1,13 @@
#if defined(Hiro_Monitor)
namespace hiro {
struct pMonitor {
static auto count() -> unsigned;
static auto geometry(unsigned monitor) -> Geometry;
static auto primary() -> unsigned;
};
}
#endif

View File

@ -1,12 +1,14 @@
namespace phoenix { #if defined(Hiro_Mouse)
Position pMouse::position() { namespace hiro {
POINT point = {0};
auto pMouse::position() -> Position {
POINT point{0};
GetCursorPos(&point); GetCursorPos(&point);
return {point.x, point.y}; return {point.x, point.y};
} }
bool pMouse::pressed(Mouse::Button button) { auto pMouse::pressed(Mouse::Button button) -> bool {
switch(button) { switch(button) {
case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000; case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000;
case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000; case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000;
@ -16,3 +18,5 @@ bool pMouse::pressed(Mouse::Button button) {
} }
} }
#endif

12
hiro/windows/mouse.hpp Normal file
View File

@ -0,0 +1,12 @@
#if defined(Hiro_Mouse)
namespace hiro {
struct pMouse {
static auto position() -> Position;
static auto pressed(Mouse::Button button) -> bool;
};
}
#endif

View File

@ -1,17 +1,41 @@
namespace phoenix { #if defined(Hiro_Object)
vector<pObject*> pObject::objects; namespace hiro {
pObject::pObject(Object& object) : object(object) { auto pObject::construct() -> void {
static unsigned uniqueId = 100;
objects.append(this);
id = uniqueId++;
locked = false;
} }
Object* pObject::find(unsigned id) { auto pObject::destruct() -> void {
for(auto& item : objects) if(item->id == id) return &item->object; }
return nullptr;
auto pObject::reconstruct() -> void {
}
auto pObject::focused() const -> bool {
return false;
}
auto pObject::remove() -> void {
}
auto pObject::reset() -> void {
}
auto pObject::setEnabled(bool enabled) -> void {
}
auto pObject::setFocused() -> void {
}
auto pObject::setFont(const string& font) -> void {
}
auto pObject::setGroup(sGroup group) -> void {
}
auto pObject::setVisible(bool visible) -> void {
} }
} }
#endif

31
hiro/windows/object.hpp Normal file
View File

@ -0,0 +1,31 @@
#if defined(Hiro_Object)
namespace hiro {
struct pObject {
pObject(mObject& reference) : reference(reference) {}
virtual ~pObject() = default;
virtual auto construct() -> void;
virtual auto destruct() -> void;
virtual auto reconstruct() -> void;
virtual auto focused() const -> bool;
virtual auto remove() -> void;
virtual auto reset() -> void;
virtual auto setEnabled(bool enabled) -> void;
virtual auto setFocused() -> void;
virtual auto setFont(const string& font) -> void;
virtual auto setGroup(sGroup group) -> void;
virtual auto setVisible(bool visible) -> void;
auto locked() const -> bool { return locks != 0; }
auto lock() -> void { ++locks; }
auto unlock() -> void { --locks; }
mObject& reference;
signed locks = 0;
};
}
#endif

View File

@ -1 +0,0 @@
1 24 "phoenix.Manifest"

View File

@ -1,7 +1,5 @@
#include "platform.hpp" #include "platform.hpp"
#include "utility.cpp" #include "utility.cpp"
#include "settings.cpp"
#include "desktop.cpp" #include "desktop.cpp"
#include "monitor.cpp" #include "monitor.cpp"
@ -9,17 +7,27 @@
#include "mouse.cpp" #include "mouse.cpp"
#include "browser-window.cpp" #include "browser-window.cpp"
#include "message-window.cpp" #include "message-window.cpp"
#include "object.cpp" #include "object.cpp"
#include "group.cpp"
#include "hotkey.cpp"
#include "font.cpp" #include "font.cpp"
#include "timer.cpp" #include "timer.cpp"
#include "window.cpp" #include "window.cpp"
#include "status-bar.cpp"
#include "menu-bar.cpp"
#include "popup-menu.cpp"
#include "action/action.cpp" #include "action/action.cpp"
#include "action/menu.cpp" #include "action/menu.cpp"
#include "action/separator.cpp" #include "action/menu-separator.cpp"
#include "action/item.cpp" #include "action/menu-item.cpp"
#include "action/check-item.cpp" #include "action/menu-check-item.cpp"
#include "action/radio-item.cpp" #include "action/menu-radio-item.cpp"
#include "sizable.cpp"
#include "layout.cpp"
#include "widget/widget.cpp" #include "widget/widget.cpp"
#include "widget/button.cpp" #include "widget/button.cpp"
@ -27,7 +35,7 @@
#include "widget/check-button.cpp" #include "widget/check-button.cpp"
#include "widget/check-label.cpp" #include "widget/check-label.cpp"
#include "widget/combo-button.cpp" #include "widget/combo-button.cpp"
#include "widget/console.cpp" #include "widget/combo-button-item.cpp"
#include "widget/frame.cpp" #include "widget/frame.cpp"
#include "widget/hex-edit.cpp" #include "widget/hex-edit.cpp"
#include "widget/horizontal-scroller.cpp" #include "widget/horizontal-scroller.cpp"
@ -35,10 +43,14 @@
#include "widget/label.cpp" #include "widget/label.cpp"
#include "widget/line-edit.cpp" #include "widget/line-edit.cpp"
#include "widget/list-view.cpp" #include "widget/list-view.cpp"
#include "widget/list-view-column.cpp"
#include "widget/list-view-item.cpp"
#include "widget/list-view-cell.cpp"
#include "widget/progress-bar.cpp" #include "widget/progress-bar.cpp"
#include "widget/radio-button.cpp" #include "widget/radio-button.cpp"
#include "widget/radio-label.cpp" #include "widget/radio-label.cpp"
#include "widget/tab-frame.cpp" #include "widget/tab-frame.cpp"
#include "widget/tab-frame-item.cpp"
#include "widget/text-edit.cpp" #include "widget/text-edit.cpp"
#include "widget/vertical-scroller.cpp" #include "widget/vertical-scroller.cpp"
#include "widget/vertical-slider.cpp" #include "widget/vertical-slider.cpp"

View File

@ -1,25 +1,4 @@
namespace phoenix { namespace hiro {
struct AppMessage {
enum : unsigned {
ListView_onActivate = 0,
};
};
typedef LRESULT CALLBACK (*WindowProc)(HWND, UINT, WPARAM, LPARAM);
struct pApplication {
static void run();
static bool pendingEvents();
static void processEvents();
static void quit();
static void initialize();
};
struct Settings {
bimap<Keyboard::Scancode, unsigned> keymap;
};
struct pFont; struct pFont;
struct pObject; struct pObject;
@ -28,620 +7,81 @@ struct pMenu;
struct pLayout; struct pLayout;
struct pWidget; struct pWidget;
struct pFont { struct AppMessage {
static string serif(unsigned size, string style); enum : unsigned {
static string sans(unsigned size, string style); None = WM_APP,
static string monospace(unsigned size, string style); ListView_onActivate,
static Size size(string font, string text); ListView_onChange,
};
static HFONT create(string description);
static void free(HFONT hfont);
static Size size(HFONT hfont, string text);
}; };
struct pDesktop { using WindowProc = auto CALLBACK (*)(HWND, UINT, WPARAM, LPARAM) -> LRESULT;
static Size size();
static Geometry workspace();
};
struct pMonitor {
static unsigned count();
static Geometry geometry(unsigned monitor);
static unsigned primary();
};
struct pKeyboard {
static bool pressed(Keyboard::Scancode scancode);
static vector<bool> state();
static void initialize();
};
struct pMouse {
static Position position();
static bool pressed(Mouse::Button button);
};
struct pBrowserWindow {
static string directory(BrowserWindow::State& state);
static string open(BrowserWindow::State& state);
static string save(BrowserWindow::State& state);
};
struct pMessageWindow {
static MessageWindow::Response error(MessageWindow::State& state);
static MessageWindow::Response information(MessageWindow::State& state);
static MessageWindow::Response question(MessageWindow::State& state);
static MessageWindow::Response warning(MessageWindow::State& state);
};
struct pObject {
static vector<pObject*> objects;
Object& object;
uintptr_t id;
bool locked;
pObject(Object& object);
static Object* find(unsigned id);
virtual ~pObject() {}
void constructor() {}
void destructor() {}
};
struct pTimer : public pObject {
Timer& timer;
UINT_PTR htimer;
void setEnabled(bool enabled);
void setInterval(unsigned interval);
pTimer(Timer& timer) : pObject(timer), timer(timer) {}
void constructor();
};
struct pWindow : public pObject {
static vector<pWindow*> modal;
static void updateModality();
Window& window;
HWND hwnd;
HMENU hmenu;
HWND hstatus;
HFONT hstatusfont;
HBRUSH brush;
COLORREF brushColor;
static Window& none();
void append(Layout& layout);
void append(Menu& menu);
void append(Widget& widget);
bool focused();
Geometry frameMargin();
Geometry geometry();
void remove(Layout& layout);
void remove(Menu& menu);
void remove(Widget& widget);
void setBackgroundColor(Color color);
void setDroppable(bool droppable);
void setFocused();
void setFullScreen(bool fullScreen);
void setGeometry(Geometry geometry);
void setMenuFont(string font);
void setMenuVisible(bool visible);
void setModal(bool modal);
void setResizable(bool resizable);
void setStatusFont(string font);
void setStatusText(string text);
void setStatusVisible(bool visible);
void setTitle(string text);
void setVisible(bool visible);
void setWidgetFont(string font);
pWindow(Window& window) : pObject(window), window(window) {}
void constructor();
void destructor();
void updateMenu();
void onClose();
void onDrop(WPARAM wparam);
bool onEraseBackground();
void onModalBegin();
void onModalEnd();
void onMove();
void onSize();
};
struct pAction : public pObject {
Action& action;
Menu* parentMenu;
Window* parentWindow;
void setEnabled(bool enabled);
void setVisible(bool visible);
pAction(Action& action) : pObject(action), action(action) {}
void constructor();
};
struct pMenu : public pAction {
Menu& menu;
HMENU hmenu;
HBITMAP hbitmap;
void append(Action& action);
void remove(Action& action);
void setImage(const image& image);
void setText(string text);
pMenu(Menu& menu) : pAction(menu), menu(menu), hbitmap(0) {}
void constructor();
void destructor();
void createBitmap();
void update(Window& parentWindow, Menu* parentMenu = nullptr);
};
struct pSeparator : public pAction {
Separator& separator;
pSeparator(Separator& separator) : pAction(separator), separator(separator) {}
void constructor();
void destructor();
};
struct pItem : public pAction {
Item& item;
HBITMAP hbitmap;
void setImage(const image& image);
void setText(string text);
pItem(Item& item) : pAction(item), item(item), hbitmap(0) {}
void constructor();
void destructor();
void createBitmap();
void onActivate();
};
struct pCheckItem : public pAction {
CheckItem& checkItem;
void setChecked(bool checked);
void setText(string text);
pCheckItem(CheckItem& checkItem) : pAction(checkItem), checkItem(checkItem) {}
void constructor();
void destructor();
void onToggle();
};
struct pRadioItem : public pAction {
RadioItem& radioItem;
void setChecked();
void setGroup(const group<RadioItem>& group);
void setText(string text);
pRadioItem(RadioItem& radioItem) : pAction(radioItem), radioItem(radioItem) {}
void constructor();
void destructor();
void onActivate();
};
struct pSizable : public pObject {
Sizable& sizable;
pSizable(Sizable& sizable) : pObject(sizable), sizable(sizable) {}
};
struct pLayout : public pSizable {
Layout& layout;
pLayout(Layout& layout) : pSizable(layout), layout(layout) {}
};
struct pWidget : public pSizable {
Widget& widget;
HWND parentHwnd;
HWND hwnd;
HFONT hfont;
bool focused();
virtual Size minimumSize();
virtual void setEnabled(bool enabled);
void setFocused();
void setFont(string font);
virtual void setGeometry(Geometry geometry);
virtual void setVisible(bool visible);
pWidget(Widget& widget) : pSizable(widget), widget(widget) { parentHwnd = pWindow::none().p.hwnd; }
void constructor();
void destructor();
virtual void orphan();
void setDefaultFont();
void synchronize();
};
struct pButton : public pWidget {
Button& button;
HBITMAP hbitmap;
HIMAGELIST himagelist;
Size minimumSize();
void setBordered(bool bordered);
void setImage(const image& image, Orientation orientation);
void setText(string text);
pButton(Button& button) : pWidget(button), button(button), hbitmap(0), himagelist(0) {}
void constructor();
void destructor();
void orphan();
void onActivate();
};
struct pCanvas : public pWidget {
Canvas& canvas;
uint32_t* surface = nullptr;
unsigned surfaceWidth = 0;
unsigned surfaceHeight = 0;
void setDroppable(bool droppable);
void setGeometry(Geometry geometry);
void setMode(Canvas::Mode mode);
void setSize(Size size);
pCanvas(Canvas& canvas) : pWidget(canvas), canvas(canvas) {}
void constructor();
void destructor();
void orphan();
void paint();
void rasterize();
void redraw();
void release();
};
struct pCheckButton : public pWidget {
CheckButton& checkButton;
HBITMAP hbitmap;
HIMAGELIST himagelist;
Size minimumSize();
void setChecked(bool checked);
void setImage(const image& image, Orientation orientation);
void setText(string text);
pCheckButton(CheckButton& checkButton) : pWidget(checkButton), checkButton(checkButton) {}
void constructor();
void destructor();
void orphan();
void onToggle();
};
struct pCheckLabel : public pWidget {
CheckLabel& checkLabel;
Size minimumSize();
void setChecked(bool checked);
void setText(string text);
pCheckLabel(CheckLabel& checkLabel) : pWidget(checkLabel), checkLabel(checkLabel) {}
void constructor();
void destructor();
void orphan();
void onToggle();
};
struct pComboButton : public pWidget {
ComboButton& comboButton;
void append(string text);
void remove(unsigned selection);
Size minimumSize();
void reset();
void setGeometry(Geometry geometry);
void setSelection(unsigned selection);
void setText(unsigned selection, string text);
pComboButton(ComboButton& comboButton) : pWidget(comboButton), comboButton(comboButton) {}
void constructor();
void destructor();
void orphan();
void onChange();
};
struct pConsole : public pWidget {
Console& console;
LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM);
HBRUSH backgroundBrush = nullptr;
void print(string text);
void reset();
void setBackgroundColor(Color color);
void setForegroundColor(Color color);
void setPrompt(string prompt);
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
void orphan();
bool keyPress(unsigned key);
};
struct pFrame : public pWidget {
Frame& frame;
void setEnabled(bool enabled);
void setGeometry(Geometry geometry);
void setText(string text);
void setVisible(bool visible);
pFrame(Frame& frame) : pWidget(frame), frame(frame) {}
void constructor();
void destructor();
void orphan();
};
struct pHexEdit : public pWidget {
HexEdit& hexEdit;
WindowProc windowProc = nullptr;
HWND scrollBar = nullptr;
HBRUSH backgroundBrush = nullptr;
void setBackgroundColor(Color color);
void setColumns(unsigned columns);
void setForegroundColor(Color color);
void setLength(unsigned length);
void setOffset(unsigned offset);
void setRows(unsigned rows);
void update();
pHexEdit(HexEdit& hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {}
void constructor();
void destructor();
void orphan();
bool keyPress(unsigned key);
signed rows();
signed rowsScrollable();
signed scrollPosition();
void scrollTo(signed position);
};
struct pHorizontalScroller : public pWidget {
HorizontalScroller& horizontalScroller;
Size minimumSize();
void setLength(unsigned length);
void setPosition(unsigned position);
pHorizontalScroller(HorizontalScroller& horizontalScroller) : pWidget(horizontalScroller), horizontalScroller(horizontalScroller) {}
void constructor();
void destructor();
void orphan();
void onChange(WPARAM wparam);
};
struct pHorizontalSlider : public pWidget {
HorizontalSlider& horizontalSlider;
Size minimumSize();
void setLength(unsigned length);
void setPosition(unsigned position);
pHorizontalSlider(HorizontalSlider& horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {}
void constructor();
void destructor();
void orphan();
void onChange();
};
struct pLabel : public pWidget {
Label& label;
Size minimumSize();
void setText(string text);
pLabel(Label& label) : pWidget(label), label(label) {}
void constructor();
void destructor();
void orphan();
};
struct pLineEdit : public pWidget {
LineEdit& lineEdit;
HBRUSH backgroundBrush = nullptr;
Size minimumSize();
void setBackgroundColor(Color color);
void setEditable(bool editable);
void setForegroundColor(Color color);
void setText(string text);
string text();
pLineEdit(LineEdit& lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {}
void constructor();
void destructor();
void orphan();
void onChange();
};
struct pListView : public pWidget {
ListView& listView;
HIMAGELIST imageList;
vector<vector<unsigned>> imageMap;
vector<image> images;
bool lostFocus;
void append(const lstring& text);
void autoSizeColumns();
void remove(unsigned selection);
void reset();
void setBackgroundColor(Color color);
void setCheckable(bool checkable);
void setChecked(unsigned selection, bool checked);
void setForegroundColor(Color color);
void setGeometry(Geometry geometry);
void setHeaderText(const lstring& text);
void setHeaderVisible(bool visible);
void setImage(unsigned selection, unsigned position, const image& image);
void setSelected(bool selected);
void setSelection(unsigned selection);
void setText(unsigned selection, unsigned position, string text);
pListView(ListView& listView) : pWidget(listView), listView(listView), imageList(nullptr) {}
void constructor();
void destructor();
void orphan();
void buildImageList();
void onActivate(LPARAM lparam);
void onChange(LPARAM lparam);
LRESULT onCustomDraw(LPARAM lparam);
};
struct pProgressBar : public pWidget {
ProgressBar& progressBar;
Size minimumSize();
void setPosition(unsigned position);
pProgressBar(ProgressBar& progressBar) : pWidget(progressBar), progressBar(progressBar) {}
void constructor();
void destructor();
void orphan();
};
struct pRadioButton : public pWidget {
RadioButton& radioButton;
HBITMAP hbitmap;
HIMAGELIST himagelist;
Size minimumSize();
void setChecked();
void setGroup(const group<RadioButton>& group);
void setImage(const image& image, Orientation orientation);
void setText(string text);
pRadioButton(RadioButton& radioButton) : pWidget(radioButton), radioButton(radioButton) {}
void constructor();
void destructor();
void orphan();
void onActivate();
};
struct pRadioLabel : public pWidget {
RadioLabel& radioLabel;
Size minimumSize();
void setChecked();
void setGroup(const group<RadioLabel>& group);
void setText(string text);
pRadioLabel(RadioLabel& radioLabel) : pWidget(radioLabel), radioLabel(radioLabel) {}
void constructor();
void destructor();
void orphan();
void onActivate();
};
struct pTabFrame : public pWidget {
TabFrame& tabFrame;
WindowProc windowProc = nullptr;
HIMAGELIST imageList = nullptr;
void append(string text, const image& image);
void remove(unsigned selection);
void setEnabled(bool enabled);
void setGeometry(Geometry geometry);
void setImage(unsigned selection, const image& image);
void setSelection(unsigned selection);
void setText(unsigned selection, string text);
void setVisible(bool visible);
pTabFrame(TabFrame& tabFrame) : pWidget(tabFrame), tabFrame(tabFrame) {}
void constructor();
void destructor();
void orphan();
void buildImageList();
void synchronizeLayout();
void onChange();
void onDrawItem(LPARAM lparam);
};
struct pTextEdit : public pWidget {
TextEdit& textEdit;
HBRUSH backgroundBrush = nullptr;
void setBackgroundColor(Color color);
void setCursorPosition(unsigned position);
void setEditable(bool editable);
void setForegroundColor(Color color);
void setText(string text);
void setWordWrap(bool wordWrap);
string text();
pTextEdit(TextEdit& textEdit) : pWidget(textEdit), textEdit(textEdit) {}
void constructor();
void destructor();
void orphan();
void onChange();
};
struct pVerticalScroller : public pWidget {
VerticalScroller& verticalScroller;
Size minimumSize();
void setLength(unsigned length);
void setPosition(unsigned position);
pVerticalScroller(VerticalScroller& verticalScroller) : pWidget(verticalScroller), verticalScroller(verticalScroller) {}
void constructor();
void destructor();
void orphan();
void onChange(WPARAM wparam);
};
struct pVerticalSlider : public pWidget {
VerticalSlider& verticalSlider;
Size minimumSize();
void setLength(unsigned length);
void setPosition(unsigned position);
pVerticalSlider(VerticalSlider& verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {}
void constructor();
void destructor();
void orphan();
void onChange();
};
struct pViewport : public pWidget {
Viewport& viewport;
uintptr_t handle();
void setDroppable(bool droppable);
pViewport(Viewport& viewport) : pWidget(viewport), viewport(viewport) {}
void constructor();
void destructor();
void orphan();
};
} }
#define Declare(Name, Base) \
p##Name(m##Name& reference) : p##Base(reference) {} \
auto self() const -> m##Name& { return (m##Name&)reference; } \
auto state() const -> m##Name::State& { return self().state; } \
auto construct() -> void override; \
auto destruct() -> void override; \
auto reconstruct() -> void override { destruct(), construct(); } \
#include "font.hpp"
#include "desktop.hpp"
#include "monitor.hpp"
#include "keyboard.hpp"
#include "mouse.hpp"
#include "browser-window.hpp"
#include "message-window.hpp"
#include "object.hpp"
#include "group.hpp"
#include "hotkey.hpp"
#include "timer.hpp"
#include "window.hpp"
#include "status-bar.hpp"
#include "menu-bar.hpp"
#include "popup-menu.hpp"
#include "action/action.hpp"
#include "action/menu.hpp"
#include "action/menu-separator.hpp"
#include "action/menu-item.hpp"
#include "action/menu-check-item.hpp"
#include "action/menu-radio-item.hpp"
#include "sizable.hpp"
#include "layout.hpp"
#include "widget/widget.hpp"
#include "widget/button.hpp"
#include "widget/canvas.hpp"
#include "widget/check-button.hpp"
#include "widget/check-label.hpp"
#include "widget/combo-button.hpp"
#include "widget/combo-button-item.hpp"
#include "widget/frame.hpp"
#include "widget/hex-edit.hpp"
#include "widget/horizontal-scroller.hpp"
#include "widget/horizontal-slider.hpp"
#include "widget/label.hpp"
#include "widget/line-edit.hpp"
#include "widget/list-view.hpp"
#include "widget/list-view-column.hpp"
#include "widget/list-view-item.hpp"
#include "widget/list-view-cell.hpp"
#include "widget/progress-bar.hpp"
#include "widget/radio-button.hpp"
#include "widget/radio-label.hpp"
#include "widget/tab-frame.hpp"
#include "widget/tab-frame-item.hpp"
#include "widget/text-edit.hpp"
#include "widget/vertical-scroller.hpp"
#include "widget/vertical-slider.hpp"
#include "widget/viewport.hpp"
#include "application.hpp"
#undef Declare

Some files were not shown because too many files have changed in this diff Show More