Update to v106r69 release.

byuu says:

The biggest change was improving WonderSwan emulation. With help from
trap15, I tracked down a bug where I was checking the wrong bit for
reverse DMA transfers. Then I also emulated VTOTAL to support variable
refresh rate. Then I improved HyperVoice emulation which should be
unsigned samples in three of four modes. That got Fire Lancer running
great. I also rewrote the disassembler. The old one disassembled many
instructions completely wrong, and deviated too much from any known x86
syntax. I also emulated some of the quirks of the V30 (two-byte POP into
registers fails, SALC is just XLAT mirrored, etc) which probably don't
matter unless someone tries to run code to verify it's a NEC CPU and not
an Intel CPU, but hey, why not?

I also put more work into the MSX skeleton, but it's still just a
skeleton with no real emulation yet.
This commit is contained in:
Tim Allen
2019-01-02 10:52:08 +11:00
parent 3159285eaa
commit aaf094e7c4
115 changed files with 3319 additions and 1394 deletions

View File

@@ -12,6 +12,9 @@ auto pSizable::minimumSize() const -> Size {
return {0, 0};
}
auto pSizable::setCollapsible(bool collapsible) -> void {
}
auto pSizable::setGeometry(Geometry geometry) -> void {
self().doSize();
}

View File

@@ -6,6 +6,7 @@ struct pSizable : pObject {
Declare(Sizable, Object)
virtual auto minimumSize() const -> Size;
virtual auto setCollapsible(bool collapsible) -> void;
virtual auto setGeometry(Geometry geometry) -> void;
};

View File

@@ -28,6 +28,8 @@
}
-(void) run:(NSTimer*)instance {
if(Application::state().quit) return;
if(timer->enabled()) {
timer->doActivate();
}

View File

@@ -1,5 +1,9 @@
#if defined(Hiro_Label)
//todo:
//* Label::onButtonPress()
//* Label::onButtonRelease()
@implementation CocoaLabel : NSTextView
-(id) initWith:(hiro::mLabel&)labelReference {

View File

@@ -106,3 +106,7 @@
#if defined(Hiro_Button) && defined(Hiro_ComboButton) && defined(Hiro_LineEdit) && defined(Hiro_ListView) && defined(Hiro_MessageDialog)
#define Hiro_BrowserDialog
#endif
#if defined(Hiro_Label)
#define Hiro_AboutDialog
#endif

View File

@@ -72,6 +72,14 @@ auto Color::setRed(signed red) -> type& {
return *this;
}
auto Color::setValue(uint32_t value) -> type& {
state.alpha = value >> 24 & 255;
state.red = value >> 16 & 255;
state.green = value >> 8 & 255;
state.blue = value >> 0 & 255;
return *this;
}
auto Color::value() const -> uint32_t {
return state.alpha << 24 | state.red << 16 | state.green << 8 | state.blue << 0;
}

View File

@@ -121,6 +121,7 @@ struct Color {
auto setColor(int red, int green, int blue, int alpha = 255) -> type&;
auto setGreen(int green) -> type&;
auto setRed(int red) -> type&;
auto setValue(uint32_t value) -> type&;
auto value() const -> uint32_t;
//private:
@@ -180,29 +181,7 @@ struct Alignment {
};
#endif
#if defined(Hiro_Cursor)
struct Cursor {
using type = Cursor;
Cursor(int offset = 0, int length = 0);
explicit operator bool() const;
auto operator==(const Cursor& source) const -> bool;
auto operator!=(const Cursor& source) const -> bool;
auto length() const -> int;
auto offset() const -> int;
auto setCursor(int offset = 0, int length = 0) -> type&;
auto setLength(int length = 0) -> type&;
auto setOffset(int offset = 0) -> type&;
//private:
struct State {
int offset;
int length;
} state;
};
#endif
#include "cursor.hpp"
#if defined(Hiro_Position)
struct Position {
@@ -1063,28 +1042,7 @@ struct mIconViewItem : mObject {
};
#endif
#if defined(Hiro_Label)
struct mLabel : mWidget {
Declare(Label)
auto alignment() const -> Alignment;
auto backgroundColor() const -> Color;
auto foregroundColor() const -> Color;
auto setAlignment(Alignment alignment = {}) -> type&;
auto setBackgroundColor(Color color = {}) -> type&;
auto setForegroundColor(Color color = {}) -> type&;
auto setText(const string& text = "") -> type&;
auto text() const -> string;
//private:
struct State {
Alignment alignment;
Color backgroundColor;
Color foregroundColor;
string text;
} state;
};
#endif
#include "widget/label.hpp"
#if defined(Hiro_LineEdit)
struct mLineEdit : mWidget {
@@ -1227,91 +1185,8 @@ struct mTextEdit : mWidget {
};
#endif
#if defined(Hiro_TreeView)
struct mTreeView : mWidget {
Declare(TreeView)
using mObject::remove;
auto append(sTreeViewItem item) -> type&;
auto backgroundColor() const -> Color;
auto doActivate() const -> void;
auto doChange() const -> void;
auto doContext() const -> void;
auto doToggle(sTreeViewItem item) const -> void;
auto foregroundColor() const -> Color;
auto item(const string& path) const -> TreeViewItem;
auto itemCount() const -> uint;
auto items() const -> vector<TreeViewItem>;
auto onActivate(const function<void ()>& callback = {}) -> type&;
auto onChange(const function<void ()>& callback = {}) -> type&;
auto onContext(const function<void ()>& callback = {}) -> type&;
auto onToggle(const function<void (sTreeViewItem)>& callback = {}) -> type&;
auto remove(sTreeViewItem item) -> type&;
auto reset() -> type&;
auto selected() const -> TreeViewItem;
auto setBackgroundColor(Color color = {}) -> type&;
auto setForegroundColor(Color color = {}) -> type&;
auto setParent(mObject* parent = nullptr, int offset = -1) -> type&;
//private:
struct State {
Color backgroundColor;
Color foregroundColor;
vector<sTreeViewItem> items;
function<void ()> onActivate;
function<void ()> onChange;
function<void ()> onContext;
function<void (sTreeViewItem)> onToggle;
string selectedPath;
} state;
auto destruct() -> void override;
};
#endif
#if defined(Hiro_TreeView)
struct mTreeViewItem : mObject {
Declare(TreeViewItem)
auto append(sTreeViewItem item) -> type&;
auto backgroundColor(bool recursive = false) const -> Color;
auto checkable() const -> bool;
auto checked() const -> bool;
auto foregroundColor(bool recursive = false) const -> Color;
auto icon() const -> image;
auto item(const string& path) const -> TreeViewItem;
auto itemCount() const -> uint;
auto items() const -> vector<TreeViewItem>;
auto path() const -> string;
auto remove() -> type& override;
auto remove(sTreeViewItem item) -> type&;
auto selected() const -> bool;
auto setBackgroundColor(Color color = {}) -> type&;
auto setCheckable(bool checkable = true) -> type&;
auto setChecked(bool checked = true) -> type&;
auto setExpanded(bool expanded = true) -> type&;
auto setFocused() -> type& override;
auto setForegroundColor(Color color = {}) -> type&;
auto setIcon(const image& icon = {}) -> type&;
auto setParent(mObject* parent = nullptr, int offset = -1) -> type&;
auto setSelected() -> type&;
auto setText(const string& text = "") -> type&;
auto text() const -> string;
//private:
struct State {
Color backgroundColor;
bool checkable = false;
bool checked = false;
Color foregroundColor;
image icon;
vector<sTreeViewItem> items;
string text;
} state;
auto destruct() -> void override;
};
#endif
#include "widget/tree-view.hpp"
#include "widget/tree-view-item.hpp"
#if defined(Hiro_VerticalScrollBar)
struct mVerticalScrollBar : mWidget {

View File

@@ -1,11 +1,11 @@
#if defined(Hiro_Cursor)
Cursor::Cursor(signed offset, signed length) {
Cursor::Cursor(int offset, int length) {
setCursor(offset, length);
}
Cursor::operator bool() const {
return offset() && length();
return offset() || length();
}
auto Cursor::operator==(const Cursor& source) const -> bool {
@@ -16,27 +16,27 @@ auto Cursor::operator!=(const Cursor& source) const -> bool {
return !operator==(source);
}
auto Cursor::length() const -> signed {
auto Cursor::length() const -> int {
return state.length;
}
auto Cursor::offset() const -> signed {
auto Cursor::offset() const -> int {
return state.offset;
}
auto Cursor::setCursor(signed offset, signed length) -> type& {
auto Cursor::setCursor(int offset, int length) -> type& {
state.offset = offset;
state.length = length;
return *this;
}
auto Cursor::setOffset(signed offset) -> type& {
state.offset = offset;
auto Cursor::setLength(int length) -> type& {
state.length = length;
return *this;
}
auto Cursor::setLength(signed length) -> type& {
state.length = length;
auto Cursor::setOffset(int offset) -> type& {
state.offset = offset;
return *this;
}

23
hiro/core/cursor.hpp Normal file
View File

@@ -0,0 +1,23 @@
#if defined(Hiro_Cursor)
struct Cursor {
using type = Cursor;
Cursor(int offset = 0, int length = 0);
explicit operator bool() const;
auto operator==(const Cursor& source) const -> bool;
auto operator!=(const Cursor& source) const -> bool;
auto length() const -> int;
auto offset() const -> int;
auto setCursor(int offset = 0, int length = 0) -> type&;
auto setLength(int length = 0) -> type&;
auto setOffset(int offset = 0) -> type&;
//private:
struct State {
int offset;
int length;
} state;
};
#endif

View File

@@ -52,10 +52,12 @@
#define DeclareSharedSizable(Name) \
DeclareSharedObject(Name) \
auto collapsible() const { return self().collapsible(); } \
auto doSize() const { return self().doSize(); } \
auto geometry() const { return self().geometry(); } \
auto minimumSize() const { return self().minimumSize(); } \
auto onSize(const function<void ()>& callback = {}) { return self().onSize(callback), *this; } \
auto setCollapsible(bool collapsible = true) { return self().setCollapsible(collapsible), *this; } \
auto setGeometry(Geometry geometry) { return self().setGeometry(geometry), *this; } \
#define DeclareSharedWidget(Name) \
@@ -461,7 +463,11 @@ struct Label : sLabel {
auto alignment() const { return self().alignment(); }
auto backgroundColor() const { return self().backgroundColor(); }
auto doMousePress(Mouse::Button button) const { return self().doMousePress(button); }
auto doMouseRelease(Mouse::Button button) const { return self().doMouseRelease(button); }
auto foregroundColor() const { return self().foregroundColor(); }
auto onMousePress(const function<void (Mouse::Button)>& callback = {}) { return self().onMousePress(callback), *this; }
auto onMouseRelease(const function<void (Mouse::Button)>& callback = {}) { return self().onMouseRelease(callback), *this; }
auto setAlignment(Alignment alignment = {}) { return self().setAlignment(alignment), *this; }
auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; }
auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; }
@@ -540,10 +546,16 @@ struct SourceEdit : sSourceEdit {
auto doChange() const { return self().doChange(); }
auto doMove() const { return self().doMove(); }
auto editable() const { return self().editable(); }
auto language() const { return self().language(); }
auto numbered() const { return self().numbered(); }
auto onChange(const function<void ()>& callback = {}) { return self().onChange(callback), *this; }
auto onMove(const function<void ()>& callback = {}) { return self().onMove(callback), *this; }
auto scheme() const { return self().scheme(); }
auto setCursor(Cursor cursor = {}) { return self().setCursor(cursor), *this; }
auto setEditable(bool editable = true) { return self().setEditable(editable), *this; }
auto setLanguage(const string& language = "") { return self().setLanguage(language), *this; }
auto setNumbered(bool numbered = true) { return self().setNumbered(numbered), *this; }
auto setScheme(const string& scheme = "") { return self().setScheme(scheme), *this; }
auto setText(const string& text = "") { return self().setText(text), *this; }
auto setWordWrap(bool wordWrap = true) { return self().setWordWrap(wordWrap), *this; }
auto text() const { return self().text(); }
@@ -749,6 +761,7 @@ struct TreeViewItem : sTreeViewItem {
auto backgroundColor() const { return self().backgroundColor(); }
auto checkable() const { return self().checkable(); }
auto checked() const { return self().checked(); }
auto expanded() const { return self().expanded(); }
auto foregroundColor() const { return self().foregroundColor(); }
auto icon() const { return self().icon(); }
auto item(const string& path) const { return self().item(path); }

View File

@@ -4,6 +4,10 @@ auto mSizable::allocate() -> pObject* {
return new pSizable(*this);
}
auto mSizable::collapsible() const -> bool {
return state.collapsible;
}
auto mSizable::doSize() const -> void {
if(state.onSize) return state.onSize();
}
@@ -21,6 +25,12 @@ auto mSizable::onSize(const function<void ()>& callback) -> type& {
return *this;
}
auto mSizable::setCollapsible(bool collapsible) -> type& {
state.collapsible = collapsible;
signal(setCollapsible, collapsible);
return *this;
}
auto mSizable::setGeometry(Geometry geometry) -> type& {
state.geometry = geometry;
signal(setGeometry, geometry);

View File

@@ -2,15 +2,17 @@
struct mSizable : mObject {
Declare(Sizable)
auto collapsible() const -> bool;
auto doSize() const -> void;
auto geometry() const -> Geometry;
virtual auto minimumSize() const -> Size;
auto onSize(const function<void ()>& callback = {}) -> type&;
virtual auto setCollapsible(bool collapsible = true) -> type&;
virtual auto setGeometry(Geometry geometry) -> type&;
//private:
//sizeof(mSizable) == 24
struct State {
bool collapsible = false;
Geometry geometry;
function<void ()> onSize;
} state;

View File

@@ -14,10 +14,28 @@ auto mLabel::backgroundColor() const -> Color {
return state.backgroundColor;
}
auto mLabel::doMousePress(Mouse::Button button) const -> void {
if(state.onMousePress) return state.onMousePress(button);
}
auto mLabel::doMouseRelease(Mouse::Button button) const -> void {
if(state.onMouseRelease) return state.onMouseRelease(button);
}
auto mLabel::foregroundColor() const -> Color {
return state.foregroundColor;
}
auto mLabel::onMousePress(const function<void (Mouse::Button)>& callback) -> type& {
state.onMousePress = callback;
return *this;
}
auto mLabel::onMouseRelease(const function<void (Mouse::Button)>& callback) -> type& {
state.onMouseRelease = callback;
return *this;
}
auto mLabel::setAlignment(Alignment alignment) -> type& {
state.alignment = alignment;
signal(setAlignment, alignment);

View File

@@ -0,0 +1,28 @@
#if defined(Hiro_Label)
struct mLabel : mWidget {
Declare(Label)
auto alignment() const -> Alignment;
auto backgroundColor() const -> Color;
auto doMousePress(Mouse::Button button) const -> void;
auto doMouseRelease(Mouse::Button button) const -> void;
auto foregroundColor() const -> Color;
auto onMousePress(const function<void (Mouse::Button)>& callback = {}) -> type&;
auto onMouseRelease(const function<void (Mouse::Button)>& callback = {}) -> type&;
auto setAlignment(Alignment alignment = {}) -> type&;
auto setBackgroundColor(Color color = {}) -> type&;
auto setForegroundColor(Color color = {}) -> type&;
auto setText(const string& text = "") -> type&;
auto text() const -> string;
//private:
struct State {
Alignment alignment;
Color backgroundColor;
Color foregroundColor;
function<void (Mouse::Button)> onMousePress;
function<void (Mouse::Button)> onMouseRelease;
string text;
} state;
};
#endif

View File

@@ -7,7 +7,7 @@ auto mSourceEdit::allocate() -> pObject* {
//
auto mSourceEdit::cursor() const -> Cursor {
return state.cursor;
return signal(cursor);
}
auto mSourceEdit::doChange() const -> void {
@@ -22,6 +22,14 @@ auto mSourceEdit::editable() const -> bool {
return state.editable;
}
auto mSourceEdit::language() const -> string {
return state.language;
}
auto mSourceEdit::numbered() const -> bool {
return state.numbered;
}
auto mSourceEdit::onChange(const function<void ()>& callback) -> type& {
state.onChange = callback;
return *this;
@@ -32,8 +40,11 @@ auto mSourceEdit::onMove(const function<void ()>& callback) -> type& {
return *this;
}
auto mSourceEdit::scheme() const -> string {
return state.scheme;
}
auto mSourceEdit::setCursor(Cursor cursor) -> type& {
state.cursor = cursor;
signal(setCursor, cursor);
return *this;
}
@@ -44,6 +55,24 @@ auto mSourceEdit::setEditable(bool editable) -> type& {
return *this;
}
auto mSourceEdit::setLanguage(const string& language) -> type& {
state.language = language;
signal(setLanguage, language);
return *this;
}
auto mSourceEdit::setNumbered(bool numbered) -> type& {
state.numbered = numbered;
signal(setNumbered, numbered);
return *this;
}
auto mSourceEdit::setScheme(const string& scheme) -> type& {
state.scheme = scheme;
signal(setScheme, scheme);
return *this;
}
auto mSourceEdit::setText(const string& text) -> type& {
state.text = text;
signal(setText, text);

View File

@@ -6,10 +6,16 @@ struct mSourceEdit : mWidget {
auto doChange() const -> void;
auto doMove() const -> void;
auto editable() const -> bool;
auto language() const -> string;
auto numbered() const -> bool;
auto onChange(const function<void ()>& callback = {}) -> type&;
auto onMove(const function<void ()>& callback = {}) -> type&;
auto scheme() const -> string;
auto setCursor(Cursor cursor = {}) -> type&;
auto setEditable(bool editable) -> type&;
auto setLanguage(const string& language = "") -> type&;
auto setNumbered(bool numbered = true) -> type&;
auto setScheme(const string& scheme = "") -> type&;
auto setText(const string& text = "") -> type&;
auto setWordWrap(bool wordWrap = true) -> type&;
auto text() const -> string;
@@ -17,10 +23,12 @@ struct mSourceEdit : mWidget {
//private:
struct State {
Cursor cursor;
bool editable = true;
string language;
bool numbered = true;
function<void ()> onChange;
function<void ()> onMove;
string scheme;
string text;
bool wordWrap = true;
} state;

View File

@@ -39,6 +39,10 @@ auto mTreeViewItem::checked() const -> bool {
return state.checked;
}
auto mTreeViewItem::expanded() const -> bool {
return state.expanded;
}
auto mTreeViewItem::foregroundColor(bool recursive) const -> Color {
if(auto color = state.foregroundColor) return color;
if(recursive) {
@@ -122,6 +126,7 @@ auto mTreeViewItem::setChecked(bool checked) -> type& {
}
auto mTreeViewItem::setExpanded(bool expanded) -> type& {
state.expanded = expanded;
signal(setExpanded, expanded);
return *this;
}

View File

@@ -0,0 +1,45 @@
#if defined(Hiro_TreeView)
struct mTreeViewItem : mObject {
Declare(TreeViewItem)
auto append(sTreeViewItem item) -> type&;
auto backgroundColor(bool recursive = false) const -> Color;
auto checkable() const -> bool;
auto checked() const -> bool;
auto expanded() const -> bool;
auto foregroundColor(bool recursive = false) const -> Color;
auto icon() const -> image;
auto item(const string& path) const -> TreeViewItem;
auto itemCount() const -> uint;
auto items() const -> vector<TreeViewItem>;
auto path() const -> string;
auto remove() -> type& override;
auto remove(sTreeViewItem item) -> type&;
auto selected() const -> bool;
auto setBackgroundColor(Color color = {}) -> type&;
auto setCheckable(bool checkable = true) -> type&;
auto setChecked(bool checked = true) -> type&;
auto setExpanded(bool expanded = true) -> type&;
auto setFocused() -> type& override;
auto setForegroundColor(Color color = {}) -> type&;
auto setIcon(const image& icon = {}) -> type&;
auto setParent(mObject* parent = nullptr, int offset = -1) -> type&;
auto setSelected() -> type&;
auto setText(const string& text = "") -> type&;
auto text() const -> string;
//private:
struct State {
Color backgroundColor;
bool checkable = false;
bool checked = false;
bool expanded = false;
Color foregroundColor;
image icon;
vector<sTreeViewItem> items;
string text;
} state;
auto destruct() -> void override;
};
#endif

View File

@@ -0,0 +1,41 @@
#if defined(Hiro_TreeView)
struct mTreeView : mWidget {
Declare(TreeView)
using mObject::remove;
auto append(sTreeViewItem item) -> type&;
auto backgroundColor() const -> Color;
auto doActivate() const -> void;
auto doChange() const -> void;
auto doContext() const -> void;
auto doToggle(sTreeViewItem item) const -> void;
auto foregroundColor() const -> Color;
auto item(const string& path) const -> TreeViewItem;
auto itemCount() const -> uint;
auto items() const -> vector<TreeViewItem>;
auto onActivate(const function<void ()>& callback = {}) -> type&;
auto onChange(const function<void ()>& callback = {}) -> type&;
auto onContext(const function<void ()>& callback = {}) -> type&;
auto onToggle(const function<void (sTreeViewItem)>& callback = {}) -> type&;
auto remove(sTreeViewItem item) -> type&;
auto reset() -> type&;
auto selected() const -> TreeViewItem;
auto setBackgroundColor(Color color = {}) -> type&;
auto setForegroundColor(Color color = {}) -> type&;
auto setParent(mObject* parent = nullptr, int offset = -1) -> type&;
//private:
struct State {
Color backgroundColor;
Color foregroundColor;
vector<sTreeViewItem> items;
function<void ()> onActivate;
function<void ()> onChange;
function<void ()> onContext;
function<void (sTreeViewItem)> onToggle;
string selectedPath;
} state;
auto destruct() -> void override;
};
#endif

View File

@@ -0,0 +1,141 @@
#if defined(Hiro_AboutDialog)
auto AboutDialog::setAuthor(const string& author) -> type& {
state.author = author;
return *this;
}
auto AboutDialog::setDescription(const string& description) -> type& {
state.description = description;
return *this;
}
auto AboutDialog::setLicense(const string& license) -> type& {
state.license = license;
return *this;
}
auto AboutDialog::setLogo(const image& logo) -> type& {
state.logo = logo;
state.logo.transform();
state.logo.alphaBlend(0xfffff0);
return *this;
}
auto AboutDialog::setName(const string& name) -> type& {
state.name = name;
return *this;
}
auto AboutDialog::setParent(sWindow parent) -> type& {
state.parent = parent;
return *this;
}
auto AboutDialog::setVersion(const string& version) -> type& {
state.version = version;
return *this;
}
auto AboutDialog::setWebsite(const string& website) -> type& {
state.website = website;
return *this;
}
auto AboutDialog::show() -> void {
Window window;
window.onClose([&] { window.setModal(false); });
VerticalLayout layout{&window};
layout.setPadding(5);
Label nameLabel{&layout, Size{~0, 0}};
nameLabel.setCollapsible();
nameLabel.setAlignment(0.5);
nameLabel.setForegroundColor({0, 0, 0});
nameLabel.setFont(Font().setFamily("Georgia").setBold().setSize(36.0));
nameLabel.setText(state.name ? state.name : Application::name());
nameLabel.setVisible(!state.logo);
Canvas logoCanvas{&layout, Size{~0, 0}};
logoCanvas.setCollapsible();
logoCanvas.setIcon(state.logo);
logoCanvas.setVisible((bool)state.logo);
Label descriptionLabel{&layout, Size{~0, 0}};
descriptionLabel.setCollapsible();
descriptionLabel.setAlignment(0.5);
descriptionLabel.setForegroundColor({0, 0, 0});
descriptionLabel.setText(state.description);
if(!state.description) descriptionLabel.setVisible(false);
HorizontalLayout versionLayout{&layout, Size{~0, 0}, 0};
versionLayout.setCollapsible();
Label versionLabel{&versionLayout, Size{~0, 0}, 3};
versionLabel.setAlignment(1.0);
versionLabel.setFont(Font().setBold());
versionLabel.setForegroundColor({0, 0, 0});
versionLabel.setText("Version:");
Label versionValue{&versionLayout, Size{~0, 0}};
versionValue.setAlignment(0.0);
versionValue.setFont(Font().setBold());
versionValue.setForegroundColor({0, 0, 0});
versionValue.setText(state.version);
if(!state.version) versionLayout.setVisible(false);
HorizontalLayout authorLayout{&layout, Size{~0, 0}, 0};
authorLayout.setCollapsible();
Label authorLabel{&authorLayout, Size{~0, 0}, 3};
authorLabel.setAlignment(1.0);
authorLabel.setFont(Font().setBold());
authorLabel.setForegroundColor({0, 0, 0});
authorLabel.setText("Author:");
Label authorValue{&authorLayout, Size{~0, 0}};
authorValue.setAlignment(0.0);
authorValue.setFont(Font().setBold());
authorValue.setForegroundColor({0, 0, 0});
authorValue.setText(state.author);
if(!state.author) authorLayout.setVisible(false);
HorizontalLayout licenseLayout{&layout, Size{~0, 0}, 0};
licenseLayout.setCollapsible();
Label licenseLabel{&licenseLayout, Size{~0, 0}, 3};
licenseLabel.setAlignment(1.0);
licenseLabel.setFont(Font().setBold());
licenseLabel.setForegroundColor({0, 0, 0});
licenseLabel.setText("License:");
Label licenseValue{&licenseLayout, Size{~0, 0}};
licenseValue.setAlignment(0.0);
licenseValue.setFont(Font().setBold());
licenseValue.setForegroundColor({0, 0, 0});
licenseValue.setText(state.license);
if(!state.license) licenseLayout.setVisible(false);
HorizontalLayout websiteLayout{&layout, Size{~0, 0}, 0};
websiteLayout.setCollapsible();
Label websiteLabel{&websiteLayout, Size{~0, 0}, 3};
websiteLabel.setAlignment(1.0);
websiteLabel.setFont(Font().setBold());
websiteLabel.setForegroundColor({0, 0, 0});
websiteLabel.setText("Website:");
Label websiteValue{&websiteLayout, Size{~0, 0}};
websiteValue.setAlignment(0.0);
websiteValue.setFont(Font().setBold());
websiteValue.setForegroundColor({0, 0, 240});
websiteValue.setText(state.website);
websiteValue.onMouseRelease([&](Mouse::Button button) {
if(button == Mouse::Button::Left) invoke(state.website);
});
if(!state.website) websiteLayout.setVisible(false);
window.setTitle({"About ", state.name ? state.name : Application::name(), " ..."});
window.setBackgroundColor({255, 255, 240});
window.setSize({max(360, layout.minimumSize().width()), layout.minimumSize().height()});
window.setResizable(false);
window.setCentered(state.parent);
window.setDismissable();
window.setVisible();
window.setModal();
}
#endif

View File

@@ -0,0 +1,29 @@
#if defined(Hiro_AboutDialog)
struct AboutDialog {
using type = AboutDialog;
auto setAuthor(const string& author = "") -> type&;
auto setDescription(const string& description = "") -> type&;
auto setLicense(const string& license = "") -> type&;
auto setLogo(const image& logo = {}) -> type&;
auto setName(const string& name = "") -> type&;
auto setParent(sWindow parent = {}) -> type&;
auto setVersion(const string& version = "") -> type&;
auto setWebsite(const string& website = "") -> type&;
auto show() -> void;
private:
struct State {
string author;
string description;
string license;
image logo;
string name;
sWindow parent;
string version;
string website;
} state;
};
#endif

View File

@@ -162,7 +162,7 @@ auto BrowserDialogWindow::run() -> BrowserDialog::Response {
auto part = filter.split("|", 1L);
filterList.append(ComboButtonItem().setText(part.left()));
}
optionList.setVisible((bool)state.options).onChange([&] { response.option = optionList.selected().text(); });
optionList.setCollapsible().setVisible((bool)state.options).onChange([&] { response.option = optionList.selected().text(); });
for(auto& option : state.options) {
optionList.append(ComboButtonItem().setText(option));
}

View File

@@ -10,4 +10,5 @@ namespace hiro {
#include "list-view.cpp"
#include "browser-dialog.cpp"
#include "message-dialog.cpp"
#include "about-dialog.cpp"
}

View File

@@ -8,4 +8,5 @@ namespace hiro {
#include "shared.hpp"
#include "browser-dialog.hpp"
#include "message-dialog.hpp"
#include "about-dialog.hpp"
}

View File

@@ -40,19 +40,23 @@ auto mHorizontalLayout::destruct() -> void {
auto mHorizontalLayout::minimumSize() const -> Size {
float width = 0;
float spacing = 0;
for(auto index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(cell.size().width() == Size::Minimum || cell.size().width() == Size::Maximum) {
width += cell.sizable().minimumSize().width();
} else {
width += cell.size().width();
}
if(index != cellCount() - 1) width += cell.spacing();
width += spacing;
spacing = cell.spacing();
}
float height = 0;
for(auto index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(cell.size().height() == Size::Minimum || cell.size().height() == Size::Maximum) {
height = max(height, cell.sizable().minimumSize().height());
continue;
@@ -108,10 +112,10 @@ auto mHorizontalLayout::setFont(const Font& font) -> type& {
return *this;
}
auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
mSizable::setGeometry(geometry);
if(!visible(true)) return *this;
auto mHorizontalLayout::setGeometry(Geometry requestedGeometry) -> type& {
if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
geometry.setY(geometry.y() + padding().y());
geometry.setWidth (geometry.width() - padding().x() - padding().width());
@@ -120,8 +124,9 @@ auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
vector<float> widths;
widths.resize(cellCount());
uint maximumWidths = 0;
for(auto index : range(cellCount())) {
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
float width = 0;
if(cell.size().width() == Size::Maximum) {
width = Size::Maximum;
@@ -135,9 +140,13 @@ auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
}
float fixedWidth = 0;
for(uint index : range(state.cells.size())) {
float spacing = 0;
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(widths[index] != Size::Maximum) fixedWidth += widths[index];
if(index != cellCount() - 1) fixedWidth += cell(index).spacing();
fixedWidth += spacing;
spacing = cell.spacing();
}
float maximumWidth = (geometry.width() - fixedWidth) / maximumWidths;
@@ -146,8 +155,9 @@ auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
}
float height = 0;
for(auto index : range(cellCount())) {
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(cell.size().height() == Size::Maximum) {
height = geometry.height();
break;
@@ -160,10 +170,11 @@ auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
float geometryX = geometry.x();
float geometryY = geometry.y();
for(auto index : range(cellCount())) {
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
float geometryWidth = widths[index];
float geometryHeight = height;
auto cell = this->cell(index);
auto alignment = cell.alignment();
if(!alignment) alignment = this->alignment();
if(!alignment) alignment = 0.5;
@@ -177,6 +188,7 @@ auto mHorizontalLayout::setGeometry(Geometry geometry) -> type& {
geometryX += geometryWidth + cell.spacing();
}
mSizable::setGeometry(requestedGeometry);
return *this;
}
@@ -218,6 +230,11 @@ auto mHorizontalLayoutCell::alignment() const -> maybe<float> {
return state.alignment;
}
auto mHorizontalLayoutCell::collapsible() const -> bool {
if(state.sizable) return state.sizable->collapsible() && !state.sizable->visible();
return false;
}
auto mHorizontalLayoutCell::destruct() -> void {
if(auto& sizable = state.sizable) sizable->destruct();
mObject::destruct();

View File

@@ -49,6 +49,7 @@ struct mHorizontalLayoutCell : mObject {
using type = mHorizontalLayoutCell;
auto alignment() const -> maybe<float>;
auto collapsible() const -> bool;
auto setAlignment(maybe<float> alignment) -> type&;
auto setEnabled(bool enabled) -> type& override;
auto setFont(const Font& font) -> type& override;

View File

@@ -26,6 +26,7 @@ struct HorizontalLayoutCell : sHorizontalLayoutCell {
DeclareSharedObject(HorizontalLayoutCell)
auto alignment() const { return self().alignment(); }
auto collapsible() const { return self().collapsible(); }
auto setAlignment(maybe<float> alignment = {}) { return self().setAlignment(alignment), *this; }
auto setSizable(sSizable sizable) { return self().setSizable(sizable), *this; }
auto setSize(Size size) { return self().setSize(size), *this; }
@@ -58,6 +59,7 @@ struct VerticalLayoutCell : sVerticalLayoutCell {
DeclareSharedObject(VerticalLayoutCell)
auto alignment() const { return self().alignment(); }
auto collapsible() const { return self().collapsible(); }
auto setAlignment(maybe<float> alignment = {}) { return self().setAlignment(alignment), *this; }
auto setSizable(sSizable sizable) { return self().setSizable(sizable), *this; }
auto setSize(Size size) { return self().setSize(size), *this; }

View File

@@ -143,10 +143,10 @@ auto mTableLayout::setFont(const Font& font) -> type& {
return *this;
}
auto mTableLayout::setGeometry(Geometry geometry) -> type& {
mSizable::setGeometry(geometry);
if(!visible(true)) return *this;
auto mTableLayout::setGeometry(Geometry requestedGeometry) -> type& {
if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
geometry.setY(geometry.y() + padding().y());
geometry.setWidth (geometry.width() - padding().x() - padding().width());
@@ -250,6 +250,7 @@ auto mTableLayout::setGeometry(Geometry geometry) -> type& {
geometryY += heights[y] + row.spacing();
}
mSizable::setGeometry(requestedGeometry);
return *this;
}

View File

@@ -42,6 +42,7 @@ auto mVerticalLayout::minimumSize() const -> Size {
float width = 0;
for(auto index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(cell.size().width() == Size::Minimum || cell.size().width() == Size::Maximum) {
width = max(width, cell.sizable().minimumSize().width());
continue;
@@ -50,14 +51,17 @@ auto mVerticalLayout::minimumSize() const -> Size {
}
float height = 0;
float spacing = 0;
for(auto index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(cell.size().height() == Size::Minimum || cell.size().height() == Size::Maximum) {
height += cell.sizable().minimumSize().height();
} else {
height += cell.size().height();
}
if(index != cellCount() - 1) height += cell.spacing();
height += spacing;
spacing = cell.spacing();
}
return {
@@ -108,18 +112,19 @@ auto mVerticalLayout::setFont(const Font& font) -> type& {
return *this;
}
auto mVerticalLayout::setGeometry(Geometry geometry) -> type& {
mSizable::setGeometry(geometry);
if(!visible(true)) return *this;
auto mVerticalLayout::setGeometry(Geometry requestedGeometry) -> type& {
if(!visible(true)) return mSizable::setGeometry(requestedGeometry), *this;
auto geometry = requestedGeometry;
geometry.setX(geometry.x() + padding().x());
geometry.setY(geometry.y() + padding().y());
geometry.setWidth (geometry.width() - padding().x() - padding().width());
geometry.setHeight(geometry.height() - padding().y() - padding().height());
float width = 0;
for(auto index : range(cellCount())) {
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(cell.size().width() == Size::Maximum) {
width = geometry.width();
break;
@@ -133,8 +138,9 @@ auto mVerticalLayout::setGeometry(Geometry geometry) -> type& {
vector<float> heights;
heights.resize(cellCount());
uint maximumHeights = 0;
for(auto index : range(cellCount())) {
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
float height = 0;
if(cell.size().height() == Size::Maximum) {
height = Size::Maximum;
@@ -148,9 +154,13 @@ auto mVerticalLayout::setGeometry(Geometry geometry) -> type& {
}
float fixedHeight = 0;
for(uint index : range(state.cells.size())) {
float spacing = 0;
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
if(heights[index] != Size::Maximum) fixedHeight += heights[index];
if(index != cellCount() - 1) fixedHeight += cell(index).spacing();
fixedHeight += spacing;
spacing = cell.spacing();
}
float maximumHeight = (geometry.height() - fixedHeight) / maximumHeights;
@@ -160,10 +170,11 @@ auto mVerticalLayout::setGeometry(Geometry geometry) -> type& {
float geometryX = geometry.x();
float geometryY = geometry.y();
for(auto index : range(cellCount())) {
for(uint index : range(cellCount())) {
auto cell = this->cell(index);
if(cell.collapsible()) continue;
float geometryWidth = width;
float geometryHeight = heights[index];
auto cell = this->cell(index);
auto alignment = cell.alignment();
if(!alignment) alignment = this->alignment();
if(!alignment) alignment = 0.0;
@@ -177,6 +188,7 @@ auto mVerticalLayout::setGeometry(Geometry geometry) -> type& {
geometryY += geometryHeight + cell.spacing();
}
mSizable::setGeometry(requestedGeometry);
return *this;
}
@@ -218,6 +230,11 @@ auto mVerticalLayoutCell::alignment() const -> maybe<float> {
return state.alignment;
}
auto mVerticalLayoutCell::collapsible() const -> bool {
if(state.sizable) return state.sizable->collapsible() && !state.sizable->visible();
return false;
}
auto mVerticalLayoutCell::destruct() -> void {
if(auto& sizable = state.sizable) sizable->destruct();
mObject::destruct();

View File

@@ -49,6 +49,7 @@ struct mVerticalLayoutCell : mObject {
using type = mVerticalLayoutCell;
auto alignment() const -> maybe<float>;
auto collapsible() const -> bool;
auto setAlignment(maybe<float> alignment) -> type&;
auto setEnabled(bool enabled) -> type& override;
auto setFont(const Font& font) -> type& override;

View File

@@ -10,6 +10,9 @@ auto pApplication::run() -> void {
while(!Application::state().quit) {
Application::doMain();
processEvents();
//avoid spinlooping the thread when there is no main loop ...
//when there is one, Application::onMain() is expected to sleep when possible instead
if(!Application::state().onMain) usleep(2000);
}
}
@@ -18,7 +21,13 @@ auto pApplication::pendingEvents() -> bool {
}
auto pApplication::processEvents() -> void {
while(pendingEvents()) gtk_main_iteration_do(false);
//GTK can sometimes return gtk_pending_events() == true forever,
//no matter how many times gtk_main_iteration_do() is called.
//implement a timeout to prevent hiro from hanging forever in this case.
auto time = chrono::millisecond();
while(pendingEvents() && chrono::millisecond() - time < 50) {
gtk_main_iteration_do(false);
}
for(auto& window : state().windows) window->_synchronizeGeometry();
}

View File

@@ -16,7 +16,8 @@ auto pFont::size(PangoFontDescription* font, const string& text) -> Size {
pango_layout_set_text(layout, text, -1);
int width = 0, height = 0;
pango_layout_get_pixel_size(layout, &width, &height);
g_object_unref((gpointer)layout);
g_object_unref(layout);
g_object_unref(context);
return {width, height};
}
@@ -29,7 +30,7 @@ auto pFont::family(const string& family) -> string {
#elif defined(DISPLAY_XORG)
if(family == Font::Sans ) return "Sans";
if(family == Font::Serif) return "Serif";
if(family == Font::Mono ) return "Liberation Mono";
if(family == Font::Mono ) return "Monospace";
return family ? family : "Sans";
#else
return family;

View File

@@ -12,6 +12,9 @@ auto pSizable::minimumSize() const -> Size {
return {0, 0};
}
auto pSizable::setCollapsible(bool collapsible) -> void {
}
auto pSizable::setGeometry(Geometry geometry) -> void {
self().doSize();
}

View File

@@ -6,6 +6,7 @@ struct pSizable : pObject {
Declare(Sizable, Object)
virtual auto minimumSize() const -> Size;
virtual auto setCollapsible(bool collapsible) -> void;
virtual auto setGeometry(Geometry geometry) -> void;
};

View File

@@ -3,6 +3,9 @@
namespace hiro {
static auto Timer_trigger(pTimer* p) -> signed {
//prevent all timers from firing once the program has been terminated
if(Application::state().quit) return false;
//timer may have been disabled prior to triggering, so check state
if(p->self().enabled(true)) p->self().doActivate();

View File

@@ -46,6 +46,24 @@ static auto Label_expose(GtkWidget* widget, GdkEvent* event, pLabel* p) -> int {
return false;
}
static auto Label_mousePress(GtkWidget* widget, GdkEventButton* event, pLabel* p) -> int {
switch(event->button) {
case 1: p->self().doMousePress(Mouse::Button::Left); break;
case 2: p->self().doMousePress(Mouse::Button::Middle); break;
case 3: p->self().doMousePress(Mouse::Button::Right); break;
}
return true;
}
static auto Label_mouseRelease(GtkWidget* widget, GdkEventButton* event, pLabel* p) -> int {
switch(event->button) {
case 1: p->self().doMouseRelease(Mouse::Button::Left); break;
case 2: p->self().doMouseRelease(Mouse::Button::Middle); break;
case 3: p->self().doMouseRelease(Mouse::Button::Right); break;
}
return true;
}
auto pLabel::construct() -> void {
gtkWidget = gtk_event_box_new();
subWidget = gtk_label_new("");
@@ -57,6 +75,8 @@ auto pLabel::construct() -> void {
setForegroundColor(state().foregroundColor);
setText(state().text);
g_signal_connect(G_OBJECT(gtkWidget), "button-press-event", G_CALLBACK(Label_mousePress), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "button-release-event", G_CALLBACK(Label_mouseRelease), (gpointer)this);
#if HIRO_GTK==2
g_signal_connect(G_OBJECT(subWidget), "expose-event", G_CALLBACK(Label_expose), (gpointer)this);
#elif HIRO_GTK==3

View File

@@ -7,13 +7,7 @@ static auto SourceEdit_change(GtkTextBuffer*, pSourceEdit* p) -> void {
}
static auto SourceEdit_move(GObject*, GParamSpec*, pSourceEdit* p) -> void {
signed offset = 0;
g_object_get(G_OBJECT(p->gtkSourceBuffer), "cursor-position", &offset, nullptr);
if(p->state().cursor.offset() != offset) {
p->state().cursor.setOffset(offset);
if(!p->locked()) p->self().doMove();
}
if(!p->locked()) p->self().doMove();
}
auto pSourceEdit::construct() -> void {
@@ -24,16 +18,16 @@ auto pSourceEdit::construct() -> void {
gtk_scrolled_window_set_shadow_type(gtkScrolledWindow, GTK_SHADOW_ETCHED_IN);
gtkSourceLanguageManager = gtk_source_language_manager_get_default();
gtkSourceLanguage = gtk_source_language_manager_get_language(gtkSourceLanguageManager, "cpp");
gtkSourceLanguage = gtk_source_language_manager_get_language(gtkSourceLanguageManager, "");
gtkSourceStyleSchemeManager = gtk_source_style_scheme_manager_get_default();
gtkSourceStyleScheme = gtk_source_style_scheme_manager_get_scheme(gtkSourceStyleSchemeManager, "oblivion");
gtkSourceStyleScheme = gtk_source_style_scheme_manager_get_scheme(gtkSourceStyleSchemeManager, "classic");
gtkSourceBuffer = gtk_source_buffer_new(nullptr);
gtkTextBuffer = GTK_TEXT_BUFFER(gtkSourceBuffer);
gtk_source_buffer_set_highlight_matching_brackets(gtkSourceBuffer, true);
gtk_source_buffer_set_highlight_syntax(gtkSourceBuffer, true);
//gtk_source_buffer_set_language(gtkSourceBuffer, gtkSourceLanguage);
gtk_source_buffer_set_language(gtkSourceBuffer, gtkSourceLanguage);
gtk_source_buffer_set_style_scheme(gtkSourceBuffer, gtkSourceStyleScheme);
gtkSourceView = (GtkSourceView*)gtk_source_view_new_with_buffer(gtkSourceBuffer);
@@ -55,6 +49,9 @@ auto pSourceEdit::construct() -> void {
gtk_widget_show(gtkWidgetSourceView);
setEditable(state().editable);
setLanguage(state().language);
setNumbered(state().numbered);
setScheme(state().scheme);
setText(state().text);
setWordWrap(state().wordWrap);
@@ -70,6 +67,23 @@ auto pSourceEdit::destruct() -> void {
gtk_widget_destroy(gtkWidget);
}
auto pSourceEdit::cursor() const -> Cursor {
Cursor cursor;
int offset = 0;
g_object_get(G_OBJECT(gtkSourceBuffer), "cursor-position", &offset, nullptr);
cursor.setOffset(offset);
GtkTextIter start, end;
if(gtk_text_buffer_get_selection_bounds(gtkTextBuffer, &start, &end)) {
//if selecting text from left to right, the cursor may be ahead of the selection start ...
//since hiro combines selection bounds (end-start) into length, move the offset to the start
int origin = gtk_text_iter_get_offset(&start);
cursor.setOffset(origin);
int length = gtk_text_iter_get_offset(&end) - origin;
cursor.setLength(length);
}
return cursor;
}
auto pSourceEdit::setCursor(Cursor cursor) -> void {
lock();
GtkTextIter offset, length;
@@ -92,45 +106,33 @@ auto pSourceEdit::setFocused() -> void {
gtk_widget_grab_focus(gtkWidgetSourceView);
}
/*
auto pSourceEdit::setPosition(signed position) -> void {
lock();
GtkTextIter iter;
//note: iterators must be initialized via get_iter() before calling set_offset()
gtk_text_buffer_get_end_iter(gtkTextBuffer, &iter);
if(position >= 0) {
gtk_text_iter_set_offset(&iter, position);
} else {
state().position = gtk_text_iter_get_offset(&iter);
}
gtk_text_buffer_place_cursor(gtkTextBuffer, &iter);
auto mark = gtk_text_buffer_get_mark(gtkTextBuffer, "insert");
gtk_text_view_scroll_mark_onscreen(gtkTextView, mark);
unlock();
auto pSourceEdit::setLanguage(const string& language) -> void {
string name;
if(language == "C") name = "c";
if(language == "C++") name = "cpp";
if(language == "Make") name = "makefile";
gtkSourceLanguage = gtk_source_language_manager_get_language(gtkSourceLanguageManager, name);
gtk_source_buffer_set_language(gtkSourceBuffer, gtkSourceLanguage);
}
auto pSourceEdit::setSelected(Position selected) -> void {
lock();
GtkTextIter iter;
gtk_text_buffer_get_end_iter(gtkTextBuffer, &iter);
signed offset = gtk_text_iter_get_offset(&iter);
if(selected.x() < 0 || selected.x() > offset) selected.setX(offset);
if(selected.y() < 0 || selected.y() > offset) selected.setY(offset);
state().selected = selected;
GtkTextIter startIter;
gtk_text_buffer_get_start_iter(gtkTextBuffer, &startIter);
gtk_text_iter_set_offset(&startIter, selected.x());
GtkTextIter endIter;
gtk_text_buffer_get_end_iter(gtkTextBuffer, &endIter);
gtk_text_iter_set_offset(&endIter, selected.y());
gtk_text_buffer_select_range(gtkTextBuffer, &startIter, &endIter);
unlock();
auto pSourceEdit::setNumbered(bool numbered) -> void {
gtk_source_view_set_show_line_numbers(gtkSourceView, numbered);
}
auto pSourceEdit::setScheme(const string& requestedScheme) -> void {
auto scheme = requestedScheme ? requestedScheme : "classic";
gtkSourceStyleScheme = gtk_source_style_scheme_manager_get_scheme(gtkSourceStyleSchemeManager, scheme.downcase());
if(!gtkSourceStyleScheme) gtkSourceStyleScheme = gtk_source_style_scheme_manager_get_scheme(gtkSourceStyleSchemeManager, "classic");
gtk_source_buffer_set_style_scheme(gtkSourceBuffer, gtkSourceStyleScheme);
}
*/
auto pSourceEdit::setText(const string& text) -> void {
lock();
//prevent Ctrl+Z from undoing the newly assigned text ...
//for instance, a text editor widget setting the initial document here
gtk_source_buffer_begin_not_undoable_action(gtkSourceBuffer);
gtk_text_buffer_set_text(gtkTextBuffer, text, -1);
gtk_source_buffer_end_not_undoable_action(gtkSourceBuffer);
unlock();
}

View File

@@ -5,9 +5,13 @@ namespace hiro {
struct pSourceEdit : pWidget {
Declare(SourceEdit, Widget)
auto cursor() const -> Cursor;
auto setCursor(Cursor cursor) -> void;
auto setEditable(bool editable) -> void;
auto setFocused() -> void override;
auto setLanguage(const string& language) -> void;
auto setNumbered(bool numbered) -> void;
auto setScheme(const string& scheme) -> void;
auto setText(const string& text) -> void;
auto setWordWrap(bool wordWrap) -> void;
auto text() const -> string;

View File

@@ -294,30 +294,40 @@ auto pTableView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* p
}
}
auto pTableView::_doEvent(GdkEventButton* event) -> signed {
GtkTreePath* path = nullptr;
gtk_tree_view_get_path_at_pos(gtkTreeView, event->x, event->y, &path, nullptr, nullptr, nullptr);
auto pTableView::_doEvent(GdkEventButton* gdkEvent) -> signed {
if(gdkEvent->type == GDK_BUTTON_PRESS) {
//detect when the empty space of the GtkTreeView is clicked; and clear the selection
GtkTreePath* gtkPath = nullptr;
gtk_tree_view_get_path_at_pos(gtkTreeView, gdkEvent->x, gdkEvent->y, &gtkPath, nullptr, nullptr, nullptr);
if(!gtkPath) {
//the first time a GtkTreeView widget is clicked, even if the empty space of the widget is clicked,
//a "changed" signal will be sent after the "button-press-event", to activate the first item in the tree
//this is undesirable, so set a flag to undo the next selection change during the "changed" signal
suppressChange = true;
if(gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) {
gtk_tree_selection_unselect_all(gtkTreeSelection);
for(auto& item : state().items) item->setSelected(false);
self().doChange();
return true;
}
}
if(event->type == GDK_BUTTON_PRESS) {
//when clicking in empty space below the last table 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) {
for(auto& item : state().items) item->setSelected(false);
self().doChange();
return true;
if(gdkEvent->button == 3) {
//multi-selection mode:
//if multiple items are selected, and one item is right-clicked on (for a context menu), GTK clears selection on all other items
//block this behavior so that onContext() handler can work on more than one selected item at a time
if(gtkPath && gtk_tree_selection_path_is_selected(gtkTreeSelection, gtkPath)) return true;
}
}
if(event->type == GDK_BUTTON_PRESS && event->button == 3) {
//this check prevents the loss of selection on other items if the item under the mouse cursor is currently selected
if(path && gtk_tree_selection_path_is_selected(gtkTreeSelection, path)) return true;
}
if(event->type == GDK_BUTTON_RELEASE && event->button == 3) {
//handle action during right-click release; as button-press-event is sent prior to selection update
//without this, the callback handler would see the previous selection state instead
self().doContext();
return false;
if(gdkEvent->type == GDK_BUTTON_RELEASE) {
suppressChange = false;
if(gdkEvent->button == 3) {
//handle action during right-click release; as button-press-event is sent prior to selection update
//without this, the callback handler would see the previous selection state instead
self().doContext();
return false;
}
}
return false;
@@ -365,6 +375,12 @@ auto pTableView::_doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const c
//this prevents firing an onChange event when the actual selection has not changed
//this is particularly important for the motion-notify-event binding
auto pTableView::_updateSelected() -> void {
if(suppressChange) {
suppressChange = false;
gtk_tree_selection_unselect_all(gtkTreeSelection);
return;
}
vector<unsigned> selected;
GList* list = gtk_tree_selection_get_selected_rows(gtkTreeSelection, &gtkTreeModel);

View File

@@ -44,6 +44,7 @@ struct pTableView : pWidget {
GtkListStore* gtkListStore = nullptr;
GtkTreeModel* gtkTreeModel = nullptr;
vector<uint> currentSelection;
bool suppressChange = false;
};
}

View File

@@ -25,6 +25,8 @@ auto pTreeView::construct() -> void {
gtkTreeView = GTK_TREE_VIEW(gtkWidgetChild);
gtkTreeSelection = gtk_tree_view_get_selection(gtkTreeView);
gtk_tree_view_set_headers_visible(gtkTreeView, false);
gtk_tree_view_set_show_expanders(gtkTreeView, false);
gtk_tree_view_set_level_indentation(gtkTreeView, 20);
gtk_container_add(GTK_CONTAINER(gtkWidget), gtkWidgetChild);
gtk_widget_show(gtkWidgetChild);
@@ -58,10 +60,19 @@ auto pTreeView::construct() -> void {
g_signal_connect(G_OBJECT(gtkTreeSelection), "changed", G_CALLBACK(TreeView_change), (gpointer)this);
g_signal_connect(G_OBJECT(gtkCellToggle), "toggled", G_CALLBACK(TreeView_toggle), (gpointer)this);
//Ctrl+F triggers a small popup window at the bottom of the GtkTreeView, which clears the currently selected item(s)
//this is undesirable for amethyst, which uses the active item to display a document to edit, and binds Ctrl+F to a document find function
//for now, disable GtkTreeView's interactive search: longer term, more thought will need to go into if this is ever desirable or not
//gtk_tree_view_set_enable_search(gtkTreeView, false) does not work
//gtk_tree_view_set_search_column(gtkTreeView, -1) does not work
gtkEntry = (GtkEntry*)gtk_entry_new();
gtk_tree_view_set_search_entry(gtkTreeView, gtkEntry);
pWidget::construct();
}
auto pTreeView::destruct() -> void {
gtk_widget_destroy(GTK_WIDGET(gtkEntry));
gtk_widget_destroy(gtkWidgetChild);
gtk_widget_destroy(gtkWidget);
}
@@ -105,24 +116,39 @@ auto pTreeView::_activatePath(GtkTreePath* gtkPath) -> void {
}
auto pTreeView::_buttonEvent(GdkEventButton* gdkEvent) -> signed {
GtkTreePath* gtkPath = nullptr;
gtk_tree_view_get_path_at_pos(gtkTreeView, gdkEvent->x, gdkEvent->y, &gtkPath, nullptr, nullptr, nullptr);
if(gdkEvent->type == GDK_BUTTON_PRESS) {
//detect when the empty space of the GtkTreeView is clicked; and clear the selection
if(gtkPath == nullptr && gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) {
gtk_tree_selection_unselect_all(gtkTreeSelection);
state().selectedPath.reset();
self().doChange();
return true;
GtkTreePath* gtkPath = nullptr;
gtk_tree_view_get_path_at_pos(gtkTreeView, gdkEvent->x, gdkEvent->y, &gtkPath, nullptr, nullptr, nullptr);
if(!gtkPath) {
//the first time a GtkTreeView widget is clicked, even if the empty space of the widget is clicked,
//a "changed" signal will be sent after the "button-press-event", to activate the first item in the tree
//this is undesirable, so set a flag to undo the next selection change during the "changed" signal
suppressChange = true;
if(gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) {
gtk_tree_selection_unselect_all(gtkTreeSelection);
state().selectedPath.reset();
self().doChange();
return true;
}
}
if(gdkEvent->button == 3) {
//multi-selection mode: (not implemented in TreeView yet ... but code is here anyway for future use)
//if multiple items are selected, and one item is right-clicked on (for a context menu), GTK clears selection on all other items
//block this behavior so that onContext() handler can work on more than one selected item at a time
if(gtkPath && gtk_tree_selection_path_is_selected(gtkTreeSelection, gtkPath)) return true;
}
}
if(gdkEvent->type == GDK_BUTTON_RELEASE && gdkEvent->button == 3) {
//handle right-click context menu
//have to detect on button release instead of press; as GTK+ does not update new selection prior to press event
self().doContext();
return false;
if(gdkEvent->type == GDK_BUTTON_RELEASE) {
suppressChange = false;
if(gdkEvent->button == 3) {
//handle action during right-click release; as button-press-event is sent prior to selection update
//without this, the callback handler would see the previous selection state instead
self().doContext();
return false;
}
}
return false;
@@ -173,6 +199,12 @@ auto pTreeView::_togglePath(string path) -> void {
}
auto pTreeView::_updateSelected() -> void {
if(suppressChange) {
suppressChange = false;
gtk_tree_selection_unselect_all(gtkTreeSelection);
return;
}
GtkTreeIter iter;
if(gtk_tree_selection_get_selected(gtkTreeSelection, &gtkTreeModel, &iter)) {
char* gtkPath = gtk_tree_model_get_string_from_iter(gtkTreeModel, &iter);

View File

@@ -27,6 +27,8 @@ struct pTreeView : pWidget {
GtkCellRenderer* gtkCellToggle = nullptr;
GtkCellRenderer* gtkCellPixbuf = nullptr;
GtkCellRenderer* gtkCellText = nullptr;
GtkEntry* gtkEntry = nullptr;
bool suppressChange = false;
};
}

View File

@@ -329,7 +329,9 @@ auto pWindow::setGeometry(Geometry geometry) -> void {
setMinimumSize(state().minimumSize);
auto time1 = chrono::millisecond();
while(chrono::millisecond() - time1 < 20) Application::processEvents();
while(chrono::millisecond() - time1 < 20) {
Application::processEvents();
}
gtk_window_resize(GTK_WINDOW(widget), geometry.width(), geometry.height() + _menuHeight() + _statusHeight());
@@ -627,7 +629,7 @@ auto pWindow::_synchronizeState() -> void {
if(!gtk_widget_get_realized(widget)) return;
#if defined(DISPLAY_WINDOWS)
auto window = GDK_WINDOW_HWND(gtk_widget_get_window(widget));
auto window = (HWND)GDK_WINDOW_HWND(gtk_widget_get_window(widget));
bool maximized = IsZoomed(window);
bool minimized = IsIconic(window);

View File

@@ -189,6 +189,8 @@ struct QtLabel : public QWidget {
Q_OBJECT
public:
QtLabel(pLabel& p) : p(p) {}
auto mousePressEvent(QMouseEvent*) -> void;
auto mouseReleaseEvent(QMouseEvent*) -> void;
auto paintEvent(QPaintEvent*) -> void;
pLabel& p;
};

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,9 @@ auto pSizable::minimumSize() const -> Size {
return {0, 0};
}
auto pSizable::setCollapsible(bool collapsible) -> void {
}
auto pSizable::setGeometry(Geometry geometry) -> void {
self().doSize();
}

View File

@@ -6,6 +6,7 @@ struct pSizable : pObject {
Declare(Sizable, Object)
virtual auto minimumSize() const -> Size;
virtual auto setCollapsible(bool collapsible) -> void;
virtual auto setGeometry(Geometry geometry) -> void;
};

View File

@@ -25,6 +25,7 @@ auto pTimer::setInterval(unsigned interval) -> void {
}
auto QtTimer::onActivate() -> void {
if(Application::state().quit) return;
p.self().doActivate();
}

View File

@@ -40,6 +40,22 @@ auto pLabel::setText(const string& text) -> void {
qtLabel->update();
}
auto QtLabel::mousePressEvent(QMouseEvent* event) -> void {
switch(event->button()) {
case Qt::LeftButton: p.self().doMousePress(Mouse::Button::Left); break;
case Qt::MidButton: p.self().doMousePress(Mouse::Button::Middle); break;
case Qt::RightButton: p.self().doMousePress(Mouse::Button::Right); break;
}
}
auto QtLabel::mouseReleaseEvent(QMouseEvent* event) -> void {
switch(event->button()) {
case Qt::LeftButton: p.self().doMouseRelease(Mouse::Button::Left); break;
case Qt::MidButton: p.self().doMouseRelease(Mouse::Button::Middle); break;
case Qt::RightButton: p.self().doMouseRelease(Mouse::Button::Right); break;
}
}
//QLabel ignores QPalette ... so we have to implement our own Label class atop QWidget ...
auto QtLabel::paintEvent(QPaintEvent* event) -> void {
QPainter painter(p.qtLabel);

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 B

View File

@@ -3,6 +3,7 @@ namespace name=Icon
binary name=Add file=icon/action/add.png
binary name=Attach file=icon/action/attach.png
binary name=Bookmark file=icon/action/bookmark.png
binary name=Close file=icon/action/close.png
binary name=FullScreen file=icon/action/full-screen.png
binary name=Mute file=icon/action/mute.png
binary name=New file=icon/action/new.png
@@ -53,6 +54,7 @@ namespace name=Icon
binary name=Binary file=icon/emblem/binary.png
binary name=File file=icon/emblem/file.png
binary name=Folder file=icon/emblem/folder.png
binary name=FolderOpen file=icon/emblem/folder-open.png
binary name=Font file=icon/emblem/font.png
binary name=Image file=icon/emblem/image.png
binary name=Markup file=icon/emblem/markup.png

View File

@@ -62,6 +62,27 @@ const unsigned char Bookmark[686] = {
221,234,14,26,128,72,36,194,78,163,215,90,127,221,211,211,211,189,147,194,104,52,218,7,240,7,70,86,184,198,50,151,
228,191,0,0,0,0,73,69,78,68,174,66,96,130,
};
const unsigned char Close[586] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,
215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99,
97,112,101,46,111,114,103,155,238,60,26,0,0,1,199,73,68,65,84,56,141,165,147,205,106,26,97,20,134,31,51,14,
5,77,71,218,136,100,83,20,131,67,118,198,149,76,93,185,51,5,23,221,100,153,69,46,32,189,130,118,81,122,3,189,
130,118,147,149,12,130,139,226,118,50,232,106,4,133,4,162,208,162,20,132,128,197,159,90,181,240,165,167,27,45,147,161,
41,20,15,156,205,57,231,121,57,63,223,23,18,17,182,177,157,173,232,7,4,18,64,26,136,250,98,81,224,96,157,251,
167,192,126,62,159,63,214,117,253,163,109,219,230,26,140,218,182,109,234,186,254,33,159,207,31,3,251,247,8,17,217,120,
194,178,172,83,160,11,92,105,154,118,89,173,86,143,170,213,234,145,166,105,151,192,21,208,181,44,235,84,68,18,27,46,
228,91,98,58,149,74,189,31,12,6,79,0,1,30,133,195,225,57,128,82,106,23,248,9,132,146,201,228,184,223,239,191,
2,190,4,71,184,245,60,239,34,147,201,92,3,11,96,172,148,210,148,82,26,48,6,22,153,76,230,218,243,188,11,224,
118,3,133,2,103,52,70,163,209,139,66,161,240,188,215,235,61,243,39,76,211,252,218,104,52,154,241,120,252,19,48,123,
104,137,119,173,86,171,183,92,46,247,214,93,252,241,213,106,245,180,221,110,119,129,59,63,224,239,32,90,175,215,15,202,
229,242,107,165,148,2,230,1,241,93,93,215,181,90,173,246,174,84,42,125,6,126,4,5,210,177,88,236,205,108,54,251,
5,124,7,200,102,179,223,0,58,157,206,222,186,230,177,97,24,59,211,233,244,237,223,150,56,175,84,42,205,72,36,50,
4,22,185,92,110,232,56,206,141,227,56,55,185,92,110,8,44,34,145,200,176,82,169,52,239,117,231,123,7,136,200,161,
235,186,103,197,98,241,124,50,153,156,136,136,33,34,198,100,50,57,41,22,139,231,174,235,158,137,200,161,159,9,10,32,
34,166,136,188,92,195,155,152,177,142,153,193,250,224,25,255,219,182,254,141,191,1,124,82,8,56,142,215,29,200,0,0,
0,0,73,69,78,68,174,66,96,130,
};
const unsigned char FullScreen[650] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0,
@@ -1116,6 +1137,28 @@ const unsigned char Folder[581] = {
119,199,119,159,130,243,227,251,248,159,1,34,140,69,194,139,223,71,22,33,158,28,99,167,49,0,0,0,0,73,69,78,
68,174,66,96,130,
};
const unsigned char FolderOpen[625] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,
215,1,66,40,155,120,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0,119,119,119,46,105,110,107,115,99,
97,112,101,46,111,114,103,155,238,60,26,0,0,1,238,73,68,65,84,56,141,165,147,59,79,148,65,20,134,159,153,239,
219,93,195,71,178,33,94,18,27,45,181,48,33,86,212,118,22,90,108,225,63,48,177,163,38,196,206,146,248,11,44,164,
129,127,161,198,80,24,45,76,136,196,196,74,140,72,34,176,11,24,216,203,156,51,231,88,44,139,44,40,20,158,100,170,
57,239,115,46,239,76,112,119,254,39,194,252,252,252,75,119,127,248,151,187,174,136,60,90,88,88,120,127,46,96,110,110,
110,175,213,106,53,205,12,51,99,212,81,167,211,97,101,101,229,85,85,85,15,70,201,235,235,235,0,44,46,46,14,252,
40,177,20,17,87,85,182,183,183,201,57,143,65,106,181,218,76,187,221,62,112,119,220,157,170,170,112,119,102,103,103,63,
1,119,79,0,4,85,197,204,198,32,211,211,211,147,83,83,83,84,85,69,81,20,196,24,233,118,187,44,45,45,221,25,
117,85,170,170,169,102,114,254,115,70,0,17,161,219,237,18,66,32,132,64,140,17,128,148,210,241,230,75,17,241,148,210,
24,32,231,204,168,109,119,63,3,80,213,227,37,150,41,37,83,85,114,206,44,127,140,236,245,34,80,59,215,58,171,238,
215,102,158,44,247,66,140,95,75,85,69,68,200,57,179,219,139,60,125,124,143,34,134,35,143,128,127,188,147,164,118,233,
217,139,183,183,75,17,49,17,193,204,8,56,19,141,130,181,239,191,112,31,234,9,167,124,7,98,12,220,184,60,65,8,
88,41,34,166,58,4,20,49,80,196,64,12,225,140,240,68,101,250,253,76,188,10,128,31,217,56,92,90,89,20,20,49,
208,40,227,25,225,64,140,94,202,100,115,26,69,28,141,105,165,170,90,74,137,131,1,52,39,235,108,237,15,232,167,140,
251,176,218,64,51,73,109,108,21,101,17,216,218,235,15,71,8,33,152,153,241,101,167,206,245,107,77,118,15,133,190,24,
189,164,199,162,211,35,197,16,216,216,57,36,134,184,85,186,195,234,38,172,254,172,115,171,89,231,205,234,15,178,93,252,
67,59,237,125,178,219,235,50,55,174,188,251,176,89,221,4,103,237,243,183,11,133,39,98,3,179,231,191,1,223,162,81,
163,208,43,119,152,0,0,0,0,73,69,78,68,174,66,96,130,
};
const unsigned char Font[627] = {
137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,
97,0,0,0,4,115,66,73,84,8,8,8,8,124,8,100,136,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,

View File

@@ -3,6 +3,7 @@ namespace Action {
extern const unsigned char Add[323];
extern const unsigned char Attach[649];
extern const unsigned char Bookmark[686];
extern const unsigned char Close[586];
extern const unsigned char FullScreen[650];
extern const unsigned char Mute[632];
extern const unsigned char New[477];
@@ -57,6 +58,7 @@ extern const unsigned char Audio[688];
extern const unsigned char Binary[560];
extern const unsigned char File[741];
extern const unsigned char Folder[581];
extern const unsigned char FolderOpen[625];
extern const unsigned char Font[627];
extern const unsigned char Image[558];
extern const unsigned char Markup[709];

View File

@@ -12,6 +12,9 @@ auto pSizable::minimumSize() const -> Size {
return {0, 0};
}
auto pSizable::setCollapsible(bool collapsible) -> void {
}
auto pSizable::setGeometry(Geometry geometry) -> void {
self().doSize();
}

View File

@@ -6,6 +6,7 @@ struct pSizable : pObject {
Declare(Sizable, Object)
virtual auto minimumSize() const -> Size;
virtual auto setCollapsible(bool collapsible) -> void;
virtual auto setGeometry(Geometry geometry) -> void;
};

View File

@@ -8,6 +8,8 @@ namespace hiro {
static vector<pTimer*> timers;
static auto CALLBACK Timer_timeoutProc(HWND hwnd, UINT msg, UINT_PTR timerID, DWORD time) -> void {
if(Application::state().quit) return;
for(auto& timer : timers) {
if(timer->htimer == timerID) return timer->self().doActivate();
}

View File

@@ -95,6 +95,22 @@ auto pLabel::windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> ma
return msg == WM_ERASEBKGND;
}
if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) {
switch(msg) {
case WM_LBUTTONDOWN: self().doMousePress(Mouse::Button::Left); break;
case WM_MBUTTONDOWN: self().doMousePress(Mouse::Button::Middle); break;
case WM_RBUTTONDOWN: self().doMousePress(Mouse::Button::Right); break;
}
}
if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) {
switch(msg) {
case WM_LBUTTONUP: self().doMouseRelease(Mouse::Button::Left); break;
case WM_MBUTTONUP: self().doMouseRelease(Mouse::Button::Middle); break;
case WM_RBUTTONUP: self().doMouseRelease(Mouse::Button::Right); break;
}
}
return pWidget::windowProc(hwnd, msg, wparam, lparam);
}

View File

@@ -51,10 +51,9 @@ auto pLineEdit::onChange() -> void {
}
auto pLineEdit::windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -> maybe<LRESULT> {
if(msg == WM_KEYDOWN) {
if(msg == WM_KEYDOWN && wparam == VK_RETURN) {
self().doActivate();
}
return pWidget::windowProc(hwnd, msg, wparam, lparam);
}