mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-30 20:29:58 +02:00
Update to v106r47 release.
byuu says: This is probably the largest code-change diff I've done in years. I spent four days working 10-16 hours a day reworking layouts in hiro completely. The result is we now have TableLayout, which will allow for better horizontal+vertical combined alignment. Windows, GTK2, and now GTK3 are fully supported. Windows is getting the initial window geometry wrong by a bit. GTK2 and GTK3 work perfectly. I basically abandoned trying to detect resize signals, and instead keep a list of all hiro windows that are allocated, and every time the main loop runs, it will query all of them to see if they've been resized. I'm disgusted that I have to do this, but after fighting with GTK for years, I'm about sick of it. GTK was doing this crazy thing where it would trigger another size-allocate inside of a previous size-allocate, and so my layouts would be halfway through resizing all the widgets, and then the size-allocate would kick off another one. That would end up leaving the rest of the first layout loop with bad widget sizes. And if I detected a second re-entry and blocked it, then the entire window would end up with the older geometry. I started trying to build a message queue system to allow the second layout resize to occur after the first one completed, but this was just too much madness, so I went with the simpler solution. Qt4 has some geometry problems, and doesn't show tab frame layouts properly yet. Qt5 causes an ICE error and tanks my entire Xorg display server, so ... something is seriously wrong there, and it's not hiro's fault. Creating a dummy Qt5 application without even using hiro, just int main() { TestObject object; } with object performing a dynamic\_cast to a derived type segfaults. Memory is getting corrupted where GCC allocates the vtables for classes, just by linking in Qt. Could be somehow related to the -fPIC requirement that only Qt5 has ... could just be that FreeBSD 10.1 has a buggy implementation of Qt5. I don't know. It's beyond my ability to debug, so this one's going to stay broken. The Cocoa port is busted. I'll fix it up to compile again, but that's about all I'm going to do. Many optimizations mean bsnes and higan open faster. GTK2 and GTK3 both resize windows very quickly now. higan crashes when you load a game, so that's not good. bsnes works though. bsnes also has the start of a localization engine now. Still a long way to go. The makefiles received a rather substantial restructuring. Including the ruby and hiro makefiles will add the necessary compilation rules for you, which also means that moc will run for the qt4 and qt5 targets, and windres will run for the Windows targets.
This commit is contained in:
@@ -2,18 +2,16 @@
|
||||
|
||||
namespace hiro {
|
||||
|
||||
vector<pWindow*> pApplication::windows;
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
XlibDisplay* pApplication::display = nullptr;
|
||||
#endif
|
||||
|
||||
auto pApplication::run() -> void {
|
||||
if(Application::state.onMain) {
|
||||
while(!Application::state.quit) {
|
||||
Application::doMain();
|
||||
processEvents();
|
||||
}
|
||||
} else {
|
||||
gtk_main();
|
||||
while(!Application::state.quit) {
|
||||
Application::doMain();
|
||||
processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +21,7 @@ auto pApplication::pendingEvents() -> bool {
|
||||
|
||||
auto pApplication::processEvents() -> void {
|
||||
while(pendingEvents()) gtk_main_iteration_do(false);
|
||||
for(auto& window : windows) window->_synchronizeGeometry();
|
||||
}
|
||||
|
||||
auto pApplication::quit() -> void {
|
||||
@@ -30,7 +29,7 @@ auto pApplication::quit() -> void {
|
||||
if(gtk_main_level()) gtk_main_quit();
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
//todo: Keyboard::poll() is being called after Application::quit();
|
||||
//TODO: Keyboard::poll() is being called after Application::quit();
|
||||
//so if display is closed; this causes a segfault
|
||||
//XCloseDisplay(display);
|
||||
//display = nullptr;
|
||||
@@ -46,15 +45,17 @@ auto pApplication::initialize() -> void {
|
||||
auto name = Application::state.name ? Application::state.name : string{"hiro"};
|
||||
gdk_set_program_class(name);
|
||||
|
||||
#if 1
|
||||
#if defined(BUILD_DEBUG)
|
||||
//force a trap on Gtk-CRITICAL and Gtk-WARNING messages
|
||||
//this allows gdb to perform a backtrace to find an error's origin point
|
||||
int argc = 3;
|
||||
char* argv[] = {name.get(), new char[7], new char[19], nullptr};
|
||||
strcpy(argv[1], "--sync");
|
||||
strcpy(argv[2], "--g-fatal-warnings");
|
||||
g_log_set_always_fatal(GLogLevelFlags(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING));
|
||||
#else
|
||||
int argc = 1;
|
||||
char* argv[] = {name.get(), nullptr};
|
||||
#else
|
||||
//--g-fatal-warnings will force a trap on Gtk-CRITICAL and Gtk-WARNING messages
|
||||
//this allows gdb to perform a backtrace to find an error's origin point
|
||||
int argc = 2;
|
||||
char* argv[] = {name.get(), new char[19], nullptr};
|
||||
strcpy(argv[1], "--g-fatal-warnings");
|
||||
#endif
|
||||
char** argvp = argv;
|
||||
|
||||
|
@@ -3,16 +3,18 @@
|
||||
namespace hiro {
|
||||
|
||||
struct pApplication {
|
||||
#if defined(DISPLAY_XORG)
|
||||
static XlibDisplay* display;
|
||||
#endif
|
||||
|
||||
static auto run() -> void;
|
||||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
|
||||
static auto initialize() -> void;
|
||||
|
||||
static vector<pWindow*> windows;
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
static XlibDisplay* display;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -21,9 +21,13 @@
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gtk/gtk.h>
|
||||
#if defined(Hiro_SourceEdit)
|
||||
#include <gtksourceview/gtksourceview.h>
|
||||
#include <gtksourceview/gtksourcelanguagemanager.h>
|
||||
#include <gtksourceview/gtksourcestyleschememanager.h>
|
||||
#if HIRO_GTK==2
|
||||
#include <gtksourceview/gtksourceview.h>
|
||||
#include <gtksourceview/gtksourcelanguagemanager.h>
|
||||
#include <gtksourceview/gtksourcestyleschememanager.h>
|
||||
#elif HIRO_GTK==3
|
||||
#include <gtksourceview/gtksource.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <nall/windows/guard.hpp>
|
||||
#include <nall/windows/registry.hpp>
|
||||
|
@@ -1,33 +0,0 @@
|
||||
#if defined(Hiro_Layout)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
auto pLayout::construct() -> void {
|
||||
for(auto& sizable : state().sizables) sizable->construct();
|
||||
}
|
||||
|
||||
auto pLayout::destruct() -> void {
|
||||
for(auto& sizable : state().sizables) sizable->destruct();
|
||||
}
|
||||
|
||||
auto pLayout::setEnabled(bool enabled) -> void {
|
||||
for(auto& sizable : state().sizables) {
|
||||
if(auto self = sizable->self()) self->setEnabled(sizable->enabled(true));
|
||||
}
|
||||
}
|
||||
|
||||
auto pLayout::setFont(const Font& font) -> void {
|
||||
for(auto& sizable : state().sizables) {
|
||||
if(auto self = sizable->self()) self->setFont(sizable->font(true));
|
||||
}
|
||||
}
|
||||
|
||||
auto pLayout::setVisible(bool visible) -> void {
|
||||
for(auto& sizable : state().sizables) {
|
||||
if(auto self = sizable->self()) self->setVisible(sizable->visible(true));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,15 +0,0 @@
|
||||
#if defined(Hiro_Layout)
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pLayout : pSizable {
|
||||
Declare(Layout, Sizable)
|
||||
|
||||
auto setEnabled(bool enabled) -> void override;
|
||||
auto setFont(const Font& font) -> void override;
|
||||
auto setVisible(bool visible) -> void override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@@ -13,7 +13,7 @@ auto pMenuBar::append(sMenu menu) -> void {
|
||||
parent->_append(*menu);
|
||||
if(menu->self()) {
|
||||
menu->self()->setFont(menu->font(true));
|
||||
menu->self()->setVisible(menu->visible(true));
|
||||
menu->self()->setVisible(menu->visible());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,9 @@ auto pObject::setFocused() -> void {
|
||||
auto pObject::setFont(const Font& font) -> void {
|
||||
}
|
||||
|
||||
auto pObject::setParent(mObject* parent, int offset) -> void {
|
||||
}
|
||||
|
||||
auto pObject::setVisible(bool visible) -> void {
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace hiro {
|
||||
|
||||
struct pObject {
|
||||
struct pObject : mLock {
|
||||
pObject(mObject& reference) : reference(reference) {}
|
||||
virtual ~pObject() {}
|
||||
auto self() const -> mObject& { return (mObject&)reference; }
|
||||
@@ -16,22 +16,10 @@ struct pObject {
|
||||
virtual auto setEnabled(bool enabled) -> void;
|
||||
virtual auto setFocused() -> void;
|
||||
virtual auto setFont(const Font& font) -> void;
|
||||
virtual auto setParent(mObject* parent, int offset) -> void;
|
||||
virtual auto setVisible(bool visible) -> void;
|
||||
|
||||
auto locked() const -> bool { return locks || Application::state.quit; }
|
||||
auto lock() -> void { ++locks; }
|
||||
auto unlock() -> void { --locks; }
|
||||
|
||||
struct Lock {
|
||||
Lock(pObject& self) : self(self) { self.locks++; }
|
||||
~Lock() { self.locks--; }
|
||||
|
||||
pObject& self;
|
||||
};
|
||||
auto acquire() -> Lock { return {*this}; }
|
||||
|
||||
mObject& reference;
|
||||
signed locks = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -26,7 +26,6 @@
|
||||
#include "action/menu-radio-item.cpp"
|
||||
|
||||
#include "sizable.cpp"
|
||||
#include "layout.cpp"
|
||||
|
||||
#include "widget/widget.cpp"
|
||||
#include "widget/button.cpp"
|
||||
|
@@ -37,7 +37,6 @@ namespace hiro {
|
||||
#include "action/menu-radio-item.hpp"
|
||||
|
||||
#include "sizable.hpp"
|
||||
#include "layout.hpp"
|
||||
|
||||
#include "widget/widget.hpp"
|
||||
#include "widget/button.hpp"
|
||||
|
@@ -11,8 +11,8 @@ struct Settings {
|
||||
int frameY = 24;
|
||||
int frameWidth = 8;
|
||||
int frameHeight = 28;
|
||||
int menuHeight = 20;
|
||||
int statusHeight = 20;
|
||||
int menuHeight = 8;
|
||||
int statusHeight = 4;
|
||||
} geometry;
|
||||
};
|
||||
|
||||
|
@@ -17,37 +17,36 @@ auto pFrame::destruct() -> void {
|
||||
gtk_widget_destroy(gtkWidget);
|
||||
}
|
||||
|
||||
auto pFrame::append(shared_pointer<mLayout> layout) -> void {
|
||||
if(auto layout = _layout()) layout->setFont(layout->self().font(true));
|
||||
auto pFrame::append(sSizable sizable) -> void {
|
||||
if(auto sizable = _sizable()) sizable->setFont(sizable->self().font(true));
|
||||
}
|
||||
|
||||
auto pFrame::container(mWidget& widget) -> GtkWidget* {
|
||||
return gtk_widget_get_parent(gtkWidget);
|
||||
}
|
||||
|
||||
auto pFrame::remove(shared_pointer<mLayout> layout) -> void {
|
||||
auto pFrame::remove(sSizable sizable) -> void {
|
||||
}
|
||||
|
||||
auto pFrame::setEnabled(bool enabled) -> void {
|
||||
if(auto layout = _layout()) layout->setEnabled(layout->self().enabled(true));
|
||||
if(auto sizable = _sizable()) sizable->setEnabled(sizable->self().enabled(true));
|
||||
pWidget::setEnabled(enabled);
|
||||
}
|
||||
|
||||
auto pFrame::setFont(const Font& font) -> void {
|
||||
if(auto layout = _layout()) layout->setFont(layout->self().font(true));
|
||||
if(auto sizable = _sizable()) sizable->setFont(sizable->self().font(true));
|
||||
pFont::setFont(gtkLabel, font);
|
||||
}
|
||||
|
||||
auto pFrame::setGeometry(Geometry geometry) -> void {
|
||||
pWidget::setGeometry(geometry);
|
||||
if(auto layout = state().layout) {
|
||||
if(auto& sizable = state().sizable) {
|
||||
Size size = pFont::size(self().font(true), state().text);
|
||||
if(!state().text) size.setHeight(10);
|
||||
geometry.setX(geometry.x() + 2);
|
||||
geometry.setY(geometry.y() + (size.height() - 1));
|
||||
geometry.setWidth(geometry.width() - 5);
|
||||
geometry.setHeight(geometry.height() - (size.height() + 2));
|
||||
layout->setGeometry(geometry);
|
||||
sizable->setGeometry(geometry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +55,15 @@ auto pFrame::setText(const string& text) -> void {
|
||||
}
|
||||
|
||||
auto pFrame::setVisible(bool visible) -> void {
|
||||
if(auto layout = _layout()) layout->setVisible(layout->self().visible(true));
|
||||
if(auto sizable = _sizable()) sizable->setVisible(sizable->self().visible(true));
|
||||
pWidget::setVisible(visible);
|
||||
}
|
||||
|
||||
auto pFrame::_layout() -> pLayout* {
|
||||
if(auto layout = state().layout) return layout->self();
|
||||
return nullptr;
|
||||
auto pFrame::_sizable() -> maybe<pSizable&> {
|
||||
if(auto& sizable = state().sizable) {
|
||||
if(auto self = sizable->self()) return *self;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,16 +5,16 @@ namespace hiro {
|
||||
struct pFrame : pWidget {
|
||||
Declare(Frame, Widget)
|
||||
|
||||
auto append(shared_pointer<mLayout> layout) -> void;
|
||||
auto append(sSizable sizable) -> void;
|
||||
auto container(mWidget& widget) -> GtkWidget* override;
|
||||
auto remove(shared_pointer<mLayout> layout) -> void;
|
||||
auto remove(sSizable sizable) -> void;
|
||||
auto setEnabled(bool enabled) -> void override;
|
||||
auto setFont(const Font& font) -> void override;
|
||||
auto setGeometry(Geometry geometry) -> void override;
|
||||
auto setText(const string& text) -> void;
|
||||
auto setVisible(bool visible) -> void override;
|
||||
|
||||
auto _layout() -> pLayout*;
|
||||
auto _sizable() -> maybe<pSizable&>;
|
||||
|
||||
GtkWidget* gtkLabel = nullptr;
|
||||
};
|
||||
|
@@ -30,7 +30,7 @@ auto pHorizontalSlider::destruct() -> void {
|
||||
}
|
||||
|
||||
auto pHorizontalSlider::minimumSize() const -> Size {
|
||||
return {0, 20};
|
||||
return {3, 20};
|
||||
}
|
||||
|
||||
auto pHorizontalSlider::setLength(unsigned length) -> void {
|
||||
|
@@ -5,7 +5,7 @@ namespace hiro {
|
||||
struct pHorizontalSlider : pWidget {
|
||||
Declare(HorizontalSlider, Widget)
|
||||
|
||||
auto minimumSize() const -> Size;
|
||||
auto minimumSize() const -> Size override;
|
||||
auto setLength(unsigned length) -> void;
|
||||
auto setPosition(unsigned position) -> void;
|
||||
};
|
||||
|
@@ -43,7 +43,7 @@ auto pIconView::construct() -> void {
|
||||
setFlow(state().flow);
|
||||
setForegroundColor(state().foregroundColor);
|
||||
setOrientation(state().orientation);
|
||||
for(auto position : range(self().items())) {
|
||||
for(auto position : range(self().itemCount())) {
|
||||
auto& item = state().items[position];
|
||||
append(item);
|
||||
}
|
||||
|
@@ -3,17 +3,17 @@
|
||||
namespace hiro {
|
||||
|
||||
auto pTabFrameItem::construct() -> void {
|
||||
if(auto layout = state().layout) layout->construct();
|
||||
if(auto& sizable = state().sizable) sizable->construct();
|
||||
}
|
||||
|
||||
auto pTabFrameItem::destruct() -> void {
|
||||
if(auto layout = state().layout) layout->destruct();
|
||||
if(auto& sizable = state().sizable) sizable->destruct();
|
||||
}
|
||||
|
||||
auto pTabFrameItem::append(sLayout layout) -> void {
|
||||
auto pTabFrameItem::append(sSizable sizable) -> void {
|
||||
}
|
||||
|
||||
auto pTabFrameItem::remove(sLayout layout) -> void {
|
||||
auto pTabFrameItem::remove(sSizable sizable) -> void {
|
||||
}
|
||||
|
||||
auto pTabFrameItem::setClosable(bool closable) -> void {
|
||||
@@ -46,9 +46,11 @@ auto pTabFrameItem::setText(const string& text) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto pTabFrameItem::_parent() -> pTabFrame* {
|
||||
if(auto parent = self().parentTabFrame()) return parent->self();
|
||||
return nullptr;
|
||||
auto pTabFrameItem::_parent() -> maybe<pTabFrame&> {
|
||||
if(auto parent = self().parentTabFrame()) {
|
||||
if(auto self = parent->self()) return *self;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,15 +5,15 @@ namespace hiro {
|
||||
struct pTabFrameItem : pObject {
|
||||
Declare(TabFrameItem, Object)
|
||||
|
||||
auto append(sLayout layout) -> void;
|
||||
auto remove(sLayout layout) -> void;
|
||||
auto append(sSizable sizable) -> void;
|
||||
auto remove(sSizable sizable) -> void;
|
||||
auto setClosable(bool closable) -> void;
|
||||
auto setIcon(const image& icon) -> void;
|
||||
auto setMovable(bool movable) -> void;
|
||||
auto setSelected() -> void;
|
||||
auto setText(const string& text) -> void;
|
||||
|
||||
auto _parent() -> pTabFrame*;
|
||||
auto _parent() -> maybe<pTabFrame&>;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ static auto TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned pos
|
||||
|
||||
static auto TabFrame_close(GtkButton* button, pTabFrame* p) -> void {
|
||||
maybe<unsigned> position;
|
||||
for(auto n : range(p->tabs)) {
|
||||
for(auto n : range(p->tabs.size())) {
|
||||
if(button == (GtkButton*)p->tabs[n].close) {
|
||||
position = n;
|
||||
break;
|
||||
@@ -29,7 +29,7 @@ static auto TabFrame_move(GtkNotebook* notebook, GtkWidget* page, unsigned moveT
|
||||
if(auto item = p->self().item(position)) item->state.selected = true;
|
||||
|
||||
maybe<unsigned> moveFrom;
|
||||
for(auto n : range(p->tabs)) {
|
||||
for(auto n : range(p->tabs.size())) {
|
||||
if(page == p->tabs[n].child) {
|
||||
moveFrom = n;
|
||||
break;
|
||||
@@ -109,13 +109,13 @@ auto pTabFrame::container(mWidget& widget) -> GtkWidget* {
|
||||
mObject* object = &widget;
|
||||
while(object) {
|
||||
if(object->parentTabFrameItem()) break;
|
||||
if(auto layout = object->parentLayout()) { object = layout; continue; }
|
||||
if(auto parent = object->parent()) { object = parent; continue; }
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned position = 0;
|
||||
uint position = 0;
|
||||
for(auto& item : state().items) {
|
||||
if(item->state.layout.data() == object) return tabs[position].child;
|
||||
if(item->state.sizable.data() == object) return tabs[position].child;
|
||||
position++;
|
||||
}
|
||||
|
||||
@@ -144,20 +144,13 @@ auto pTabFrame::remove(sTabFrameItem item) -> void {
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pTabFrame::setEnabled(bool enabled) -> void {
|
||||
for(auto& item : state().items) {
|
||||
if(auto layout = item->state.layout) {
|
||||
if(layout->self()) layout->self()->setEnabled(layout->enabled(true));
|
||||
}
|
||||
}
|
||||
pWidget::setEnabled(enabled);
|
||||
}
|
||||
|
||||
auto pTabFrame::setFont(const Font& font) -> void {
|
||||
for(auto n : range(tabs.size())) {
|
||||
pFont::setFont(tabs[n].title, font);
|
||||
if(auto layout = state().items[n]->state.layout) {
|
||||
if(layout->self()) layout->self()->setFont(layout->font(true));
|
||||
if(auto sizable = state().items[n]->state.sizable) {
|
||||
if(auto self = sizable->self()) {
|
||||
self->setFont(sizable->font(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +167,7 @@ auto pTabFrame::setGeometry(Geometry geometry) -> void {
|
||||
geometry.setHeight(geometry.height() - 6);
|
||||
}
|
||||
for(auto& item : state().items) {
|
||||
if(item->state.layout) item->state.layout->setGeometry(geometry);
|
||||
if(item->state.sizable) item->state.sizable->setGeometry(geometry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,10 +179,6 @@ auto pTabFrame::setItemIcon(unsigned position, const image& icon) -> void {
|
||||
_synchronizeTab(position);
|
||||
}
|
||||
|
||||
auto pTabFrame::setItemLayout(unsigned position, shared_pointer<mLayout> layout) -> void {
|
||||
//if(layout->self()) layout->self()->setParent();
|
||||
}
|
||||
|
||||
auto pTabFrame::setItemMovable(unsigned position, bool movable) -> void {
|
||||
lock();
|
||||
gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(gtkWidget), tabs[position].child, movable);
|
||||
@@ -202,6 +191,10 @@ auto pTabFrame::setItemSelected(unsigned position) -> void {
|
||||
unlock();
|
||||
}
|
||||
|
||||
auto pTabFrame::setItemSizable(unsigned position, sSizable sizable) -> void {
|
||||
//if(layout->self()) layout->self()->setParent();
|
||||
}
|
||||
|
||||
auto pTabFrame::setItemText(unsigned position, const string& text) -> void {
|
||||
_synchronizeTab(position);
|
||||
}
|
||||
@@ -218,22 +211,11 @@ auto pTabFrame::setNavigation(Navigation navigation) -> void {
|
||||
setGeometry(self().geometry());
|
||||
}
|
||||
|
||||
auto pTabFrame::setVisible(bool visible) -> void {
|
||||
for(auto& item : state().items) {
|
||||
if(auto layout = item->state.layout) {
|
||||
if(layout->self()) {
|
||||
layout->self()->setVisible(layout->visible(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
pWidget::setVisible(visible);
|
||||
}
|
||||
|
||||
auto pTabFrame::_synchronizeLayout() -> void {
|
||||
for(auto& item : state().items) {
|
||||
if(auto layout = item->state.layout) {
|
||||
if(auto self = layout->self()) {
|
||||
self->setVisible(layout->visible(true) && item->selected());
|
||||
if(auto& sizable = item->state.sizable) {
|
||||
if(auto self = sizable->self()) {
|
||||
self->setVisible(sizable->visible() && item->selected());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,7 +244,7 @@ auto pTabFrame::_synchronizeTab(unsigned position) -> void {
|
||||
auto pTabFrame::_tabHeight() -> unsigned {
|
||||
signed height = 1;
|
||||
|
||||
for(auto n : range(self().items())) {
|
||||
for(auto n : range(self().itemCount())) {
|
||||
GtkAllocation imageAllocation, titleAllocation, closeAllocation;
|
||||
gtk_widget_get_allocation(tabs[n].image, &imageAllocation);
|
||||
gtk_widget_get_allocation(tabs[n].title, &titleAllocation);
|
||||
@@ -279,7 +261,7 @@ auto pTabFrame::_tabHeight() -> unsigned {
|
||||
auto pTabFrame::_tabWidth() -> unsigned {
|
||||
signed width = 1;
|
||||
|
||||
for(auto n : range(self().items())) {
|
||||
for(auto n : range(self().itemCount())) {
|
||||
GtkAllocation imageAllocation, titleAllocation, closeAllocation;
|
||||
gtk_widget_get_allocation(tabs[n].image, &imageAllocation);
|
||||
gtk_widget_get_allocation(tabs[n].title, &titleAllocation);
|
||||
|
@@ -8,20 +8,16 @@ struct pTabFrame : pWidget {
|
||||
auto append(sTabFrameItem item) -> void;
|
||||
auto container(mWidget& widget) -> GtkWidget* override;
|
||||
auto remove(sTabFrameItem item) -> void;
|
||||
auto setEnabled(bool enabled) -> void override;
|
||||
auto setFont(const Font& font) -> void override;
|
||||
auto setGeometry(Geometry geometry) -> void override;
|
||||
auto setItemClosable(unsigned position, bool closable) -> void;
|
||||
auto setItemIcon(unsigned position, const image& icon) -> void;
|
||||
auto setItemLayout(unsigned position, sLayout layout) -> void;
|
||||
auto setItemMovable(unsigned position, bool movable) -> void;
|
||||
auto setItemSelected(unsigned position) -> void;
|
||||
auto setItemSizable(unsigned position, sSizable sizable) -> void;
|
||||
auto setItemText(unsigned position, const string& text) -> void;
|
||||
auto setNavigation(Navigation navigation) -> void;
|
||||
auto setVisible(bool visible) -> void override;
|
||||
|
||||
auto _append(shared_pointer<mTabFrameItem> item) -> void;
|
||||
auto _remove(shared_pointer<mTabFrameItem> item) -> void;
|
||||
auto _synchronizeLayout() -> void;
|
||||
auto _synchronizeTab(unsigned position) -> void;
|
||||
auto _tabHeight() -> unsigned;
|
||||
|
@@ -48,11 +48,14 @@ auto pTableViewCell::_parent() -> maybe<pTableViewItem&> {
|
||||
auto pTableViewCell::_setState() -> void {
|
||||
if(auto parent = _parent()) {
|
||||
if(auto grandparent = _grandparent()) {
|
||||
grandparent->lock();
|
||||
gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 0, state().checked, -1);
|
||||
gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 1, CreatePixbuf(state().icon), -1);
|
||||
gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 2, state().text.data(), -1);
|
||||
grandparent->unlock();
|
||||
if(auto& tableViewHeader = grandparent->state().header) {
|
||||
if(self().offset() < tableViewHeader->columnCount()) {
|
||||
auto lock = grandparent->acquire();
|
||||
gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 0, state().checked, -1);
|
||||
gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 1, CreatePixbuf(state().icon), -1);
|
||||
gtk_list_store_set(grandparent->gtkListStore, &parent->gtkIter, 3 * self().offset() + 2, state().text.data(), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ namespace hiro {
|
||||
auto pTableViewColumn::construct() -> void {
|
||||
if(auto grandparent = _grandparent()) {
|
||||
auto handle = grandparent.data();
|
||||
unsigned offset = self().offset();
|
||||
uint offset = self().offset();
|
||||
|
||||
#if HIRO_GTK==2
|
||||
gtkHeader = gtk_hbox_new(false, 0);
|
||||
|
@@ -4,19 +4,17 @@ namespace hiro {
|
||||
|
||||
auto pTableViewItem::construct() -> void {
|
||||
if(auto parent = _parent()) {
|
||||
parent->lock();
|
||||
auto lock = parent->acquire();
|
||||
gtk_list_store_append(parent->gtkListStore, >kIter);
|
||||
_setState();
|
||||
parent->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
auto pTableViewItem::destruct() -> void {
|
||||
if(auto parent = _parent()) {
|
||||
parent->lock();
|
||||
auto lock = parent->acquire();
|
||||
gtk_list_store_remove(parent->gtkListStore, >kIter);
|
||||
parent->_updateSelected();
|
||||
parent->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +32,7 @@ auto pTableViewItem::setBackgroundColor(Color color) -> void {
|
||||
|
||||
auto pTableViewItem::setFocused() -> void {
|
||||
if(auto parent = _parent()) {
|
||||
auto lock = parent->acquire();
|
||||
GtkTreePath* path = gtk_tree_path_new_from_string(string{self().offset()});
|
||||
gtk_tree_view_set_cursor(parent->gtkTreeView, path, nullptr, false);
|
||||
gtk_tree_view_scroll_to_cell(parent->gtkTreeView, path, nullptr, true, 0.5, 0.0);
|
||||
@@ -57,7 +56,7 @@ auto pTableViewItem::_parent() -> maybe<pTableView&> {
|
||||
|
||||
auto pTableViewItem::_setState() -> void {
|
||||
if(auto parent = _parent()) {
|
||||
parent->lock();
|
||||
auto lock = parent->acquire();
|
||||
if(state().selected) {
|
||||
gtk_tree_selection_select_iter(parent->gtkTreeSelection, >kIter);
|
||||
} else {
|
||||
@@ -67,7 +66,6 @@ auto pTableViewItem::_setState() -> void {
|
||||
for(auto& cell : state().cells) {
|
||||
if(auto self = cell->self()) self->_setState();
|
||||
}
|
||||
parent->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -184,6 +184,8 @@ auto pTableView::_columnWidth(unsigned _column) -> unsigned {
|
||||
}
|
||||
|
||||
auto pTableView::_createModel() -> void {
|
||||
auto lock = acquire();
|
||||
|
||||
gtk_tree_view_set_model(gtkTreeView, nullptr);
|
||||
gtkListStore = nullptr;
|
||||
gtkTreeModel = nullptr;
|
||||
@@ -204,6 +206,11 @@ auto pTableView::_createModel() -> void {
|
||||
gtkListStore = gtk_list_store_newv(types.size(), types.data());
|
||||
gtkTreeModel = GTK_TREE_MODEL(gtkListStore);
|
||||
gtk_tree_view_set_model(gtkTreeView, gtkTreeModel);
|
||||
|
||||
// for(auto& item : state().items) {
|
||||
// gtk_list_store_append(gtkListStore, &item->self()->gtkIter);
|
||||
// item->self()->_setState();
|
||||
// }
|
||||
}
|
||||
|
||||
auto pTableView::_doActivate() -> void {
|
||||
@@ -385,7 +392,7 @@ auto pTableView::_updateSelected() -> void {
|
||||
|
||||
bool identical = selected.size() == currentSelection.size();
|
||||
if(identical) {
|
||||
for(auto n : range(selected)) {
|
||||
for(auto n : range(selected.size())) {
|
||||
if(selected[n] != currentSelection[n]) {
|
||||
identical = false;
|
||||
break;
|
||||
@@ -410,7 +417,7 @@ auto pTableView::_width(unsigned column) -> unsigned {
|
||||
unsigned width = 1;
|
||||
if(!header->column(column).visible()) return width;
|
||||
if(header->visible()) width = max(width, _columnWidth(column));
|
||||
for(auto row : range(state().items)) {
|
||||
for(auto row : range(self().itemCount())) {
|
||||
width = max(width, _cellWidth(row, column));
|
||||
}
|
||||
return width;
|
||||
|
@@ -30,7 +30,7 @@ auto pVerticalSlider::destruct() -> void {
|
||||
}
|
||||
|
||||
auto pVerticalSlider::minimumSize() const -> Size {
|
||||
return {20, 0};
|
||||
return {20, 3};
|
||||
}
|
||||
|
||||
auto pVerticalSlider::setLength(unsigned length) -> void {
|
||||
|
@@ -5,7 +5,7 @@ namespace hiro {
|
||||
struct pVerticalSlider : pWidget {
|
||||
Declare(VerticalSlider, Widget)
|
||||
|
||||
auto minimumSize() const -> Size;
|
||||
auto minimumSize() const -> Size override;
|
||||
auto setLength(unsigned length) -> void;
|
||||
auto setPosition(unsigned position) -> void;
|
||||
};
|
||||
|
@@ -44,18 +44,16 @@ auto pWidget::setGeometry(Geometry geometry) -> void {
|
||||
if(geometry.width() < 1) geometry.setWidth (1);
|
||||
if(geometry.height() < 1) geometry.setHeight(1);
|
||||
gtk_widget_set_size_request(gtkWidget, geometry.width(), geometry.height());
|
||||
if(gtk_widget_get_realized(gtkWidget)) {
|
||||
if(0 && gtk_widget_get_realized(gtkWidget)) {
|
||||
static bool locked = false;
|
||||
if(!locked) {
|
||||
locked = true;
|
||||
auto time = chrono::millisecond();
|
||||
while(chrono::millisecond() - time < 20) {
|
||||
gtk_main_iteration_do(false);
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(gtkWidget, &allocation);
|
||||
if(allocation.width != geometry.width ()) continue;
|
||||
if(allocation.height != geometry.height()) continue;
|
||||
break;
|
||||
if(allocation.width == geometry.width() && allocation.height == geometry.height()) break;
|
||||
gtk_main_iteration_do(false);
|
||||
}
|
||||
locked = false;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ static auto Window_close(GtkWidget* widget, GdkEvent* event, pWindow* p) -> sign
|
||||
} else {
|
||||
p->self().setVisible(false);
|
||||
}
|
||||
if(p->state().modal && !p->pObject::state().visible) p->self().setModal(false);
|
||||
if(p->self().modal() && !p->self().visible()) p->self().setModal(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,62 +30,28 @@ static auto Window_draw(GtkWidget* widget, cairo_t* context, pWindow* p) -> sign
|
||||
|
||||
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint(context);
|
||||
} else {
|
||||
#if HIRO_GTK==3
|
||||
auto style = gtk_widget_get_style_context(widget);
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(widget, &allocation);
|
||||
gtk_render_background(style, context, 0, 0, allocation.width, allocation.height);
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//GTK2 expose-event
|
||||
static auto Window_expose(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed {
|
||||
if(auto color = p->state().backgroundColor) {
|
||||
cairo_t* context = gdk_cairo_create(gtk_widget_get_window(widget));
|
||||
Window_draw(widget, context, p);
|
||||
cairo_destroy(context);
|
||||
}
|
||||
cairo_t* context = gdk_cairo_create(gtk_widget_get_window(widget));
|
||||
Window_draw(widget, context, p);
|
||||
cairo_destroy(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
static auto Window_configure(GtkWidget* widget, GdkEvent* event, pWindow* p) -> signed {
|
||||
if(!gtk_widget_get_realized(p->widget)) return false;
|
||||
if(!p->pObject::state().visible) return false;
|
||||
GdkWindow* gdkWindow = gtk_widget_get_window(widget);
|
||||
|
||||
GdkRectangle border, client;
|
||||
gdk_window_get_frame_extents(gdkWindow, &border);
|
||||
#if HIRO_GTK==2
|
||||
gdk_window_get_geometry(gdkWindow, nullptr, nullptr, &client.width, &client.height, nullptr);
|
||||
#elif HIRO_GTK==3
|
||||
gdk_window_get_geometry(gdkWindow, nullptr, nullptr, &client.width, &client.height);
|
||||
#endif
|
||||
gdk_window_get_origin(gdkWindow, &client.x, &client.y);
|
||||
|
||||
if(!p->state().fullScreen) {
|
||||
//update geometry settings
|
||||
settings.geometry.frameX = client.x - border.x;
|
||||
settings.geometry.frameY = client.y - border.y;
|
||||
settings.geometry.frameWidth = border.width - client.width;
|
||||
settings.geometry.frameHeight = border.height - client.height;
|
||||
}
|
||||
|
||||
Geometry geometry = {
|
||||
client.x,
|
||||
client.y + p->_menuHeight(),
|
||||
client.width,
|
||||
client.height - p->_menuHeight() - p->_statusHeight()
|
||||
};
|
||||
|
||||
//move
|
||||
if(geometry.x() != p->state().geometry.x() || geometry.y() != p->state().geometry.y()) {
|
||||
if(!p->state().fullScreen) {
|
||||
p->state().geometry.setPosition({geometry.x(), geometry.y()});
|
||||
}
|
||||
if(!p->locked()) p->self().doMove();
|
||||
}
|
||||
|
||||
//size
|
||||
if(geometry.width() != p->state().geometry.width() || geometry.height() != p->state().geometry.height()) {
|
||||
p->onSizePending = true;
|
||||
}
|
||||
|
||||
p->_synchronizeMargin();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,11 +64,17 @@ GtkSelectionData* data, unsigned type, unsigned timestamp, pWindow* p) -> void {
|
||||
}
|
||||
|
||||
static auto Window_getPreferredWidth(GtkWidget* widget, int* minimalWidth, int* naturalWidth) -> void {
|
||||
//TODO: get pWindow; use sizeRequest
|
||||
if(auto p = (pWindow*)g_object_get_data(G_OBJECT(widget), "hiro::window")) {
|
||||
*minimalWidth = 1;
|
||||
*naturalWidth = 1; //p->state().geometry.width();
|
||||
}
|
||||
}
|
||||
|
||||
static auto Window_getPreferredHeight(GtkWidget* widget, int* minimalHeight, int* naturalHeight) -> void {
|
||||
//TODO: get pWindow; use sizeRequest
|
||||
if(auto p = (pWindow*)g_object_get_data(G_OBJECT(widget), "hiro::window")) {
|
||||
*minimalHeight = 1;
|
||||
*naturalHeight = p->state().geometry.height();
|
||||
}
|
||||
}
|
||||
|
||||
static auto Window_keyPress(GtkWidget* widget, GdkEventKey* event, pWindow* p) -> signed {
|
||||
@@ -128,28 +100,10 @@ static auto Window_keyRelease(GtkWidget* widget, GdkEventKey* event, pWindow* p)
|
||||
}
|
||||
|
||||
static auto Window_sizeAllocate(GtkWidget* widget, GtkAllocation* allocation, pWindow* p) -> void {
|
||||
//size-allocate is sent before window-state-event when maximizing a window
|
||||
//this means Window::onSize() handler would have the old maximized state if we used the latter signal
|
||||
p->_synchronizeState();
|
||||
|
||||
//size-allocate sent from gtk_fixed_move(); detect if layout unchanged and return
|
||||
if(allocation->width == p->lastAllocation.width
|
||||
&& allocation->height == p->lastAllocation.height) return;
|
||||
|
||||
if(!p->state().fullScreen) {
|
||||
p->state().geometry.setSize({allocation->width, allocation->height});
|
||||
}
|
||||
|
||||
if(auto& layout = p->state().layout) {
|
||||
layout->setGeometry(p->self().geometry().setPosition(0, 0));
|
||||
}
|
||||
|
||||
if(!p->locked() && p->onSizePending) {
|
||||
p->onSizePending = false;
|
||||
p->self().doSize();
|
||||
}
|
||||
|
||||
p->lastAllocation = *allocation;
|
||||
p->_synchronizeGeometry();
|
||||
p->_synchronizeMargin();
|
||||
return;
|
||||
}
|
||||
|
||||
static auto Window_sizeRequest(GtkWidget* widget, GtkRequisition* requisition, pWindow* p) -> void {
|
||||
@@ -172,10 +126,6 @@ static auto Window_stateEvent(GtkWidget* widget, GdkEvent* event, pWindow* p) ->
|
||||
}
|
||||
|
||||
auto pWindow::construct() -> void {
|
||||
lastAllocation.width = 0;
|
||||
lastAllocation.height = 0;
|
||||
onSizePending = false;
|
||||
|
||||
widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_resizable(GTK_WINDOW(widget), true);
|
||||
|
||||
@@ -245,13 +195,22 @@ auto pWindow::construct() -> void {
|
||||
widgetClass->get_preferred_height = Window_getPreferredHeight;
|
||||
#endif
|
||||
g_signal_connect(G_OBJECT(widget), "window-state-event", G_CALLBACK(Window_stateEvent), (gpointer)this);
|
||||
|
||||
g_object_set_data(G_OBJECT(widget), "hiro::window", (gpointer)this);
|
||||
g_object_set_data(G_OBJECT(formContainer), "hiro::window", (gpointer)this);
|
||||
|
||||
pApplication::windows.append(this);
|
||||
}
|
||||
|
||||
auto pWindow::destruct() -> void {
|
||||
gtk_widget_destroy(widget);
|
||||
}
|
||||
for(uint offset : range(pApplication::windows.size())) {
|
||||
if(pApplication::windows[offset] == this) {
|
||||
pApplication::windows.remove(offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto pWindow::append(sLayout layout) -> void {
|
||||
gtk_widget_destroy(widget);
|
||||
}
|
||||
|
||||
auto pWindow::append(sMenuBar menuBar) -> void {
|
||||
@@ -260,6 +219,9 @@ auto pWindow::append(sMenuBar menuBar) -> void {
|
||||
_setMenuVisible(menuBar->visible(true));
|
||||
}
|
||||
|
||||
auto pWindow::append(sSizable sizable) -> void {
|
||||
}
|
||||
|
||||
auto pWindow::append(sStatusBar statusBar) -> void {
|
||||
_setStatusEnabled(statusBar->enabled(true));
|
||||
_setStatusFont(statusBar->font(true));
|
||||
@@ -285,13 +247,13 @@ auto pWindow::frameMargin() const -> Geometry {
|
||||
};
|
||||
}
|
||||
|
||||
auto pWindow::remove(sLayout layout) -> void {
|
||||
}
|
||||
|
||||
auto pWindow::remove(sMenuBar menuBar) -> void {
|
||||
_setMenuVisible(false);
|
||||
}
|
||||
|
||||
auto pWindow::remove(sSizable sizable) -> void {
|
||||
}
|
||||
|
||||
auto pWindow::remove(sStatusBar statusBar) -> void {
|
||||
_setStatusVisible(false);
|
||||
}
|
||||
@@ -317,10 +279,6 @@ auto pWindow::setEnabled(bool enabled) -> void {
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
if(auto self = statusBar->self()) self->setEnabled(statusBar->enabled(true));
|
||||
}
|
||||
|
||||
if(auto& layout = state().layout) {
|
||||
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
|
||||
}
|
||||
}
|
||||
|
||||
auto pWindow::setFocused() -> void {
|
||||
@@ -329,31 +287,28 @@ auto pWindow::setFocused() -> void {
|
||||
|
||||
auto pWindow::setFullScreen(bool fullScreen) -> void {
|
||||
if(fullScreen) {
|
||||
windowedGeometry = state().geometry;
|
||||
gtk_window_fullscreen(GTK_WINDOW(widget));
|
||||
state().geometry = Monitor::geometry(Monitor::primary());
|
||||
} else {
|
||||
gtk_window_unfullscreen(GTK_WINDOW(widget));
|
||||
state().geometry = windowedGeometry;
|
||||
}
|
||||
auto time = chrono::millisecond();
|
||||
while(chrono::millisecond() - time < 20) gtk_main_iteration_do(false);
|
||||
while(chrono::millisecond() - time < 20) Application::processEvents();
|
||||
}
|
||||
|
||||
auto pWindow::setGeometry(Geometry geometry) -> void {
|
||||
Geometry margin = frameMargin();
|
||||
auto margin = frameMargin();
|
||||
gtk_window_move(GTK_WINDOW(widget), geometry.x() - margin.x(), geometry.y() - margin.y());
|
||||
|
||||
setMaximumSize(state().maximumSize);
|
||||
setMinimumSize(state().minimumSize);
|
||||
|
||||
gtk_widget_set_size_request(formContainer, geometry.width(), geometry.height());
|
||||
auto time1 = chrono::millisecond();
|
||||
while(chrono::millisecond() - time1 < 20) gtk_main_iteration_do(false);
|
||||
while(chrono::millisecond() - time1 < 20) Application::processEvents();
|
||||
|
||||
gtk_window_resize(GTK_WINDOW(widget), geometry.width(), geometry.height() + _menuHeight() + _statusHeight());
|
||||
|
||||
auto time2 = chrono::millisecond();
|
||||
while(chrono::millisecond() - time2 < 20) gtk_main_iteration_do(false);
|
||||
while(chrono::millisecond() - time2 < 20) Application::processEvents();
|
||||
}
|
||||
|
||||
auto pWindow::setMaximized(bool maximized) -> void {
|
||||
@@ -366,9 +321,9 @@ auto pWindow::setMaximized(bool maximized) -> void {
|
||||
}
|
||||
|
||||
auto pWindow::setMaximumSize(Size size) -> void {
|
||||
if(size.height()) size.setHeight(size.height() + _menuHeight() + _statusHeight());
|
||||
|
||||
//TODO: this doesn't have any effect in GTK2 or GTK3
|
||||
GdkGeometry geometry;
|
||||
if(size.height()) size.setHeight(size.height() + _menuHeight() + _statusHeight());
|
||||
geometry.max_width = !state().resizable ? state().geometry.width() : size.width() ? size.width() : 32767;
|
||||
geometry.max_height = !state().resizable ? state().geometry.height() : size.height() ? size.height() : 32767;
|
||||
gtk_window_set_geometry_hints(GTK_WINDOW(widget), nullptr, &geometry, GDK_HINT_MAX_SIZE);
|
||||
@@ -384,12 +339,13 @@ auto pWindow::setMinimized(bool minimized) -> void {
|
||||
}
|
||||
|
||||
auto pWindow::setMinimumSize(Size size) -> void {
|
||||
if(size.height()) size.setHeight(size.height() + _menuHeight() + _statusHeight());
|
||||
gtk_widget_set_size_request(formContainer, size.width(), size.height()); //for GTK3
|
||||
|
||||
GdkGeometry geometry;
|
||||
if(size.height()) size.setHeight(size.height() + _menuHeight() + _statusHeight());
|
||||
geometry.min_width = !state().resizable ? state().geometry.width() : size.width() ? size.width() : 1;
|
||||
geometry.min_height = !state().resizable ? state().geometry.height() : size.height() ? size.height() : 1;
|
||||
gtk_window_set_geometry_hints(GTK_WINDOW(widget), nullptr, &geometry, GDK_HINT_MIN_SIZE);
|
||||
gtk_window_set_geometry_hints(GTK_WINDOW(widget), nullptr, &geometry, GDK_HINT_MIN_SIZE); //for GTK2
|
||||
}
|
||||
|
||||
auto pWindow::setModal(bool modal) -> void {
|
||||
@@ -424,57 +380,47 @@ auto pWindow::setTitle(const string& title) -> void {
|
||||
|
||||
auto pWindow::setVisible(bool visible) -> void {
|
||||
gtk_widget_set_visible(widget, visible);
|
||||
|
||||
if(auto& menuBar = state().menuBar) {
|
||||
if(menuBar->self()) menuBar->self()->setVisible(menuBar->visible(true));
|
||||
}
|
||||
|
||||
if(auto& layout = state().layout) {
|
||||
if(layout->self()) layout->self()->setVisible(layout->visible(true));
|
||||
}
|
||||
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
if(statusBar->self()) statusBar->self()->setVisible(statusBar->visible(true));
|
||||
}
|
||||
|
||||
//GTK+ returns invalid widget sizes below without this call
|
||||
Application::processEvents();
|
||||
|
||||
if(visible) {
|
||||
if(gtk_widget_get_visible(gtkMenu)) {
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(gtkMenu, &allocation);
|
||||
settings.geometry.menuHeight = allocation.height;
|
||||
}
|
||||
|
||||
if(gtk_widget_get_visible(gtkStatus)) {
|
||||
GtkAllocation allocation;
|
||||
gtk_widget_get_allocation(gtkStatus, &allocation);
|
||||
settings.geometry.statusHeight = allocation.height;
|
||||
}
|
||||
}
|
||||
|
||||
if(auto& layout = state().layout) {
|
||||
layout->setGeometry(self().geometry().setPosition(0, 0));
|
||||
}
|
||||
_synchronizeMargin();
|
||||
}
|
||||
|
||||
auto pWindow::_append(mWidget& widget) -> void {
|
||||
if(!widget.self()) return;
|
||||
if(auto parent = widget.parentWidget(true)) {
|
||||
if(auto instance = parent->self()) widget.self()->gtkParent = instance->container(widget);
|
||||
} else {
|
||||
widget.self()->gtkParent = formContainer;
|
||||
if(auto pWidget = widget.self()) {
|
||||
if(auto parent = widget.parentWidget(true)) {
|
||||
if(auto instance = parent->self()) {
|
||||
pWidget->gtkParent = instance->container(widget);
|
||||
}
|
||||
} else {
|
||||
pWidget->gtkParent = formContainer;
|
||||
}
|
||||
if(pWidget->gtkParent) {
|
||||
gtk_fixed_put(GTK_FIXED(pWidget->gtkParent), pWidget->gtkWidget, 0, 0);
|
||||
}
|
||||
}
|
||||
gtk_fixed_put(GTK_FIXED(widget.self()->gtkParent), widget.self()->gtkWidget, 0, 0);
|
||||
}
|
||||
|
||||
auto pWindow::_append(mMenu& menu) -> void {
|
||||
if(menu.self()) gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), menu.self()->widget);
|
||||
if(auto pMenu = menu.self()) {
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), pMenu->widget);
|
||||
}
|
||||
}
|
||||
|
||||
auto pWindow::_menuHeight() const -> signed {
|
||||
return gtk_widget_get_visible(gtkMenu) ? settings.geometry.menuHeight : 0;
|
||||
auto pWindow::_menuHeight() const -> int {
|
||||
if(auto& menuBar = state().menuBar) {
|
||||
if(menuBar->visible()) {
|
||||
return settings.geometry.menuHeight + _menuTextHeight();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pWindow::_menuTextHeight() const -> int {
|
||||
int height = 0;
|
||||
if(auto& menuBar = state().menuBar) {
|
||||
for(auto& menu : menuBar->state.menus) {
|
||||
height = max(height, menu->font(true).size(menu->text()).height());
|
||||
}
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
auto pWindow::_setIcon(const string& pathname) -> bool {
|
||||
@@ -530,14 +476,116 @@ auto pWindow::_setStatusVisible(bool visible) -> void {
|
||||
setResizable(self().resizable());
|
||||
}
|
||||
|
||||
auto pWindow::_statusHeight() const -> signed {
|
||||
return gtk_widget_get_visible(gtkStatus) ? settings.geometry.statusHeight : 0;
|
||||
auto pWindow::_statusHeight() const -> int {
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
if(statusBar->visible()) {
|
||||
return settings.geometry.statusHeight + _statusTextHeight();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pWindow::_statusTextHeight() const -> int {
|
||||
int height = 0;
|
||||
if(auto& statusBar = state().statusBar) {
|
||||
height = statusBar->font(true).size(statusBar->text()).height();
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
//GTK is absolutely hopeless with window sizing
|
||||
//it will send size-allocate events during resizing of widgets during size-allocate events
|
||||
//instead of fighting with configure-event and size-allocate, just poll the state instead
|
||||
auto pWindow::_synchronizeGeometry() -> void {
|
||||
if(locked()) return;
|
||||
auto lock = acquire();
|
||||
|
||||
if(!gtk_widget_get_realized(widget)) return;
|
||||
if(!gtk_widget_get_visible(widget)) return;
|
||||
|
||||
GtkAllocation allocation;
|
||||
|
||||
gtk_widget_get_allocation(formContainer, &allocation);
|
||||
if(allocation.width != lastSize.width || allocation.height != lastSize.height) {
|
||||
auto size = self().geometry().size();
|
||||
state().geometry.setSize({allocation.width, allocation.height});
|
||||
if(auto& sizable = state().sizable) {
|
||||
sizable->setGeometry(self().geometry().setPosition());
|
||||
}
|
||||
self().doSize();
|
||||
|
||||
//for GTK3: the window will not update after changing widget sizes until sending size-allocate
|
||||
//size-allocate will also call _synchronizeMargin() which is also important for window sizing
|
||||
//GtkAllocation is a typedef of GdkRectangle
|
||||
GtkAllocation rectangle;
|
||||
gtk_widget_get_allocation(widget, &rectangle);
|
||||
g_signal_emit_by_name(G_OBJECT(widget), "size-allocate", &rectangle, (gpointer)this, nullptr);
|
||||
}
|
||||
lastSize = allocation;
|
||||
|
||||
gtk_widget_get_allocation(widget, &allocation);
|
||||
if(allocation.x != lastMove.x || allocation.y != lastMove.y) {
|
||||
state().geometry.setPosition({allocation.x, allocation.y});
|
||||
self().doMove();
|
||||
}
|
||||
lastMove = allocation;
|
||||
}
|
||||
|
||||
auto pWindow::_synchronizeMargin() -> void {
|
||||
if(locked()) return;
|
||||
auto lock = acquire();
|
||||
|
||||
if(!gtk_widget_get_realized(widget)) return;
|
||||
if(!gtk_widget_get_visible(widget)) return;
|
||||
if(state().fullScreen || state().maximized || state().minimized) return;
|
||||
|
||||
auto window = gtk_widget_get_window(widget);
|
||||
GdkRectangle border, client;
|
||||
gdk_window_get_frame_extents(window, &border);
|
||||
gdk_window_get_origin(window, &client.x, &client.y);
|
||||
#if HIRO_GTK==2
|
||||
gdk_window_get_geometry(window, nullptr, nullptr, &client.width, &client.height, nullptr);
|
||||
#elif HIRO_GTK==3
|
||||
gdk_window_get_geometry(window, nullptr, nullptr, &client.width, &client.height);
|
||||
#endif
|
||||
|
||||
settings.geometry.frameX = client.x - border.x;
|
||||
settings.geometry.frameY = client.y - border.y;
|
||||
settings.geometry.frameWidth = border.width - client.width;
|
||||
settings.geometry.frameHeight = border.height - client.height;
|
||||
|
||||
if(gtk_widget_get_visible(gtkMenu)) {
|
||||
GtkAllocation allocation;
|
||||
auto time = chrono::millisecond();
|
||||
while(chrono::millisecond() - time < 20) {
|
||||
gtk_widget_get_allocation(gtkMenu, &allocation);
|
||||
if(allocation.height > 1) {
|
||||
settings.geometry.menuHeight = allocation.height - _menuTextHeight();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(gtk_widget_get_visible(gtkStatus)) {
|
||||
GtkAllocation allocation;
|
||||
auto time = chrono::millisecond();
|
||||
while(chrono::millisecond() - time < 20) {
|
||||
gtk_widget_get_allocation(gtkStatus, &allocation);
|
||||
if(allocation.height > 1) {
|
||||
settings.geometry.statusHeight = allocation.height - _statusTextHeight();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//GTK doesn't add gtk_window_is_maximized() until 3.12;
|
||||
//and doesn't appear to have a companion gtk_window_is_(hidden,iconic,minimized);
|
||||
//so we have to do this the hard way
|
||||
auto pWindow::_synchronizeState() -> void {
|
||||
if(locked()) return;
|
||||
auto lock = acquire();
|
||||
|
||||
if(!gtk_widget_get_realized(widget)) return;
|
||||
|
||||
#if defined(DISPLAY_WINDOWS)
|
||||
|
@@ -5,13 +5,13 @@ namespace hiro {
|
||||
struct pWindow : pObject {
|
||||
Declare(Window, Object)
|
||||
|
||||
auto append(sLayout layout) -> void;
|
||||
auto append(sMenuBar menuBar) -> void;
|
||||
auto append(sSizable sizable) -> void;
|
||||
auto append(sStatusBar statusBar) -> void;
|
||||
auto focused() const -> bool override;
|
||||
auto frameMargin() const -> Geometry;
|
||||
auto remove(sLayout layout) -> void;
|
||||
auto remove(sMenuBar menuBar) -> void;
|
||||
auto remove(sSizable sizable) -> void;
|
||||
auto remove(sStatusBar statusBar) -> void;
|
||||
auto setBackgroundColor(Color color) -> void;
|
||||
auto setDismissable(bool dismissable) -> void;
|
||||
@@ -31,7 +31,8 @@ struct pWindow : pObject {
|
||||
|
||||
auto _append(mWidget& widget) -> void;
|
||||
auto _append(mMenu& menu) -> void;
|
||||
auto _menuHeight() const -> signed;
|
||||
auto _menuHeight() const -> int;
|
||||
auto _menuTextHeight() const -> int;
|
||||
auto _setIcon(const string& basename) -> bool;
|
||||
auto _setMenuEnabled(bool enabled) -> void;
|
||||
auto _setMenuFont(const Font& font) -> void;
|
||||
@@ -40,7 +41,10 @@ struct pWindow : pObject {
|
||||
auto _setStatusFont(const Font& font) -> void;
|
||||
auto _setStatusText(const string& text) -> void;
|
||||
auto _setStatusVisible(bool visible) -> void;
|
||||
auto _statusHeight() const -> signed;
|
||||
auto _statusHeight() const -> int;
|
||||
auto _statusTextHeight() const -> int;
|
||||
auto _synchronizeGeometry() -> void;
|
||||
auto _synchronizeMargin() -> void;
|
||||
auto _synchronizeState() -> void;
|
||||
|
||||
GtkWidget* widget = nullptr;
|
||||
@@ -49,9 +53,8 @@ struct pWindow : pObject {
|
||||
GtkWidget* statusContainer = nullptr;
|
||||
GtkWidget* gtkMenu = nullptr;
|
||||
GtkWidget* gtkStatus = nullptr;
|
||||
GtkAllocation lastAllocation = {0};
|
||||
Geometry windowedGeometry{128, 128, 256, 256};
|
||||
bool onSizePending = false;
|
||||
GtkAllocation lastMove = {0};
|
||||
GtkAllocation lastSize = {0};
|
||||
};
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user