Update to v094r40 release.

byuu says:

Changelog:
- updated to newest hiro API
- SFC performance profile builds once again
- hiro: Qt port completed

Errata 1: the hiro/Qt target won't run tomoko just yet. Starts by
crashing inside InputSettings because hiro/Qt isn't forcefully selecting
the first item added to a ComboButton just yet. Even with a monkey patch
to get around that, the UI is incredibly unstable. Lots of geometry
calculation bugs, and a crash when you try and access certain folders in
the browser dialog. Lots of work left to be done there, sadly.

Errata 2: the hiro/Windows port has black backgrounds on all ListView
items. It's because I need to test for unassigned colors and grab the
default Windows brush colors in those cases.

Note: alternating row colors on multi-column ListView widgets is gone
now. Not a bug. May add it back later, but I'm not sure. It doesn't
interact nicely with per-cell background colors.

Things left to do:

First, I have to fix the Windows and Qt target bugs.

Next, I need to go through and revise the hiro API even more (nothing
too major.)

Next, I need to update icarus to use the new hiro API, and add support
for the SFC games database.

Next, I have to rewrite my TSV->BML cheat code tool.

Next, I need to post a final WIP of higan+icarus publicly and wait a few
days.

Next, I need to fix any bugs reported from the final WIP that I can.

Finally, I should be able to release v095.
This commit is contained in:
Tim Allen
2015-08-18 20:18:00 +10:00
parent 0271d6a12b
commit 4344b916b6
200 changed files with 7246 additions and 5659 deletions

View File

@@ -8,7 +8,7 @@ auto pMenuBar::construct() -> void {
auto pMenuBar::destruct() -> void {
}
auto pMenuBar::append(shared_pointer<mMenu> menu) -> void {
auto pMenuBar::append(sMenu menu) -> void {
if(auto parent = _parent()) {
parent->_append(*menu);
if(menu->self()) {
@@ -18,7 +18,7 @@ auto pMenuBar::append(shared_pointer<mMenu> menu) -> void {
}
}
auto pMenuBar::remove(shared_pointer<mMenu> menu) -> void {
auto pMenuBar::remove(sMenu menu) -> void {
}
auto pMenuBar::setEnabled(bool enabled) -> void {

View File

@@ -5,8 +5,8 @@ namespace hiro {
struct pMenuBar : pObject {
Declare(MenuBar, Object)
auto append(shared_pointer<mMenu> menu) -> void;
auto remove(shared_pointer<mMenu> menu) -> void;
auto append(sMenu menu) -> void;
auto remove(sMenu menu) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const string& font) -> void override;
auto setVisible(bool visible) -> void override;

View File

@@ -46,6 +46,7 @@
#include "widget/label.cpp"
#include "widget/line-edit.cpp"
#include "widget/list-view.cpp"
#include "widget/list-view-header.cpp"
#include "widget/list-view-column.cpp"
#include "widget/list-view-item.cpp"
#include "widget/list-view-cell.cpp"

View File

@@ -57,6 +57,7 @@ namespace hiro {
#include "widget/label.hpp"
#include "widget/line-edit.hpp"
#include "widget/list-view.hpp"
#include "widget/list-view-header.hpp"
#include "widget/list-view-column.hpp"
#include "widget/list-view-item.hpp"
#include "widget/list-view-cell.hpp"

View File

@@ -1,16 +1,5 @@
namespace hiro {
void Settings::load() {
string path = {configpath(), "hiro/"};
Configuration::Document::load({path, "gtk.bml"});
}
void Settings::save() {
string path = {configpath(), "hiro/"};
directory::create(path, 0755);
Configuration::Document::save({path, "gtk.bml"});
}
Settings::Settings() {
geometry.append(geometry.frameX = 4, "FrameX");
geometry.append(geometry.frameY = 24, "FrameY");
@@ -23,4 +12,15 @@ Settings::Settings() {
append(window, "Window");
}
auto Settings::load() -> void {
string path = {configpath(), "hiro/"};
Configuration::Document::load({path, "gtk.bml"});
}
auto Settings::save() -> void {
string path = {configpath(), "hiro/"};
directory::create(path, 0755);
Configuration::Document::save({path, "gtk.bml"});
}
}

View File

@@ -16,9 +16,9 @@ struct Settings : Configuration::Document {
unsigned backgroundColor;
} window;
void load();
void save();
Settings();
auto load() -> void;
auto save() -> void;
};
static Settings* settings = nullptr;

View File

@@ -52,12 +52,12 @@ auto pHexEdit::construct() -> void {
gtk_widget_show(subWidget);
gtk_widget_show(container);
setAddress(state().address);
setBackgroundColor(state().backgroundColor);
setColumns(state().columns);
setForegroundColor(state().foregroundColor);
setRows(state().rows);
setLength(state().length);
setOffset(state().offset);
update();
g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(HexEdit_keyPress), (gpointer)this);
@@ -80,6 +80,12 @@ auto pHexEdit::focused() const -> bool {
return GTK_WIDGET_HAS_FOCUS(subWidget) || GTK_WIDGET_HAS_FOCUS(scrollBar);
}
auto pHexEdit::setAddress(unsigned address) -> void {
setScroll();
updateScroll();
update();
}
auto pHexEdit::setBackgroundColor(Color color) -> void {
GdkColor gdkColor = CreateColor(color);
gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
@@ -100,12 +106,6 @@ auto pHexEdit::setLength(unsigned length) -> void {
update();
}
auto pHexEdit::setOffset(unsigned offset) -> void {
setScroll();
updateScroll();
update();
}
auto pHexEdit::setRows(unsigned rows) -> void {
setScroll();
update();
@@ -120,16 +120,16 @@ auto pHexEdit::update() -> void {
unsigned position = cursorPosition();
string output;
unsigned offset = state().offset;
unsigned address = state().address;
for(auto row : range(state().rows)) {
output.append(hex(offset, 8L));
output.append(hex(address, 8L));
output.append(" ");
string hexdata;
string ansidata = " ";
for(auto column : range(state().columns)) {
if(offset < state().length) {
uint8_t data = self().doRead(offset++);
if(address < state().length) {
uint8_t data = self().doRead(address++);
hexdata.append(hex(data, 2L));
hexdata.append(" ");
ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
@@ -141,7 +141,7 @@ auto pHexEdit::update() -> void {
output.append(hexdata);
output.append(ansidata);
if(offset >= state().length) break;
if(address >= state().length) break;
if(row != state().rows - 1) output.append("\n");
}
@@ -179,9 +179,9 @@ auto pHexEdit::keyPress(unsigned scancode, unsigned mask) -> bool {
if(scancode == GDK_Up) {
if(cursorY != 0) return false;
signed newOffset = state().offset - state().columns;
if(newOffset >= 0) {
self().setOffset(newOffset);
signed newAddress = state().address - state().columns;
if(newAddress >= 0) {
self().setAddress(newAddress);
update();
}
return true;
@@ -191,34 +191,34 @@ auto pHexEdit::keyPress(unsigned scancode, unsigned mask) -> bool {
if(cursorY >= rows() - 1) return true;
if(cursorY != state().rows - 1) return false;
signed newOffset = state().offset + state().columns;
if(newOffset + state().columns * state().rows - (state().columns - 1) <= state().length) {
self().setOffset(newOffset);
signed newAddress = state().address + state().columns;
if(newAddress + state().columns * state().rows - (state().columns - 1) <= state().length) {
self().setAddress(newAddress);
update();
}
return true;
}
if(scancode == GDK_Page_Up) {
signed newOffset = state().offset - state().columns * state().rows;
if(newOffset >= 0) {
self().setOffset(newOffset);
signed newAddress = state().address - state().columns * state().rows;
if(newAddress >= 0) {
self().setAddress(newAddress);
} else {
self().setOffset(0);
self().setAddress(0);
}
update();
return true;
}
if(scancode == GDK_Page_Down) {
signed newOffset = state().offset + state().columns * state().rows;
signed newAddress = state().address + state().columns * state().rows;
for(auto n : range(state().rows)) {
if(newOffset + state().columns * state().rows - (state().columns - 1) <= state().length) {
self().setOffset(newOffset);
if(newAddress + state().columns * state().rows - (state().columns - 1) <= state().length) {
self().setAddress(newAddress);
update();
break;
}
newOffset -= state().columns;
newAddress -= state().columns;
}
return true;
}
@@ -238,10 +238,10 @@ auto pHexEdit::keyPress(unsigned scancode, unsigned mask) -> bool {
cursorX /= 3;
if(cursorX < state().columns) {
//not in ANSI region
unsigned offset = state().offset + (cursorY * state().columns + cursorX);
unsigned address = state().address + (cursorY * state().columns + cursorX);
if(offset >= state().length) return false; //do not edit past end of data
uint8_t data = self().doRead(offset);
if(address >= state().length) return false; //do not edit past end of data
uint8_t data = self().doRead(address);
//write modified value
if(cursorNibble == 1) {
@@ -249,7 +249,7 @@ auto pHexEdit::keyPress(unsigned scancode, unsigned mask) -> bool {
} else {
data = (data & 0x0f) | (scancode << 4);
}
self().doWrite(offset, data);
self().doWrite(address, data);
//auto-advance cursor to next nibble/byte
position++;
@@ -278,7 +278,7 @@ auto pHexEdit::rowsScrollable() -> signed {
auto pHexEdit::scroll(signed position) -> void {
if(position > rowsScrollable()) position = rowsScrollable();
if(position < 0) position = 0;
self().setOffset(position * state().columns);
self().setAddress(position * state().columns);
}
auto pHexEdit::setCursorPosition(unsigned position) -> void {
@@ -304,7 +304,7 @@ auto pHexEdit::setScroll() -> void {
}
auto pHexEdit::updateScroll() -> void {
unsigned row = state().offset / state().columns;
unsigned row = state().address / state().columns;
gtk_range_set_value(GTK_RANGE(scrollBar), row);
}

View File

@@ -6,11 +6,11 @@ struct pHexEdit : pWidget {
Declare(HexEdit, Widget)
auto focused() const -> bool override;
auto setAddress(unsigned address) -> void;
auto setBackgroundColor(Color color) -> void;
auto setColumns(unsigned columns) -> void;
auto setForegroundColor(Color color) -> void;
auto setLength(unsigned length) -> void;
auto setOffset(unsigned offset) -> void;
auto setRows(unsigned rows) -> void;
auto update() -> void;

View File

@@ -116,7 +116,7 @@ auto pIconView::setGeometry(Geometry geometry) -> void {
}
auto pIconView::setItemIcon(unsigned position, const image& icon) -> void {
if(position >= self().items()) return;
if(position >= self().itemCount()) return;
GtkTreeIter iter;
if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) {
if(icon) {
@@ -129,7 +129,7 @@ auto pIconView::setItemIcon(unsigned position, const image& icon) -> void {
}
auto pIconView::setItemSelected(unsigned position, bool selected) -> void {
if(position >= self().items()) return;
if(position >= self().itemCount()) return;
lock();
GtkTreePath* path = gtk_tree_path_new_from_string(string{position});
if(selected) {
@@ -165,7 +165,7 @@ auto pIconView::setItemSelectedNone() -> void {
}
auto pIconView::setItemText(unsigned position, const string& text) -> void {
if(position >= self().items()) return;
if(position >= self().itemCount()) return;
GtkTreeIter iter;
if(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, string{position})) {
gtk_list_store_set(store, &iter, 1, (const char*)text, -1);
@@ -216,7 +216,7 @@ auto pIconView::_updateSelected() -> void {
currentSelection = selected;
for(auto& item : state().items) item->state.selected = false;
for(auto& position : currentSelection) {
if(position >= self().items()) continue;
if(position >= self().itemCount()) continue;
state().items[position]->state.selected = true;
}

View File

@@ -5,7 +5,7 @@ namespace hiro {
auto pLabel::construct() -> void {
gtkWidget = gtk_label_new("");
_setAlignment();
setAlignment(state().alignment);
setText(state().text);
pWidget::construct();
@@ -16,30 +16,23 @@ auto pLabel::destruct() -> void {
}
auto pLabel::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
auto size = pFont::size(self().font(true), state().text);
return {size.width(), size.height()};
}
auto pLabel::setHorizontalAlignment(double alignment) -> void {
_setAlignment();
auto pLabel::setAlignment(Alignment alignment) -> void {
if(!alignment) alignment = {0.0, 0.5};
gtk_misc_set_alignment(GTK_MISC(gtkWidget), alignment.horizontal(), alignment.vertical());
auto justify = GTK_JUSTIFY_CENTER;
if(alignment.horizontal() < 0.333) justify = GTK_JUSTIFY_LEFT;
if(alignment.horizontal() > 0.666) justify = GTK_JUSTIFY_RIGHT;
gtk_label_set_justify(GTK_LABEL(gtkWidget), justify);
}
auto pLabel::setText(const string& text) -> void {
gtk_label_set_text(GTK_LABEL(gtkWidget), text);
}
auto pLabel::setVerticalAlignment(double alignment) -> void {
_setAlignment();
}
auto pLabel::_setAlignment() -> void {
gtk_misc_set_alignment(GTK_MISC(gtkWidget), state().horizontalAlignment, state().verticalAlignment);
auto justify = GTK_JUSTIFY_CENTER;
if(state().horizontalAlignment < 0.333) justify = GTK_JUSTIFY_LEFT;
if(state().horizontalAlignment > 0.666) justify = GTK_JUSTIFY_RIGHT;
gtk_label_set_justify(GTK_LABEL(gtkWidget), justify);
}
}
#endif

View File

@@ -6,11 +6,8 @@ struct pLabel : pWidget {
Declare(Label, Widget)
auto minimumSize() const -> Size override;
auto setHorizontalAlignment(double alignment) -> void;
auto setAlignment(Alignment alignment) -> void;
auto setText(const string& text) -> void;
auto setVerticalAlignment(double alignment) -> void;
auto _setAlignment() -> void;
};
}

View File

@@ -3,36 +3,58 @@
namespace hiro {
auto pListViewCell::construct() -> void {
_setState();
}
auto pListViewCell::destruct() -> void {
}
auto pListViewCell::setAlignment(Alignment alignment) -> void {
}
auto pListViewCell::setBackgroundColor(Color color) -> void {
}
auto pListViewCell::setCheckable(bool checkable) -> void {
}
auto pListViewCell::setChecked(bool checked) -> void {
_setState();
}
auto pListViewCell::setForegroundColor(Color color) -> void {
}
auto pListViewCell::setIcon(const image& icon) -> void {
if(auto item = _parent()) {
if(auto view = item->_parent()) {
gtk_list_store_set(view->gtkListStore, &item->gtkIter, 1 + self().offset() * 2, CreatePixbuf(icon), -1);
}
}
_setState();
}
auto pListViewCell::setText(const string& text) -> void {
if(auto item = _parent()) {
if(auto view = item->_parent()) {
gtk_list_store_set(view->gtkListStore, &item->gtkIter, 1 + self().offset() * 2 + 1, text.data(), -1);
}
}
_setState();
}
auto pListViewCell::_parent() -> pListViewItem* {
if(auto parent = self().parentListViewItem()) return parent->self();
return nullptr;
auto pListViewCell::_grandparent() -> maybe<pListView&> {
if(auto parent = _parent()) return parent->_parent();
return nothing;
}
auto pListViewCell::_parent() -> maybe<pListViewItem&> {
if(auto parent = self().parentListViewItem()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pListViewCell::_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();
}
}
}
}

View File

@@ -5,12 +5,17 @@ namespace hiro {
struct pListViewCell : pObject {
Declare(ListViewCell, Object)
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setCheckable(bool checkable) -> void;
auto setChecked(bool checked) -> void;
auto setForegroundColor(Color color) -> void;
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
auto _parent() -> pListViewItem*;
auto _grandparent() -> maybe<pListView&>;
auto _parent() -> maybe<pListViewItem&>;
auto _setState() -> void;
};
}

View File

@@ -3,91 +3,82 @@
namespace hiro {
auto pListViewColumn::construct() -> void {
unsigned offset = self().offset();
if(auto grandparent = _grandparent()) {
auto handle = grandparent.data();
unsigned offset = self().offset();
gtkHeader = gtk_hbox_new(false, 0);
gtkHeader = gtk_hbox_new(false, 0);
gtkHeaderIcon = gtk_image_new();
gtk_box_pack_start(GTK_BOX(gtkHeader), gtkHeaderIcon, false, false, 0);
gtkHeaderIcon = gtk_image_new();
gtk_box_pack_start(GTK_BOX(gtkHeader), gtkHeaderIcon, false, false, 0);
gtkHeaderText = gtk_label_new(state().text);
gtk_box_pack_start(GTK_BOX(gtkHeader), gtkHeaderText, true, false, 2);
gtkHeaderText = gtk_label_new(state().text);
gtk_box_pack_start(GTK_BOX(gtkHeader), gtkHeaderText, true, false, 2);
gtkColumn = gtk_tree_view_column_new();
gtk_tree_view_column_set_sizing(gtkColumn, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_title(gtkColumn, "");
gtk_tree_view_column_set_widget(gtkColumn, gtkHeader);
gtkColumn = gtk_tree_view_column_new();
gtk_tree_view_column_set_sizing(gtkColumn, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_title(gtkColumn, "");
gtk_tree_view_column_set_widget(gtkColumn, gtkHeader);
if(offset == 0) {
gtkCellToggle = gtk_cell_renderer_toggle_new();
gtk_tree_view_column_pack_start(gtkColumn, gtkCellToggle, false);
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellToggle, "active", 0, nullptr);
gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)ListView_cellRendererToggleDataFunc, (gpointer)_parent(), nullptr);
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellToggle, "active", 3 * offset + 0, nullptr);
gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellToggle), (GtkTreeCellDataFunc)ListView_dataFunc, (gpointer)handle, nullptr);
gtkCellIcon = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_column_pack_start(gtkColumn, gtkCellIcon, false);
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellIcon, "pixbuf", 3 * offset + 1, nullptr);
gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellIcon), (GtkTreeCellDataFunc)ListView_dataFunc, (gpointer)handle, nullptr);
gtkCellText = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(gtkColumn, gtkCellText, true); //text must expand to cell width for horizontal alignment to work
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellText, "text", 3 * offset + 2, nullptr);
gtk_tree_view_column_set_cell_data_func(gtkColumn, GTK_CELL_RENDERER(gtkCellText), (GtkTreeCellDataFunc)ListView_dataFunc, (gpointer)handle, nullptr);
g_signal_connect(G_OBJECT(gtkColumn), "clicked", G_CALLBACK(ListView_headerActivate), (gpointer)handle);
g_signal_connect(G_OBJECT(gtkCellText), "edited", G_CALLBACK(ListView_edit), (gpointer)handle);
g_signal_connect(G_OBJECT(gtkCellToggle), "toggled", G_CALLBACK(ListView_toggle), (gpointer)handle);
gtk_tree_view_append_column(grandparent->gtkTreeView, gtkColumn);
gtk_widget_show_all(gtkHeader);
grandparent->_createModel();
_setState();
}
gtkCellIcon = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_column_pack_start(gtkColumn, gtkCellIcon, false);
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellIcon, "pixbuf", 1 + offset * 2 + 0, nullptr);
gtkCellText = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(gtkColumn, gtkCellText, false);
gtk_tree_view_column_set_attributes(gtkColumn, gtkCellText, "text", 1 + offset * 2 + 1, nullptr);
g_signal_connect(G_OBJECT(gtkColumn), "clicked", G_CALLBACK(ListView_headerActivate), (gpointer)_parent());
g_signal_connect(G_OBJECT(gtkCellText), "edited", G_CALLBACK(ListView_edit), (gpointer)_parent());
if(gtkCellToggle) g_signal_connect(G_OBJECT(gtkCellToggle), "toggled", G_CALLBACK(ListView_toggle), (gpointer)_parent());
}
auto pListViewColumn::destruct() -> void {
if(auto grandparent = _grandparent()) {
gtk_tree_view_remove_column(grandparent->gtkTreeView, gtkColumn);
gtkColumn = nullptr;
grandparent->_createModel();
}
}
auto pListViewColumn::setActive() -> void {
if(auto parent = _parent()) {
gtk_tree_view_set_search_column(parent->gtkTreeView, 1 + self().offset() * 2 + 1);
}
_setState();
}
auto pListViewColumn::setAlignment(Alignment alignment) -> void {
}
auto pListViewColumn::setBackgroundColor(Color color) -> void {
if(color) {
GdkColor gdkColor = CreateColor(color);
if(gtkCellToggle) g_object_set(G_OBJECT(gtkCellToggle), "cell-background-gdk", &gdkColor, nullptr);
g_object_set(G_OBJECT(gtkCellIcon), "cell-background-gdk", &gdkColor, nullptr);
g_object_set(G_OBJECT(gtkCellText), "cell-background-gdk", &gdkColor, nullptr);
} else {
if(gtkCellToggle) g_object_set(G_OBJECT(gtkCellToggle), "cell-background-set", FALSE, nullptr);
g_object_set(G_OBJECT(gtkCellIcon), "cell-background-set", FALSE, nullptr);
g_object_set(G_OBJECT(gtkCellText), "cell-background-set", FALSE, nullptr);
}
}
auto pListViewColumn::setEditable(bool editable) -> void {
g_object_set(G_OBJECT(gtkCellText), "editable", editable ? TRUE : FALSE, nullptr);
g_object_set(G_OBJECT(gtkCellText), "editable", editable ? true : false, nullptr);
}
auto pListViewColumn::setExpandable(bool expandable) -> void {
if(auto parent = _parent()) {
parent->resizeColumns();
if(auto grandparent = _grandparent()) {
grandparent->resizeColumns();
}
}
auto pListViewColumn::setFont(const string& font) -> void {
pFont::setFont(gtkHeaderText, font);
auto fontDescription = pFont::create(font);
g_object_set(G_OBJECT(gtkCellText), "font-desc", fontDescription, nullptr);
pango_font_description_free(fontDescription);
}
auto pListViewColumn::setForegroundColor(Color color) -> void {
if(color) {
GdkColor gdkColor = CreateColor(color);
g_object_set(G_OBJECT(gtkCellText), "foreground-gdk", &gdkColor, nullptr);
} else {
g_object_set(G_OBJECT(gtkCellText), "foreground-set", FALSE, nullptr);
}
}
auto pListViewColumn::setHorizontalAlignment(double alignment) -> void {
_setAlignment();
}
auto pListViewColumn::setIcon(const image& icon) -> void {
@@ -99,40 +90,47 @@ auto pListViewColumn::setIcon(const image& icon) -> void {
}
auto pListViewColumn::setResizable(bool resizable) -> void {
gtk_tree_view_column_set_resizable(gtkColumn, resizable);
_setState();
}
auto pListViewColumn::setSortable(bool sortable) -> void {
_setState();
}
auto pListViewColumn::setText(const string& text) -> void {
gtk_label_set_text(GTK_LABEL(gtkHeaderText), text);
}
auto pListViewColumn::setVerticalAlignment(double alignment) -> void {
_setAlignment();
_setState();
}
auto pListViewColumn::setVisible(bool visible) -> void {
gtk_tree_view_column_set_visible(gtkColumn, visible);
_setState();
}
auto pListViewColumn::setWidth(signed width) -> void {
if(auto parent = _parent()) {
parent->resizeColumns();
if(auto grandparent = _grandparent()) {
grandparent->resizeColumns();
}
}
auto pListViewColumn::_parent() -> pListView* {
if(auto parent = self().parentListView()) return parent->self();
return nullptr;
auto pListViewColumn::_grandparent() -> maybe<pListView&> {
if(auto parent = _parent()) return parent->_parent();
return nothing;
}
auto pListViewColumn::_setAlignment() -> void {
gtk_tree_view_column_set_alignment(gtkColumn, state().horizontalAlignment);
gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(gtkCellText), state().horizontalAlignment, state().verticalAlignment);
//set multi-line text alignment
auto pangoAlignment = PANGO_ALIGN_CENTER;
if(state().horizontalAlignment < 0.333) pangoAlignment = PANGO_ALIGN_LEFT;
if(state().horizontalAlignment > 0.666) pangoAlignment = PANGO_ALIGN_RIGHT;
g_object_set(G_OBJECT(gtkCellText), "alignment", pangoAlignment, nullptr);
auto pListViewColumn::_parent() -> maybe<pListViewHeader&> {
if(auto parent = self().parentListViewHeader()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pListViewColumn::_setState() -> void {
if(auto grandparent = _grandparent()) {
gtk_tree_view_set_search_column(grandparent->gtkTreeView, 3 * self().offset() + 2);
gtk_tree_view_column_set_resizable(gtkColumn, state().resizable);
gtk_tree_view_column_set_clickable(gtkColumn, state().sortable);
gtk_label_set_text(GTK_LABEL(gtkHeaderText), state().text);
gtk_tree_view_column_set_visible(gtkColumn, self().visible());
}
}
}

View File

@@ -6,21 +6,24 @@ struct pListViewColumn : pObject {
Declare(ListViewColumn, Object)
auto setActive() -> void;
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setEditable(bool editable) -> void;
auto setExpandable(bool expandable) -> void;
auto setFont(const string& font) -> void override;
auto setForegroundColor(Color color) -> void;
auto setHorizontalAlignment(double alignment) -> void;
auto setHorizontalAlignment(double) -> void {}
auto setIcon(const image& icon) -> void;
auto setResizable(bool resizable) -> void;
auto setSortable(bool sortable) -> void;
auto setText(const string& text) -> void;
auto setVerticalAlignment(double alignment) -> void;
auto setVerticalAlignment(double) -> void {}
auto setVisible(bool visible) -> void override;
auto setWidth(signed width) -> void;
auto _parent() -> pListView*;
auto _setAlignment() -> void;
auto _grandparent() -> maybe<pListView&>;
auto _parent() -> maybe<pListViewHeader&>;
auto _setState() -> void;
GtkTreeViewColumn* gtkColumn = nullptr;
GtkWidget* gtkHeader = nullptr;

View File

@@ -0,0 +1,41 @@
#if defined(Hiro_ListView)
namespace hiro {
auto pListViewHeader::construct() -> void {
_setState();
}
auto pListViewHeader::destruct() -> void {
}
auto pListViewHeader::append(sListViewColumn column) -> void {
_setState();
}
auto pListViewHeader::remove(sListViewColumn column) -> void {
}
auto pListViewHeader::setVisible(bool visible) -> void {
_setState();
}
auto pListViewHeader::_parent() -> maybe<pListView&> {
if(auto parent = self().parentListView()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pListViewHeader::_setState() -> void {
if(auto parent = _parent()) {
gtk_tree_view_set_headers_visible(parent->gtkTreeView, self().visible());
for(auto& column : state().columns) {
if(auto self = column->self()) self->_setState();
}
}
}
}
#endif

View File

@@ -0,0 +1,18 @@
#if defined(Hiro_ListView)
namespace hiro {
struct pListViewHeader : pObject {
Declare(ListViewHeader, Object)
auto append(sListViewColumn column) -> void;
auto remove(sListViewColumn column) -> void;
auto setVisible(bool visible) -> void override;
auto _parent() -> maybe<pListView&>;
auto _setState() -> void;
};
}
#endif

View File

@@ -3,9 +3,21 @@
namespace hiro {
auto pListViewItem::construct() -> void {
if(auto parent = _parent()) {
parent->lock();
gtk_list_store_append(parent->gtkListStore, &gtkIter);
_setState();
parent->unlock();
}
}
auto pListViewItem::destruct() -> void {
if(auto parent = _parent()) {
parent->lock();
gtk_list_store_remove(parent->gtkListStore, &gtkIter);
parent->_updateSelected();
parent->unlock();
}
}
auto pListViewItem::append(sListViewCell cell) -> void {
@@ -14,18 +26,12 @@ auto pListViewItem::append(sListViewCell cell) -> void {
auto pListViewItem::remove(sListViewCell cell) -> void {
}
auto pListViewItem::setAlignment(Alignment alignment) -> void {
}
auto pListViewItem::setBackgroundColor(Color color) -> void {
}
auto pListViewItem::setCheckable(bool checkable) -> void {
}
auto pListViewItem::setChecked(bool checked) -> void {
if(auto parent = _parent()) {
gtk_list_store_set(parent->gtkListStore, &gtkIter, 0, checked, -1);
}
}
auto pListViewItem::setFocused() -> void {
if(auto parent = _parent()) {
GtkTreePath* path = gtk_tree_path_new_from_string(string{self().offset()});
@@ -39,23 +45,32 @@ auto pListViewItem::setForegroundColor(Color color) -> void {
}
auto pListViewItem::setSelected(bool selected) -> void {
_setState();
}
auto pListViewItem::_parent() -> maybe<pListView&> {
if(auto parent = self().parentListView()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
auto pListViewItem::_setState() -> void {
if(auto parent = _parent()) {
parent->lock();
if(selected) {
if(state().selected) {
gtk_tree_selection_select_iter(parent->gtkTreeSelection, &gtkIter);
} else {
gtk_tree_selection_unselect_iter(parent->gtkTreeSelection, &gtkIter);
}
parent->_updateSelected();
for(auto& cell : state().cells) {
if(auto self = cell->self()) self->_setState();
}
parent->unlock();
}
}
auto pListViewItem::_parent() -> pListView* {
if(auto parent = self().parentListView()) return parent->self();
return nullptr;
}
}
#endif

View File

@@ -7,14 +7,14 @@ struct pListViewItem : pObject {
auto append(sListViewCell cell) -> void;
auto remove(sListViewCell cell) -> void;
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setCheckable(bool checkable) -> void;
auto setChecked(bool checked) -> void;
auto setFocused() -> void;
auto setForegroundColor(Color color) -> void;
auto setSelected(bool selected) -> void;
auto _parent() -> pListView*;
auto _parent() -> maybe<pListView&>;
auto _setState() -> void;
GtkTreeIter gtkIter;
};

View File

@@ -10,8 +10,10 @@ static auto ListView_headerActivate(GtkTreeViewColumn* column, pListView* p) ->
static auto ListView_mouseMoveEvent(GtkWidget*, GdkEvent*, pListView* p) -> signed { return p->_doMouseMove(); }
static auto ListView_popup(GtkTreeView*, pListView* p) -> void { return p->_doContext(); }
static auto ListView_cellRendererToggleDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pListView* p) -> void { return p->_doCellRendererToggleDataFunc(renderer, iter); }
static auto ListView_toggle(GtkCellRendererToggle*, const char* path, pListView* p) -> void { return p->_doToggle(path); }
static auto ListView_dataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, pListView* p) -> void { return p->_doDataFunc(column, renderer, iter); }
static auto ListView_toggle(GtkCellRendererToggle* toggle, const char* path, pListView* p) -> void { return p->_doToggle(toggle, path); }
//gtk_tree_view_set_rules_hint(gtkTreeView, true);
auto pListView::construct() -> void {
gtkWidget = gtk_scrolled_window_new(0, 0);
@@ -29,12 +31,9 @@ auto pListView::construct() -> void {
setBackgroundColor(state().backgroundColor);
setBatchable(state().batchable);
setCheckable(state().checkable);
setBordered(state().bordered);
setFont(self().font(true));
setForegroundColor(state().foregroundColor);
setGridVisible(state().gridVisible);
setHeaderVisible(state().headerVisible);
setSortable(state().sortable);
g_signal_connect(G_OBJECT(gtkTreeView), "button-press-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this);
g_signal_connect(G_OBJECT(gtkTreeView), "button-release-event", G_CALLBACK(ListView_buttonEvent), (gpointer)this);
@@ -51,68 +50,25 @@ auto pListView::destruct() -> void {
gtk_widget_destroy(gtkWidget);
}
auto pListView::append(sListViewColumn column) -> void {
gtk_tree_view_append_column(gtkTreeView, column->self()->gtkColumn);
gtk_widget_show_all(column->self()->gtkHeader);
column->setBackgroundColor(column->backgroundColor());
column->setEditable(column->editable());
column->setFont(column->font());
column->setForegroundColor(column->foregroundColor());
column->setHorizontalAlignment(column->horizontalAlignment());
column->setResizable(column->resizable());
column->setVerticalAlignment(column->verticalAlignment());
setCheckable(state().checkable);
setSortable(state().sortable);
_createModel();
resizeColumns();
gtk_tree_view_set_rules_hint(gtkTreeView, self().columns() >= 2); //two or more columns + checkbutton column
auto pListView::append(sListViewHeader header) -> void {
}
auto pListView::append(sListViewItem item) -> void {
gtk_list_store_append(gtkListStore, &item->self()->gtkIter);
item->setChecked(item->checked());
item->setSelected(item->selected());
for(auto column : range(self().columns())) {
if(auto cell = item->cell(column)) {
if(auto self = cell->self()) {
self->setIcon(cell->state.icon);
self->setText(cell->state.text);
}
}
}
}
auto pListView::checkAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setChecked(true);
}
}
auto pListView::focused() -> bool {
auto pListView::focused() const -> bool {
return GTK_WIDGET_HAS_FOCUS(gtkTreeView);
}
auto pListView::remove(sListViewColumn column) -> void {
if(auto delegate = column->self()) {
gtk_tree_view_remove_column(gtkTreeView, delegate->gtkColumn);
delegate->gtkColumn = nullptr;
}
_createModel();
gtk_tree_view_set_rules_hint(gtkTreeView, self().columns() >= 2); //two or more columns + checkbutton column
auto pListView::remove(sListViewHeader header) -> void {
}
auto pListView::remove(sListViewItem item) -> void {
lock();
if(auto delegate = item->self()) {
gtk_list_store_remove(gtkListStore, &delegate->gtkIter);
_updateSelected();
}
unlock();
}
auto pListView::reset() -> void {
GList* list = gtk_tree_view_get_columns(gtkTreeView), *p = list;
GList* list = gtk_tree_view_get_columns(gtkTreeView);
GList* p = list;
while(p && p->data) {
gtk_tree_view_remove_column(gtkTreeView, (GtkTreeViewColumn*)p->data);
p = p->next;
@@ -125,41 +81,40 @@ auto pListView::reset() -> void {
auto pListView::resizeColumns() -> void {
lock();
vector<signed> widths;
signed minimumWidth = 0;
signed expandable = 0;
for(auto column : range(state().columns)) {
signed width = _width(column);
widths.append(width);
minimumWidth += width;
if(state().columns[column]->expandable()) expandable++;
}
if(auto& header = state().header) {
vector<signed> widths;
signed minimumWidth = 0;
signed expandable = 0;
for(auto column : range(header->columnCount())) {
signed width = _width(column);
widths.append(width);
minimumWidth += width;
if(header->column(column).expandable()) expandable++;
}
signed maximumWidth = self().geometry().width() - 6;
if(auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow)) {
if(gtk_widget_get_visible(scrollBar)) maximumWidth -= scrollBar->allocation.width;
}
signed maximumWidth = self().geometry().width() - 6;
if(auto scrollBar = gtk_scrolled_window_get_vscrollbar(gtkScrolledWindow)) {
if(gtk_widget_get_visible(scrollBar)) maximumWidth -= scrollBar->allocation.width;
}
signed expandWidth = 0;
if(expandable && maximumWidth > minimumWidth) {
expandWidth = (maximumWidth - minimumWidth) / expandable;
}
signed expandWidth = 0;
if(expandable && maximumWidth > minimumWidth) {
expandWidth = (maximumWidth - minimumWidth) / expandable;
}
for(auto column : range(state().columns)) {
if(auto self = state().columns[column]->self()) {
signed width = widths[column];
if(self->state().expandable) width += expandWidth;
gtk_tree_view_column_set_fixed_width(self->gtkColumn, width);
for(auto column : range(header->columnCount())) {
if(auto self = header->state.columns[column]->self()) {
signed width = widths[column];
if(self->state().expandable) width += expandWidth;
gtk_tree_view_column_set_fixed_width(self->gtkColumn, width);
}
}
}
unlock();
}
auto pListView::selectAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setSelected(true);
}
auto pListView::setAlignment(Alignment alignment) -> void {
}
auto pListView::setBackgroundColor(Color color) -> void {
@@ -171,10 +126,8 @@ auto pListView::setBatchable(bool batchable) -> void {
gtk_tree_selection_set_mode(gtkTreeSelection, batchable ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE);
}
auto pListView::setCheckable(bool checkable) -> void {
if(auto delegate = _column(0)) {
gtk_cell_renderer_set_visible(delegate->gtkCellToggle, checkable);
}
auto pListView::setBordered(bool bordered) -> void {
gtk_tree_view_set_grid_lines(gtkTreeView, bordered ? GTK_TREE_VIEW_GRID_LINES_BOTH : GTK_TREE_VIEW_GRID_LINES_NONE);
}
auto pListView::setFocused() -> void {
@@ -182,8 +135,8 @@ auto pListView::setFocused() -> void {
}
auto pListView::setFont(const string& font) -> void {
for(auto& column : state().columns) {
if(auto delegate = column->self()) delegate->setFont(column->font(true));
if(auto& header = state().header) {
if(auto self = header->self()) self->_setState();
}
}
@@ -192,39 +145,22 @@ auto pListView::setForegroundColor(Color color) -> void {
gtk_widget_modify_text(gtkWidgetChild, GTK_STATE_NORMAL, color ? &gdkColor : nullptr);
}
auto pListView::setGridVisible(bool visible) -> void {
gtk_tree_view_set_grid_lines(gtkTreeView, visible ? GTK_TREE_VIEW_GRID_LINES_BOTH : GTK_TREE_VIEW_GRID_LINES_NONE);
}
auto pListView::setHeaderVisible(bool visible) -> void {
gtk_tree_view_set_headers_visible(gtkTreeView, visible);
}
auto pListView::setSortable(bool sortable) -> void {
for(auto& column : state().columns) {
if(auto delegate = column->self()) {
gtk_tree_view_column_set_clickable(delegate->gtkColumn, sortable);
auto pListView::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry(geometry);
if(auto& header = state().header) {
for(auto& column : header->state.columns) {
if(column->state.expandable) return resizeColumns();
}
}
}
auto pListView::uncheckAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setChecked(false);
}
}
auto pListView::unselectAll() -> void {
for(auto& item : state().items) {
if(auto delegate = item->self()) delegate->setSelected(false);
}
}
auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned {
unsigned width = 8; //margin
if(state().checkable && _column == 0) width += 32; //checkbox
unsigned width = 8;
if(auto item = self().item(_row)) {
if(auto cell = item->cell(_column)) {
if(cell->state.checkable) {
width += 32;
}
if(auto& icon = cell->state.icon) {
width += icon.width() + 2;
}
@@ -236,19 +172,16 @@ auto pListView::_cellWidth(unsigned _row, unsigned _column) -> unsigned {
return width;
}
auto pListView::_column(unsigned column) -> pListViewColumn* {
if(auto delegate = self().column(column)) return delegate->self();
return nullptr;
}
auto pListView::_columnWidth(unsigned _column) -> unsigned {
unsigned width = 8; //margin
if(auto column = self().column(_column)) {
if(auto& icon = column->state.icon) {
width += icon.width() + 2;
}
if(auto& text = column->state.text) {
width += Font::size(column->font(true), text).width();
unsigned width = 8;
if(auto& header = state().header) {
if(auto column = header->column(_column)) {
if(auto& icon = column->state.icon) {
width += icon.width() + 2;
}
if(auto& text = column->state.text) {
width += Font::size(column->font(true), text).width();
}
}
}
return width;
@@ -260,12 +193,15 @@ auto pListView::_createModel() -> void {
gtkTreeModel = nullptr;
vector<GType> types;
unsigned position = 0;
for(auto column : state().columns) {
if(!column->self()->gtkColumn) continue; //column is being removed
if(position++ == 0) types.append(G_TYPE_BOOLEAN);
types.append(GDK_TYPE_PIXBUF);
types.append(G_TYPE_STRING);
if(auto& header = state().header) {
for(auto column : header->state.columns) {
if(auto self = column->self()) {
if(!self->gtkColumn) continue; //may not have been created yet; or recently destroyed
types.append(G_TYPE_BOOLEAN);
types.append(GDK_TYPE_PIXBUF);
types.append(G_TYPE_STRING);
}
}
}
if(!types) return; //no columns available
@@ -278,15 +214,6 @@ auto pListView::_doActivate() -> void {
if(!locked()) self().doActivate();
}
auto pListView::_doCellRendererToggleDataFunc(GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
auto row = decimal(path);
if(auto item = self().item(row)) {
gtk_cell_renderer_set_visible(renderer, state().checkable && item->state.checkable);
}
g_free(path);
}
auto pListView::_doChange() -> void {
if(!locked()) _updateSelected();
}
@@ -295,18 +222,70 @@ auto pListView::_doContext() -> void {
if(!locked()) self().doContext();
}
auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void {
for(auto& column : state().columns) {
if(auto delegate = column->self()) {
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
auto row = decimal(path);
auto pListView::_doDataFunc(GtkTreeViewColumn* gtkColumn, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void {
auto path = gtk_tree_model_get_string_from_iter(gtkTreeModel, iter);
auto row = decimal(path);
g_free(path);
if(auto& header = state().header) {
for(auto& column : header->state.columns) {
if(auto p = column->self()) {
if(renderer != GTK_CELL_RENDERER(p->gtkCellToggle)
&& renderer != GTK_CELL_RENDERER(p->gtkCellIcon)
&& renderer != GTK_CELL_RENDERER(p->gtkCellText)
) continue;
if(auto item = self().item(row)) {
if(auto cell = item->cell(column->offset())) {
if(string{text} != cell->state.text) {
cell->setText(text);
if(!locked()) self().doEdit(cell);
if(renderer == GTK_CELL_RENDERER(p->gtkCellToggle)) {
gtk_cell_renderer_set_visible(renderer, cell->state.checkable);
} else if(renderer == GTK_CELL_RENDERER(p->gtkCellText)) {
auto alignment = cell->alignment(true);
if(!alignment) alignment = {0.0, 0.5};
//note: below line will center column header text; but causes strange glitches
//(specifically, windows fail to respond to the close button ... some kind of heap corruption inside GTK+)
//gtk_tree_view_column_set_alignment(gtkColumn, alignment.horizontal());
gtk_cell_renderer_set_alignment(renderer, alignment.horizontal(), alignment.vertical());
auto pangoAlignment = PANGO_ALIGN_CENTER;
if(alignment.horizontal() < 0.333) pangoAlignment = PANGO_ALIGN_LEFT;
if(alignment.horizontal() > 0.666) pangoAlignment = PANGO_ALIGN_RIGHT;
g_object_set(G_OBJECT(renderer), "alignment", pangoAlignment, nullptr);
auto font = pFont::create(cell->font(true));
g_object_set(G_OBJECT(renderer), "font-desc", font, nullptr);
pango_font_description_free(font);
if(auto color = cell->foregroundColor(true)) {
auto gdkColor = CreateColor(color);
g_object_set(G_OBJECT(renderer), "foreground-gdk", &gdkColor, nullptr);
} else {
g_object_set(G_OBJECT(renderer), "foreground-set", false, nullptr);
}
}
if(auto color = cell->backgroundColor(true)) {
auto gdkColor = CreateColor(color);
g_object_set(G_OBJECT(renderer), "cell-background-gdk", &gdkColor, nullptr);
} else {
g_object_set(G_OBJECT(renderer), "cell-background-set", false, nullptr);
}
}
}
}
}
}
}
auto pListView::_doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void {
if(auto& header = state().header) {
for(auto& column : header->state.columns) {
if(auto delegate = column->self()) {
if(gtkCellRendererText == GTK_CELL_RENDERER_TEXT(delegate->gtkCellText)) {
auto row = decimal(path);
if(auto item = self().item(row)) {
if(auto cell = item->cell(column->offset())) {
if(string{text} != cell->state.text) {
cell->setText(text);
if(!locked()) self().doEdit(cell);
}
return;
}
return;
}
}
}
@@ -322,7 +301,7 @@ auto pListView::_doEvent(GdkEventButton* event) -> signed {
//when clicking in empty space below the last list view item; GTK+ does not deselect all items;
//below code enables this functionality, to match behavior with all other UI toolkits (and because it's very convenient to have)
if(path == nullptr && gtk_tree_selection_count_selected_rows(gtkTreeSelection) > 0) {
self().unselectAll();
for(auto& item : state().items) item->setSelected(false);
self().doChange();
return true;
}
@@ -344,11 +323,13 @@ auto pListView::_doEvent(GdkEventButton* event) -> signed {
}
auto pListView::_doHeaderActivate(GtkTreeViewColumn* gtkTreeViewColumn) -> void {
for(auto& column : state().columns) {
if(auto delegate = column->self()) {
if(gtkTreeViewColumn == delegate->gtkColumn) {
if(!locked()) self().doSort(column);
return;
if(auto& header = state().header) {
for(auto& column : header->state.columns) {
if(auto delegate = column->self()) {
if(gtkTreeViewColumn == delegate->gtkColumn) {
if(!locked()) self().doSort(column);
return;
}
}
}
}
@@ -363,12 +344,21 @@ auto pListView::_doMouseMove() -> signed {
return false;
}
auto pListView::_doToggle(const char* path) -> void {
if(auto item = self().item(decimal(path))) {
if(auto delegate = item->self()) {
item->state.checked = !item->state.checked;
delegate->setChecked(item->state.checked);
if(!locked()) self().doToggle(item);
auto pListView::_doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const char* path) -> void {
if(auto& header = state().header) {
for(auto& column : header->state.columns) {
if(auto delegate = column->self()) {
if(gtkCellRendererToggle == GTK_CELL_RENDERER_TOGGLE(delegate->gtkCellToggle)) {
auto row = decimal(path);
if(auto item = self().item(row)) {
if(auto cell = item->cell(column->offset())) {
cell->setChecked(!cell->checked());
if(!locked()) self().doToggle(cell);
return;
}
}
}
}
}
}
}
@@ -411,7 +401,7 @@ auto pListView::_updateSelected() -> void {
currentSelection = selected;
for(auto& item : state().items) item->state.selected = false;
for(auto& position : currentSelection) {
if(position >= self().items()) continue;
if(position >= self().itemCount()) continue;
self().item(position)->state.selected = true;
}
@@ -419,16 +409,17 @@ auto pListView::_updateSelected() -> void {
}
auto pListView::_width(unsigned column) -> unsigned {
if(auto width = state().columns[column]->width()) return width;
unsigned width = 1;
if(!state().columns[column]->visible()) return width;
if(state().headerVisible) {
width = max(width, _columnWidth(column));
if(auto& header = state().header) {
if(auto width = header->column(column).width()) return width;
unsigned width = 1;
if(!header->column(column).visible()) return width;
if(header->visible()) width = max(width, _columnWidth(column));
for(auto row : range(state().items)) {
width = max(width, _cellWidth(row, column));
}
return width;
}
for(auto row : range(state().items)) {
width = max(width, _cellWidth(row, column));
}
return width;
return 1;
}
}

View File

@@ -5,40 +5,34 @@ namespace hiro {
struct pListView : pWidget {
Declare(ListView, Widget)
auto append(sListViewColumn column) -> void;
auto append(sListViewHeader column) -> void;
auto append(sListViewItem item) -> void;
auto checkAll() -> void;
auto focused() -> bool;
auto remove(sListViewColumn column) -> void;
auto focused() const -> bool override;
auto remove(sListViewHeader column) -> void;
auto remove(sListViewItem item) -> void;
auto reset() -> void;
auto resizeColumns() -> void;
auto selectAll() -> void;
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setBatchable(bool batchable) -> void;
auto setCheckable(bool checkable) -> void;
auto setBordered(bool bordered) -> void;
auto setFocused() -> void override;
auto setFont(const string& font) -> void override;
auto setForegroundColor(Color color) -> void;
auto setGridVisible(bool visible) -> void;
auto setHeaderVisible(bool visible) -> void;
auto setSortable(bool sortable) -> void;
auto uncheckAll() -> void;
auto unselectAll() -> void;
auto setGeometry(Geometry geometry) -> void override;
auto _cellWidth(unsigned row, unsigned column) -> unsigned;
auto _column(unsigned column) -> pListViewColumn*;
auto _columnWidth(unsigned column) -> unsigned;
auto _createModel() -> void;
auto _doActivate() -> void;
auto _doCellRendererToggleDataFunc(GtkCellRenderer* renderer, GtkTreeIter* iter) -> void;
auto _doChange() -> void;
auto _doContext() -> void;
auto _doEdit(GtkCellRendererText* renderer, const char* path, const char* text) -> void;
auto _doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeIter* iter) -> void;
auto _doEdit(GtkCellRendererText* gtkCellRendererText, const char* path, const char* text) -> void;
auto _doEvent(GdkEventButton* event) -> signed;
auto _doHeaderActivate(GtkTreeViewColumn* column) -> void;
auto _doMouseMove() -> signed;
auto _doToggle(const char* path) -> void;
auto _doToggle(GtkCellRendererToggle* gtkCellRendererToggle, const char* path) -> void;
auto _updateSelected() -> void;
auto _width(unsigned column) -> unsigned;

View File

@@ -125,9 +125,9 @@ auto pTabFrame::remove(sTabFrameItem item) -> void {
//the new tab will be the one after this one
unsigned displacement = 1;
//... unless it's the last tab, in which case it's the one before it
if(item->offset() == self().items() - 1) displacement = -1;
if(item->offset() == self().itemCount() - 1) displacement = -1;
//... unless there are no tabs left, in which case nothing is selected
if(self().items() > 1) {
if(self().itemCount() > 1) {
setItemSelected(item->offset() + displacement);
}
}