diff --git a/bsnes/phoenix/gtk/gtk.hpp b/bsnes/phoenix/gtk/gtk.hpp index 69d3e485..389708bc 100755 --- a/bsnes/phoenix/gtk/gtk.hpp +++ b/bsnes/phoenix/gtk/gtk.hpp @@ -166,14 +166,18 @@ struct Label : Widget { struct ListBox : Widget { nall::function onActivate; nall::function onChange; + nall::function onTick; void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = ""); void setFocused(); void setHeaderVisible(bool headerVisible = true); + void setCheckable(bool checkable = true); void setFont(Font &font); void reset(); void resizeColumnsToContent(); void addItem(const char *text); void setItem(unsigned row, const char *text); + bool checked(unsigned row); + void setChecked(unsigned row, bool checked = true); nall::optional selection(); void setSelection(unsigned row); ListBox(); diff --git a/bsnes/phoenix/gtk/listbox.cpp b/bsnes/phoenix/gtk/listbox.cpp index ab04fc7a..dbeab5c3 100755 --- a/bsnes/phoenix/gtk/listbox.cpp +++ b/bsnes/phoenix/gtk/listbox.cpp @@ -1,3 +1,10 @@ +static void ListBox_activate(ListBox *self) { + signed selection = -1; + if(auto position = self->selection()) selection = position(); + self->listBox->selection = selection; + if(self->onActivate) self->onActivate(); +} + static void ListBox_change(ListBox *self) { signed selection = -1; if(auto position = self->selection()) selection = position(); @@ -6,11 +13,10 @@ static void ListBox_change(ListBox *self) { if(self->onChange) self->onChange(); } -static void ListBox_activate(ListBox *self) { - signed selection = -1; - if(auto position = self->selection()) selection = position(); - self->listBox->selection = selection; - if(self->onActivate) self->onActivate(); +static void ListBox_tick(GtkCellRendererToggle *cell, gchar *path_string, ListBox *self) { + unsigned index = strunsigned(path_string); + self->setChecked(index, !self->checked(index)); + if(self->onTick) self->onTick(index); } void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) { @@ -22,10 +28,10 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns gtk_widget_set_size_request(object->widget, width, height); lstring list; - list.split("\t", text); + list.split("\t", string("\t", text)); GType *v = (GType*)malloc(list.size() * sizeof(GType)); - for(unsigned i = 0; i < list.size(); i++) v[i] = G_TYPE_STRING; + for(unsigned i = 0; i < list.size(); i++) v[i] = (i == 0 ? G_TYPE_BOOLEAN : G_TYPE_STRING); listBox->store = gtk_list_store_newv(list.size(), v); free(v); @@ -33,20 +39,30 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget); g_object_unref(G_OBJECT(listBox->store)); - //alternate color of each row if there is more than one column - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(object->subWidget), list.size() >= 2); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), false); - for(unsigned i = 0; i < list.size(); i++) { - listBox->column[i].renderer = gtk_cell_renderer_text_new(); - listBox->column[i].column = gtk_tree_view_column_new_with_attributes( - list[i], listBox->column[i].renderer, "text", i, (void*)0 - ); + if(i == 0) { + listBox->column[i].renderer = gtk_cell_renderer_toggle_new(); + listBox->column[i].column = gtk_tree_view_column_new_with_attributes( + "", listBox->column[i].renderer, "active", i, (void*)0 + ); + gtk_tree_view_column_set_resizable(listBox->column[i].column, false); + gtk_tree_view_column_set_visible(listBox->column[i].column, listBox->checkable); + g_signal_connect(listBox->column[i].renderer, "toggled", G_CALLBACK(ListBox_tick), (gpointer)this); + } else { + listBox->column[i].renderer = gtk_cell_renderer_text_new(); + listBox->column[i].column = gtk_tree_view_column_new_with_attributes( + "", listBox->column[i].renderer, "text", i, (void*)0 + ); + gtk_tree_view_column_set_resizable(listBox->column[i].column, true); + } listBox->column[i].label = gtk_label_new(list[i]); gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(listBox->column[i].column), listBox->column[i].label); gtk_tree_view_append_column(GTK_TREE_VIEW(object->subWidget), listBox->column[i].column); gtk_widget_show(listBox->column[i].label); } + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), false); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(object->subWidget), list.size() >= 3); //>= 2 + one for the checkbox column + gtk_tree_view_set_search_column(GTK_TREE_VIEW(object->subWidget), 1); g_signal_connect_swapped(G_OBJECT(object->subWidget), "cursor-changed", G_CALLBACK(ListBox_change), (gpointer)this); g_signal_connect_swapped(G_OBJECT(object->subWidget), "row-activated", G_CALLBACK(ListBox_activate), (gpointer)this); @@ -65,6 +81,11 @@ void ListBox::setHeaderVisible(bool visible) { gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), visible); } +void ListBox::setCheckable(bool checkable) { + listBox->checkable = checkable; + if(object->subWidget) gtk_tree_view_column_set_visible(listBox->column[0].column, checkable); +} + void ListBox::setFont(Font &font) { Widget::setFont(font); unsigned columns = 1; @@ -95,9 +116,8 @@ void ListBox::addItem(const char *text) { list.split("\t", text); GtkTreeIter iter; gtk_list_store_append(listBox->store, &iter); - for(unsigned i = 0; i < list.size(); i++) { - gtk_list_store_set(listBox->store, &iter, i, (const char*)list[i], -1); - } + unsigned index = 1; + foreach(item, list) gtk_list_store_set(listBox->store, &iter, index++, (const char*)item, -1); } void ListBox::setItem(unsigned row, const char *text) { @@ -110,9 +130,28 @@ void ListBox::setItem(unsigned row, const char *text) { lstring list; list.split("\t", text); - for(unsigned i = 0; i < list.size(); i++) { - gtk_list_store_set(listBox->store, &iter, i, (const char*)list[i], -1); - } + unsigned index = 1; + foreach(item, list) gtk_list_store_set(listBox->store, &iter, index++, (const char*)item, -1); +} + +bool ListBox::checked(unsigned row) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget)); + GtkTreePath *path = gtk_tree_path_new_from_string(string(row)); + GtkTreeIter iter; + bool state; + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, 0, &state, -1); + gtk_tree_path_free(path); + return state; +} + +void ListBox::setChecked(unsigned row, bool checked) { + GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget)); + GtkTreePath *path = gtk_tree_path_new_from_string(string(row)); + GtkTreeIter iter; + gtk_tree_model_get_iter(model, &iter, path); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1); + gtk_tree_path_free(path); } optional ListBox::selection() { @@ -152,4 +191,5 @@ void ListBox::setSelection(unsigned row) { ListBox::ListBox() { listBox = new ListBox::Data; + listBox->checkable = false; } diff --git a/bsnes/phoenix/gtk/object.cpp b/bsnes/phoenix/gtk/object.cpp index c17e8f09..f09960ac 100755 --- a/bsnes/phoenix/gtk/object.cpp +++ b/bsnes/phoenix/gtk/object.cpp @@ -43,6 +43,7 @@ struct ListBox::Data { GtkWidget *label; }; linear_vector column; + bool checkable; signed selection; }; diff --git a/bsnes/phoenix/qt/listbox.cpp b/bsnes/phoenix/qt/listbox.cpp index 1cde6ecb..42eb56d6 100755 --- a/bsnes/phoenix/qt/listbox.cpp +++ b/bsnes/phoenix/qt/listbox.cpp @@ -16,6 +16,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns listBox->setAlternatingRowColors(list.size() >= 2); listBox->connect(listBox, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); listBox->connect(listBox, SIGNAL(itemSelectionChanged()), SLOT(onChange())); + listBox->connect(listBox, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*))); if(parent.window->defaultFont) listBox->setFont(*parent.window->defaultFont); listBox->show(); } @@ -24,6 +25,14 @@ void ListBox::setHeaderVisible(bool headerVisible) { listBox->setHeaderHidden(headerVisible == false); } +void ListBox::setCheckable(bool checkable) { + listBox->checkable = checkable; + if(listBox->checkable) { + auto items = listBox->findItems("", Qt::MatchContains); + for(unsigned i = 0; i < items.size(); i++) items[i]->setCheckState(0, Qt::Unchecked); + } +} + void ListBox::reset() { listBox->clear(); } @@ -33,19 +42,36 @@ void ListBox::resizeColumnsToContent() { } void ListBox::addItem(const char *text) { + object->locked = true; auto items = listBox->findItems("", Qt::MatchContains); QTreeWidgetItem *item = new QTreeWidgetItem(listBox); + if(listBox->checkable) item->setCheckState(0, Qt::Unchecked); item->setData(0, Qt::UserRole, (unsigned)items.size()); lstring list; list.split("\t", text); for(unsigned i = 0; i < list.size(); i++) item->setText(i, (const char*)list[i]); + object->locked = false; } void ListBox::setItem(unsigned row, const char *text) { + object->locked = true; QTreeWidgetItem *item = listBox->topLevelItem(row); lstring list; list.split("\t", text); for(unsigned i = 0; i < list.size(); i++) item->setText(i, (const char*)list[i]); + object->locked = false; +} + +bool ListBox::checked(unsigned row) { + QTreeWidgetItem *item = listBox->topLevelItem(row); + return (item ? item->checkState(0) == Qt::Checked : false); +} + +void ListBox::setChecked(unsigned row, bool checked) { + object->locked = true; + QTreeWidgetItem *item = listBox->topLevelItem(row); + if(item) item->setCheckState(0, checked ? Qt::Checked : Qt::Unchecked); + object->locked = false; } optional ListBox::selection() { diff --git a/bsnes/phoenix/qt/qt.hpp b/bsnes/phoenix/qt/qt.hpp index d24c81d0..2a571585 100755 --- a/bsnes/phoenix/qt/qt.hpp +++ b/bsnes/phoenix/qt/qt.hpp @@ -220,12 +220,16 @@ struct Label : Widget { struct ListBox : Widget { nall::function onActivate; nall::function onChange; + nall::function onTick; void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = ""); void setHeaderVisible(bool headerVisible = true); + void setCheckable(bool checkable = true); void reset(); void resizeColumnsToContent(); void addItem(const char *text); void setItem(unsigned row, const char *text); + bool checked(unsigned row); + void setChecked(unsigned row, bool checked = true); nall::optional selection(); void setSelection(unsigned row); ListBox(); diff --git a/bsnes/phoenix/qt/qt.moc b/bsnes/phoenix/qt/qt.moc index cd12750f..744c9485 100755 --- a/bsnes/phoenix/qt/qt.moc +++ b/bsnes/phoenix/qt/qt.moc @@ -1,7 +1,7 @@ /**************************************************************************** ** Meta object code from reading C++ file 'qt.moc.hpp' ** -** Created: Sat Oct 2 21:32:41 2010 +** Created: Mon Oct 4 00:53:54 2010 ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.2) ** ** WARNING! All changes made in this file will be lost! @@ -641,7 +641,7 @@ static const uint qt_meta_data_ListBox__Data[] = { 4, // revision 0, // classname 0, 0, // classinfo - 2, 14, // methods + 3, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -651,12 +651,14 @@ static const uint qt_meta_data_ListBox__Data[] = { // slots: signature, parameters, type, tag, flags 15, 14, 14, 14, 0x0a, 28, 14, 14, 14, 0x0a, + 44, 39, 14, 14, 0x0a, 0 // eod }; static const char qt_meta_stringdata_ListBox__Data[] = { "ListBox::Data\0\0onActivate()\0onChange()\0" + "item\0onTick(QTreeWidgetItem*)\0" }; const QMetaObject ListBox::Data::staticMetaObject = { @@ -690,9 +692,10 @@ int ListBox::Data::qt_metacall(QMetaObject::Call _c, int _id, void **_a) switch (_id) { case 0: onActivate(); break; case 1: onChange(); break; + case 2: onTick((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break; default: ; } - _id -= 2; + _id -= 3; } return _id; } diff --git a/bsnes/phoenix/qt/qt.moc.hpp b/bsnes/phoenix/qt/qt.moc.hpp index 4fd5ac81..e57f9baa 100755 --- a/bsnes/phoenix/qt/qt.moc.hpp +++ b/bsnes/phoenix/qt/qt.moc.hpp @@ -213,8 +213,10 @@ struct ListBox::Data : public QTreeWidget { public: ListBox &self; + bool checkable; Data(ListBox &self) : self(self) { + checkable = false; } public slots: @@ -225,6 +227,10 @@ public slots: void onChange() { if(self.object->locked == false && self.onChange) self.onChange(); } + + void onTick(QTreeWidgetItem *item) { + if(self.object->locked == false && self.onTick) self.onTick(item->data(0, Qt::UserRole).toUInt()); + } }; struct ProgressBar::Data : public QProgressBar { diff --git a/bsnes/phoenix/windows/button.cpp b/bsnes/phoenix/windows/button.cpp index edd88705..06b04efd 100755 --- a/bsnes/phoenix/windows/button.cpp +++ b/bsnes/phoenix/windows/button.cpp @@ -6,5 +6,5 @@ void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsi parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); } diff --git a/bsnes/phoenix/windows/checkbox.cpp b/bsnes/phoenix/windows/checkbox.cpp index e1ca0e5c..39164391 100755 --- a/bsnes/phoenix/windows/checkbox.cpp +++ b/bsnes/phoenix/windows/checkbox.cpp @@ -6,7 +6,7 @@ void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); } bool CheckBox::checked() { diff --git a/bsnes/phoenix/windows/combobox.cpp b/bsnes/phoenix/windows/combobox.cpp index 99e8cccf..6cba64ac 100755 --- a/bsnes/phoenix/windows/combobox.cpp +++ b/bsnes/phoenix/windows/combobox.cpp @@ -7,7 +7,7 @@ void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); //CreateWindow height parameter is the height of the expanded list box; //need additional code to override default ComboBox control height diff --git a/bsnes/phoenix/windows/editbox.cpp b/bsnes/phoenix/windows/editbox.cpp index 21a2e01d..f9091f1e 100755 --- a/bsnes/phoenix/windows/editbox.cpp +++ b/bsnes/phoenix/windows/editbox.cpp @@ -8,7 +8,7 @@ void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns ); setText(text); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); } string EditBox::getText() { diff --git a/bsnes/phoenix/windows/label.cpp b/bsnes/phoenix/windows/label.cpp index eb047d80..12c54183 100755 --- a/bsnes/phoenix/windows/label.cpp +++ b/bsnes/phoenix/windows/label.cpp @@ -6,7 +6,7 @@ void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsig parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); setText(text); } diff --git a/bsnes/phoenix/windows/listbox.cpp b/bsnes/phoenix/windows/listbox.cpp index 51b9d1bf..f2bf4ba1 100755 --- a/bsnes/phoenix/windows/listbox.cpp +++ b/bsnes/phoenix/windows/listbox.cpp @@ -7,7 +7,7 @@ void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT); lstring list; @@ -34,6 +34,10 @@ void ListBox::setHeaderVisible(bool headerVisible) { ); } +void ListBox::setCheckable(bool checkable) { + ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT | (checkable ? LVS_EX_CHECKBOXES : 0)); +} + void ListBox::reset() { ListView_DeleteAllItems(widget->window); } @@ -54,7 +58,9 @@ void ListBox::addItem(const char *text) { item.iSubItem = 0; utf16_t wtext(list[0]); item.pszText = wtext; + object->locked = true; ListView_InsertItem(widget->window, &item); + object->locked = false; for(unsigned i = 1; i < list.size(); i++) { utf16_t wtext(list[i]); ListView_SetItemText(widget->window, row, i, wtext); @@ -86,6 +92,16 @@ void ListBox::setSelection(unsigned row) { } } +bool ListBox::checked(unsigned row) { + return ListView_GetCheckState(widget->window, row); +} + +void ListBox::setChecked(unsigned row, bool checked) { + object->locked = true; + ListView_SetCheckState(widget->window, row, checked); + object->locked = false; +} + ListBox::ListBox() { listBox = new ListBox::Data; listBox->lostFocus = false; diff --git a/bsnes/phoenix/windows/menu.cpp b/bsnes/phoenix/windows/menu.cpp index ed24a15a..a7a36b03 100755 --- a/bsnes/phoenix/windows/menu.cpp +++ b/bsnes/phoenix/windows/menu.cpp @@ -1,5 +1,5 @@ Action::Action() { - os.objects.append(this); + OS::os->objects.append(this); action = new Action::Data; } diff --git a/bsnes/phoenix/windows/object.cpp b/bsnes/phoenix/windows/object.cpp index d9e7002d..2a5b8785 100755 --- a/bsnes/phoenix/windows/object.cpp +++ b/bsnes/phoenix/windows/object.cpp @@ -70,6 +70,7 @@ struct VerticalSlider::Data { }; struct OS::Data { + nall::array objects; HFONT proportionalFont; HFONT monospaceFont; }; @@ -78,6 +79,7 @@ void Object::unused() { } Object::Object() { + OS::initialize(); static unsigned guid = 100; object = new Object::Data; object->id = guid++; diff --git a/bsnes/phoenix/windows/radiobox.cpp b/bsnes/phoenix/windows/radiobox.cpp index f86e943d..27bb692b 100755 --- a/bsnes/phoenix/windows/radiobox.cpp +++ b/bsnes/phoenix/windows/radiobox.cpp @@ -9,7 +9,7 @@ void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, un parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); setChecked(); } @@ -24,7 +24,7 @@ void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, GetParent(radioBox->parent->widget->window), (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(radioBox->parentWindow->window->defaultFont ? radioBox->parentWindow->window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(radioBox->parentWindow->window->defaultFont ? radioBox->parentWindow->window->defaultFont : OS::os->proportionalFont), 0); } bool RadioBox::checked() { diff --git a/bsnes/phoenix/windows/textbox.cpp b/bsnes/phoenix/windows/textbox.cpp index d815dab9..ea3b2670 100755 --- a/bsnes/phoenix/windows/textbox.cpp +++ b/bsnes/phoenix/windows/textbox.cpp @@ -6,7 +6,7 @@ void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, uns parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0 ); SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this); - SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : os.os->proportionalFont), 0); + SendMessage(widget->window, WM_SETFONT, (WPARAM)(parent.window->defaultFont ? parent.window->defaultFont : OS::os->proportionalFont), 0); } string TextBox::text() { diff --git a/bsnes/phoenix/windows/widget.cpp b/bsnes/phoenix/windows/widget.cpp index 1741a9b5..70ac5301 100755 --- a/bsnes/phoenix/windows/widget.cpp +++ b/bsnes/phoenix/windows/widget.cpp @@ -33,8 +33,8 @@ void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height } Widget::Widget() { - os.objects.append(this); + OS::os->objects.append(this); widget = new Widget::Data; widget->window = 0; - widget->font = os.os->proportionalFont; + widget->font = OS::os->proportionalFont; } diff --git a/bsnes/phoenix/windows/windows.cpp b/bsnes/phoenix/windows/windows.cpp index 8a1ce782..14bd25c5 100755 --- a/bsnes/phoenix/windows/windows.cpp +++ b/bsnes/phoenix/windows/windows.cpp @@ -29,14 +29,72 @@ namespace phoenix { #include "viewport.cpp" #include "messagewindow.cpp" -OS &os = OS::handle(); +OS::Data *OS::os = 0; Window Window::None; static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); +static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); -OS& OS::handle() { - static OS os; - return os; +void OS::initialize() { + static bool initialized = false; + if(initialized == true) return; + initialized = true; + + InitCommonControls(); + CoInitialize(0); + + os = new OS::Data; + os->proportionalFont = Font_createFont("Tahoma", 8, false, false); + os->monospaceFont = Font_createFont("Courier New", 8, false, false); + + WNDCLASS wc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = OS_windowProc; + wc.lpszClassName = L"phoenix_window"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Canvas_windowProc; + wc.lpszClassName = L"phoenix_canvas"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Label_windowProc; + wc.lpszClassName = L"phoenix_label"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); + + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = Viewport_windowProc; + wc.lpszClassName = L"phoenix_viewport"; + wc.lpszMenuName = 0; + wc.style = CS_HREDRAW | CS_VREDRAW; + RegisterClass(&wc); } bool OS::pending() { @@ -268,7 +326,7 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM unsigned id = LOWORD(wparam); HWND control = GetDlgItem(window.widget->window, id); if(control == 0) { - Object *object_ptr = (Object*)os.findObject(id); + Object *object_ptr = (Object*)OS::findObject(id); if(object_ptr) { if(dynamic_cast(object_ptr)) { MenuItem &menuItem = (MenuItem&)*object_ptr; @@ -334,8 +392,12 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM ListBox &listBox = (ListBox&)*object_ptr; LPNMHDR nmhdr = (LPNMHDR)lparam; LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam; + if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) { - if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) { + unsigned imagemask = ((nmlistview->uNewState & LVIS_STATEIMAGEMASK) >> 12) - 1; + if(imagemask == 0 || imagemask == 1) { + if(listBox.object->locked == false && listBox.onTick) listBox.onTick(nmlistview->iItem); + } else if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) { listBox.listBox->lostFocus = true; } else { if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) { @@ -392,66 +454,8 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM } Object* OS::findObject(unsigned id) { - foreach(object, objects) { if(object->object->id == id) return object; } + foreach(object, os->objects) { if(object->object->id == id) return object; } return 0; } -OS::OS() { - InitCommonControls(); - CoInitialize(0); - - os = new OS::Data; - os->proportionalFont = Font_createFont("Tahoma", 8, false, false); - os->monospaceFont = Font_createFont("Courier New", 8, false, false); - - WNDCLASS wc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(2)); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = OS_windowProc; - wc.lpszClassName = L"phoenix_window"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); - - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = Canvas_windowProc; - wc.lpszClassName = L"phoenix_canvas"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); - - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = Label_windowProc; - wc.lpszClassName = L"phoenix_label"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); - - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.hIcon = LoadIcon(0, IDI_APPLICATION); - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = Viewport_windowProc; - wc.lpszClassName = L"phoenix_viewport"; - wc.lpszMenuName = 0; - wc.style = CS_HREDRAW | CS_VREDRAW; - RegisterClass(&wc); -} - } diff --git a/bsnes/phoenix/windows/windows.hpp b/bsnes/phoenix/windows/windows.hpp index 5e0044e3..763e9750 100755 --- a/bsnes/phoenix/windows/windows.hpp +++ b/bsnes/phoenix/windows/windows.hpp @@ -178,12 +178,16 @@ struct Label : Widget { struct ListBox : Widget { nall::function onActivate; nall::function onChange; + nall::function onTick; void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = ""); void setHeaderVisible(bool headerVisible = true); + void setCheckable(bool checkable = true); void reset(); void resizeColumnsToContent(); void addItem(const char *text); void setItem(unsigned row, const char *text); + bool checked(unsigned row); + void setChecked(unsigned row, bool checked = true); nall::optional selection(); void setSelection(unsigned row); ListBox(); @@ -254,26 +258,21 @@ struct MessageWindow : Object { }; struct OS : Object { - bool pending(); - void run(); - void main(); - void quit(); - unsigned desktopWidth(); - unsigned desktopHeight(); - nall::string folderSelect(Window &parent, const char *path = ""); - nall::string fileOpen(Window &parent, const char *filter, const char *path = ""); - nall::string fileSave(Window &parent, const char *filter, const char *path = ""); + static bool pending(); + static void run(); + static void main(); + static void quit(); + static unsigned desktopWidth(); + static unsigned desktopHeight(); + static nall::string folderSelect(Window &parent, const char *path = ""); + static nall::string fileOpen(Window &parent, const char *filter, const char *path = ""); + static nall::string fileSave(Window &parent, const char *filter, const char *path = ""); //private: - static OS& handle(); + static void initialize(); struct Data; - Data *os; - Object* findObject(unsigned id); - nall::array objects; -private: - OS(); + static Data *os; + static Object* findObject(unsigned id); friend class Object; }; -extern OS &os; - }; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 10b6122e..844c2b49 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "070.07"; + static const char Version[] = "070.08"; static const unsigned SerializerVersion = 13; } } diff --git a/bsnes/ui-phoenix/tools/cheat-editor.cpp b/bsnes/ui-phoenix/tools/cheat-editor.cpp index 065cc08d..d358b0a9 100755 --- a/bsnes/ui-phoenix/tools/cheat-editor.cpp +++ b/bsnes/ui-phoenix/tools/cheat-editor.cpp @@ -5,10 +5,9 @@ void CheatEditor::load(string filename) { cheatList.reset(); for(unsigned i = 0; i < 128; i++) { cheatList.addItem(""); - cheatText[i][0] = strunsigned<3, ' '>(i + 1); - cheatText[i][1] = " "; - cheatText[i][2] = ""; - cheatText[i][3] = ""; + cheatText[i][CheatSlot] = strunsigned<3, ' '>(i + 1); + cheatText[i][CheatCode] = ""; + cheatText[i][CheatDesc] = ""; } unsigned n = 0; @@ -32,9 +31,8 @@ void CheatEditor::load(string filename) { code.rtrim("+"); SNES::cheat[n].enabled = enabled; SNES::cheat[n] = code; - cheatText[n][1] = (enabled == false ? " " : "*"); - cheatText[n][2] = code; - cheatText[n][3] = description; + cheatText[n][CheatCode] = code; + cheatText[n][CheatDesc] = description; if(++n >= 128) break; } } @@ -48,7 +46,7 @@ void CheatEditor::load(string filename) { void CheatEditor::save(string filename) { signed lastSave = -1; for(signed i = 127; i >= 0; i--) { - if(cheatText[i][2] != "" || cheatText[i][3] != "") { + if(cheatText[i][CheatCode] != "" || cheatText[i][CheatDesc] != "") { lastSave = i; break; } @@ -63,10 +61,10 @@ void CheatEditor::save(string filename) { fp.print("\n"); fp.print(string("\n")); for(unsigned i = 0; i <= lastSave; i++) { - fp.print(string(" \n")); - fp.print(string(" \n")); + fp.print(string(" \n")); + fp.print(string(" \n")); lstring list; - list.split("+", cheatText[i][2]); + list.split("+", cheatText[i][CheatCode]); foreach(code, list) { fp.print(string(" ", code, "\n")); } @@ -89,6 +87,7 @@ void CheatEditor::create() { cheatList.create(*this, x, y, 500, 250, "Slot\tCode\tDescription"); y += 255; cheatList.setHeaderVisible(); + cheatList.setCheckable(); codeLabel.create(*this, x, y, 80, Style::TextBoxHeight, "Code(s):"); codeEdit.create (*this, x + 80, y, 420, Style::TextBoxHeight); y += Style::TextBoxHeight + 5; @@ -102,8 +101,8 @@ void CheatEditor::create() { setGeometry(160, 160, 510, y); synchronize(); - cheatList.onActivate = { &CheatEditor::toggle, this }; cheatList.onChange = { &CheatEditor::synchronize, this }; + cheatList.onTick = { &CheatEditor::toggle, this }; codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this }; clearAllButton.onTick = { &CheatEditor::clearAll, this }; clearButton.onTick = { &CheatEditor::clear, this }; @@ -112,8 +111,8 @@ void CheatEditor::create() { void CheatEditor::synchronize() { clearAllButton.setEnabled(SNES::cartridge.loaded()); if(auto position = cheatList.selection()) { - codeEdit.setText(cheatText[position()][2]); - descEdit.setText(cheatText[position()][3]); + codeEdit.setText(cheatText[position()][1]); + descEdit.setText(cheatText[position()][2]); codeEdit.setEnabled(true); descEdit.setEnabled(true); clearButton.setEnabled(true); @@ -130,35 +129,28 @@ void CheatEditor::refresh() { SNES::cheat.synchronize(); for(unsigned i = 0; i < 128; i++) { lstring list; - list.split("+", cheatText[i][2]); + list.split("+", cheatText[i][CheatCode]); string cheatCode = list[0]; if(list.size() > 1) cheatCode.append("..."); + cheatList.setChecked(i, SNES::cheat[i].enabled); cheatList.setItem(i, string( - cheatText[i][0], cheatText[i][1], "\t", cheatCode, "\t", cheatText[i][3] + cheatText[i][CheatSlot], "\t", cheatCode, "\t", cheatText[i][CheatDesc] )); } cheatList.resizeColumnsToContent(); } -void CheatEditor::toggle() { - if(auto position = cheatList.selection()) { - if(cheatText[position()][1] == " ") { - cheatText[position()][1] = "*"; - SNES::cheat[position()].enabled = true; - } else { - cheatText[position()][1] = " "; - SNES::cheat[position()].enabled = false; - } - } +void CheatEditor::toggle(unsigned row) { + SNES::cheat[row].enabled = cheatList.checked(row); refresh(); } void CheatEditor::bind() { if(auto position = cheatList.selection()) { - cheatText[position()][2] = codeEdit.text(); - cheatText[position()][3] = descEdit.text(); - SNES::cheat[position()] = cheatText[position()][2]; + cheatText[position()][CheatCode] = codeEdit.text(); + cheatText[position()][CheatDesc] = descEdit.text(); + SNES::cheat[position()] = cheatText[position()][CheatCode]; refresh(); } } @@ -168,9 +160,9 @@ void CheatEditor::clearAll() { for(unsigned i = 0; i < 128; i++) { SNES::cheat[i].enabled = false; SNES::cheat[i] = ""; - cheatText[i][1] = " "; - cheatText[i][2] = ""; - cheatText[i][3] = ""; + cheatList.setChecked(i, false); + cheatText[i][CheatCode] = ""; + cheatText[i][CheatDesc] = ""; } SNES::cheat.synchronize(); refresh(); @@ -183,9 +175,9 @@ void CheatEditor::clear() { if(auto position = cheatList.selection()) { SNES::cheat[position()].enabled = false; SNES::cheat[position()] = ""; - cheatText[position()][1] = " "; - cheatText[position()][2] = ""; - cheatText[position()][3] = ""; + cheatList.setChecked(position(), false); + cheatText[position()][CheatCode] = ""; + cheatText[position()][CheatDesc] = ""; SNES::cheat.synchronize(); refresh(); codeEdit.setText(""); diff --git a/bsnes/ui-phoenix/tools/cheat-editor.hpp b/bsnes/ui-phoenix/tools/cheat-editor.hpp index e588b8fe..5ecbea2d 100755 --- a/bsnes/ui-phoenix/tools/cheat-editor.hpp +++ b/bsnes/ui-phoenix/tools/cheat-editor.hpp @@ -12,10 +12,11 @@ struct CheatEditor : Window { void create(); private: - string cheatText[128][4]; + enum : unsigned { CheatSlot, CheatCode, CheatDesc }; + string cheatText[128][3]; void synchronize(); void refresh(); - void toggle(); + void toggle(unsigned row); void bind(); void clearAll(); void clear();