mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-04-21 11:12:06 +02:00
Update to v070r08 release.
byuu says: - all three ports of phoenix gain the ability to use ListBox::setCheckable(), checked(row), setChecked(row, checked = true); - cheat editor updated to take advantage of this Some fun differences between the implementations. Windows was the least flexible, it only lets you have a check at the start of each item. Luckily that's all I need for my purposes so it'll work. It's also a lot easier, as now I don't need a ton of extra code to try and set per-column checkboxes. Now both Windows and Qt can put text into the first item with the checkbox, but GTK+ cannot. Further, Qt needs this because even if you hide the checkbox column, it still tries to search for typed text from the checkbox column. GTK+ does this too, but unlike GTK+, Qt lacks an API call to set the search column. Since my code basically has to change this in real-time since you have to call the setProperty functions after create(), this means I always set up the checkbox columns regardless of whether or not they are used. For Qt, I had to work around this and it'll be an annoying edge case if you try and use setCheckable(true) and then setCheckable(false), because Qt has no way to clear the checkboxes from an item once you've enabled them for the first time. But without doing it this way, there's no way for eg the ROM file loader to allow type-searching, so that's the way I do it. Windows works the same, and GTK+ has a separate column (hidden from the phoenix API standpoint) for the checkboxes, with no column header label text. All in all, a major hassle, but it was the only really major GUI hit from leaving Qt, aside from the horror that's going to be the debugger, which needs all kinds of highly specialized controls.
This commit is contained in:
parent
440a59c879
commit
5286481d8d
@ -166,14 +166,18 @@ struct Label : Widget {
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
nall::function<void (unsigned)> 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<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
|
@ -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<unsigned> ListBox::selection() {
|
||||
@ -152,4 +191,5 @@ void ListBox::setSelection(unsigned row) {
|
||||
|
||||
ListBox::ListBox() {
|
||||
listBox = new ListBox::Data;
|
||||
listBox->checkable = false;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ struct ListBox::Data {
|
||||
GtkWidget *label;
|
||||
};
|
||||
linear_vector<GtkColumn> column;
|
||||
bool checkable;
|
||||
signed selection;
|
||||
};
|
||||
|
||||
|
@ -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<unsigned> ListBox::selection() {
|
||||
|
@ -220,12 +220,16 @@ struct Label : Widget {
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
nall::function<void (unsigned)> 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<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1,5 +1,5 @@
|
||||
Action::Action() {
|
||||
os.objects.append(this);
|
||||
OS::os->objects.append(this);
|
||||
action = new Action::Data;
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ struct VerticalSlider::Data {
|
||||
};
|
||||
|
||||
struct OS::Data {
|
||||
nall::array<Object*> 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++;
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<MenuItem*>(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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -178,12 +178,16 @@ struct Label : Widget {
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
nall::function<void (unsigned)> 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<unsigned> 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<Object*> objects;
|
||||
private:
|
||||
OS();
|
||||
static Data *os;
|
||||
static Object* findObject(unsigned id);
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
fp.print(string("<cartridge sha256=\"", SNES::cartridge.sha256(), "\">\n"));
|
||||
for(unsigned i = 0; i <= lastSave; i++) {
|
||||
fp.print(string(" <cheat enabled=\"", cheatText[i][1] == " " ? "false" : "true", "\">\n"));
|
||||
fp.print(string(" <description><![CDATA[", cheatText[i][3], "]]></description>\n"));
|
||||
fp.print(string(" <cheat enabled=\"", cheatList.checked(i), "\">\n"));
|
||||
fp.print(string(" <description><![CDATA[", cheatText[i][CheatDesc], "]]></description>\n"));
|
||||
lstring list;
|
||||
list.split("+", cheatText[i][2]);
|
||||
list.split("+", cheatText[i][CheatCode]);
|
||||
foreach(code, list) {
|
||||
fp.print(string(" <code>", code, "</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("");
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user