mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
314aee8c5c
commit
f0c17ffc0d
|
@ -12,8 +12,7 @@ target := tomoko
|
|||
# console := true
|
||||
|
||||
# compiler
|
||||
flags += -I. -O3 -fopenmp
|
||||
link += -fopenmp
|
||||
flags += -I. -O3
|
||||
objects := libco
|
||||
|
||||
# profile-guided optimization mode
|
||||
|
@ -44,11 +43,13 @@ ifeq ($(platform),windows)
|
|||
else ifeq ($(platform),macosx)
|
||||
flags += -march=native
|
||||
else ifeq ($(platform),linux)
|
||||
flags += -march=native
|
||||
flags += -march=native -fopenmp
|
||||
link += -fopenmp
|
||||
link += -Wl,-export-dynamic
|
||||
link += -lX11 -lXext -ldl
|
||||
else ifeq ($(platform),bsd)
|
||||
flags += -march=native
|
||||
flags += -march=native -fopenmp
|
||||
link += -fopenmp
|
||||
link += -Wl,-export-dynamic
|
||||
link += -lX11 -lXext
|
||||
else
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
1 24 "higan.Manifest"
|
||||
2 ICON DISCARDABLE "higan.ico"
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Emulator {
|
||||
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 License[] = "GPLv3";
|
||||
static const char Website[] = "http://byuu.org/";
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#define Hiro_MessageWindow
|
||||
|
||||
#define Hiro_Object
|
||||
#define Hiro_Group
|
||||
|
||||
#define Hiro_Hotkey
|
||||
#define Hiro_Timer
|
||||
|
||||
|
@ -48,22 +50,22 @@
|
|||
#define Hiro_CheckButton
|
||||
#define Hiro_CheckLabel
|
||||
#define Hiro_ComboButton
|
||||
#define Hiro_Console
|
||||
//#define Hiro_Console
|
||||
#define Hiro_Frame
|
||||
#define Hiro_HexEdit
|
||||
#define Hiro_HorizontalScroller
|
||||
#define Hiro_HorizontalSlider
|
||||
#define Hiro_IconView
|
||||
//#define Hiro_IconView
|
||||
#define Hiro_Label
|
||||
#define Hiro_LineEdit
|
||||
#define Hiro_ListView
|
||||
#define Hiro_ProgressBar
|
||||
#define Hiro_RadioButton
|
||||
#define Hiro_RadioLabel
|
||||
#define Hiro_SourceView
|
||||
//#define Hiro_SourceView
|
||||
#define Hiro_TabFrame
|
||||
#define Hiro_TextEdit
|
||||
#define Hiro_TreeView
|
||||
//#define Hiro_TreeView
|
||||
#define Hiro_VerticalScroller
|
||||
#define Hiro_VerticalSlider
|
||||
#define Hiro_Viewport
|
||||
|
|
|
@ -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 {
|
||||
return state.checked;
|
||||
}
|
||||
|
@ -28,20 +14,36 @@ auto mMenuRadioItem::doActivate() const -> void {
|
|||
if(state.onActivate) return state.onActivate();
|
||||
}
|
||||
|
||||
auto mMenuRadioItem::group() const -> sGroup {
|
||||
return state.group;
|
||||
}
|
||||
|
||||
auto mMenuRadioItem::onActivate(const function<void ()>& function) -> type& {
|
||||
state.onActivate = function;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mMenuRadioItem::setChecked() -> type& {
|
||||
for(auto& weak : state.group) {
|
||||
if(auto item = weak.acquire()) item->state.checked = false;
|
||||
if(auto group = this->group()) {
|
||||
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;
|
||||
signal(setChecked);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mMenuRadioItem::setGroup(sGroup group) -> type& {
|
||||
state.group = group;
|
||||
signal(setGroup, group);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mMenuRadioItem::setText(const string& text) -> type& {
|
||||
state.text = text;
|
||||
signal(setText, text);
|
||||
|
|
|
@ -43,7 +43,10 @@ namespace hiro {
|
|||
#include "mouse.cpp"
|
||||
#include "browser-window.cpp"
|
||||
#include "message-window.cpp"
|
||||
|
||||
#include "object.cpp"
|
||||
#include "group.cpp"
|
||||
|
||||
#include "hotkey.cpp"
|
||||
#include "timer.cpp"
|
||||
#include "window.cpp"
|
||||
|
@ -80,6 +83,7 @@ namespace hiro {
|
|||
#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/radio-button.cpp"
|
||||
#include "widget/radio-label.cpp"
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace hiro {
|
|||
|
||||
Declare(Keyboard)
|
||||
Declare(Object)
|
||||
Declare(Group)
|
||||
Declare(Timer)
|
||||
Declare(Hotkey)
|
||||
Declare(Window)
|
||||
|
@ -64,6 +65,7 @@ Declare(LineEdit)
|
|||
Declare(ListView)
|
||||
Declare(ListViewColumn)
|
||||
Declare(ListViewItem)
|
||||
Declare(ListViewCell)
|
||||
Declare(ProgressBar)
|
||||
Declare(RadioButton)
|
||||
Declare(RadioLabel)
|
||||
|
@ -409,6 +411,7 @@ struct mObject {
|
|||
auto enabled(bool recursive = false) const -> bool;
|
||||
virtual auto focused() const -> bool;
|
||||
auto font(bool recursive = false) const -> string;
|
||||
virtual auto group() const -> sGroup;
|
||||
auto offset() const -> signed;
|
||||
auto offset(signed displacement) -> type&;
|
||||
auto parent() const -> mObject*;
|
||||
|
@ -417,6 +420,7 @@ struct mObject {
|
|||
auto parentIconView(bool recursive = false) const -> mIconView*;
|
||||
auto parentLayout(bool recursive = false) const -> mLayout*;
|
||||
auto parentListView(bool recursive = false) const -> mListView*;
|
||||
auto parentListViewItem(bool recursive = false) const -> mListViewItem*;
|
||||
auto parentMenu(bool recursive = false) const -> mMenu*;
|
||||
auto parentMenuBar(bool recursive = false) const -> mMenuBar*;
|
||||
auto parentPopupMenu(bool recursive = false) const -> mPopupMenu*;
|
||||
|
@ -432,6 +436,7 @@ struct mObject {
|
|||
virtual auto setEnabled(bool enabled = true) -> type&;
|
||||
virtual auto setFocused() -> 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 setVisible(bool visible = true) -> type&;
|
||||
auto visible(bool recursive = false) const -> bool;
|
||||
|
@ -453,6 +458,23 @@ struct mObject {
|
|||
};
|
||||
#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)
|
||||
struct mHotkey : mObject {
|
||||
Declare(Hotkey)
|
||||
|
@ -596,6 +618,7 @@ struct mMenuBar : mObject {
|
|||
auto remove() -> type& override;
|
||||
auto remove(sMenu menu) -> type&;
|
||||
auto reset() -> type&;
|
||||
//TODO setParent
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
|
@ -616,6 +639,7 @@ struct mPopupMenu : mObject {
|
|||
auto append(sAction action) -> type&;
|
||||
auto remove(sAction action) -> type&;
|
||||
auto reset() -> type&;
|
||||
//TODO setParent
|
||||
auto setVisible(bool visible = true) -> type& override;
|
||||
|
||||
//private:
|
||||
|
@ -651,6 +675,7 @@ struct mMenu : mAction {
|
|||
auto remove(sAction action) -> type&;
|
||||
auto reset() -> type&;
|
||||
auto setIcon(const image& icon = {}) -> type&;
|
||||
//TODO setParent
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto text() const -> string;
|
||||
|
||||
|
@ -721,17 +746,17 @@ struct mMenuRadioItem : mAction {
|
|||
|
||||
auto checked() const -> bool;
|
||||
auto doActivate() const -> void;
|
||||
auto group() const -> sGroup override;
|
||||
auto onActivate(const function<void ()>& function = {}) -> type&;
|
||||
auto setChecked() -> type&;
|
||||
auto setGroup(sGroup group = {}) -> type& override;
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto text() const -> string;
|
||||
|
||||
static auto group(const vector<wMenuRadioItem>& group) -> void;
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
bool checked = true;
|
||||
vector<wMenuRadioItem> group;
|
||||
bool checked = false;
|
||||
sGroup group;
|
||||
function<void ()> onActivate;
|
||||
string text;
|
||||
} state;
|
||||
|
@ -923,12 +948,12 @@ struct mComboButton : mWidget {
|
|||
auto remove(sComboButtonItem item) -> type&;
|
||||
auto reset() -> type&;
|
||||
auto selected() const -> sComboButtonItem;
|
||||
auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override;
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
vector<sComboButtonItem> items;
|
||||
function<void ()> onChange;
|
||||
signed selected = -1;
|
||||
} state;
|
||||
|
||||
auto destruct() -> void override;
|
||||
|
@ -950,6 +975,7 @@ struct mComboButtonItem : mObject {
|
|||
//private:
|
||||
struct State {
|
||||
image icon;
|
||||
bool selected = false;
|
||||
string text;
|
||||
} state;
|
||||
};
|
||||
|
@ -989,6 +1015,7 @@ struct mFrame : mWidget {
|
|||
auto layout() const -> sLayout;
|
||||
auto remove(sLayout layout) -> type&;
|
||||
auto reset() -> type&;
|
||||
//TODO setParent()
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto text() const -> string;
|
||||
|
||||
|
@ -1106,6 +1133,7 @@ struct mIconView : mWidget {
|
|||
auto setForegroundColor(Color color = {}) -> type&;
|
||||
auto setMultiSelect(bool multipleSelections = true) -> type&;
|
||||
auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&;
|
||||
//TODO setParent()
|
||||
auto setSelected(const vector<signed>& selections) -> type&;
|
||||
|
||||
//private:
|
||||
|
@ -1203,14 +1231,16 @@ struct mListView : mWidget {
|
|||
auto append(sListViewColumn column) -> type&;
|
||||
auto append(sListViewItem item) -> type&;
|
||||
auto backgroundColor() const -> Color;
|
||||
auto batchable() const -> bool;
|
||||
auto checkable() const -> bool;
|
||||
auto checkAll() -> type&;
|
||||
auto checked() const -> vector<sListViewItem>;
|
||||
auto column(unsigned position) const -> sListViewColumn;
|
||||
auto columns() const -> unsigned;
|
||||
auto doActivate() const -> void;
|
||||
auto doChange() 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 doToggle(sListViewItem item) const -> void;
|
||||
auto foregroundColor() const -> Color;
|
||||
|
@ -1218,45 +1248,49 @@ struct mListView : mWidget {
|
|||
auto headerVisible() const -> bool;
|
||||
auto item(unsigned position) const -> sListViewItem;
|
||||
auto items() const -> unsigned;
|
||||
auto multiSelect() const -> bool;
|
||||
auto onActivate(const function<void ()>& function = {}) -> type&;
|
||||
auto onChange(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 onToggle(const function<void (sListViewItem)>& function = {}) -> type&;
|
||||
auto remove(sListViewColumn column) -> type&;
|
||||
auto remove(sListViewItem item) -> type&;
|
||||
auto reset() -> type&;
|
||||
auto resizeColumns() -> type&;
|
||||
auto selectAll() -> type&;
|
||||
auto selected() const -> sListViewItem;
|
||||
auto selectedItems() const -> vector<sListViewItem>;
|
||||
auto setBackgroundColor(Color color = {}) -> type&;
|
||||
auto setBatchable(bool batchable = true) -> type&;
|
||||
auto setCheckable(bool checkable = true) -> type&;
|
||||
auto setChecked(bool checked = true) -> type&;
|
||||
auto setForegroundColor(Color color = {}) -> type&;
|
||||
auto setGridVisible(bool visible = true) -> type&;
|
||||
auto setHeaderVisible(bool visible = true) -> type&;
|
||||
auto setMultiSelect(bool multiSelect = true) -> type&;
|
||||
auto setSelected(bool selected = true) -> type&;
|
||||
auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& override;
|
||||
auto setSortable(bool sortable = true) -> type&;
|
||||
auto sortable() const -> bool;
|
||||
auto uncheckAll() -> type&;
|
||||
auto unselectAll() -> type&;
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
unsigned activeColumn = 0;
|
||||
Color backgroundColor;
|
||||
bool batchable = false;
|
||||
bool checkable = false;
|
||||
vector<sListViewColumn> columns;
|
||||
Color foregroundColor;
|
||||
bool gridVisible = false;
|
||||
bool headerVisible = false;
|
||||
vector<sListViewItem> items;
|
||||
bool multiSelect = false;
|
||||
function<void ()> onActivate;
|
||||
function<void ()> onChange;
|
||||
function<void ()> onContext;
|
||||
function<void (sListViewItem, sListViewColumn)> onEdit;
|
||||
function<void (sListViewCell)> onEdit;
|
||||
function<void (sListViewColumn)> onSort;
|
||||
function<void (sListViewItem)> onToggle;
|
||||
bool sortable = false;
|
||||
} state;
|
||||
|
||||
auto destruct() -> void override;
|
||||
|
@ -1270,6 +1304,7 @@ struct mListViewColumn : mObject {
|
|||
auto active() const -> bool;
|
||||
auto backgroundColor() const -> Color;
|
||||
auto editable() const -> bool;
|
||||
auto expandable() const -> bool;
|
||||
auto foregroundColor() const -> Color;
|
||||
auto horizontalAlignment() const -> double;
|
||||
auto icon() const -> image;
|
||||
|
@ -1278,17 +1313,16 @@ struct mListViewColumn : mObject {
|
|||
auto setActive() -> type&;
|
||||
auto setBackgroundColor(Color color = {}) -> type&;
|
||||
auto setEditable(bool editable = true) -> type&;
|
||||
auto setExpandable(bool expandable = true) -> type&;
|
||||
auto setFont(const string& font = "") -> type&;
|
||||
auto setForegroundColor(Color color = {}) -> type&;
|
||||
auto setHorizontalAlignment(double alignment = 0.0) -> type&;
|
||||
auto setIcon(const image& icon = {}) -> type&;
|
||||
auto setResizable(bool resizable = true) -> type&;
|
||||
auto setSortable(bool sortable = true) -> type&;
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto setVerticalAlignment(double alignment = 0.5) -> type&;
|
||||
auto setVisible(bool visible = true) -> type&;
|
||||
auto setWidth(signed width = 0) -> type&;
|
||||
auto sortable() const -> bool;
|
||||
auto text() const -> string;
|
||||
auto verticalAlignment() const -> double;
|
||||
auto width() const -> signed;
|
||||
|
@ -1297,12 +1331,12 @@ struct mListViewColumn : mObject {
|
|||
struct State {
|
||||
Color backgroundColor;
|
||||
bool editable = false;
|
||||
bool expandable = false;
|
||||
string font;
|
||||
Color foregroundColor;
|
||||
double horizontalAlignment = 0.0;
|
||||
image icon;
|
||||
bool resizable = true;
|
||||
bool sortable = false;
|
||||
string text;
|
||||
double verticalAlignment = 0.5;
|
||||
bool visible = true;
|
||||
|
@ -1315,24 +1349,52 @@ struct mListViewColumn : mObject {
|
|||
struct mListViewItem : mObject {
|
||||
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 icon(unsigned column = 0) const -> image;
|
||||
auto foregroundColor() const -> Color;
|
||||
auto remove() -> type& override;
|
||||
auto remove(sListViewCell cell) -> type&;
|
||||
auto selected() const -> bool;
|
||||
auto setBackgroundColor(Color color = {}) -> type&;
|
||||
auto setChecked(bool checked = true) -> type&;
|
||||
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 setText(const lstring& text) -> type&;
|
||||
auto setText(unsigned column, const string& text = "") -> type&;
|
||||
auto text(unsigned column = 0) const -> string;
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
Color backgroundColor;
|
||||
vector<sListViewCell> cells;
|
||||
bool checked = false;
|
||||
vector<image> icon;
|
||||
Color foregroundColor;
|
||||
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;
|
||||
};
|
||||
#endif
|
||||
|
@ -1358,23 +1420,23 @@ struct mRadioButton : mWidget {
|
|||
auto bordered() const -> bool;
|
||||
auto checked() const -> bool;
|
||||
auto doActivate() const -> void;
|
||||
auto group() const -> sGroup override;
|
||||
auto icon() const -> image;
|
||||
auto onActivate(const function<void ()>& function = {}) -> type&;
|
||||
auto orientation() const -> Orientation;
|
||||
auto setBordered(bool bordered = true) -> type&;
|
||||
auto setChecked() -> type&;
|
||||
auto setGroup(sGroup group = {}) -> type& override;
|
||||
auto setIcon(const image& icon = {}) -> type&;
|
||||
auto setOrientation(Orientation orientation = Orientation::Horizontal) -> type&;
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto text() const -> string;
|
||||
|
||||
static auto group(const vector<wRadioButton>& group) -> void;
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
bool bordered = true;
|
||||
bool checked = true;
|
||||
vector<wRadioButton> group;
|
||||
bool checked = false;
|
||||
sGroup group;
|
||||
image icon;
|
||||
function<void ()> onActivate;
|
||||
Orientation orientation = Orientation::Horizontal;
|
||||
|
@ -1389,17 +1451,17 @@ struct mRadioLabel : mWidget {
|
|||
|
||||
auto checked() const -> bool;
|
||||
auto doActivate() const -> void;
|
||||
auto group() const -> sGroup override;
|
||||
auto onActivate(const function<void ()>& function = {}) -> type&;
|
||||
auto setChecked() -> type&;
|
||||
auto setGroup(sGroup group = {}) -> type& override;
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto text() const -> string;
|
||||
|
||||
static auto group(const vector<wRadioLabel>& group) -> void;
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
bool checked = true;
|
||||
vector<wRadioLabel> group;
|
||||
bool checked = false;
|
||||
sGroup group;
|
||||
function<void ()> onActivate;
|
||||
string text;
|
||||
} state;
|
||||
|
@ -1460,7 +1522,6 @@ struct mTabFrame : mWidget {
|
|||
function<void ()> onChange;
|
||||
function<void (sTabFrameItem)> onClose;
|
||||
function<void (sTabFrameItem, sTabFrameItem)> onMove;
|
||||
unsigned selected = 0;
|
||||
} state;
|
||||
|
||||
auto destruct() -> void override;
|
||||
|
@ -1494,6 +1555,7 @@ struct mTabFrameItem : mObject {
|
|||
image icon;
|
||||
sLayout layout;
|
||||
bool movable = false;
|
||||
bool selected = false;
|
||||
string text;
|
||||
} state;
|
||||
|
||||
|
@ -1563,6 +1625,7 @@ struct mTreeView : mWidget {
|
|||
auto setBackgroundColor(Color color = {}) -> type&;
|
||||
auto setCheckable(bool checkable = true) -> type&;
|
||||
auto setForegroundColor(Color color = {}) -> type&;
|
||||
//TODO setParent
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
|
@ -1597,6 +1660,7 @@ struct mTreeViewItem : mObject {
|
|||
auto setChecked(bool checked = true) -> type&;
|
||||
auto setFocused() -> type& override;
|
||||
auto setIcon(const image& icon = {}) -> type&;
|
||||
//TODO setParent
|
||||
auto setSelected() -> type&;
|
||||
auto setText(const string& text = "") -> type&;
|
||||
auto text() const -> string;
|
||||
|
|
|
@ -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
|
|
@ -31,10 +31,18 @@ auto mObject::destruct() -> void {
|
|||
//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
|
||||
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;
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_PopupMenu)
|
||||
if(dynamic_cast<const mPopupMenu*>(this)) return false;
|
||||
#endif
|
||||
|
||||
if(auto object = parent()) return object->abstract();
|
||||
return true;
|
||||
}
|
||||
|
@ -56,6 +64,10 @@ auto mObject::font(bool recursive) const -> string {
|
|||
return Application::font();
|
||||
}
|
||||
|
||||
auto mObject::group() const -> sGroup {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto mObject::offset() const -> signed {
|
||||
return state.offset;
|
||||
}
|
||||
|
@ -119,6 +131,16 @@ auto mObject::parentListView(bool recursive) const -> mListView* {
|
|||
}
|
||||
#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)
|
||||
auto mObject::parentMenu(bool recursive) const -> mMenu* {
|
||||
if(auto menu = dynamic_cast<mMenu*>(parent())) return menu;
|
||||
|
@ -246,6 +268,10 @@ auto mObject::setFont(const string& font) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mObject::setGroup(sGroup group) -> type& {
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mObject::setParent(mObject* parent, signed offset) -> type& {
|
||||
destruct();
|
||||
state.parent = parent;
|
||||
|
|
|
@ -16,8 +16,7 @@ auto mComboButtonItem::remove() -> type& {
|
|||
}
|
||||
|
||||
auto mComboButtonItem::selected() const -> bool {
|
||||
if(auto comboButton = parentComboButton()) return comboButton->state.selected == offset();
|
||||
return false;
|
||||
return state.selected;
|
||||
}
|
||||
|
||||
auto mComboButtonItem::setIcon(const image& icon) -> type& {
|
||||
|
@ -28,9 +27,10 @@ auto mComboButtonItem::setIcon(const image& icon) -> type& {
|
|||
|
||||
auto mComboButtonItem::setSelected() -> type& {
|
||||
if(auto parent = parentComboButton()) {
|
||||
parent->state.selected = offset();
|
||||
signal(setSelected);
|
||||
for(auto& item : parent->state.items) item->state.selected = false;
|
||||
}
|
||||
state.selected = true;
|
||||
signal(setSelected);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ auto mComboButton::append(sComboButtonItem item) -> type& {
|
|||
state.items.append(item);
|
||||
item->setParent(this, items() - 1);
|
||||
signal(append, item);
|
||||
if(state.selected < 0) item->setSelected();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -49,17 +48,23 @@ auto mComboButton::remove(sComboButtonItem item) -> type& {
|
|||
|
||||
auto mComboButton::reset() -> type& {
|
||||
signal(reset);
|
||||
for(auto& item : state.items) {
|
||||
item->setParent();
|
||||
}
|
||||
for(auto& item : state.items) item->setParent();
|
||||
state.items.reset();
|
||||
state.selected = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -19,6 +19,10 @@ auto mListViewColumn::editable() const -> bool {
|
|||
return state.editable;
|
||||
}
|
||||
|
||||
auto mListViewColumn::expandable() const -> bool {
|
||||
return state.expandable;
|
||||
}
|
||||
|
||||
auto mListViewColumn::foregroundColor() const -> Color {
|
||||
return state.foregroundColor;
|
||||
}
|
||||
|
@ -58,6 +62,12 @@ auto mListViewColumn::setEditable(bool editable) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewColumn::setExpandable(bool expandable) -> type& {
|
||||
state.expandable = expandable;
|
||||
signal(setExpandable, expandable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewColumn::setFont(const string& font) -> type& {
|
||||
state.font = font;
|
||||
signal(setFont, this->font(true));
|
||||
|
@ -89,12 +99,6 @@ auto mListViewColumn::setResizable(bool resizable) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewColumn::setSortable(bool sortable) -> type& {
|
||||
state.sortable = sortable;
|
||||
signal(setSortable, sortable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewColumn::setText(const string& text) -> type& {
|
||||
state.text = text;
|
||||
signal(setText, text);
|
||||
|
@ -115,15 +119,11 @@ auto mListViewColumn::setVisible(bool visible) -> type& {
|
|||
}
|
||||
|
||||
auto mListViewColumn::setWidth(signed width) -> type& {
|
||||
state.width = width;
|
||||
state.width = max(0, width);
|
||||
signal(setWidth, width);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewColumn::sortable() const -> bool {
|
||||
return state.sortable;
|
||||
}
|
||||
|
||||
auto mListViewColumn::text() const -> string {
|
||||
return state.text;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
return state.checked;
|
||||
}
|
||||
|
||||
auto mListViewItem::icon(unsigned column) const -> image {
|
||||
return state.icon(column, {});
|
||||
auto mListViewItem::foregroundColor() const -> Color {
|
||||
return state.foregroundColor;
|
||||
}
|
||||
|
||||
auto mListViewItem::remove() -> type& {
|
||||
|
@ -19,10 +39,26 @@ auto mListViewItem::remove() -> type& {
|
|||
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 {
|
||||
return state.selected;
|
||||
}
|
||||
|
||||
auto mListViewItem::setBackgroundColor(Color color) -> type& {
|
||||
state.backgroundColor = color;
|
||||
signal(setBackgroundColor, color);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewItem::setChecked(bool checked) -> type& {
|
||||
state.checked = checked;
|
||||
signal(setChecked, checked);
|
||||
|
@ -34,9 +70,16 @@ auto mListViewItem::setFocused() -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListViewItem::setIcon(unsigned column, const image& icon) -> type& {
|
||||
state.icon(column) = icon;
|
||||
signal(setIcon, column, icon);
|
||||
auto mListViewItem::setForegroundColor(Color color) -> type& {
|
||||
state.foregroundColor = color;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -46,24 +89,4 @@ auto mListViewItem::setSelected(bool selected) -> type& {
|
|||
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
|
||||
|
|
|
@ -30,10 +30,20 @@ auto mListView::backgroundColor() const -> Color {
|
|||
return state.backgroundColor;
|
||||
}
|
||||
|
||||
auto mListView::batchable() const -> bool {
|
||||
return state.batchable;
|
||||
}
|
||||
|
||||
auto mListView::checkable() const -> bool {
|
||||
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> {
|
||||
vector<sListViewItem> items;
|
||||
for(auto& item : state.items) {
|
||||
|
@ -63,8 +73,8 @@ auto mListView::doContext() const -> void {
|
|||
if(state.onContext) return state.onContext();
|
||||
}
|
||||
|
||||
auto mListView::doEdit(sListViewItem item, sListViewColumn column) const -> void {
|
||||
if(state.onEdit) return state.onEdit(item, column);
|
||||
auto mListView::doEdit(sListViewCell cell) const -> void {
|
||||
if(state.onEdit) return state.onEdit(cell);
|
||||
}
|
||||
|
||||
auto mListView::doSort(sListViewColumn column) const -> void {
|
||||
|
@ -96,10 +106,6 @@ auto mListView::items() const -> unsigned {
|
|||
return state.items.size();
|
||||
}
|
||||
|
||||
auto mListView::multiSelect() const -> bool {
|
||||
return state.multiSelect;
|
||||
}
|
||||
|
||||
auto mListView::onActivate(const function<void ()>& function) -> type& {
|
||||
state.onActivate = function;
|
||||
return *this;
|
||||
|
@ -115,7 +121,7 @@ auto mListView::onContext(const function<void ()>& function) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListView::onEdit(const function<void (sListViewItem, sListViewColumn)>& function) -> type& {
|
||||
auto mListView::onEdit(const function<void (sListViewCell)>& function) -> type& {
|
||||
state.onEdit = function;
|
||||
return *this;
|
||||
}
|
||||
|
@ -154,10 +160,10 @@ auto mListView::remove(sListViewItem item) -> type& {
|
|||
|
||||
auto mListView::reset() -> type& {
|
||||
signal(reset);
|
||||
for(auto& column : state.columns) column->setParent();
|
||||
state.columns.reset();
|
||||
for(auto& item : state.items) item->setParent();
|
||||
state.items.reset();
|
||||
for(auto& column : state.columns) column->setParent();
|
||||
state.columns.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -166,6 +172,12 @@ auto mListView::resizeColumns() -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListView::selectAll() -> type& {
|
||||
for(auto& item : state.items) item->state.selected = true;
|
||||
signal(selectAll);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListView::selected() const -> sListViewItem {
|
||||
for(auto& item : state.items) {
|
||||
if(item->selected()) return item;
|
||||
|
@ -187,15 +199,15 @@ auto mListView::setBackgroundColor(Color color) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListView::setCheckable(bool checkable) -> type& {
|
||||
state.checkable = checkable;
|
||||
signal(setCheckable, checkable);
|
||||
auto mListView::setBatchable(bool batchable) -> type& {
|
||||
state.batchable = batchable;
|
||||
signal(setBatchable, batchable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mListView::setChecked(bool checked) -> type& {
|
||||
for(auto& item : state.items) item->state.checked = checked;
|
||||
signal(setChecked, checked);
|
||||
auto mListView::setCheckable(bool checkable) -> type& {
|
||||
state.checkable = checkable;
|
||||
signal(setCheckable, checkable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -217,15 +229,34 @@ auto mListView::setHeaderVisible(bool visible) -> type& {
|
|||
return *this;
|
||||
}
|
||||
|
||||
auto mListView::setMultiSelect(bool multiSelect) -> type& {
|
||||
state.multiSelect = multiSelect;
|
||||
signal(setMultiSelect, multiSelect);
|
||||
auto mListView::setParent(mObject* parent, signed offset) -> type& {
|
||||
for(auto& item : state.items) item->destruct();
|
||||
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;
|
||||
}
|
||||
|
||||
auto mListView::setSelected(bool selected) -> type& {
|
||||
for(auto& item : state.items) item->state.selected = selected;
|
||||
signal(setSelected, selected);
|
||||
auto mListView::setSortable(bool sortable) -> type& {
|
||||
state.sortable = sortable;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
return state.bordered;
|
||||
}
|
||||
|
@ -32,6 +18,10 @@ auto mRadioButton::doActivate() const -> void {
|
|||
if(state.onActivate) return state.onActivate();
|
||||
}
|
||||
|
||||
auto mRadioButton::group() const -> sGroup {
|
||||
return state.group;
|
||||
}
|
||||
|
||||
auto mRadioButton::icon() const -> image {
|
||||
return state.icon;
|
||||
}
|
||||
|
@ -52,14 +42,26 @@ auto mRadioButton::setBordered(bool bordered) -> type& {
|
|||
}
|
||||
|
||||
auto mRadioButton::setChecked() -> type& {
|
||||
for(auto& weak : state.group) {
|
||||
if(auto item = weak.acquire()) item->state.checked = false;
|
||||
if(auto group = this->group()) {
|
||||
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;
|
||||
signal(setChecked);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mRadioButton::setGroup(sGroup group) -> type& {
|
||||
state.group = group;
|
||||
signal(setGroup, group);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mRadioButton::setIcon(const image& icon) -> type& {
|
||||
state.icon = icon;
|
||||
signal(setIcon, icon);
|
||||
|
|
|
@ -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 {
|
||||
return state.checked;
|
||||
}
|
||||
|
@ -28,20 +14,36 @@ auto mRadioLabel::doActivate() const -> void {
|
|||
if(state.onActivate) return state.onActivate();
|
||||
}
|
||||
|
||||
auto mRadioLabel::group() const -> sGroup {
|
||||
return state.group;
|
||||
}
|
||||
|
||||
auto mRadioLabel::onActivate(const function<void ()>& function) -> type& {
|
||||
state.onActivate = function;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mRadioLabel::setChecked() -> type& {
|
||||
for(auto& weak : state.group) {
|
||||
if(auto item = weak.acquire()) item->state.checked = false;
|
||||
if(auto group = this->group()) {
|
||||
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;
|
||||
signal(setChecked);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mRadioLabel::setGroup(sGroup group) -> type& {
|
||||
state.group = group;
|
||||
signal(setGroup, group);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto mRadioLabel::setText(const string& text) -> type& {
|
||||
state.text = text;
|
||||
signal(setText, text);
|
||||
|
|
|
@ -15,6 +15,7 @@ auto mTabFrameItem::append(sLayout layout) -> type& {
|
|||
if(auto& layout = state.layout) remove(layout);
|
||||
state.layout = layout;
|
||||
layout->setParent(this, 0);
|
||||
signal(append, layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -40,8 +41,9 @@ auto mTabFrameItem::remove() -> type& {
|
|||
}
|
||||
|
||||
auto mTabFrameItem::remove(sLayout layout) -> type& {
|
||||
layout->setParent();
|
||||
signal(remove, layout);
|
||||
state.layout.reset();
|
||||
layout->setParent();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -51,8 +53,7 @@ auto mTabFrameItem::reset() -> type& {
|
|||
}
|
||||
|
||||
auto mTabFrameItem::selected() const -> bool {
|
||||
if(auto tabFrame = parentTabFrame()) return offset() == tabFrame->state.selected;
|
||||
return false;
|
||||
return state.selected;
|
||||
}
|
||||
|
||||
auto mTabFrameItem::setClosable(bool closable) -> type& {
|
||||
|
@ -81,7 +82,10 @@ auto mTabFrameItem::setParent(mObject* parent, signed offset) -> 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);
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,10 @@ auto mTabFrame::reset() -> type& {
|
|||
}
|
||||
|
||||
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& {
|
||||
|
|
|
@ -19,6 +19,7 @@ auto mWindow::append(shared_pointer<mLayout> layout) -> type& {
|
|||
layout->setGeometry(geometry().setPosition(0, 0));
|
||||
layout->setParent(this, 0);
|
||||
layout->setGeometry(geometry().setPosition(0, 0));
|
||||
signal(append, layout);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -129,6 +130,7 @@ auto mWindow::onSize(const function<void ()>& function) -> type& {
|
|||
}
|
||||
|
||||
auto mWindow::remove(shared_pointer<mLayout> layout) -> type& {
|
||||
signal(remove, layout);
|
||||
layout->setParent();
|
||||
state.layout.reset();
|
||||
return *this;
|
||||
|
|
|
@ -35,27 +35,27 @@ auto BrowserDialogWindow::accept() -> void {
|
|||
auto selectedItems = view.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});
|
||||
state.response.append(string{state.path, name});
|
||||
}
|
||||
|
||||
if(state.action == "openFiles") {
|
||||
for(auto selectedItem : selectedItems) {
|
||||
string name = selectedItem->text(0);
|
||||
string name = selectedItem->cell(0)->text();
|
||||
state.response.append(string{state.path, name, isFolder(name) ? "/" : ""});
|
||||
}
|
||||
}
|
||||
|
||||
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});
|
||||
state.response.append(string{state.path, name, "/"});
|
||||
}
|
||||
|
||||
if(state.action == "saveFile") {
|
||||
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(file::exists({state.path, name})) {
|
||||
if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return;
|
||||
|
@ -64,7 +64,7 @@ auto BrowserDialogWindow::accept() -> void {
|
|||
}
|
||||
|
||||
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, "/"});
|
||||
}
|
||||
|
||||
|
@ -76,13 +76,13 @@ auto BrowserDialogWindow::activate() -> void {
|
|||
auto selectedItem = view.selected();
|
||||
|
||||
if(state.action == "saveFile" && selectedItem) {
|
||||
string name = selectedItem->text(0);
|
||||
string name = selectedItem->cell(0)->text();
|
||||
if(isFolder(name)) return setPath({state.path, name});
|
||||
fileName.setText(name);
|
||||
}
|
||||
|
||||
if(state.action == "selectFolder" && selectedItem) {
|
||||
string name = selectedItem->text(0);
|
||||
string name = selectedItem->cell(0)->text();
|
||||
if(isFolder(name)) return setPath({state.path, name});
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ auto BrowserDialogWindow::change() -> void {
|
|||
fileName.setText("");
|
||||
if(state.action == "saveFile") {
|
||||
if(auto selectedItem = view.selected()) {
|
||||
string name = selectedItem->text(0);
|
||||
string name = selectedItem->cell(0)->text();
|
||||
if(!isFolder(name)) fileName.setText(name);
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ auto BrowserDialogWindow::run() -> lstring {
|
|||
pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); });
|
||||
pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); });
|
||||
pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); });
|
||||
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); });
|
||||
for(auto& filter : state.filters) {
|
||||
auto part = filter.split<1>("|");
|
||||
|
@ -161,8 +161,8 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
pathName.setText(state.path = path);
|
||||
|
||||
view.reset();
|
||||
view.append(ListViewColumn().setWidth(~0));
|
||||
view.append(ListViewColumn().setWidth( 0).setForegroundColor({192, 128, 128}));
|
||||
view.append(ListViewColumn().setExpandable());
|
||||
view.append(ListViewColumn().setForegroundColor({192, 128, 128}));
|
||||
|
||||
auto contents = directory::contents(path);
|
||||
bool folderMode = state.action == "openFolder";
|
||||
|
@ -171,20 +171,20 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
|||
if(!content.endsWith("/")) continue;
|
||||
if(folderMode && isMatch(content.rtrim("/"))) continue;
|
||||
|
||||
ListViewItem item{&view};
|
||||
item.setIcon(0, Icon::Emblem::Folder);
|
||||
item.setText(0, content.rtrim("/"));
|
||||
item.setText(1, octal<3>(storage::mode({path, content}) & 0777));
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content.rtrim("/")).setIcon(Icon::Emblem::Folder))
|
||||
.append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777)))
|
||||
);
|
||||
}
|
||||
|
||||
for(auto content : contents) {
|
||||
if(content.endsWith("/") && !folderMode) continue;
|
||||
if(!isMatch(content.rtrim("/"))) continue;
|
||||
|
||||
ListViewItem item{&view};
|
||||
item.setIcon(0, folderMode ? Icon::Action::Open : Icon::Emblem::File);
|
||||
item.setText(0, content.rtrim("/"));
|
||||
item.setText(1, octal<3>(storage::mode({path, content}) & 0777));
|
||||
view.append(ListViewItem()
|
||||
.append(ListViewCell().setText(content.rtrim("/")).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File))
|
||||
.append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777)))
|
||||
);
|
||||
}
|
||||
|
||||
if(view.items()) view.item(0)->setSelected();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#define Declare(Name) \
|
||||
using type = Name; \
|
||||
Name() : s##Name(new m##Name, [](m##Name* p) { \
|
||||
Name() : s##Name(new m##Name, [](auto p) { \
|
||||
p->unbind(); \
|
||||
delete p; \
|
||||
}) { \
|
||||
|
@ -51,6 +51,27 @@ struct Object : sObject {
|
|||
};
|
||||
#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)
|
||||
struct Hotkey : sHotkey {
|
||||
DeclareObject(Hotkey)
|
||||
|
@ -222,16 +243,11 @@ struct MenuRadioItem : sMenuRadioItem {
|
|||
|
||||
auto checked() const -> bool { return self().checked(); }
|
||||
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 setChecked() -> type& { return self().setChecked(), *this; }
|
||||
auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
|
||||
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
|
||||
|
||||
|
@ -345,6 +361,7 @@ struct ComboButton : sComboButton {
|
|||
auto remove(sComboButtonItem item) -> type& { return self().remove(item), *this; }
|
||||
auto reset() -> type& { return self().reset(), *this; }
|
||||
auto selected() const -> sComboButtonItem { return self().selected(); }
|
||||
auto setParent(mObject* parent = nullptr, signed offset = -1) -> type& { return self().setParent(parent, offset), *this; }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -524,14 +541,16 @@ struct ListView : sListView {
|
|||
auto append(sListViewColumn column) -> type& { return self().append(column), *this; }
|
||||
auto append(sListViewItem item) -> type& { return self().append(item), *this; }
|
||||
auto backgroundColor() const -> Color { return self().backgroundColor(); }
|
||||
auto batchable() const -> bool { return self().batchable(); }
|
||||
auto checkable() const -> bool { return self().checkable(); }
|
||||
auto checkAll() -> type& { return self().checkAll(), *this; }
|
||||
auto checked() const -> vector<sListViewItem> { return self().checked(); }
|
||||
auto column(unsigned position) -> sListViewColumn { return self().column(position); }
|
||||
auto columns() const -> unsigned { return self().columns(); }
|
||||
auto doActivate() const -> void { return self().doActivate(); }
|
||||
auto doChange() const -> void { return self().doChange(); }
|
||||
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 doToggle(sListViewItem item) const -> void { return self().doToggle(item); }
|
||||
auto foregroundColor() const -> Color { return self().foregroundColor(); }
|
||||
|
@ -539,27 +558,29 @@ struct ListView : sListView {
|
|||
auto headerVisible() const -> bool { return self().headerVisible(); }
|
||||
auto item(unsigned position) -> sListViewItem { return self().item(position); }
|
||||
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 onChange(const function<void ()>& function = {}) -> type& { return self().onChange(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 onToggle(const function<void (sListViewItem)>& function = {}) -> type& { return self().onToggle(function), *this; }
|
||||
auto remove(sListViewColumn column) -> type& { return self().remove(column), *this; }
|
||||
auto remove(sListViewItem item) -> type& { return self().remove(item), *this; }
|
||||
auto reset() -> type& { return self().reset(), *this; }
|
||||
auto resizeColumns() -> type& { return self().resizeColumns(), *this; }
|
||||
auto selectAll() -> type& { return self().selectAll(), *this; }
|
||||
auto selected() const -> sListViewItem { return self().selected(); }
|
||||
auto selectedItems() const -> vector<sListViewItem> { return self().selectedItems(); }
|
||||
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 setChecked(bool checked = true) -> type& { return self().setChecked(checked), *this; }
|
||||
auto setForegroundColor(Color color = {}) -> type& { return self().setForegroundColor(color), *this; }
|
||||
auto setGridVisible(bool visible = true) -> type& { return self().setGridVisible(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 setSelected(bool selected = true) -> type& { return self().setSelected(selected), *this; }
|
||||
auto setSortable(bool sortable = true) -> type& { return self().setSortable(sortable), *this; }
|
||||
auto sortable() const -> bool { return self().sortable(); }
|
||||
auto uncheckAll() -> type& { return self().uncheckAll(), *this; }
|
||||
auto unselectAll() -> type& { return self().unselectAll(), *this; }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -570,6 +591,7 @@ struct ListViewColumn : sListViewColumn {
|
|||
auto active() const -> bool { return self().active(); }
|
||||
auto backgroundColor() const -> Color { return self().backgroundColor(); }
|
||||
auto editable() const -> bool { return self().editable(); }
|
||||
auto expandable() const -> bool { return self().expandable(); }
|
||||
auto foregroundColor() const -> Color { return self().foregroundColor(); }
|
||||
auto horizontalAlignment() const -> double { return self().horizontalAlignment(); }
|
||||
auto icon() const -> image { return self().icon(); }
|
||||
|
@ -577,15 +599,14 @@ struct ListViewColumn : sListViewColumn {
|
|||
auto setActive() -> type& { return self().setActive(), *this; }
|
||||
auto setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *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 setHorizontalAlignment(double alignment = 0.0) -> type& { return self().setHorizontalAlignment(alignment), *this; }
|
||||
auto setIcon(const image& icon = {}) -> type& { return self().setIcon(icon), *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 setVerticalAlignment(double alignment = 0.5) -> type& { return self().setVerticalAlignment(alignment), *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 verticalAlignment() const -> double { return self().verticalAlignment(); }
|
||||
auto width() const -> signed { return self().width(); }
|
||||
|
@ -596,15 +617,33 @@ struct ListViewColumn : sListViewColumn {
|
|||
struct ListViewItem : sListViewItem {
|
||||
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 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 setBackgroundColor(Color color = {}) -> type& { return self().setBackgroundColor(color), *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 setText(const lstring& text) -> type& { return self().setText(text), *this; }
|
||||
auto setText(unsigned column, const string& text = "") -> type& { return self().setText(column, text), *this; }
|
||||
auto text(unsigned column = 0) const -> string { return self().text(column); }
|
||||
};
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
|
@ -624,6 +663,7 @@ struct RadioButton : sRadioButton {
|
|||
auto bordered() const -> bool { return self().bordered(); }
|
||||
auto checked() const -> bool { return self().checked(); }
|
||||
auto doActivate() const -> void { return self().doActivate(); }
|
||||
auto group() const -> sGroup { return self().group(); }
|
||||
auto icon() const -> image { return self().icon(); }
|
||||
auto onActivate(const function<void ()>& function = {}) -> type& { return self().onActivate(function), *this; }
|
||||
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 setText(const string& text = "") -> type& { return self().setText(text), *this; }
|
||||
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
|
||||
|
||||
|
@ -648,16 +682,11 @@ struct RadioLabel : sRadioLabel {
|
|||
|
||||
auto checked() const -> bool { return self().checked(); }
|
||||
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 setChecked() -> type& { return self().setChecked(), *this; }
|
||||
auto setText(const string& text = "") -> type& { return self().setText(text), *this; }
|
||||
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
|
||||
|
||||
|
|
|
@ -8,13 +8,11 @@ static auto MenuRadioItem_activate(GtkCheckMenuItem* gtkCheckMenuItem, pMenuRadi
|
|||
|
||||
auto pMenuRadioItem::construct() -> void {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -23,55 +21,54 @@ auto pMenuRadioItem::destruct() -> void {
|
|||
}
|
||||
|
||||
auto pMenuRadioItem::setChecked() -> void {
|
||||
_parent().lock();
|
||||
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), false);
|
||||
}
|
||||
}
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(widget), true);
|
||||
_parent().unlock();
|
||||
lock();
|
||||
gtk_check_menu_item_set_active(gtkCheckMenuItem, true);
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pMenuRadioItem::setGroup(const vector<shared_pointer_weak<mMenuRadioItem>>& group) -> void {
|
||||
_parent().lock();
|
||||
shared_pointer<mMenuRadioItem> first;
|
||||
for(auto& weak : group) {
|
||||
if(!first) {
|
||||
first = weak.acquire();
|
||||
continue;
|
||||
}
|
||||
if(auto item = weak.acquire()) {
|
||||
if(item->self() && first->self()) {
|
||||
GSList* currentGroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(first->self()->widget));
|
||||
if(currentGroup != gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item->self()->widget))) {
|
||||
gtk_radio_menu_item_set_group(GTK_RADIO_MENU_ITEM(item->self()->widget), currentGroup);
|
||||
auto pMenuRadioItem::setGroup(sGroup group) -> void {
|
||||
if(!group) return;
|
||||
|
||||
maybe<GtkRadioMenuItem*> gtkRadioMenuItem;
|
||||
for(auto& weak : group->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
if(auto menuRadioItem = dynamic_cast<mMenuRadioItem*>(object.data())) {
|
||||
if(auto self = menuRadioItem->self()) {
|
||||
self->lock();
|
||||
gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, nullptr);
|
||||
if(!gtkRadioMenuItem) gtkRadioMenuItem = self->gtkRadioMenuItem;
|
||||
else gtk_radio_menu_item_set_group(self->gtkRadioMenuItem, gtk_radio_menu_item_get_group(*gtkRadioMenuItem));
|
||||
gtk_check_menu_item_set_active(self->gtkCheckMenuItem, menuRadioItem->checked());
|
||||
self->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_parent().unlock();
|
||||
}
|
||||
|
||||
auto pMenuRadioItem::setText(const string& text) -> void {
|
||||
gtk_menu_item_set_label(GTK_MENU_ITEM(widget), _mnemonic(text));
|
||||
}
|
||||
|
||||
auto pMenuRadioItem::_doActivate() -> void {
|
||||
if(!_parent().locked()) {
|
||||
bool wasChecked = state().checked;
|
||||
self().setChecked();
|
||||
if(!wasChecked) self().doActivate();
|
||||
auto pMenuRadioItem::groupLocked() const -> bool {
|
||||
if(auto group = state().group) {
|
||||
for(auto& weak : group->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
if(auto self = object->self()) {
|
||||
if(self->locked()) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return locked();
|
||||
}
|
||||
|
||||
auto pMenuRadioItem::_parent() -> pMenuRadioItem& {
|
||||
if(state().group.size()) {
|
||||
if(auto item = state().group.first().acquire()) {
|
||||
if(item->self()) return *item->self();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
auto pMenuRadioItem::_doActivate() -> void {
|
||||
if(groupLocked()) return;
|
||||
bool wasChecked = state().checked;
|
||||
self().setChecked();
|
||||
if(!wasChecked) self().doActivate();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,11 +6,15 @@ struct pMenuRadioItem : pAction {
|
|||
Declare(MenuRadioItem, Action)
|
||||
|
||||
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 groupLocked() const -> bool;
|
||||
|
||||
auto _doActivate() -> void;
|
||||
auto _parent() -> pMenuRadioItem&;
|
||||
|
||||
GtkCheckMenuItem* gtkCheckMenuItem = nullptr;
|
||||
GtkRadioMenuItem* gtkRadioMenuItem = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -2,31 +2,31 @@
|
|||
|
||||
namespace hiro {
|
||||
|
||||
string pFont::serif(unsigned size, string style) {
|
||||
auto pFont::serif(unsigned size, string style) -> string {
|
||||
if(size == 0) size = 8;
|
||||
if(style == "") style = "Normal";
|
||||
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(style == "") style = "Normal";
|
||||
return {"Sans, ", size, ", ", style};
|
||||
}
|
||||
|
||||
string pFont::monospace(unsigned size, string style) {
|
||||
auto pFont::monospace(unsigned size, string style) -> string {
|
||||
if(size == 0) size = 8;
|
||||
return {"Liberation Mono, ", size, ", ", style};
|
||||
}
|
||||
|
||||
Size pFont::size(string font, string text) {
|
||||
auto pFont::size(string font, string text) -> Size {
|
||||
PangoFontDescription* description = create(font);
|
||||
Size size = pFont::size(description, text);
|
||||
free(description);
|
||||
return size;
|
||||
}
|
||||
|
||||
PangoFontDescription* pFont::create(string description) {
|
||||
auto pFont::create(string description) -> PangoFontDescription* {
|
||||
lstring part = description.split<2>(",").strip();
|
||||
|
||||
string family = "Sans";
|
||||
|
@ -47,11 +47,11 @@ PangoFontDescription* pFont::create(string description) {
|
|||
return font;
|
||||
}
|
||||
|
||||
void pFont::free(PangoFontDescription* font) {
|
||||
auto pFont::free(PangoFontDescription* font) -> void {
|
||||
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());
|
||||
PangoLayout* layout = pango_layout_new(context);
|
||||
pango_layout_set_font_description(layout, font);
|
||||
|
@ -62,13 +62,13 @@ Size pFont::size(PangoFontDescription* font, string text) {
|
|||
return {width, height};
|
||||
}
|
||||
|
||||
void pFont::setFont(GtkWidget* widget, string font) {
|
||||
auto pFont::setFont(GtkWidget* widget, string font) -> void {
|
||||
auto gtkFont = pFont::create(font);
|
||||
pFont::setFont(widget, (gpointer)gtkFont);
|
||||
pFont::free(gtkFont);
|
||||
}
|
||||
|
||||
void pFont::setFont(GtkWidget* widget, gpointer font) {
|
||||
auto pFont::setFont(GtkWidget* widget, gpointer font) -> void {
|
||||
if(font == nullptr) return;
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
namespace hiro {
|
||||
|
||||
struct pFont {
|
||||
static string serif(unsigned size, string style);
|
||||
static string sans(unsigned size, string style);
|
||||
static string monospace(unsigned size, string style);
|
||||
static Size size(string font, string text);
|
||||
static auto serif(unsigned size, string style) -> string;
|
||||
static auto sans(unsigned size, string style) -> string;
|
||||
static auto monospace(unsigned size, string style) -> string;
|
||||
static auto size(string font, string text) -> Size;
|
||||
|
||||
static PangoFontDescription* create(string description);
|
||||
static void free(PangoFontDescription* font);
|
||||
static Size size(PangoFontDescription* font, string text);
|
||||
static void setFont(GtkWidget* widget, string font);
|
||||
static void setFont(GtkWidget* widget, gpointer font);
|
||||
static auto create(string description) -> PangoFontDescription*;
|
||||
static auto free(PangoFontDescription* font) -> void;
|
||||
static auto size(PangoFontDescription* font, string text) -> Size;
|
||||
static auto setFont(GtkWidget* widget, string font) -> void;
|
||||
static auto setFont(GtkWidget* widget, gpointer font) -> void;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#if defined(Hiro_Group)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
auto pGroup::construct() -> void {
|
||||
}
|
||||
|
||||
auto pGroup::destruct() -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
#if defined(Hiro_Group)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pGroup : pObject {
|
||||
Declare(Group, Object)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -240,7 +240,7 @@ auto pKeyboard::initialize() -> void {
|
|||
#include <hiro/platform/xorg/keyboard.hpp>
|
||||
#endif
|
||||
|
||||
//print("[phoenix/gtk] warning: unhandled key: ", key, "\n");
|
||||
//print("[hiro/gtk] warning: unhandled key: ", key, "\n");
|
||||
append(0);
|
||||
}
|
||||
#undef map
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
#include "mouse.cpp"
|
||||
#include "browser-window.cpp"
|
||||
#include "message-window.cpp"
|
||||
|
||||
#include "object.cpp"
|
||||
#include "group.cpp"
|
||||
|
||||
#include "hotkey.cpp"
|
||||
#include "timer.cpp"
|
||||
#include "window.cpp"
|
||||
|
@ -45,6 +48,7 @@
|
|||
#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/radio-button.cpp"
|
||||
#include "widget/radio-label.cpp"
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace hiro {
|
|||
struct pMenu;
|
||||
struct pLayout;
|
||||
struct pWidget;
|
||||
};
|
||||
}
|
||||
|
||||
#define Declare(Name, Base) \
|
||||
p##Name(m##Name& reference) : p##Base(reference) {} \
|
||||
|
@ -19,7 +19,10 @@ namespace hiro {
|
|||
#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"
|
||||
|
@ -56,6 +59,7 @@ namespace hiro {
|
|||
#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"
|
||||
|
|
|
@ -12,6 +12,8 @@ static auto CreateColor(const Color& color) -> GdkColor {
|
|||
#endif
|
||||
|
||||
static auto CreatePixbuf(const nall::image& image, bool scale = false) -> GdkPixbuf* {
|
||||
if(!image) return nullptr;
|
||||
|
||||
nall::image gdkImage = image;
|
||||
gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16);
|
||||
if(scale) gdkImage.scale(15, 15);
|
||||
|
|
|
@ -8,17 +8,12 @@ auto pComboButtonItem::construct() -> void {
|
|||
auto pComboButtonItem::destruct() -> void {
|
||||
}
|
||||
|
||||
auto pComboButtonItem::setIcon(const image& icon) -> void {
|
||||
auto pComboButtonItem::setIcon(image icon) -> void {
|
||||
if(auto parent = _parent()) {
|
||||
if(icon) {
|
||||
auto copy = icon;
|
||||
auto size = pFont::size(self().font(true), " ").height();
|
||||
copy.scale(size, size);
|
||||
auto pixbuf = CreatePixbuf(copy);
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 0, pixbuf, -1);
|
||||
} else {
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 0, nullptr, -1);
|
||||
}
|
||||
auto size = pFont::size(self().font(true), " ").height();
|
||||
if(icon) icon.scale(size, size);
|
||||
auto pixbuf = CreatePixbuf(icon);
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 0, pixbuf, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace hiro {
|
|||
struct pComboButtonItem : pObject {
|
||||
Declare(ComboButtonItem, Object)
|
||||
|
||||
auto setIcon(const image& icon) -> void;
|
||||
auto setIcon(image icon) -> void;
|
||||
auto setSelected() -> void;
|
||||
auto setText(const string& text) -> void;
|
||||
|
||||
|
|
|
@ -17,10 +17,7 @@ auto pComboButton::construct() -> void {
|
|||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, true);
|
||||
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(gtkWidget), gtkCellText, "text", 1, nullptr);
|
||||
|
||||
for(auto& item : state().items) {
|
||||
append(item);
|
||||
if(item->selected()) item->setSelected();
|
||||
}
|
||||
for(auto& item : state().items) append(item);
|
||||
|
||||
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 {
|
||||
lock();
|
||||
if(auto delegate = item->self()) {
|
||||
gtk_list_store_append(gtkListStore, &delegate->gtkIter);
|
||||
item->setIcon(item->state.icon);
|
||||
item->setText(item->state.text);
|
||||
if(auto self = item->self()) {
|
||||
gtk_list_store_append(gtkListStore, &self->gtkIter);
|
||||
self->setIcon(item->state.icon);
|
||||
if(item->state.selected) self->setSelected();
|
||||
self->setText(item->state.text);
|
||||
}
|
||||
if(gtk_combo_box_get_active(gtkComboBox) < 0) item->setSelected();
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
@ -46,25 +45,19 @@ auto pComboButton::minimumSize() const -> Size {
|
|||
signed maximumWidth = 0;
|
||||
for(auto& item : state().items) {
|
||||
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()
|
||||
);
|
||||
}
|
||||
Size size = pFont::size(font, " ");
|
||||
return {maximumWidth + 40, size.height() + 12};
|
||||
return {maximumWidth + 40, pFont::size(font, " ").height() + 12};
|
||||
}
|
||||
|
||||
auto pComboButton::remove(sComboButtonItem item) -> void {
|
||||
lock();
|
||||
if(auto delegate = item->self()) {
|
||||
gtk_list_store_remove(gtkListStore, &delegate->gtkIter);
|
||||
//if the currently selected item is removed; GTK+ deselects everything
|
||||
//detect this behavior and select the first item instead of nothing
|
||||
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;
|
||||
}
|
||||
if(gtk_combo_box_get_active(gtkComboBox) < 0) {
|
||||
if(auto item = self().item(0)) item->setSelected();
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
|
@ -83,10 +76,13 @@ auto pComboButton::setFont(const string& font) -> void {
|
|||
}
|
||||
|
||||
auto pComboButton::_updateSelected() -> void {
|
||||
for(auto& item : state().items) item->state.selected = false;
|
||||
signed selected = gtk_combo_box_get_active(gtkComboBox);
|
||||
if(selected >= 0) {
|
||||
state().selected = selected;
|
||||
if(!locked()) self().doChange();
|
||||
if(auto item = self().item(selected)) {
|
||||
item->state.selected = true;
|
||||
if(!locked()) self().doChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -63,6 +63,12 @@ auto pListViewColumn::setEditable(bool editable) -> void {
|
|||
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 {
|
||||
pFont::setFont(gtkHeaderText, font);
|
||||
auto fontDescription = pFont::create(font);
|
||||
|
@ -95,10 +101,6 @@ auto pListViewColumn::setResizable(bool resizable) -> void {
|
|||
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 {
|
||||
gtk_label_set_text(GTK_LABEL(gtkHeaderText), text);
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ struct pListViewColumn : pObject {
|
|||
auto setActive() -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setEditable(bool editable) -> void;
|
||||
auto setExpandable(bool expandable) -> void;
|
||||
auto setFont(const string& font) -> void override;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
auto setHorizontalAlignment(double alignment) -> void;
|
||||
auto setIcon(const image& icon) -> void;
|
||||
auto setResizable(bool resizable) -> void;
|
||||
auto setSortable(bool sortable) -> void;
|
||||
auto setText(const string& text) -> void;
|
||||
auto setVerticalAlignment(double alignment) -> void;
|
||||
auto setVisible(bool visible) -> void override;
|
||||
|
|
|
@ -8,6 +8,15 @@ auto pListViewItem::construct() -> 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 {
|
||||
if(auto parent = _parent()) {
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 0, checked, -1);
|
||||
|
@ -23,15 +32,7 @@ auto pListViewItem::setFocused() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto pListViewItem::setIcon(unsigned column, const image& icon) -> void {
|
||||
if(auto parent = _parent()) {
|
||||
if(icon) {
|
||||
auto pixbuf = CreatePixbuf(icon, true);
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 1 + column * 2, pixbuf, -1);
|
||||
} else {
|
||||
gtk_list_store_set(parent->gtkListStore, >kIter, 1 + column * 2, nullptr, -1);
|
||||
}
|
||||
}
|
||||
auto pListViewItem::setForegroundColor(Color color) -> 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, >kIter, 1 + column * 2 + 1, text.data(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
auto pListViewItem::_parent() -> pListView* {
|
||||
if(auto parent = self().parentListView()) return parent->self();
|
||||
return nullptr;
|
||||
|
|
|
@ -5,11 +5,13 @@ namespace hiro {
|
|||
struct pListViewItem : pObject {
|
||||
Declare(ListViewItem, Object)
|
||||
|
||||
auto append(sListViewCell cell) -> void;
|
||||
auto remove(sListViewCell cell) -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setChecked(bool checked) -> void;
|
||||
auto setFocused() -> void;
|
||||
auto setIcon(unsigned column, const image& icon) -> void;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
auto setSelected(bool selected) -> void;
|
||||
auto setText(unsigned column, const string& text) -> void;
|
||||
|
||||
auto _parent() -> pListView*;
|
||||
|
||||
|
|
|
@ -26,12 +26,13 @@ auto pListView::construct() -> void {
|
|||
gtk_widget_show(gtkWidgetChild);
|
||||
|
||||
setBackgroundColor(state().backgroundColor);
|
||||
setBatchable(state().batchable);
|
||||
setCheckable(state().checkable);
|
||||
setFont(self().font(true));
|
||||
setForegroundColor(state().foregroundColor);
|
||||
setGridVisible(state().gridVisible);
|
||||
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-release-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this);
|
||||
|
@ -56,9 +57,12 @@ auto pListView::append(sListViewColumn column) -> void {
|
|||
column->setFont(column->font());
|
||||
column->setForegroundColor(column->foregroundColor());
|
||||
column->setHorizontalAlignment(column->horizontalAlignment());
|
||||
column->setResizable(column->resizable());
|
||||
column->setVerticalAlignment(column->verticalAlignment());
|
||||
setCheckable(state().checkable);
|
||||
setSortable(state().sortable);
|
||||
_createModel();
|
||||
resizeColumns();
|
||||
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->setSelected(item->selected());
|
||||
for(auto column : range(self().columns())) {
|
||||
item->setIcon(column, item->state.icon(column, {}));
|
||||
item->setText(column, item->state.text(column, ""));
|
||||
if(auto cell = item->cell(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);
|
||||
}
|
||||
|
||||
//column widths:
|
||||
//< 0 = expanding (consume all remaining space)
|
||||
// 0 = auto (resize to contents
|
||||
//> 0 = fixed width
|
||||
auto pListView::resizeColumns() -> void {
|
||||
lock();
|
||||
|
||||
//compute the minimum width required for each column based upon the contents of all rows
|
||||
vector<signed> minimumWidths;
|
||||
for(auto column : range(self().columns())) {
|
||||
signed maximumWidth = 1;
|
||||
if(self().headerVisible()) {
|
||||
maximumWidth = max(maximumWidth, 8 //margin
|
||||
+ state().columns[column]->state.icon.width
|
||||
+ Font::size(state().columns[column]->font(true), state().columns[column]->state.text).width()
|
||||
);
|
||||
vector<signed> widths;
|
||||
signed minimumWidth = 0;
|
||||
signed expandable = 0;
|
||||
for(auto column : range(state().columns)) {
|
||||
signed width = _width(column);
|
||||
widths.append(width);
|
||||
minimumWidth += 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();
|
||||
}
|
||||
|
||||
auto pListView::selectAll() -> void {
|
||||
for(auto& item : state().items) {
|
||||
if(auto delegate = item->self()) delegate->setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
auto pListView::setBackgroundColor(Color color) -> void {
|
||||
GdkColor gdkColor = CreateColor(color);
|
||||
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 {
|
||||
if(auto delegate = _column(0)) {
|
||||
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 {
|
||||
gtk_widget_grab_focus(gtkWidgetChild);
|
||||
}
|
||||
|
@ -206,21 +198,60 @@ auto pListView::setHeaderVisible(bool visible) -> void {
|
|||
gtk_tree_view_set_headers_visible(gtkTreeView, visible);
|
||||
}
|
||||
|
||||
auto pListView::setMultiSelect(bool multiSelect) -> void {
|
||||
gtk_tree_selection_set_mode(gtkTreeSelection, multiSelect ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
|
||||
auto pListView::setSortable(bool sortable) -> void {
|
||||
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) {
|
||||
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* {
|
||||
if(auto delegate = self().column(column)) return delegate->self();
|
||||
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 {
|
||||
gtk_tree_view_set_model(gtkTreeView, nullptr);
|
||||
gtkListStore = nullptr;
|
||||
|
@ -256,13 +287,16 @@ auto pListView::_doContext() -> void {
|
|||
auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void {
|
||||
for(auto& column : state().columns) {
|
||||
if(auto delegate = column->self()) {
|
||||
if(gtkCellRendererText = GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
|
||||
if(auto item = self().item(decimal(path))) {
|
||||
if(string{text} != item->text(column->offset())) {
|
||||
item->setText(column->offset(), text);
|
||||
if(!locked()) self().doEdit(item, column);
|
||||
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
|
||||
auto row = decimal(path);
|
||||
if(auto item = self().item(row)) {
|
||||
if(auto cell = item->cell(column->offset())) {
|
||||
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;
|
||||
//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) {
|
||||
self().setSelected({});
|
||||
self().unselectAll();
|
||||
self().doChange();
|
||||
return true;
|
||||
}
|
||||
|
@ -373,6 +407,19 @@ auto pListView::_updateSelected() -> void {
|
|||
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
|
||||
|
|
|
@ -7,23 +7,28 @@ struct pListView : pWidget {
|
|||
|
||||
auto append(sListViewColumn column) -> void;
|
||||
auto append(sListViewItem item) -> void;
|
||||
auto checkAll() -> void;
|
||||
auto focused() -> bool;
|
||||
auto remove(sListViewColumn column) -> void;
|
||||
auto remove(sListViewItem item) -> void;
|
||||
auto reset() -> void;
|
||||
auto resizeColumns() -> void;
|
||||
auto selectAll() -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setBatchable(bool batchable) -> void;
|
||||
auto setCheckable(bool checkable) -> void;
|
||||
auto setChecked(bool checked) -> void;
|
||||
auto setFocused() -> void override;
|
||||
auto setFont(const string& font) -> void override;
|
||||
auto setForegroundColor(Color color) -> void;
|
||||
auto setGridVisible(bool visible) -> void;
|
||||
auto setHeaderVisible(bool visible) -> void;
|
||||
auto setMultiSelect(bool multiSelect) -> void;
|
||||
auto setSelected(bool selected) -> void;
|
||||
auto setSortable(bool sortable) -> void;
|
||||
auto uncheckAll() -> void;
|
||||
auto unselectAll() -> void;
|
||||
|
||||
auto _cellWidth(unsigned row, unsigned column) -> unsigned;
|
||||
auto _column(unsigned column) -> pListViewColumn*;
|
||||
auto _columnWidth(unsigned column) -> unsigned;
|
||||
auto _createModel() -> void;
|
||||
auto _doActivate() -> void;
|
||||
auto _doChange() -> void;
|
||||
|
@ -34,6 +39,7 @@ struct pListView : pWidget {
|
|||
auto _doMouseMove() -> signed;
|
||||
auto _doToggle(const char* path) -> void;
|
||||
auto _updateSelected() -> void;
|
||||
auto _width(unsigned column) -> unsigned;
|
||||
|
||||
GtkScrolledWindow* gtkScrolledWindow = nullptr;
|
||||
GtkWidget* gtkWidgetChild = nullptr;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace hiro {
|
||||
|
||||
static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void {
|
||||
if(p->_parent().locked()) return;
|
||||
if(p->groupLocked()) return;
|
||||
bool wasChecked = p->state().checked;
|
||||
p->setChecked();
|
||||
if(!wasChecked) p->self().doActivate();
|
||||
|
@ -12,7 +12,6 @@ static auto RadioButton_activate(GtkToggleButton*, pRadioButton* p) -> void {
|
|||
auto pRadioButton::construct() -> void {
|
||||
gtkWidget = gtk_toggle_button_new();
|
||||
|
||||
setGroup(state().group);
|
||||
setBordered(state().bordered);
|
||||
setIcon(state().icon);
|
||||
setOrientation(state().orientation);
|
||||
|
@ -48,26 +47,34 @@ auto pRadioButton::setBordered(bool bordered) -> void {
|
|||
}
|
||||
|
||||
auto pRadioButton::setChecked() -> void {
|
||||
_parent().lock();
|
||||
for(auto& weak : state().group) {
|
||||
if(auto item = weak.acquire()) {
|
||||
if(item->self()) {
|
||||
bool checked = item->self() == this;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), item->state.checked = checked);
|
||||
if(!self().group()) return;
|
||||
for(auto& weak : self().group()->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
if(auto radioButton = dynamic_cast<mRadioButton*>(object.data())) {
|
||||
if(auto self = radioButton->self()) {
|
||||
self->lock();
|
||||
bool checked = self == this;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->gtkWidget), radioButton->state.checked = checked);
|
||||
self->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_parent().unlock();
|
||||
}
|
||||
|
||||
auto pRadioButton::setGroup(const vector<wRadioButton>& group) -> void {
|
||||
_parent().lock();
|
||||
for(auto& weak : state().group) {
|
||||
if(auto item = weak.acquire()) {
|
||||
if(item->self()) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), item->checked());
|
||||
auto pRadioButton::setGroup(sGroup group) -> void {
|
||||
if(!group) return;
|
||||
for(auto& weak : group->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
auto pRadioButton::_parent() -> pRadioButton& {
|
||||
if(state().group.size()) {
|
||||
if(auto item = state().group.first().acquire()) {
|
||||
if(item->self()) return *item->self();
|
||||
auto pRadioButton::groupLocked() const -> bool {
|
||||
if(auto group = state().group) {
|
||||
for(auto& weak : group->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
if(auto self = object->self()) {
|
||||
if(self->locked()) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return *this;
|
||||
return locked();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,12 +8,12 @@ struct pRadioButton : pWidget {
|
|||
auto minimumSize() const -> Size;
|
||||
auto setBordered(bool bordered) -> void;
|
||||
auto setChecked() -> void;
|
||||
auto setGroup(const vector<wRadioButton>& group) -> void;
|
||||
auto setGroup(sGroup group) -> void;
|
||||
auto setIcon(const image& icon) -> void;
|
||||
auto setOrientation(Orientation orientation) -> void;
|
||||
auto setText(const string& text) -> void;
|
||||
|
||||
auto _parent() -> pRadioButton&;
|
||||
auto groupLocked() const -> bool;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace hiro {
|
||||
|
||||
static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void {
|
||||
if(p->_parent().locked()) return;
|
||||
if(p->groupLocked()) return;
|
||||
bool wasChecked = p->state().checked;
|
||||
p->setChecked();
|
||||
if(!wasChecked) p->self().doActivate();
|
||||
|
@ -11,8 +11,9 @@ static auto RadioLabel_activate(GtkToggleButton*, pRadioLabel* p) -> void {
|
|||
|
||||
auto pRadioLabel::construct() -> void {
|
||||
gtkWidget = gtk_radio_button_new_with_label(nullptr, "");
|
||||
gtkToggleButton = GTK_TOGGLE_BUTTON(gtkWidget);
|
||||
gtkRadioButton = GTK_RADIO_BUTTON(gtkWidget);
|
||||
|
||||
setGroup(state().group);
|
||||
setText(state().text);
|
||||
|
||||
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 {
|
||||
_parent().lock();
|
||||
for(auto& weak : state().group) {
|
||||
if(auto item = weak.acquire()) item->state.checked = false;
|
||||
}
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtkWidget), state().checked = true);
|
||||
_parent().unlock();
|
||||
lock();
|
||||
gtk_toggle_button_set_active(gtkToggleButton, true);
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pRadioLabel::setGroup(const vector<shared_pointer_weak<mRadioLabel>>& group) -> void {
|
||||
if(&_parent() == this) return;
|
||||
_parent().lock();
|
||||
gtk_radio_button_set_group(
|
||||
GTK_RADIO_BUTTON(gtkWidget),
|
||||
gtk_radio_button_get_group(GTK_RADIO_BUTTON(_parent().gtkWidget))
|
||||
);
|
||||
for(auto& weak : state().group) {
|
||||
if(auto item = weak.acquire()) {
|
||||
if(item->self() && item->checked()) {
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->self()->gtkWidget), true);
|
||||
break;
|
||||
auto pRadioLabel::setGroup(sGroup group) -> void {
|
||||
if(!group) return;
|
||||
|
||||
maybe<GtkRadioButton*> gtkRadioButton;
|
||||
for(auto& weak : group->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
if(auto radioLabel = dynamic_cast<mRadioLabel*>(object.data())) {
|
||||
if(auto self = radioLabel->self()) {
|
||||
self->lock();
|
||||
gtk_radio_button_set_group(self->gtkRadioButton, nullptr);
|
||||
if(!gtkRadioButton) gtkRadioButton = self->gtkRadioButton;
|
||||
else gtk_radio_button_set_group(self->gtkRadioButton, gtk_radio_button_get_group(*gtkRadioButton));
|
||||
gtk_toggle_button_set_active(self->gtkToggleButton, radioLabel->checked());
|
||||
self->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_parent().unlock();
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
auto pRadioLabel::_parent() -> pRadioLabel& {
|
||||
if(state().group.size()) {
|
||||
if(auto item = state().group.first().acquire()) {
|
||||
if(item->self()) return *item->self();
|
||||
auto pRadioLabel::groupLocked() const -> bool {
|
||||
if(auto group = state().group) {
|
||||
for(auto& weak : group->state.objects) {
|
||||
if(auto object = weak.acquire()) {
|
||||
if(auto self = object->self()) {
|
||||
if(self->locked()) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return *this;
|
||||
return locked();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@ struct pRadioLabel : pWidget {
|
|||
|
||||
auto minimumSize() const -> Size;
|
||||
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 _parent() -> pRadioLabel&;
|
||||
auto groupLocked() const -> bool;
|
||||
|
||||
GtkToggleButton* gtkToggleButton = nullptr;
|
||||
GtkRadioButton* gtkRadioButton = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,12 @@ auto pTabFrameItem::destruct() -> void {
|
|||
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 {
|
||||
if(auto parent = _parent()) {
|
||||
parent->setItemClosable(self().offset(), closable);
|
||||
|
|
|
@ -5,6 +5,8 @@ namespace hiro {
|
|||
struct pTabFrameItem : pObject {
|
||||
Declare(TabFrameItem, Object)
|
||||
|
||||
auto append(sLayout layout) -> void;
|
||||
auto remove(sLayout layout) -> void;
|
||||
auto setClosable(bool closable) -> void;
|
||||
auto setIcon(const image& icon) -> void;
|
||||
auto setMovable(bool movable) -> void;
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
namespace hiro {
|
||||
|
||||
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();
|
||||
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 {
|
||||
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;
|
||||
for(auto n : range(p->tabs)) {
|
||||
if(page == p->tabs[n].child) {
|
||||
|
@ -45,7 +50,6 @@ auto pTabFrame::construct() -> void {
|
|||
tabs.reset(); //todo: memory leak, need to release each tab
|
||||
for(auto& item : state().items) append(item);
|
||||
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), "switch-page", G_CALLBACK(TabFrame_change), (gpointer)this);
|
||||
|
@ -87,6 +91,7 @@ auto pTabFrame::append(sTabFrameItem item) -> void {
|
|||
|
||||
setFont(self().font(true));
|
||||
setItemMovable(item->offset(), item->movable());
|
||||
if(item->selected()) setItemSelected(item->offset());
|
||||
_synchronizeTab(tabs.size() - 1);
|
||||
setGeometry(self().geometry());
|
||||
unlock();
|
||||
|
@ -128,7 +133,10 @@ auto pTabFrame::remove(sTabFrameItem item) -> void {
|
|||
}
|
||||
tabs.remove(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();
|
||||
}
|
||||
|
||||
|
@ -218,14 +226,12 @@ auto pTabFrame::setVisible(bool visible) -> void {
|
|||
}
|
||||
|
||||
auto pTabFrame::_synchronizeLayout() -> void {
|
||||
unsigned position = 0;
|
||||
for(auto& item : state().items) {
|
||||
if(auto layout = item->state.layout) {
|
||||
if(layout->self()) {
|
||||
layout->self()->setVisible(layout->visible(true) && position == state().selected);
|
||||
if(auto self = layout->self()) {
|
||||
self->setVisible(layout->visible(true) && item->selected());
|
||||
}
|
||||
}
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -184,13 +184,16 @@ auto pWindow::construct() -> 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));
|
||||
_setMenuFont(menuBar->font(true));
|
||||
_setMenuVisible(menuBar->visible(true));
|
||||
}
|
||||
|
||||
auto pWindow::append(shared_pointer<mStatusBar> statusBar) -> void {
|
||||
auto pWindow::append(sStatusBar statusBar) -> void {
|
||||
_setStatusEnabled(statusBar->enabled(true));
|
||||
_setStatusFont(statusBar->font(true));
|
||||
_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);
|
||||
}
|
||||
|
||||
auto pWindow::remove(shared_pointer<mStatusBar> statusBar) -> void {
|
||||
auto pWindow::remove(sStatusBar statusBar) -> void {
|
||||
_setStatusVisible(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,14 @@ struct pWindow : pObject {
|
|||
GtkAllocation lastAllocation = {0};
|
||||
bool onSizePending = false;
|
||||
|
||||
auto append(shared_pointer<mMenuBar> menuBar) -> void;
|
||||
auto append(shared_pointer<mStatusBar> statusBar) -> void;
|
||||
auto append(sLayout layout) -> void;
|
||||
auto append(sMenuBar menuBar) -> void;
|
||||
auto append(sStatusBar statusBar) -> void;
|
||||
auto focused() const -> bool override;
|
||||
auto frameMargin() const -> Geometry;
|
||||
auto remove(shared_pointer<mMenuBar> menuBar) -> void;
|
||||
auto remove(shared_pointer<mStatusBar> statusBar) -> void;
|
||||
auto remove(sLayout layout) -> void;
|
||||
auto remove(sMenuBar menuBar) -> void;
|
||||
auto remove(sStatusBar statusBar) -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setDroppable(bool droppable) -> void;
|
||||
auto setEnabled(bool enabled) -> void override;
|
||||
|
|
|
@ -1,16 +1,46 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Action)
|
||||
|
||||
void pAction::setEnabled(bool enabled) {
|
||||
if(parentWindow) parentWindow->p.updateMenu();
|
||||
namespace hiro {
|
||||
|
||||
auto pAction::construct() -> void {
|
||||
}
|
||||
|
||||
void pAction::setVisible(bool visible) {
|
||||
if(parentWindow) parentWindow->p.updateMenu();
|
||||
auto pAction::destruct() -> void {
|
||||
}
|
||||
|
||||
void pAction::constructor() {
|
||||
parentMenu = 0;
|
||||
parentWindow = 0;
|
||||
auto pAction::setEnabled(bool enabled) -> void {
|
||||
_synchronize();
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,13 @@
|
|||
#if defined(Hiro_MenuSeparator)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
auto pMenuSeparator::construct() -> void {
|
||||
}
|
||||
|
||||
auto pMenuSeparator::destruct() -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
#if defined(Hiro_MenuSeparator)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pMenuSeparator : pAction {
|
||||
Declare(MenuSeparator, Action)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,113 +1,124 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Menu)
|
||||
|
||||
void pMenu::append(Action& action) {
|
||||
action.p.parentMenu = &menu;
|
||||
if(parentWindow) parentWindow->p.updateMenu();
|
||||
namespace hiro {
|
||||
|
||||
auto pMenu::construct() -> void {
|
||||
_createBitmap();
|
||||
}
|
||||
|
||||
void pMenu::remove(Action& action) {
|
||||
if(parentWindow) parentWindow->p.updateMenu();
|
||||
action.p.parentMenu = 0;
|
||||
auto pMenu::destruct() -> void {
|
||||
if(hbitmap) { DeleteObject(hbitmap); hbitmap = nullptr; }
|
||||
if(hmenu) { DestroyMenu(hmenu); hmenu = nullptr; }
|
||||
}
|
||||
|
||||
void pMenu::setImage(const image& image) {
|
||||
createBitmap();
|
||||
if(parentWindow) parentWindow->p.updateMenu();
|
||||
auto pMenu::append(sAction action) -> void {
|
||||
_synchronize();
|
||||
}
|
||||
|
||||
void pMenu::setText(string text) {
|
||||
if(parentWindow) parentWindow->p.updateMenu();
|
||||
auto pMenu::remove(sAction action) -> void {
|
||||
_synchronize();
|
||||
}
|
||||
|
||||
void pMenu::constructor() {
|
||||
hmenu = 0;
|
||||
createBitmap();
|
||||
auto pMenu::setIcon(const image& icon) -> void {
|
||||
_createBitmap();
|
||||
_synchronize();
|
||||
}
|
||||
|
||||
void pMenu::destructor() {
|
||||
if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; }
|
||||
if(parentMenu) {
|
||||
parentMenu->remove(menu);
|
||||
} else if(parentWindow) {
|
||||
//belongs to window's main menubar
|
||||
parentWindow->remove(menu);
|
||||
}
|
||||
auto pMenu::setText(const string& text) -> void {
|
||||
_synchronize();
|
||||
}
|
||||
|
||||
void pMenu::createBitmap() {
|
||||
auto pMenu::_createBitmap() -> void {
|
||||
if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; }
|
||||
|
||||
if(menu.state.image.width && menu.state.image.height) {
|
||||
nall::image nallImage = menu.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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//Windows actions lack the ability to toggle visibility.
|
||||
//To support this, menus must be destroyed and recreated when toggling any action's visibility.
|
||||
void pMenu::update(Window& parentWindow, Menu* parentMenu) {
|
||||
this->parentMenu = parentMenu;
|
||||
this->parentWindow = &parentWindow;
|
||||
|
||||
auto pMenu::_update() -> void {
|
||||
if(hmenu) DestroyMenu(hmenu);
|
||||
hmenu = CreatePopupMenu();
|
||||
|
||||
for(auto& action : menu.state.action) {
|
||||
action.p.parentMenu = &menu;
|
||||
action.p.parentWindow = &parentWindow;
|
||||
MENUINFO mi{sizeof(MENUINFO)};
|
||||
mi.fMask = MIM_STYLE;
|
||||
mi.dwStyle = MNS_NOTIFYBYPOS; //| MNS_MODELESS;
|
||||
SetMenuInfo(hmenu, &mi);
|
||||
|
||||
unsigned enabled = action.state.enabled ? 0 : MF_GRAYED;
|
||||
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));
|
||||
unsigned position = 0;
|
||||
|
||||
if(item.state.image.width && item.state.image.height) {
|
||||
MENUITEMINFO mii = {sizeof(MENUITEMINFO)};
|
||||
for(auto& action : state().actions) {
|
||||
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)
|
||||
//this causes too much spacing, so use a custom checkmark image instead
|
||||
mii.fMask = MIIM_CHECKMARKS;
|
||||
mii.hbmpUnchecked = item.p.hbitmap;
|
||||
SetMenuItemInfo(hmenu, (UINT_PTR)item.p.hmenu, FALSE, &mii);
|
||||
mii.fMask |= MIIM_CHECKMARKS;
|
||||
mii.hbmpUnchecked = bitmap;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace phoenix {
|
||||
|
||||
void pSeparator::constructor() {
|
||||
}
|
||||
|
||||
void pSeparator::destructor() {
|
||||
if(parentMenu) parentMenu->remove(separator);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Application)
|
||||
|
||||
static bool Application_keyboardProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static void Application_processDialogMessage(MSG&);
|
||||
static LRESULT CALLBACK Application_windowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
namespace hiro {
|
||||
|
||||
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;
|
||||
if(Application::main) {
|
||||
while(applicationState.quit == false) {
|
||||
Application::main();
|
||||
if(Application::state.onMain) {
|
||||
while(!Application::state.quit) {
|
||||
Application::doMain();
|
||||
processEvents();
|
||||
}
|
||||
} else {
|
||||
|
@ -19,12 +21,12 @@ void pApplication::run() {
|
|||
}
|
||||
}
|
||||
|
||||
bool pApplication::pendingEvents() {
|
||||
auto pApplication::pendingEvents() -> bool {
|
||||
MSG msg;
|
||||
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
void pApplication::processEvents() {
|
||||
auto pApplication::processEvents() -> void {
|
||||
while(pendingEvents()) {
|
||||
MSG msg;
|
||||
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
|
||||
|| msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) {
|
||||
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);
|
||||
}
|
||||
|
||||
void pApplication::initialize() {
|
||||
auto pApplication::initialize() -> void {
|
||||
CoInitialize(0);
|
||||
InitCommonControls();
|
||||
|
||||
WNDCLASS wc;
|
||||
|
||||
#if defined(Hiro_Window)
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
|
@ -64,11 +68,27 @@ void pApplication::initialize() {
|
|||
wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2));
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Application_windowProc;
|
||||
wc.lpszClassName = L"phoenix_window";
|
||||
wc.lpszClassName = L"hiroWindow";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
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.cbWndExtra = 0;
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
|
@ -76,11 +96,13 @@ void pApplication::initialize() {
|
|||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Canvas_windowProc;
|
||||
wc.lpszClassName = L"phoenix_canvas";
|
||||
wc.lpszClassName = L"hiroCanvas";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Label)
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
|
||||
|
@ -88,11 +110,13 @@ void pApplication::initialize() {
|
|||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Label_windowProc;
|
||||
wc.lpszClassName = L"phoenix_label";
|
||||
wc.lpszClassName = L"hiroLabel";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Viewport)
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
||||
|
@ -100,76 +124,80 @@ void pApplication::initialize() {
|
|||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = Viewport_windowProc;
|
||||
wc.lpszClassName = L"phoenix_viewport";
|
||||
wc.lpszClassName = L"hiroViewport";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
#endif
|
||||
|
||||
settings = new Settings;
|
||||
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;
|
||||
|
||||
GUITHREADINFO info;
|
||||
memset(&info, 0, sizeof(GUITHREADINFO));
|
||||
info.cbSize = sizeof(GUITHREADINFO);
|
||||
GetGUIThreadInfo(GetCurrentThreadId(), &info);
|
||||
Object* object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
|
||||
if(object == nullptr) return false;
|
||||
auto object = (mObject*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA);
|
||||
if(!object) return false;
|
||||
|
||||
if(dynamic_cast<Window*>(object)) {
|
||||
Window& window = (Window&)*object;
|
||||
if(pWindow::modal.size() > 0 && !pWindow::modal.find(&window.p)) return false;
|
||||
Keyboard::Keycode keysym = Keysym(wparam, lparam);
|
||||
if(keysym != Keyboard::Keycode::None) {
|
||||
if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym);
|
||||
if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym);
|
||||
if(auto window = dynamic_cast<mWindow*>(object)) {
|
||||
if(pWindow::modal && !pWindow::modal.find(window->self())) return false;
|
||||
|
||||
if(auto code = pKeyboard::_translate(wparam, lparam)) {
|
||||
if(msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) window->doKeyPress(code);
|
||||
if(msg == WM_KEYUP || msg == WM_SYSKEYUP) window->doKeyRelease(code);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(msg == WM_KEYDOWN) {
|
||||
if(dynamic_cast<ListView*>(object)) {
|
||||
ListView& listView = (ListView&)*object;
|
||||
if(0);
|
||||
|
||||
#if defined(Hiro_ListView)
|
||||
else if(auto listView = dynamic_cast<mListView*>(object)) {
|
||||
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(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) {
|
||||
//Ctrl+A = select all text
|
||||
//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;
|
||||
} else if(wparam == 'V' && GetKeyState(VK_CONTROL) < 0) {
|
||||
//Ctrl+V = paste text
|
||||
//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
|
||||
OpenClipboard(hwnd);
|
||||
HANDLE handle = GetClipboardData(CF_UNICODETEXT);
|
||||
if(handle) {
|
||||
wchar_t* text = (wchar_t*)GlobalLock(handle);
|
||||
if(text) {
|
||||
if(auto handle = GetClipboardData(CF_UNICODETEXT)) {
|
||||
if(auto text = (wchar_t*)GlobalLock(handle)) {
|
||||
string data = (const char*)utf8_t(text);
|
||||
data.replace("\r\n", "\n");
|
||||
data.replace("\r", "\n");
|
||||
data.replace("\n", "\r\n");
|
||||
GlobalUnlock(handle);
|
||||
utf16_t output(data);
|
||||
HGLOBAL resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t));
|
||||
if(resource) {
|
||||
wchar_t* write = (wchar_t*)GlobalLock(resource);
|
||||
if(write) {
|
||||
if(auto resource = GlobalAlloc(GMEM_MOVEABLE, (wcslen(output) + 1) * sizeof(wchar_t))) {
|
||||
if(auto write = (wchar_t*)GlobalLock(resource)) {
|
||||
wcscpy(write, output);
|
||||
GlobalUnlock(write);
|
||||
if(SetClipboardData(CF_UNICODETEXT, resource) == FALSE) {
|
||||
if(SetClipboardData(CF_UNICODETEXT, resource) == NULL) {
|
||||
GlobalFree(resource);
|
||||
}
|
||||
}
|
||||
|
@ -180,40 +208,45 @@ static bool Application_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*case WM_GETMINMAXINFO: {
|
||||
MINMAXINFO* mmi = (MINMAXINFO*)lparam;
|
||||
mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width;
|
||||
mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height;
|
||||
return TRUE;
|
||||
break;
|
||||
}*/
|
||||
/*
|
||||
case WM_GETMINMAXINFO: {
|
||||
MINMAXINFO* mmi = (MINMAXINFO*)lparam;
|
||||
mmi->ptMinTrackSize.x = 256 + window.p.frameMargin().width;
|
||||
mmi->ptMinTrackSize.y = 256 + window.p.frameMargin().height;
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
static LRESULT CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
Object* object = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(object == nullptr) return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
Window& window = dynamic_cast<Window*>(object) ? (Window&)*object : *((Widget*)object)->Sizable::state.window;
|
||||
static auto CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> LRESULT {
|
||||
auto object = (mObject*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(!object) return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
auto& window = dynamic_cast<mWindow*>(object) ? (mWindow&)*object : *object->parentWindow(true);
|
||||
|
||||
bool process = true;
|
||||
if(!pWindow::modal.empty() && !pWindow::modal.find(&window.p)) process = false;
|
||||
if(applicationState.quit) process = false;
|
||||
if(process == false) return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
if(pWindow::modal && !pWindow::modal.find(window.self())) process = false;
|
||||
if(Application::state.quit) process = false;
|
||||
if(!process) return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
|
||||
switch(msg) {
|
||||
case WM_CLOSE: window.p.onClose(); return TRUE;
|
||||
case WM_MOVE: window.p.onMove(); break;
|
||||
case WM_SIZE: window.p.onSize(); break;
|
||||
case WM_DROPFILES: window.p.onDrop(wparam); return FALSE;
|
||||
case WM_ERASEBKGND: if(window.p.onEraseBackground()) return true; break;
|
||||
case WM_ENTERMENULOOP: case WM_ENTERSIZEMOVE: window.p.onModalBegin(); return FALSE;
|
||||
case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: window.p.onModalEnd(); return FALSE;
|
||||
case WM_CLOSE: window.self()->onClose(); return TRUE;
|
||||
case WM_MOVE: window.self()->onMove(); break;
|
||||
case WM_SIZE: window.self()->onSize(); break;
|
||||
case WM_DROPFILES: window.self()->onDrop(wparam); return FALSE;
|
||||
case WM_ERASEBKGND: if(window.self()->onEraseBackground()) return true; break;
|
||||
case WM_ENTERMENULOOP: case WM_ENTERSIZEMOVE: window.self()->onModalBegin(); return FALSE;
|
||||
case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: window.self()->onModalEnd(); return FALSE;
|
||||
}
|
||||
|
||||
return Shared_windowProc(DefWindowProc, hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
|
@ -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(lpdata) {
|
||||
auto state = (BrowserWindow::State*)lpdata;
|
||||
|
@ -12,7 +14,7 @@ static int CALLBACK BrowserWindowCallbackProc(HWND hwnd, UINT msg, LPARAM lparam
|
|||
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 filters;
|
||||
|
@ -46,7 +48,7 @@ static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) {
|
|||
OPENFILENAME ofn;
|
||||
memset(&ofn, 0, 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.lpstrInitialDir = wpath;
|
||||
ofn.lpstrFile = wname;
|
||||
|
@ -62,11 +64,11 @@ static string BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) {
|
|||
return name;
|
||||
}
|
||||
|
||||
string pBrowserWindow::directory(BrowserWindow::State& state) {
|
||||
auto pBrowserWindow::directory(BrowserWindow::State& state) -> string {
|
||||
wchar_t wname[PATH_MAX + 1] = L"";
|
||||
|
||||
BROWSEINFO bi;
|
||||
bi.hwndOwner = state.parent ? state.parent->p.hwnd : 0;
|
||||
bi.hwndOwner = state.parent ? state.parent->self()->hwnd : 0;
|
||||
bi.pidlRoot = NULL;
|
||||
bi.pszDisplayName = wname;
|
||||
bi.lpszTitle = L"\nChoose a directory:";
|
||||
|
@ -94,12 +96,14 @@ string pBrowserWindow::directory(BrowserWindow::State& state) {
|
|||
return name;
|
||||
}
|
||||
|
||||
string pBrowserWindow::open(BrowserWindow::State& state) {
|
||||
auto pBrowserWindow::open(BrowserWindow::State& state) -> string {
|
||||
return BrowserWindow_fileDialog(0, state);
|
||||
}
|
||||
|
||||
string pBrowserWindow::save(BrowserWindow::State& state) {
|
||||
auto pBrowserWindow::save(BrowserWindow::State& state) -> string {
|
||||
return BrowserWindow_fileDialog(1, state);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
|
@ -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)};
|
||||
}
|
||||
|
||||
Geometry pDesktop::workspace() {
|
||||
auto pDesktop::workspace() -> Geometry {
|
||||
RECT rc;
|
||||
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
return {rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#if defined(Hiro_Desktop)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pDesktop {
|
||||
static auto size() -> Size;
|
||||
static auto workspace() -> Geometry;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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(style == "") style = "Normal";
|
||||
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(style == "") style = "Normal";
|
||||
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(style == "") style = "Normal";
|
||||
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);
|
||||
Size size = pFont::size(hfont, text);
|
||||
pFont::free(hfont);
|
||||
return size;
|
||||
}
|
||||
|
||||
HFONT pFont::create(string description) {
|
||||
auto pFont::create(const string& description) -> HFONT {
|
||||
lstring part = description.split<2>(",").strip();
|
||||
|
||||
string family = "Sans";
|
||||
string family = "Tahoma";
|
||||
unsigned size = 8u;
|
||||
bool bold = false;
|
||||
bool italic = false;
|
||||
|
@ -40,16 +42,16 @@ HFONT pFont::create(string description) {
|
|||
|
||||
return CreateFont(
|
||||
-(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)
|
||||
);
|
||||
}
|
||||
|
||||
void pFont::free(HFONT hfont) {
|
||||
auto pFont::free(HFONT hfont) -> void {
|
||||
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
|
||||
if(text.empty()) text = " ";
|
||||
|
||||
|
@ -62,3 +64,5 @@ Size pFont::size(HFONT hfont, string text) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,13 @@
|
|||
#if defined(Hiro_Group)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
auto pGroup::construct() -> void {
|
||||
}
|
||||
|
||||
auto pGroup::destruct() -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
#if defined(Hiro_Group)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pGroup : pObject {
|
||||
Declare(Group, Object)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,4 +15,42 @@
|
|||
#include <nall/windows/registry.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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<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>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
|
@ -0,0 +1 @@
|
|||
1 24 "hiro.Manifest"
|
|
@ -0,0 +1,13 @@
|
|||
#if defined(Hiro_Hotkey)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
auto pHotkey::construct() -> void {
|
||||
}
|
||||
|
||||
auto pHotkey::destruct() -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
#if defined(Hiro_Hotkey)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pHotkey : pObject {
|
||||
Declare(Hotkey, Object)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,144 +1,99 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Keyboard)
|
||||
|
||||
void pKeyboard::initialize() {
|
||||
auto append = [](Keyboard::Scancode scancode, unsigned keysym) {
|
||||
settings->keymap.insert(scancode, keysym);
|
||||
};
|
||||
namespace hiro {
|
||||
|
||||
append(Keyboard::Scancode::Escape, VK_ESCAPE);
|
||||
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);
|
||||
vector<uint16_t> pKeyboard::keycodes;
|
||||
|
||||
append(Keyboard::Scancode::PrintScreen, VK_SNAPSHOT);
|
||||
append(Keyboard::Scancode::ScrollLock, VK_SCROLL);
|
||||
append(Keyboard::Scancode::Pause, VK_PAUSE);
|
||||
|
||||
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);
|
||||
auto pKeyboard::poll() -> vector<bool> {
|
||||
vector<bool> result;
|
||||
for(auto& code : keycodes) result.append(pressed(code));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool pKeyboard::pressed(Keyboard::Scancode scancode) {
|
||||
if(auto result = settings->keymap.find(scancode)) {
|
||||
return GetAsyncKeyState(result()) & 0x8000;
|
||||
}
|
||||
auto pKeyboard::pressed(unsigned code) -> bool {
|
||||
uint8_t lo = code >> 0;
|
||||
uint8_t hi = code >> 8;
|
||||
if(lo && GetAsyncKeyState(lo) & 0x8000) return true;
|
||||
if(hi && GetAsyncKeyState(hi) & 0x8000) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<bool> pKeyboard::state() {
|
||||
vector<bool> output;
|
||||
output.resize((unsigned)Keyboard::Scancode::Limit);
|
||||
for(auto& n : output) n = false;
|
||||
auto pKeyboard::initialize() -> void {
|
||||
auto append = [](unsigned lo, unsigned hi = 0) {
|
||||
keycodes.append(lo << 0 | hi << 8);
|
||||
};
|
||||
|
||||
for(auto node : settings->keymap) {
|
||||
if(GetAsyncKeyState(node.value) & 0x8000) {
|
||||
output[(unsigned)node.key] = true;
|
||||
}
|
||||
#define map(name, ...) if(key == name) { append(__VA_ARGS__); continue; }
|
||||
for(auto& key : Keyboard::keys) {
|
||||
#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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 == IDCANCEL) return MessageWindow::Response::Cancel;
|
||||
if(response == IDYES) return MessageWindow::Response::Yes;
|
||||
|
@ -15,7 +17,7 @@ static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons but
|
|||
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::OkCancel) return MB_OKCANCEL;
|
||||
if(buttons == MessageWindow::Buttons::YesNo) return MB_YESNO;
|
||||
|
@ -23,32 +25,34 @@ static UINT MessageWindow_buttons(MessageWindow::Buttons buttons) {
|
|||
throw;
|
||||
}
|
||||
|
||||
MessageWindow::Response pMessageWindow::error(MessageWindow::State& state) {
|
||||
auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response {
|
||||
UINT flags = MB_ICONERROR | MessageWindow_buttons(state.buttons);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -1,4 +1,6 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Monitor)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct MonitorInfo {
|
||||
unsigned monitor = 0;
|
||||
|
@ -7,7 +9,7 @@ struct MonitorInfo {
|
|||
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;
|
||||
MONITORINFOEX mi;
|
||||
memset(&mi, 0, sizeof(MONITORINFOEX));
|
||||
|
@ -23,21 +25,23 @@ static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT l
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
unsigned pMonitor::count() {
|
||||
auto pMonitor::count() -> unsigned {
|
||||
return GetSystemMetrics(SM_CMONITORS);
|
||||
}
|
||||
|
||||
Geometry pMonitor::geometry(unsigned monitor) {
|
||||
auto pMonitor::geometry(unsigned monitor) -> Geometry {
|
||||
MonitorInfo info;
|
||||
info.monitor = monitor;
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info);
|
||||
return info.geometry;
|
||||
}
|
||||
|
||||
unsigned pMonitor::primary() {
|
||||
auto pMonitor::primary() -> unsigned {
|
||||
MonitorInfo info;
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&info);
|
||||
return info.primary;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
|
@ -1,12 +1,14 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Mouse)
|
||||
|
||||
Position pMouse::position() {
|
||||
POINT point = {0};
|
||||
namespace hiro {
|
||||
|
||||
auto pMouse::position() -> Position {
|
||||
POINT point{0};
|
||||
GetCursorPos(&point);
|
||||
return {point.x, point.y};
|
||||
}
|
||||
|
||||
bool pMouse::pressed(Mouse::Button button) {
|
||||
auto pMouse::pressed(Mouse::Button button) -> bool {
|
||||
switch(button) {
|
||||
case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000;
|
||||
case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000;
|
||||
|
@ -16,3 +18,5 @@ bool pMouse::pressed(Mouse::Button button) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#if defined(Hiro_Mouse)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pMouse {
|
||||
static auto position() -> Position;
|
||||
static auto pressed(Mouse::Button button) -> bool;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,17 +1,41 @@
|
|||
namespace phoenix {
|
||||
#if defined(Hiro_Object)
|
||||
|
||||
vector<pObject*> pObject::objects;
|
||||
namespace hiro {
|
||||
|
||||
pObject::pObject(Object& object) : object(object) {
|
||||
static unsigned uniqueId = 100;
|
||||
objects.append(this);
|
||||
id = uniqueId++;
|
||||
locked = false;
|
||||
auto pObject::construct() -> void {
|
||||
}
|
||||
|
||||
Object* pObject::find(unsigned id) {
|
||||
for(auto& item : objects) if(item->id == id) return &item->object;
|
||||
return nullptr;
|
||||
auto pObject::destruct() -> void {
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
1 24 "phoenix.Manifest"
|
|
@ -1,7 +1,5 @@
|
|||
#include "platform.hpp"
|
||||
|
||||
#include "utility.cpp"
|
||||
#include "settings.cpp"
|
||||
|
||||
#include "desktop.cpp"
|
||||
#include "monitor.cpp"
|
||||
|
@ -9,17 +7,27 @@
|
|||
#include "mouse.cpp"
|
||||
#include "browser-window.cpp"
|
||||
#include "message-window.cpp"
|
||||
|
||||
#include "object.cpp"
|
||||
#include "group.cpp"
|
||||
|
||||
#include "hotkey.cpp"
|
||||
#include "font.cpp"
|
||||
#include "timer.cpp"
|
||||
#include "window.cpp"
|
||||
#include "status-bar.cpp"
|
||||
#include "menu-bar.cpp"
|
||||
#include "popup-menu.cpp"
|
||||
|
||||
#include "action/action.cpp"
|
||||
#include "action/menu.cpp"
|
||||
#include "action/separator.cpp"
|
||||
#include "action/item.cpp"
|
||||
#include "action/check-item.cpp"
|
||||
#include "action/radio-item.cpp"
|
||||
#include "action/menu-separator.cpp"
|
||||
#include "action/menu-item.cpp"
|
||||
#include "action/menu-check-item.cpp"
|
||||
#include "action/menu-radio-item.cpp"
|
||||
|
||||
#include "sizable.cpp"
|
||||
#include "layout.cpp"
|
||||
|
||||
#include "widget/widget.cpp"
|
||||
#include "widget/button.cpp"
|
||||
|
@ -27,7 +35,7 @@
|
|||
#include "widget/check-button.cpp"
|
||||
#include "widget/check-label.cpp"
|
||||
#include "widget/combo-button.cpp"
|
||||
#include "widget/console.cpp"
|
||||
#include "widget/combo-button-item.cpp"
|
||||
#include "widget/frame.cpp"
|
||||
#include "widget/hex-edit.cpp"
|
||||
#include "widget/horizontal-scroller.cpp"
|
||||
|
@ -35,10 +43,14 @@
|
|||
#include "widget/label.cpp"
|
||||
#include "widget/line-edit.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/radio-button.cpp"
|
||||
#include "widget/radio-label.cpp"
|
||||
#include "widget/tab-frame.cpp"
|
||||
#include "widget/tab-frame-item.cpp"
|
||||
#include "widget/text-edit.cpp"
|
||||
#include "widget/vertical-scroller.cpp"
|
||||
#include "widget/vertical-slider.cpp"
|
||||
|
|
|
@ -1,25 +1,4 @@
|
|||
namespace phoenix {
|
||||
|
||||
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;
|
||||
};
|
||||
namespace hiro {
|
||||
|
||||
struct pFont;
|
||||
struct pObject;
|
||||
|
@ -28,620 +7,81 @@ struct pMenu;
|
|||
struct pLayout;
|
||||
struct pWidget;
|
||||
|
||||
struct pFont {
|
||||
static string serif(unsigned size, string style);
|
||||
static string sans(unsigned size, string style);
|
||||
static string monospace(unsigned size, string style);
|
||||
static Size size(string font, string text);
|
||||
|
||||
static HFONT create(string description);
|
||||
static void free(HFONT hfont);
|
||||
static Size size(HFONT hfont, string text);
|
||||
struct AppMessage {
|
||||
enum : unsigned {
|
||||
None = WM_APP,
|
||||
ListView_onActivate,
|
||||
ListView_onChange,
|
||||
};
|
||||
};
|
||||
|
||||
struct pDesktop {
|
||||
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();
|
||||
};
|
||||
using WindowProc = auto CALLBACK (*)(HWND, UINT, WPARAM, LPARAM) -> LRESULT;
|
||||
|
||||
}
|
||||
|
||||
#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
Loading…
Reference in New Issue