mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-04-21 19:21:58 +02:00
Update to v068r18 release.
byuu says: This WIP fixes the Mode7 repeat issue in the accuracy core. More importantly, it's the first build to include phoenix. There is a stub GUI that does basically nothing right now. It will give you a window, a command to close the emulator, and an FPS meter so you can tell how fast it is. To load a ROM, you have to drag the ROM on top of the binary. I don't know if it will work if the filename+path has spaces in it or not, so avoid that to be safe. [...] For some reason, the 64-bit binary sometimes crashes on start, maybe 1:6 times. So just keep trying. I don't know what's up with that, I'd appreciate if someone here wanted to debug that for me though :D One really good bit of news, there was that old hiro bug where keyboard input would cause the main window to beep. I spied on the main event loop and, as suspected, the status bar was getting focus and rejecting key presses. What. The. Fuck. Why would a status bar ever need focus? So I set WM_DISABLED on it, which luckily leaves the font color alone. I also had to use WM_DISABLED on the Viewport widget that I use for video output. These two combined let me have my main window with no keyboard beeping AND allow tab+shift-tab to work as you'd expect on other windows, so hooray. Now, at the moment there's no Manifest included, because Microsoft for some reason includes the processorArcitecture in the file. So I can't use the same manifest for 32-bit and 64-bit mode, or the binary will crash on one or the other. Fuck. So the status bar may look old-school or something, whatever, it's only temporary. Next up, my goal is to avoid the hiro icon corruption bullshit by making phoenix itself try and use an internal resource icon. So just compile your app with that resource icon and voila, perfect icon. Not in there yet so you get the white box. Input is hard-coded, up/down/left/right/z/x/a/s/d/c/apostrophe/return. Lastly, compilation is ... in a serious state of flux. The code is set to compile bsnes/phoenix-gtk right now. Try it at your own risk. Give me a few WIPs to get everything nice and refined. Ubuntu users will need gcc-4.5, which you can get by adding the Maverick Meerkat repository, updating apt, installing the gcc-4.5 + g++-4.5 packages, and then removing and re-updating your apt/sources.list file so you don't end up fucking your whole system when you run apt again in the future. For anyone who can work with all of that, great! Please post a framerate comparison between 32-bit and 64-bit builds. Any game, any screen, so long as the FPS is not fluctuating when you measure it (eg don't do it during an attract sequence.) If anyone complains about the 64-bit binary not working and it turns out they are on 32-bit Windows, they are going to be removed from this WIP forum :P
This commit is contained in:
parent
92ab697f8c
commit
b671e49644
bsnes
Makefile
nall
phoenix
gtk
button.cppcanvas.cppcheckbox.cppcombobox.cppeditbox.cppfont.cppgtk.cppgtk.hpphorizontalslider.cpplabel.cpplistbox.cppmenu.cppmessagewindow.cppobject.cppprogressbar.cppradiobox.cpptextbox.cppverticalslider.cppviewport.cppwidget.cppwindow.cpp
phoenix.cppphoenix.hppqt
button.cppcanvas.cppcheckbox.cppcombobox.cppeditbox.cppfont.cpphorizontalslider.cpplabel.cpplistbox.cppmenu.cppmessagewindow.cppobject.cppprogressbar.cppqt.cppqt.hppqt.moc.hppradiobox.cpptextbox.cppverticalslider.cppviewport.cppwidget.cppwindow.cpp
windows
ruby/audio
snes
sync.shui-phoenix
ui-qt
@ -1,7 +1,7 @@
|
||||
include nall/Makefile
|
||||
snes := snes
|
||||
profile := performance
|
||||
ui := qt
|
||||
ui := ui-phoenix
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
@ -88,6 +88,6 @@ clean: ui_clean
|
||||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 launcher libco nall obj out qt ruby snes Makefile sync.sh cc.bat clean.bat
|
||||
tar -cjf bsnes.tar.bz2 launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
|
||||
|
||||
help:;
|
||||
|
@ -29,10 +29,12 @@ ifeq ($(platform),)
|
||||
endif
|
||||
|
||||
ifeq ($(compiler),)
|
||||
ifeq ($(platform),osx)
|
||||
compiler := gcc-mp-4.4
|
||||
else
|
||||
ifeq ($(platform),win)
|
||||
compiler := gcc
|
||||
else ifeq ($(platform),osx)
|
||||
compiler := gcc-mp-4.5
|
||||
else
|
||||
compiler := gcc-4.5
|
||||
endif
|
||||
endif
|
||||
|
||||
|
12
bsnes/phoenix/gtk/button.cpp
Executable file
12
bsnes/phoenix/gtk/button.cpp
Executable file
@ -0,0 +1,12 @@
|
||||
static void Button_tick(Button *self) {
|
||||
if(self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_button_new_with_label(text);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "clicked", G_CALLBACK(Button_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
58
bsnes/phoenix/gtk/canvas.cpp
Executable file
58
bsnes/phoenix/gtk/canvas.cpp
Executable file
@ -0,0 +1,58 @@
|
||||
static void Canvas_expose(Canvas *self) {
|
||||
uint32_t *rgb = self->canvas->bufferRGB;
|
||||
uint32_t *bgr = self->canvas->bufferBGR;
|
||||
for(unsigned y = self->object->widget->allocation.height; y; y--) {
|
||||
for(unsigned x = self->object->widget->allocation.width; x; x--) {
|
||||
uint32_t pixel = *rgb++;
|
||||
*bgr++ = ((pixel << 16) & 0xff0000) | (pixel & 0x00ff00) | ((pixel >> 16) & 0x0000ff);
|
||||
}
|
||||
}
|
||||
|
||||
gdk_draw_rgb_32_image(
|
||||
self->object->widget->window,
|
||||
self->object->widget->style->fg_gc[GTK_WIDGET_STATE(self->object->widget)],
|
||||
0, 0, self->object->widget->allocation.width, self->object->widget->allocation.height,
|
||||
GDK_RGB_DITHER_NONE, (guchar*)self->canvas->bufferBGR, self->canvas->pitch
|
||||
);
|
||||
}
|
||||
|
||||
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
canvas->bufferRGB = new uint32_t[width * height]();
|
||||
canvas->bufferBGR = new uint32_t[width * height]();
|
||||
canvas->pitch = width * sizeof(uint32_t);
|
||||
|
||||
object->widget = gtk_drawing_area_new();
|
||||
GdkColor color;
|
||||
color.pixel = color.red = color.green = color.blue = 0;
|
||||
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
|
||||
gtk_widget_set_double_buffered(object->widget, false);
|
||||
gtk_widget_add_events(object->widget, GDK_EXPOSURE_MASK);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
uint32_t* Canvas::buffer() {
|
||||
return canvas->bufferRGB;
|
||||
}
|
||||
|
||||
void Canvas::redraw() {
|
||||
GdkRectangle rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = object->widget->allocation.width;
|
||||
rect.height = object->widget->allocation.height;
|
||||
gdk_window_invalidate_rect(object->widget->window, &rect, true);
|
||||
}
|
||||
|
||||
Canvas::Canvas() {
|
||||
canvas = new Canvas::Data;
|
||||
canvas->bufferRGB = 0;
|
||||
canvas->bufferBGR = 0;
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
if(canvas->bufferRGB) delete[] canvas->bufferRGB;
|
||||
if(canvas->bufferBGR) delete[] canvas->bufferBGR;
|
||||
}
|
22
bsnes/phoenix/gtk/checkbox.cpp
Executable file
22
bsnes/phoenix/gtk/checkbox.cpp
Executable file
@ -0,0 +1,22 @@
|
||||
static void CheckBox_tick(CheckBox *self) {
|
||||
if(self->onTick && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_check_button_new_with_label(text);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
bool CheckBox::checked() {
|
||||
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object->widget));
|
||||
}
|
||||
|
||||
void CheckBox::setChecked(bool checked) {
|
||||
object->locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(object->widget), checked);
|
||||
object->locked = false;
|
||||
}
|
43
bsnes/phoenix/gtk/combobox.cpp
Executable file
43
bsnes/phoenix/gtk/combobox.cpp
Executable file
@ -0,0 +1,43 @@
|
||||
void ComboBox_change(ComboBox *self) {
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_combo_box_new_text();
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(ComboBox_change), (gpointer)this);
|
||||
|
||||
if(*text) {
|
||||
lstring list;
|
||||
list.split("\n", text);
|
||||
foreach(item, list) addItem(item);
|
||||
}
|
||||
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void ComboBox::reset() {
|
||||
for(signed i = counter - 1; i >= 0; i--) {
|
||||
gtk_combo_box_remove_text(GTK_COMBO_BOX(object->widget), i);
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const char *text) {
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(object->widget), text);
|
||||
if(counter++ == 0) setSelection(0);
|
||||
}
|
||||
|
||||
unsigned ComboBox::selection() {
|
||||
return gtk_combo_box_get_active(GTK_COMBO_BOX(object->widget));
|
||||
}
|
||||
|
||||
void ComboBox::setSelection(unsigned item) {
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(object->widget), item);
|
||||
}
|
||||
|
||||
ComboBox::ComboBox() {
|
||||
counter = 0;
|
||||
}
|
42
bsnes/phoenix/gtk/editbox.cpp
Executable file
42
bsnes/phoenix/gtk/editbox.cpp
Executable file
@ -0,0 +1,42 @@
|
||||
static void EditBox_change(EditBox *self) {
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_scrolled_window_new(0, 0);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
object->subWidget = gtk_text_view_new();
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), GTK_WRAP_WORD_CHAR);
|
||||
gtk_container_add(GTK_CONTAINER(object->widget), object->subWidget);
|
||||
object->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(object->subWidget));
|
||||
gtk_text_buffer_set_text(object->textBuffer, text, -1);
|
||||
g_signal_connect_swapped(G_OBJECT(object->textBuffer), "changed", G_CALLBACK(EditBox_change), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->subWidget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void EditBox::setEditable(bool editable) {
|
||||
gtk_text_view_set_editable(GTK_TEXT_VIEW(object->subWidget), editable);
|
||||
}
|
||||
|
||||
void EditBox::setWordWrap(bool wordWrap) {
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(object->subWidget), wordWrap ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE);
|
||||
}
|
||||
|
||||
string EditBox::text() {
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(object->textBuffer, &start);
|
||||
gtk_text_buffer_get_end_iter(object->textBuffer, &end);
|
||||
char *temp = gtk_text_buffer_get_text(object->textBuffer, &start, &end, true);
|
||||
string text = temp;
|
||||
g_free(temp);
|
||||
return text;
|
||||
}
|
||||
|
||||
void EditBox::setText(const char *text) {
|
||||
gtk_text_buffer_set_text(object->textBuffer, text, -1);
|
||||
}
|
18
bsnes/phoenix/gtk/font.cpp
Executable file
18
bsnes/phoenix/gtk/font.cpp
Executable file
@ -0,0 +1,18 @@
|
||||
bool Font::create(const char *name, unsigned size, Font::Style style) {
|
||||
font->font = pango_font_description_new();
|
||||
pango_font_description_set_family(font->font, name);
|
||||
pango_font_description_set_absolute_size(font->font, size * PANGO_SCALE);
|
||||
pango_font_description_set_style(font->font, (style & Style::Italic) == Style::Italic ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL);
|
||||
pango_font_description_set_weight(font->font, (style & Style::Bold) == Style::Bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
Font::Font() {
|
||||
font = new Font::Data;
|
||||
font->font = 0;
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
if(font->font) pango_font_description_free(font->font);
|
||||
delete font;
|
||||
}
|
192
bsnes/phoenix/gtk/gtk.cpp
Executable file
192
bsnes/phoenix/gtk/gtk.cpp
Executable file
@ -0,0 +1,192 @@
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define None X11None
|
||||
#define Window X11Window
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
||||
#undef None
|
||||
#undef Window
|
||||
|
||||
using namespace nall;
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
#include "object.cpp"
|
||||
#include "font.cpp"
|
||||
#include "menu.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
#include "button.cpp"
|
||||
#include "canvas.cpp"
|
||||
#include "checkbox.cpp"
|
||||
#include "combobox.cpp"
|
||||
#include "editbox.cpp"
|
||||
#include "horizontalslider.cpp"
|
||||
#include "label.cpp"
|
||||
#include "listbox.cpp"
|
||||
#include "progressbar.cpp"
|
||||
#include "radiobox.cpp"
|
||||
#include "textbox.cpp"
|
||||
#include "verticalslider.cpp"
|
||||
#include "viewport.cpp"
|
||||
#include "messagewindow.cpp"
|
||||
|
||||
OS &os = OS::handle();
|
||||
Window Window::None;
|
||||
|
||||
OS& OS::handle() {
|
||||
static OS os;
|
||||
return os;
|
||||
}
|
||||
|
||||
bool OS::pending() {
|
||||
return gtk_events_pending();
|
||||
}
|
||||
|
||||
bool OS::run() {
|
||||
gtk_main_iteration_do(false);
|
||||
return gtk_events_pending();
|
||||
}
|
||||
|
||||
void OS::main() {
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
void OS::quit() {
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
unsigned OS::desktopWidth() {
|
||||
return gdk_screen_get_width(gdk_screen_get_default());
|
||||
}
|
||||
|
||||
unsigned OS::desktopHeight() {
|
||||
return gdk_screen_get_height(gdk_screen_get_default());
|
||||
}
|
||||
|
||||
string OS::folderSelect(Window &parent, const char *path) {
|
||||
string name;
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
"Select Folder",
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
(const gchar*)0
|
||||
);
|
||||
|
||||
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
name = temp;
|
||||
g_free(temp);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
string name;
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
"Open File",
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
(const gchar*)0
|
||||
);
|
||||
|
||||
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
|
||||
lstring list;
|
||||
list.split("\n", filter);
|
||||
foreach(item, list) {
|
||||
lstring part;
|
||||
part.split("\t", item);
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, string(part[0], " (", part[1], ")"));
|
||||
lstring patterns;
|
||||
patterns.split(",", part[1]);
|
||||
foreach(pattern, patterns) gtk_file_filter_add_pattern(filter, pattern);
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
}
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
name = temp;
|
||||
g_free(temp);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return name;
|
||||
}
|
||||
|
||||
string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
string name;
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new(
|
||||
"Save File",
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
(const gchar*)0
|
||||
);
|
||||
|
||||
if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
|
||||
lstring list;
|
||||
list.split("\n", filter);
|
||||
foreach(item, list) {
|
||||
lstring part;
|
||||
part.split("\t", item);
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
gtk_file_filter_set_name(filter, string(part[0], " (", part[1], ")"));
|
||||
lstring patterns;
|
||||
patterns.split(",", part[1]);
|
||||
foreach(pattern, patterns) gtk_file_filter_add_pattern(filter, pattern);
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
}
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
name = temp;
|
||||
g_free(temp);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return name;
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
os = new OS::Data;
|
||||
int argc = 1;
|
||||
char *argv[2];
|
||||
argv[0] = new char[8];
|
||||
argv[1] = 0;
|
||||
strcpy(argv[0], "phoenix");
|
||||
char **argvp = argv;
|
||||
gtk_init(&argc, &argvp);
|
||||
|
||||
gtk_rc_parse_string(
|
||||
"style \"phoenix-gtk\"\n"
|
||||
"{\n"
|
||||
" GtkComboBox::appears-as-list = 0\n"
|
||||
" GtkTreeView::vertical-separator = 0\n"
|
||||
"}\n"
|
||||
"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
|
||||
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
244
bsnes/phoenix/gtk/gtk.hpp
Executable file
244
bsnes/phoenix/gtk/gtk.hpp
Executable file
@ -0,0 +1,244 @@
|
||||
namespace phoenix {
|
||||
|
||||
struct Window;
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
Object& operator=(const Object&) = delete;
|
||||
Object(const Object&) = delete;
|
||||
//private:
|
||||
virtual void unused();
|
||||
struct Data;
|
||||
Data *object;
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *font;
|
||||
};
|
||||
|
||||
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
|
||||
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
|
||||
|
||||
struct Action : Object {
|
||||
void setFont(Font &font);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
};
|
||||
|
||||
struct MenuSeparator : Action {
|
||||
void create(Menu &parent);
|
||||
};
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
};
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
bool checked();
|
||||
void setChecked();
|
||||
private:
|
||||
MenuRadioItem *first;
|
||||
};
|
||||
|
||||
struct Widget : Object {
|
||||
virtual void setFont(Font &font);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool focused();
|
||||
void setFocused();
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setFont(Font &font);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
};
|
||||
|
||||
struct Canvas : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uint32_t* buffer();
|
||||
void redraw();
|
||||
Canvas();
|
||||
~Canvas();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *canvas;
|
||||
};
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned item);
|
||||
ComboBox();
|
||||
private:
|
||||
unsigned counter;
|
||||
};
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
};
|
||||
|
||||
struct HorizontalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
};
|
||||
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void setFont(Font &font);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *listBox;
|
||||
};
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setProgress(unsigned progress);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
private:
|
||||
RadioBox *first;
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setEditable(bool editable = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
};
|
||||
|
||||
struct VerticalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
};
|
||||
|
||||
struct Viewport : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uintptr_t handle();
|
||||
};
|
||||
|
||||
struct MessageWindow : Object {
|
||||
enum class Buttons : unsigned {
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo,
|
||||
};
|
||||
enum class Response : unsigned {
|
||||
Ok,
|
||||
Cancel,
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
bool 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 = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
struct Data;
|
||||
Data *os;
|
||||
private:
|
||||
OS();
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
}
|
24
bsnes/phoenix/gtk/horizontalslider.cpp
Executable file
24
bsnes/phoenix/gtk/horizontalslider.cpp
Executable file
@ -0,0 +1,24 @@
|
||||
static void HorizontalSlider_change(HorizontalSlider *self) {
|
||||
if(self->object->position == self->position()) return;
|
||||
self->object->position = self->position();
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
|
||||
object->position = 0;
|
||||
length += (length == 0);
|
||||
object->widget = gtk_hscale_new_with_range(0, length - 1, 1);
|
||||
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)this);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
unsigned HorizontalSlider::position() {
|
||||
return (unsigned)gtk_range_get_value(GTK_RANGE(object->widget));
|
||||
}
|
||||
|
||||
void HorizontalSlider::setPosition(unsigned position) {
|
||||
gtk_range_set_value(GTK_RANGE(object->widget), position);
|
||||
}
|
7
bsnes/phoenix/gtk/label.cpp
Executable file
7
bsnes/phoenix/gtk/label.cpp
Executable file
@ -0,0 +1,7 @@
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_label_new(text);
|
||||
gtk_misc_set_alignment(GTK_MISC(object->widget), 0.0, 0.0);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
147
bsnes/phoenix/gtk/listbox.cpp
Executable file
147
bsnes/phoenix/gtk/listbox.cpp
Executable file
@ -0,0 +1,147 @@
|
||||
static void ListBox_change(ListBox *self) {
|
||||
signed selection = -1;
|
||||
if(auto position = self->selection()) selection = position();
|
||||
if(selection == self->listBox->selection) return;
|
||||
self->listBox->selection = selection;
|
||||
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();
|
||||
}
|
||||
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
listBox->selection = -1;
|
||||
object->widget = gtk_scrolled_window_new(0, 0);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(object->widget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(object->widget), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
|
||||
GType *v = (GType*)malloc(list.size() * sizeof(GType));
|
||||
for(unsigned i = 0; i < list.size(); i++) v[i] = G_TYPE_STRING;
|
||||
listBox->store = gtk_list_store_newv(list.size(), v);
|
||||
free(v);
|
||||
|
||||
object->subWidget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(listBox->store));
|
||||
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
|
||||
);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->subWidget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void ListBox::setHeaderVisible(bool visible) {
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(object->subWidget), visible);
|
||||
}
|
||||
|
||||
void ListBox::setFont(Font &font) {
|
||||
Widget::setFont(font);
|
||||
unsigned columns = 1;
|
||||
while(true) {
|
||||
if(gtk_tree_view_get_column(GTK_TREE_VIEW(object->subWidget), columns) == 0) break;
|
||||
columns++;
|
||||
}
|
||||
for(unsigned i = 0; i < columns; i++) {
|
||||
gtk_widget_modify_font(listBox->column[i].label, font.font->font);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::reset() {
|
||||
listBox->selection = -1;
|
||||
gtk_list_store_clear(GTK_LIST_STORE(listBox->store));
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(object->subWidget), GTK_TREE_MODEL(listBox->store));
|
||||
}
|
||||
|
||||
void ListBox::resizeColumnsToContent() {
|
||||
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(object->subWidget));
|
||||
}
|
||||
|
||||
void ListBox::addItem(const char *text) {
|
||||
lstring list;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreeIter iter;
|
||||
for(unsigned i = 0; i <= row; i++) {
|
||||
if(i == 0) gtk_tree_model_get_iter_first(model, &iter);
|
||||
else gtk_tree_model_iter_next(model, &iter);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreeIter iter;
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) return { false, 0 };
|
||||
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return { true, 0 };
|
||||
for(unsigned i = 1;; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) return { false, 0 };
|
||||
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return { true, i };
|
||||
}
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
void ListBox::setSelection(unsigned row) {
|
||||
signed current = -1;
|
||||
if(auto position = selection()) current = position();
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(object->subWidget));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(object->subWidget));
|
||||
gtk_tree_selection_unselect_all(selection);
|
||||
|
||||
GtkTreeIter iter;
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) return;
|
||||
if(row == 0) {
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
return;
|
||||
}
|
||||
for(unsigned i = 1;; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) return;
|
||||
if(row == i) {
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListBox::ListBox() {
|
||||
listBox = new ListBox::Data;
|
||||
}
|
113
bsnes/phoenix/gtk/menu.cpp
Executable file
113
bsnes/phoenix/gtk/menu.cpp
Executable file
@ -0,0 +1,113 @@
|
||||
static void Action_setFont(GtkWidget *widget, gpointer font) {
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, font);
|
||||
}
|
||||
}
|
||||
|
||||
void Action::setFont(Font &font) {
|
||||
Action_setFont(object->widget, font.font->font);
|
||||
}
|
||||
|
||||
bool Action::visible() {
|
||||
return gtk_widget_get_visible(object->widget);
|
||||
}
|
||||
|
||||
void Action::setVisible(bool visible) {
|
||||
gtk_widget_set_visible(object->widget, visible);
|
||||
}
|
||||
|
||||
bool Action::enabled() {
|
||||
return gtk_widget_get_sensitive(object->widget);
|
||||
}
|
||||
|
||||
void Action::setEnabled(bool enabled) {
|
||||
gtk_widget_set_sensitive(object->widget, enabled);
|
||||
}
|
||||
|
||||
void Menu::create(Window &parent, const char *text) {
|
||||
object->menu = gtk_menu_new();
|
||||
object->widget = gtk_menu_item_new_with_label(text);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_menu_bar_append(parent.object->menu, object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void Menu::create(Menu &parent, const char *text) {
|
||||
object->menu = gtk_menu_new();
|
||||
object->widget = gtk_menu_item_new_with_label(text);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(object->widget), object->menu);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void MenuSeparator::create(Menu &parent) {
|
||||
object->widget = gtk_separator_menu_item_new();
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
static void MenuItem_tick(MenuItem *self) {
|
||||
if(self->onTick) self->onTick();
|
||||
}
|
||||
|
||||
void MenuItem::create(Menu &parent, const char *text) {
|
||||
object->widget = gtk_menu_item_new_with_label(text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "activate", G_CALLBACK(MenuItem_tick), (gpointer)this);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
static void MenuCheckItem_tick(MenuCheckItem *self) {
|
||||
if(self->onTick && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void MenuCheckItem::create(Menu &parent, const char *text) {
|
||||
object->widget = gtk_check_menu_item_new_with_label(text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuCheckItem_tick), (gpointer)this);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
bool MenuCheckItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(object->widget));
|
||||
}
|
||||
|
||||
void MenuCheckItem::setChecked(bool state) {
|
||||
object->locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(object->widget), state);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
static void MenuRadioItem_tick(MenuRadioItem *self) {
|
||||
if(self->onTick && self->checked() && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
first = this;
|
||||
object->parentMenu = &parent;
|
||||
object->widget = gtk_radio_menu_item_new_with_label(0, text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(parent.object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
|
||||
first = parent.first;
|
||||
object->parentMenu = parent.object->parentMenu;
|
||||
object->widget = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(first->object->widget), text);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(MenuRadioItem_tick), (gpointer)this);
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(object->parentMenu->object->menu), object->widget);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(object->widget));
|
||||
}
|
||||
|
||||
void MenuRadioItem::setChecked() {
|
||||
object->locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(object->widget), true);
|
||||
object->locked = false;
|
||||
}
|
65
bsnes/phoenix/gtk/messagewindow.cpp
Executable file
65
bsnes/phoenix/gtk/messagewindow.cpp
Executable file
@ -0,0 +1,65 @@
|
||||
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, gint response) {
|
||||
if(response == GTK_RESPONSE_OK) return MessageWindow::Response::Ok;
|
||||
if(response == GTK_RESPONSE_CANCEL) return MessageWindow::Response::Cancel;
|
||||
if(response == GTK_RESPONSE_YES) return MessageWindow::Response::Yes;
|
||||
if(response == GTK_RESPONSE_NO) return MessageWindow::Response::No;
|
||||
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
|
||||
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
|
||||
return MessageWindow::Response::Ok;
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, buttonsType, "%s", text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, buttonsType, "%s", text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, buttonsType, "%s", text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
GtkButtonsType buttonsType = GTK_BUTTONS_OK;
|
||||
if(buttons == Buttons::OkCancel) buttonsType = GTK_BUTTONS_OK_CANCEL;
|
||||
if(buttons == Buttons::YesNo) buttonsType = GTK_BUTTONS_YES_NO;
|
||||
|
||||
GtkWidget *dialog = gtk_message_dialog_new(
|
||||
&parent != &Window::None ? GTK_WINDOW(parent.object->widget) : (GtkWindow*)0,
|
||||
GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, buttonsType, "%s", text
|
||||
);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
gtk_widget_destroy(dialog);
|
||||
return MessageWindow_response(buttons, response);
|
||||
}
|
50
bsnes/phoenix/gtk/object.cpp
Executable file
50
bsnes/phoenix/gtk/object.cpp
Executable file
@ -0,0 +1,50 @@
|
||||
struct Object::Data {
|
||||
bool locked;
|
||||
GtkWidget *widget;
|
||||
GtkWidget *subWidget;
|
||||
GtkWidget *menuContainer;
|
||||
GtkWidget *formContainer;
|
||||
GtkWidget *statusContainer;
|
||||
GtkWidget *menu;
|
||||
GtkWidget *status;
|
||||
Menu *parentMenu;
|
||||
Window *parentWindow;
|
||||
GtkTextBuffer *textBuffer;
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
struct Font::Data {
|
||||
PangoFontDescription *font;
|
||||
};
|
||||
|
||||
struct Window::Data {
|
||||
Font *defaultFont;
|
||||
};
|
||||
|
||||
struct Canvas::Data {
|
||||
uint32_t *bufferRGB;
|
||||
uint32_t *bufferBGR;
|
||||
unsigned pitch;
|
||||
};
|
||||
|
||||
struct ListBox::Data {
|
||||
GtkListStore *store;
|
||||
struct GtkColumn {
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkWidget *label;
|
||||
};
|
||||
linear_vector<GtkColumn> column;
|
||||
signed selection;
|
||||
};
|
||||
|
||||
struct OS::Data {
|
||||
};
|
||||
|
||||
void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
object = new Object::Data;
|
||||
object->locked = false;
|
||||
}
|
11
bsnes/phoenix/gtk/progressbar.cpp
Executable file
11
bsnes/phoenix/gtk/progressbar.cpp
Executable file
@ -0,0 +1,11 @@
|
||||
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
object->widget = gtk_progress_bar_new();
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
progress = progress <= 100 ? progress : 0;
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(object->widget), (double)progress / 100.0);
|
||||
}
|
35
bsnes/phoenix/gtk/radiobox.cpp
Executable file
35
bsnes/phoenix/gtk/radiobox.cpp
Executable file
@ -0,0 +1,35 @@
|
||||
static void RadioBox_tick(RadioBox *self) {
|
||||
if(self->onTick && self->checked() && self->object->locked == false) self->onTick();
|
||||
}
|
||||
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
first = this;
|
||||
object->parentWindow = &parent;
|
||||
object->widget = gtk_radio_button_new_with_label(0, text);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
first = parent.first;
|
||||
object->parentWindow = parent.object->parentWindow;
|
||||
object->widget = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(parent.object->widget), text);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)this);
|
||||
if(object->parentWindow->window->defaultFont) setFont(*object->parentWindow->window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(object->parentWindow->object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
bool RadioBox::checked() {
|
||||
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object->widget));
|
||||
}
|
||||
|
||||
void RadioBox::setChecked() {
|
||||
object->locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(object->widget), true);
|
||||
object->locked = false;
|
||||
}
|
25
bsnes/phoenix/gtk/textbox.cpp
Executable file
25
bsnes/phoenix/gtk/textbox.cpp
Executable file
@ -0,0 +1,25 @@
|
||||
static void TextBox_change(TextBox *self) {
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_entry_new();
|
||||
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "changed", G_CALLBACK(TextBox_change), (gpointer)this);
|
||||
if(parent.window->defaultFont) setFont(*parent.window->defaultFont);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
void TextBox::setEditable(bool editable) {
|
||||
gtk_entry_set_editable(GTK_ENTRY(object->widget), editable);
|
||||
}
|
||||
|
||||
string TextBox::text() {
|
||||
return gtk_entry_get_text(GTK_ENTRY(object->widget));
|
||||
}
|
||||
|
||||
void TextBox::setText(const char *text) {
|
||||
gtk_entry_set_text(GTK_ENTRY(object->widget), text);
|
||||
}
|
24
bsnes/phoenix/gtk/verticalslider.cpp
Executable file
24
bsnes/phoenix/gtk/verticalslider.cpp
Executable file
@ -0,0 +1,24 @@
|
||||
static void VerticalSlider_change(VerticalSlider *self) {
|
||||
if(self->object->position == self->position()) return;
|
||||
self->object->position = self->position();
|
||||
if(self->onChange) self->onChange();
|
||||
}
|
||||
|
||||
void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
|
||||
object->position = 0;
|
||||
length += (length == 0);
|
||||
object->widget = gtk_vscale_new_with_range(0, length - 1, 1);
|
||||
gtk_scale_set_draw_value(GTK_SCALE(object->widget), false);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)this);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
unsigned VerticalSlider::position() {
|
||||
return (unsigned)gtk_range_get_value(GTK_RANGE(object->widget));
|
||||
}
|
||||
|
||||
void VerticalSlider::setPosition(unsigned position) {
|
||||
gtk_range_set_value(GTK_RANGE(object->widget), position);
|
||||
}
|
11
bsnes/phoenix/gtk/viewport.cpp
Executable file
11
bsnes/phoenix/gtk/viewport.cpp
Executable file
@ -0,0 +1,11 @@
|
||||
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
object->widget = gtk_drawing_area_new();
|
||||
gtk_widget_set_double_buffered(object->widget, false);
|
||||
gtk_widget_set_size_request(object->widget, width, height);
|
||||
gtk_fixed_put(GTK_FIXED(parent.object->formContainer), object->widget, x, y);
|
||||
gtk_widget_show(object->widget);
|
||||
}
|
||||
|
||||
uintptr_t Viewport::handle() {
|
||||
return GDK_WINDOW_XID(object->widget->window);
|
||||
}
|
36
bsnes/phoenix/gtk/widget.cpp
Executable file
36
bsnes/phoenix/gtk/widget.cpp
Executable file
@ -0,0 +1,36 @@
|
||||
static void Widget_setFont(GtkWidget *widget, gpointer font) {
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Widget_setFont, font);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::setFont(Font &font) {
|
||||
Widget_setFont(object->widget, font.font->font);
|
||||
}
|
||||
|
||||
bool Widget::visible() {
|
||||
return gtk_widget_get_visible(object->widget);
|
||||
}
|
||||
|
||||
void Widget::setVisible(bool visible) {
|
||||
if(visible) gtk_widget_show(object->widget);
|
||||
else gtk_widget_hide(object->widget);
|
||||
}
|
||||
|
||||
bool Widget::enabled() {
|
||||
return gtk_widget_get_sensitive(object->widget);
|
||||
}
|
||||
|
||||
void Widget::setEnabled(bool enabled) {
|
||||
gtk_widget_set_sensitive(object->widget, enabled);
|
||||
}
|
||||
|
||||
bool Widget::focused() {
|
||||
return gtk_widget_is_focus(object->widget);
|
||||
}
|
||||
|
||||
void Widget::setFocused() {
|
||||
if(visible() == false) setVisible(true);
|
||||
gtk_widget_grab_focus(object->widget);
|
||||
}
|
77
bsnes/phoenix/gtk/window.cpp
Executable file
77
bsnes/phoenix/gtk/window.cpp
Executable file
@ -0,0 +1,77 @@
|
||||
static gint Window_close(Window *window) {
|
||||
if(window->onClose) return !window->onClose();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
object->widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(object->widget), text);
|
||||
gtk_window_set_resizable(GTK_WINDOW(object->widget), false);
|
||||
gtk_widget_set_app_paintable(object->widget, true);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(object->widget), "delete_event", G_CALLBACK(Window_close), (gpointer)this);
|
||||
|
||||
object->menuContainer = gtk_vbox_new(false, 0);
|
||||
gtk_container_add(GTK_CONTAINER(object->widget), object->menuContainer);
|
||||
gtk_widget_show(object->menuContainer);
|
||||
|
||||
object->menu = gtk_menu_bar_new();
|
||||
gtk_box_pack_start(GTK_BOX(object->menuContainer), object->menu, false, false, 0);
|
||||
|
||||
object->formContainer = gtk_fixed_new();
|
||||
gtk_widget_set_size_request(object->formContainer, width, height);
|
||||
gtk_box_pack_start(GTK_BOX(object->menuContainer), object->formContainer, true, true, 0);
|
||||
gtk_widget_show(object->formContainer);
|
||||
|
||||
object->statusContainer = gtk_event_box_new();
|
||||
object->status = gtk_statusbar_new();
|
||||
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(object->status), false);
|
||||
gtk_container_add(GTK_CONTAINER(object->statusContainer), object->status);
|
||||
gtk_box_pack_start(GTK_BOX(object->menuContainer), object->statusContainer, false, false, 0);
|
||||
gtk_widget_show(object->statusContainer);
|
||||
|
||||
gtk_widget_realize(object->widget);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
gtk_window_move(GTK_WINDOW(object->widget), x, y);
|
||||
gtk_widget_set_size_request(object->formContainer, width, height);
|
||||
}
|
||||
|
||||
void Window::setFont(Font &font) {
|
||||
Widget::setFont(font);
|
||||
window->defaultFont = &font;
|
||||
}
|
||||
|
||||
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
GdkColor color;
|
||||
color.pixel = (red << 16) | (green << 8) | (blue << 0);
|
||||
color.red = (red << 8) | (red << 0);
|
||||
color.green = (green << 8) | (green << 0);
|
||||
color.blue = (blue << 8) | (blue << 0);
|
||||
gtk_widget_modify_bg(object->widget, GTK_STATE_NORMAL, &color);
|
||||
}
|
||||
|
||||
void Window::setTitle(const char *text) {
|
||||
gtk_window_set_title(GTK_WINDOW(object->widget), text);
|
||||
}
|
||||
|
||||
void Window::setStatusText(const char *text) {
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(object->status), 1);
|
||||
gtk_statusbar_push(GTK_STATUSBAR(object->status), 1, text);
|
||||
}
|
||||
|
||||
void Window::setMenuVisible(bool visible) {
|
||||
gtk_widget_set_visible(object->menu, visible);
|
||||
}
|
||||
|
||||
void Window::setStatusVisible(bool visible) {
|
||||
gtk_widget_set_visible(object->status, visible);
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data;
|
||||
window->defaultFont = 0;
|
||||
}
|
17
bsnes/phoenix/phoenix.cpp
Executable file
17
bsnes/phoenix/phoenix.cpp
Executable file
@ -0,0 +1,17 @@
|
||||
#if defined(PHOENIX_WINDOWS)
|
||||
#define UNICODE
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define _WIN32_IE 0x0600
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "phoenix.hpp"
|
||||
|
||||
#if defined(PHOENIX_WINDOWS)
|
||||
#include "windows/windows.cpp"
|
||||
#elif defined(PHOENIX_GTK)
|
||||
#include "gtk/gtk.cpp"
|
||||
#elif defined(PHOENIX_QT)
|
||||
#include "qt/qt.cpp"
|
||||
#endif
|
15
bsnes/phoenix/phoenix.hpp
Executable file
15
bsnes/phoenix/phoenix.hpp
Executable file
@ -0,0 +1,15 @@
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/foreach.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
|
||||
#if defined(PHOENIX_WINDOWS)
|
||||
#include "windows/windows.hpp"
|
||||
#elif defined(PHOENIX_GTK)
|
||||
#include "gtk/gtk.hpp"
|
||||
#elif defined(PHOENIX_QT)
|
||||
#include "qt/qt.hpp"
|
||||
#endif
|
13
bsnes/phoenix/qt/button.cpp
Executable file
13
bsnes/phoenix/qt/button.cpp
Executable file
@ -0,0 +1,13 @@
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
button->setParent(parent.window->container);
|
||||
button->setGeometry(x, y, width, height);
|
||||
button->setText(text);
|
||||
if(parent.window->defaultFont) button->setFont(*parent.window->defaultFont);
|
||||
button->show();
|
||||
button->connect(button, SIGNAL(released()), SLOT(onTick()));
|
||||
}
|
||||
|
||||
Button::Button() {
|
||||
button = new Button::Data(*this);
|
||||
widget->widget = button;
|
||||
}
|
39
bsnes/phoenix/qt/canvas.cpp
Executable file
39
bsnes/phoenix/qt/canvas.cpp
Executable file
@ -0,0 +1,39 @@
|
||||
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
canvas->image = new QImage(width, height, QImage::Format_RGB32);
|
||||
canvas->image->fill(0);
|
||||
canvas->setParent(parent.window->container);
|
||||
canvas->setGeometry(x, y, width, height);
|
||||
canvas->show();
|
||||
}
|
||||
|
||||
void Canvas::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
delete canvas->image;
|
||||
canvas->image = new QImage(width, height, QImage::Format_RGB32);
|
||||
canvas->image->fill(0);
|
||||
canvas->setGeometry(x, y, width, height);
|
||||
canvas->update();
|
||||
}
|
||||
|
||||
uint32_t* Canvas::buffer() {
|
||||
return (uint32_t*)canvas->image->bits();
|
||||
}
|
||||
|
||||
void Canvas::redraw() {
|
||||
canvas->update();
|
||||
}
|
||||
|
||||
Canvas::Canvas() {
|
||||
canvas = new Canvas::Data(*this);
|
||||
canvas->image = 0;
|
||||
widget->widget = canvas;
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
if(canvas->image) delete canvas->image;
|
||||
delete canvas;
|
||||
}
|
||||
|
||||
void Canvas::Data::paintEvent(QPaintEvent *event) {
|
||||
QPainter painter(this);
|
||||
painter.drawImage(0, 0, *image);
|
||||
}
|
21
bsnes/phoenix/qt/checkbox.cpp
Executable file
21
bsnes/phoenix/qt/checkbox.cpp
Executable file
@ -0,0 +1,21 @@
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
checkBox->setParent(parent.window->container);
|
||||
checkBox->setGeometry(x, y, width, height);
|
||||
checkBox->setText(text);
|
||||
if(parent.window->defaultFont) checkBox->setFont(*parent.window->defaultFont);
|
||||
checkBox->show();
|
||||
checkBox->connect(checkBox, SIGNAL(stateChanged(int)), SLOT(onTick()));
|
||||
}
|
||||
|
||||
bool CheckBox::checked() {
|
||||
return checkBox->isChecked();
|
||||
}
|
||||
|
||||
void CheckBox::setChecked(bool checked) {
|
||||
checkBox->setChecked(checked);
|
||||
}
|
||||
|
||||
CheckBox::CheckBox() {
|
||||
checkBox = new CheckBox::Data(*this);
|
||||
widget->widget = checkBox;
|
||||
}
|
36
bsnes/phoenix/qt/combobox.cpp
Executable file
36
bsnes/phoenix/qt/combobox.cpp
Executable file
@ -0,0 +1,36 @@
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
comboBox->setParent(parent.window->container);
|
||||
comboBox->setGeometry(x, y, width, height);
|
||||
|
||||
if(*text) {
|
||||
lstring list;
|
||||
list.split("\n", text);
|
||||
foreach(item, list) addItem((const char*)item);
|
||||
}
|
||||
|
||||
comboBox->connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange()));
|
||||
if(parent.window->defaultFont) comboBox->setFont(*parent.window->defaultFont);
|
||||
comboBox->show();
|
||||
}
|
||||
|
||||
void ComboBox::reset() {
|
||||
while(comboBox->count()) comboBox->removeItem(0);
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const char *text) {
|
||||
comboBox->addItem(text);
|
||||
}
|
||||
|
||||
unsigned ComboBox::selection() {
|
||||
signed index = comboBox->currentIndex();
|
||||
return (index >= 0 ? index : 0);
|
||||
}
|
||||
|
||||
void ComboBox::setSelection(unsigned row) {
|
||||
comboBox->setCurrentIndex(row);
|
||||
}
|
||||
|
||||
ComboBox::ComboBox() {
|
||||
comboBox = new ComboBox::Data(*this);
|
||||
widget->widget = comboBox;
|
||||
}
|
26
bsnes/phoenix/qt/editbox.cpp
Executable file
26
bsnes/phoenix/qt/editbox.cpp
Executable file
@ -0,0 +1,26 @@
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
editBox->setParent(parent.window->container);
|
||||
editBox->setGeometry(x, y, width, height);
|
||||
editBox->setText(text);
|
||||
if(parent.window->defaultFont) editBox->setFont(*parent.window->defaultFont);
|
||||
editBox->show();
|
||||
editBox->connect(editBox, SIGNAL(textChanged()), SLOT(onChange()));
|
||||
}
|
||||
|
||||
void EditBox::setEditable(bool editable) {
|
||||
}
|
||||
|
||||
void EditBox::setWordWrap(bool wordWrap) {
|
||||
editBox->setWordWrapMode(wordWrap ? QTextOption::WordWrap : QTextOption::NoWrap);
|
||||
}
|
||||
|
||||
string EditBox::text() {
|
||||
}
|
||||
|
||||
void EditBox::setText(const char *text) {
|
||||
}
|
||||
|
||||
EditBox::EditBox() {
|
||||
editBox = new EditBox::Data(*this);
|
||||
widget->widget = editBox;
|
||||
}
|
14
bsnes/phoenix/qt/font.cpp
Executable file
14
bsnes/phoenix/qt/font.cpp
Executable file
@ -0,0 +1,14 @@
|
||||
bool Font::create(const char *name, unsigned size, Font::Style style) {
|
||||
font->setFamily(name);
|
||||
font->setPointSize(size);
|
||||
font->setBold((style & Style::Bold) == Style::Bold);
|
||||
font->setItalic((style & Style::Italic) == Style::Italic);
|
||||
}
|
||||
|
||||
Font::Font() {
|
||||
font = new Font::Data(*this);
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
delete font;
|
||||
}
|
22
bsnes/phoenix/qt/horizontalslider.cpp
Executable file
22
bsnes/phoenix/qt/horizontalslider.cpp
Executable file
@ -0,0 +1,22 @@
|
||||
void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
|
||||
length += (length == 0);
|
||||
horizontalSlider->setParent(parent.window->container);
|
||||
horizontalSlider->setGeometry(x, y, width, height);
|
||||
horizontalSlider->setRange(0, length - 1);
|
||||
horizontalSlider->setPageStep(length >> 3);
|
||||
horizontalSlider->connect(horizontalSlider, SIGNAL(valueChanged(int)), SLOT(onChange()));
|
||||
horizontalSlider->show();
|
||||
}
|
||||
|
||||
unsigned HorizontalSlider::position() {
|
||||
return horizontalSlider->value();
|
||||
}
|
||||
|
||||
void HorizontalSlider::setPosition(unsigned position) {
|
||||
horizontalSlider->setValue(position);
|
||||
}
|
||||
|
||||
HorizontalSlider::HorizontalSlider() {
|
||||
horizontalSlider = new HorizontalSlider::Data(*this);
|
||||
widget->widget = horizontalSlider;
|
||||
}
|
12
bsnes/phoenix/qt/label.cpp
Executable file
12
bsnes/phoenix/qt/label.cpp
Executable file
@ -0,0 +1,12 @@
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
label->setParent(parent.window->container);
|
||||
label->setGeometry(x, y, width, height);
|
||||
label->setText(text);
|
||||
if(parent.window->defaultFont) label->setFont(*parent.window->defaultFont);
|
||||
label->show();
|
||||
}
|
||||
|
||||
Label::Label() {
|
||||
label = new Label::Data(*this);
|
||||
widget->widget = label;
|
||||
}
|
76
bsnes/phoenix/qt/listbox.cpp
Executable file
76
bsnes/phoenix/qt/listbox.cpp
Executable file
@ -0,0 +1,76 @@
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
listBox->setParent(parent.window->container);
|
||||
listBox->setGeometry(x, y, width, height);
|
||||
listBox->setAllColumnsShowFocus(true);
|
||||
listBox->setRootIsDecorated(false);
|
||||
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
QStringList labels;
|
||||
foreach(item, list) labels << (const char*)item;
|
||||
listBox->setColumnCount(list.size());
|
||||
listBox->setHeaderLabels(labels);
|
||||
for(unsigned i = 0; i < list.size(); i++) listBox->resizeColumnToContents(i);
|
||||
|
||||
listBox->setHeaderHidden(true);
|
||||
listBox->setAlternatingRowColors(list.size() >= 2);
|
||||
listBox->connect(listBox, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate()));
|
||||
listBox->connect(listBox, SIGNAL(itemSelectionChanged()), SLOT(onChange()));
|
||||
if(parent.window->defaultFont) listBox->setFont(*parent.window->defaultFont);
|
||||
listBox->show();
|
||||
}
|
||||
|
||||
void ListBox::setHeaderVisible(bool headerVisible) {
|
||||
listBox->setHeaderHidden(headerVisible == false);
|
||||
}
|
||||
|
||||
void ListBox::reset() {
|
||||
listBox->clear();
|
||||
}
|
||||
|
||||
void ListBox::resizeColumnsToContent() {
|
||||
for(unsigned i = 0; i < listBox->columnCount(); i++) listBox->resizeColumnToContents(i);
|
||||
}
|
||||
|
||||
void ListBox::addItem(const char *text) {
|
||||
auto items = listBox->findItems("", Qt::MatchContains);
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(listBox);
|
||||
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]);
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
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]);
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
QTreeWidgetItem *item = listBox->currentItem();
|
||||
if(item == 0) return { false, 0 };
|
||||
if(item->isSelected() == false) return { false, 0 };
|
||||
unsigned row = item->data(0, Qt::UserRole).toUInt();
|
||||
return { true, row };
|
||||
}
|
||||
|
||||
void ListBox::setSelection(unsigned row) {
|
||||
object->locked = true;
|
||||
QTreeWidgetItem *item = listBox->currentItem();
|
||||
if(item) item->setSelected(false);
|
||||
auto items = listBox->findItems("", Qt::MatchContains);
|
||||
for(unsigned i = 0; i < items.size(); i++) {
|
||||
if(items[i]->data(0, Qt::UserRole).toUInt() == row) {
|
||||
listBox->setCurrentItem(items[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
ListBox::ListBox() {
|
||||
listBox = new ListBox::Data(*this);
|
||||
widget->widget = listBox;
|
||||
}
|
165
bsnes/phoenix/qt/menu.cpp
Executable file
165
bsnes/phoenix/qt/menu.cpp
Executable file
@ -0,0 +1,165 @@
|
||||
void Menu::create(Window &parent, const char *text) {
|
||||
menu->setTitle(text);
|
||||
parent.window->menuBar->addMenu(menu);
|
||||
}
|
||||
|
||||
void Menu::create(Menu &parent, const char *text) {
|
||||
menu->setTitle(text);
|
||||
parent.menu->addMenu(menu);
|
||||
}
|
||||
|
||||
bool Menu::visible() {
|
||||
return menu->isVisible();
|
||||
}
|
||||
|
||||
void Menu::setVisible(bool visible) {
|
||||
menu->setVisible(visible);
|
||||
}
|
||||
|
||||
bool Menu::enabled() {
|
||||
return menu->isEnabled();
|
||||
}
|
||||
|
||||
void Menu::setEnabled(bool enabled) {
|
||||
menu->setEnabled(enabled);
|
||||
}
|
||||
|
||||
Menu::Menu() {
|
||||
menu = new Menu::Data(*this);
|
||||
}
|
||||
|
||||
void MenuSeparator::create(Menu &parent) {
|
||||
menuSeparator->action = parent.menu->addSeparator();
|
||||
}
|
||||
|
||||
bool MenuSeparator::visible() {
|
||||
return menuSeparator->action->isVisible();
|
||||
}
|
||||
|
||||
void MenuSeparator::setVisible(bool visible) {
|
||||
menuSeparator->action->setVisible(visible);
|
||||
}
|
||||
|
||||
bool MenuSeparator::enabled() {
|
||||
return menuSeparator->action->isEnabled();
|
||||
}
|
||||
|
||||
void MenuSeparator::setEnabled(bool enabled) {
|
||||
menuSeparator->action->setEnabled(enabled);
|
||||
}
|
||||
|
||||
MenuSeparator::MenuSeparator() {
|
||||
menuSeparator = new MenuSeparator::Data(*this);
|
||||
}
|
||||
|
||||
void MenuItem::create(Menu &parent, const char *text) {
|
||||
menuItem->setText(text);
|
||||
menuItem->connect(menuItem, SIGNAL(triggered()), SLOT(onTick()));
|
||||
parent.menu->addAction(menuItem);
|
||||
}
|
||||
|
||||
bool MenuItem::visible() {
|
||||
return menuItem->isVisible();
|
||||
}
|
||||
|
||||
void MenuItem::setVisible(bool visible) {
|
||||
menuItem->setVisible(visible);
|
||||
}
|
||||
|
||||
bool MenuItem::enabled() {
|
||||
return menuItem->isEnabled();
|
||||
}
|
||||
|
||||
void MenuItem::setEnabled(bool enabled) {
|
||||
menuItem->setEnabled(enabled);
|
||||
}
|
||||
|
||||
MenuItem::MenuItem() {
|
||||
menuItem = new MenuItem::Data(*this);
|
||||
}
|
||||
|
||||
void MenuCheckItem::create(Menu &parent, const char *text) {
|
||||
menuCheckItem->setText(text);
|
||||
menuCheckItem->setCheckable(true);
|
||||
menuCheckItem->connect(menuCheckItem, SIGNAL(triggered()), SLOT(onTick()));
|
||||
parent.menu->addAction(menuCheckItem);
|
||||
}
|
||||
|
||||
bool MenuCheckItem::visible() {
|
||||
return menuCheckItem->isVisible();
|
||||
}
|
||||
|
||||
void MenuCheckItem::setVisible(bool visible) {
|
||||
menuCheckItem->setVisible(visible);
|
||||
}
|
||||
|
||||
bool MenuCheckItem::enabled() {
|
||||
return menuCheckItem->isEnabled();
|
||||
}
|
||||
|
||||
void MenuCheckItem::setEnabled(bool enabled) {
|
||||
menuCheckItem->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool MenuCheckItem::checked() {
|
||||
return menuCheckItem->isChecked();
|
||||
}
|
||||
|
||||
void MenuCheckItem::setChecked(bool checked) {
|
||||
menuCheckItem->setChecked(checked);
|
||||
}
|
||||
|
||||
MenuCheckItem::MenuCheckItem() {
|
||||
menuCheckItem = new MenuCheckItem::Data(*this);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
menuRadioItem->parent = &parent;
|
||||
menuRadioItem->actionGroup = new QActionGroup(0);
|
||||
menuRadioItem->actionGroup->addAction(menuRadioItem);
|
||||
menuRadioItem->setText(text);
|
||||
menuRadioItem->setCheckable(true);
|
||||
menuRadioItem->setChecked(true);
|
||||
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
|
||||
menuRadioItem->parent->menu->addAction(menuRadioItem);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
|
||||
menuRadioItem->parent = parent.menuRadioItem->parent;
|
||||
menuRadioItem->actionGroup = parent.menuRadioItem->actionGroup;
|
||||
menuRadioItem->actionGroup->addAction(menuRadioItem);
|
||||
menuRadioItem->setText(text);
|
||||
menuRadioItem->setCheckable(true);
|
||||
menuRadioItem->connect(menuRadioItem, SIGNAL(changed()), SLOT(onTick()));
|
||||
menuRadioItem->parent->menu->addAction(menuRadioItem);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::visible() {
|
||||
return menuRadioItem->isVisible();
|
||||
}
|
||||
|
||||
void MenuRadioItem::setVisible(bool visible) {
|
||||
menuRadioItem->setVisible(visible);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::enabled() {
|
||||
return menuRadioItem->isEnabled();
|
||||
}
|
||||
|
||||
void MenuRadioItem::setEnabled(bool enabled) {
|
||||
menuRadioItem->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
return menuRadioItem->isChecked();
|
||||
}
|
||||
|
||||
void MenuRadioItem::setChecked() {
|
||||
object->locked = true;
|
||||
menuRadioItem->setChecked(true);
|
||||
object->locked = false;
|
||||
}
|
||||
|
||||
MenuRadioItem::MenuRadioItem() {
|
||||
menuRadioItem = new MenuRadioItem::Data(*this);
|
||||
}
|
41
bsnes/phoenix/qt/messagewindow.cpp
Executable file
41
bsnes/phoenix/qt/messagewindow.cpp
Executable file
@ -0,0 +1,41 @@
|
||||
static QMessageBox::StandardButtons MessageWindow_buttons(MessageWindow::Buttons buttons) {
|
||||
QMessageBox::StandardButtons standardButtons = QMessageBox::NoButton;
|
||||
if(buttons == MessageWindow::Buttons::Ok) standardButtons = QMessageBox::Ok;
|
||||
if(buttons == MessageWindow::Buttons::OkCancel) standardButtons = QMessageBox::Ok | QMessageBox::Cancel;
|
||||
if(buttons == MessageWindow::Buttons::YesNo) standardButtons = QMessageBox::Yes | QMessageBox::No;
|
||||
return standardButtons;
|
||||
}
|
||||
|
||||
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, QMessageBox::StandardButton response) {
|
||||
if(response == QMessageBox::Ok) return MessageWindow::Response::Ok;
|
||||
if(response == QMessageBox::Cancel) return MessageWindow::Response::Cancel;
|
||||
if(response == QMessageBox::Yes) return MessageWindow::Response::Yes;
|
||||
if(response == QMessageBox::No) return MessageWindow::Response::No;
|
||||
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
|
||||
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
|
||||
return MessageWindow::Response::Ok;
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::information(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::question(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::warning(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
return MessageWindow_response(
|
||||
buttons, QMessageBox::critical(&parent != &Window::None ? parent.window : 0, " ", text, MessageWindow_buttons(buttons))
|
||||
);
|
||||
}
|
6
bsnes/phoenix/qt/object.cpp
Executable file
6
bsnes/phoenix/qt/object.cpp
Executable file
@ -0,0 +1,6 @@
|
||||
void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
object = new Object::Data(*this);
|
||||
}
|
16
bsnes/phoenix/qt/progressbar.cpp
Executable file
16
bsnes/phoenix/qt/progressbar.cpp
Executable file
@ -0,0 +1,16 @@
|
||||
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
progressBar->setParent(parent.window->container);
|
||||
progressBar->setGeometry(x, y, width, height);
|
||||
progressBar->setRange(0, 100);
|
||||
progressBar->setTextVisible(false);
|
||||
progressBar->show();
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
progressBar->setValue(progress);
|
||||
}
|
||||
|
||||
ProgressBar::ProgressBar() {
|
||||
progressBar = new ProgressBar::Data(*this);
|
||||
widget->widget = progressBar;
|
||||
}
|
125
bsnes/phoenix/qt/qt.cpp
Executable file
125
bsnes/phoenix/qt/qt.cpp
Executable file
@ -0,0 +1,125 @@
|
||||
#include <QApplication>
|
||||
#include <QtGui>
|
||||
using namespace nall;
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
#include "qt.moc.hpp"
|
||||
#include "qt.moc"
|
||||
|
||||
#include "object.cpp"
|
||||
#include "font.cpp"
|
||||
#include "menu.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
#include "button.cpp"
|
||||
#include "canvas.cpp"
|
||||
#include "checkbox.cpp"
|
||||
#include "combobox.cpp"
|
||||
#include "editbox.cpp"
|
||||
#include "horizontalslider.cpp"
|
||||
#include "label.cpp"
|
||||
#include "listbox.cpp"
|
||||
#include "progressbar.cpp"
|
||||
#include "radiobox.cpp"
|
||||
#include "textbox.cpp"
|
||||
#include "verticalslider.cpp"
|
||||
#include "viewport.cpp"
|
||||
#include "messagewindow.cpp"
|
||||
|
||||
OS &os = OS::handle();
|
||||
Window Window::None;
|
||||
|
||||
OS& OS::handle() {
|
||||
static OS os;
|
||||
return os;
|
||||
}
|
||||
|
||||
bool OS::pending() {
|
||||
return QApplication::hasPendingEvents();
|
||||
}
|
||||
|
||||
bool OS::run() {
|
||||
QApplication::processEvents();
|
||||
return QApplication::hasPendingEvents();
|
||||
}
|
||||
|
||||
void OS::main() {
|
||||
QApplication::exec();
|
||||
}
|
||||
|
||||
void OS::quit() {
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
unsigned OS::desktopWidth() {
|
||||
return QApplication::desktop()->screenGeometry().width();
|
||||
}
|
||||
|
||||
unsigned OS::desktopHeight() {
|
||||
return QApplication::desktop()->screenGeometry().height();
|
||||
}
|
||||
|
||||
string OS::folderSelect(Window &parent, const char *path) {
|
||||
QString directory = QFileDialog::getExistingDirectory(
|
||||
&parent != &Window::None ? parent.window : 0, "Select Directory", path, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
|
||||
);
|
||||
return directory.toUtf8().constData();
|
||||
}
|
||||
|
||||
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
string filters;
|
||||
lstring list;
|
||||
list.split("\n", filter);
|
||||
foreach(item, list) {
|
||||
lstring part;
|
||||
part.split("\t", item);
|
||||
if(part.size() != 2) continue;
|
||||
part[1].replace(",", " ");
|
||||
filters.append(part[0]);
|
||||
filters.append(" (");
|
||||
filters.append(part[1]);
|
||||
filters.append(");;");
|
||||
}
|
||||
filters.rtrim(";;");
|
||||
|
||||
QString filename = QFileDialog::getOpenFileName(
|
||||
&parent != &Window::None ? parent.window : 0, "Open File", path, (const char*)filters
|
||||
);
|
||||
return filename.toUtf8().constData();
|
||||
}
|
||||
|
||||
string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
string filters;
|
||||
lstring list;
|
||||
list.split("\n", filter);
|
||||
foreach(item, list) {
|
||||
lstring part;
|
||||
part.split("\t", item);
|
||||
if(part.size() != 2) continue;
|
||||
part[1].replace(",", " ");
|
||||
filters.append(part[0]);
|
||||
filters.append(" (");
|
||||
filters.append(part[1]);
|
||||
filters.append(");;");
|
||||
}
|
||||
filters.rtrim(";;");
|
||||
|
||||
QString filename = QFileDialog::getSaveFileName(
|
||||
&parent != &Window::None ? parent.window : 0, "Save File", path, (const char*)filters
|
||||
);
|
||||
return filename.toUtf8().constData();
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
os = new OS::Data(*this);
|
||||
static int argc = 1;
|
||||
static char *argv[2];
|
||||
argv[0] = new char[8];
|
||||
argv[1] = 0;
|
||||
strcpy(argv[0], "phoenix");
|
||||
char **argvp = argv;
|
||||
os->application = new QApplication(argc, argvp);
|
||||
}
|
||||
|
||||
}
|
325
bsnes/phoenix/qt/qt.hpp
Executable file
325
bsnes/phoenix/qt/qt.hpp
Executable file
@ -0,0 +1,325 @@
|
||||
namespace phoenix {
|
||||
|
||||
struct Window;
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
Object& operator=(const Object&) = delete;
|
||||
Object(const Object&) = delete;
|
||||
//private:
|
||||
virtual void unused();
|
||||
struct Data;
|
||||
Data *object;
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *font;
|
||||
};
|
||||
|
||||
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
|
||||
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
|
||||
|
||||
struct Action : Object {
|
||||
virtual bool visible() = 0;
|
||||
virtual void setVisible(bool visible = true) = 0;
|
||||
virtual bool enabled() = 0;
|
||||
virtual void setEnabled(bool enabled = true) = 0;
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
Menu();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *menu;
|
||||
};
|
||||
|
||||
struct MenuSeparator : Action {
|
||||
void create(Menu &parent);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
MenuSeparator();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *menuSeparator;
|
||||
};
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
MenuItem();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *menuItem;
|
||||
};
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
MenuCheckItem();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *menuCheckItem;
|
||||
};
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
void setChecked();
|
||||
MenuRadioItem();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *menuRadioItem;
|
||||
};
|
||||
|
||||
struct Widget : Object {
|
||||
virtual void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
virtual void setFont(Font &font);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool focused();
|
||||
void setFocused();
|
||||
Widget();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *widget;
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setFont(Font &font);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
Button();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *button;
|
||||
};
|
||||
|
||||
struct Canvas : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uint32_t* buffer();
|
||||
void redraw();
|
||||
Canvas();
|
||||
~Canvas();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *canvas;
|
||||
};
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
CheckBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *checkBox;
|
||||
};
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned row);
|
||||
ComboBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *comboBox;
|
||||
};
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
EditBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *editBox;
|
||||
};
|
||||
|
||||
struct HorizontalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
HorizontalSlider();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *horizontalSlider;
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
Label();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *label;
|
||||
};
|
||||
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *listBox;
|
||||
};
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setProgress(unsigned progress);
|
||||
ProgressBar();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *progressBar;
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
RadioBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *radioBox;
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setEditable(bool editable = true);
|
||||
nall::string text();
|
||||
void setText(const char *text);
|
||||
TextBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *textBox;
|
||||
};
|
||||
|
||||
struct VerticalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
VerticalSlider();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *verticalSlider;
|
||||
};
|
||||
|
||||
struct Viewport : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uintptr_t handle();
|
||||
Viewport();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *viewport;
|
||||
};
|
||||
|
||||
struct MessageWindow : Object {
|
||||
enum class Buttons : unsigned {
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo,
|
||||
};
|
||||
enum class Response : unsigned {
|
||||
Ok,
|
||||
Cancel,
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
bool 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 = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
struct Data;
|
||||
Data *os;
|
||||
private:
|
||||
OS();
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
}
|
304
bsnes/phoenix/qt/qt.moc.hpp
Executable file
304
bsnes/phoenix/qt/qt.moc.hpp
Executable file
@ -0,0 +1,304 @@
|
||||
struct Object::Data {
|
||||
public:
|
||||
Object &self;
|
||||
bool locked;
|
||||
|
||||
Data(Object &self) : self(self) {
|
||||
locked = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Font::Data : public QFont {
|
||||
public:
|
||||
Font &self;
|
||||
|
||||
Data(Font &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Menu::Data : public QMenu {
|
||||
public:
|
||||
Menu &self;
|
||||
|
||||
Data(Menu &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct MenuSeparator::Data {
|
||||
public:
|
||||
MenuSeparator &self;
|
||||
QAction *action;
|
||||
|
||||
Data(MenuSeparator &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct MenuItem::Data : public QAction {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MenuItem &self;
|
||||
|
||||
Data(MenuItem &self) : self(self), QAction(0) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onTick() {
|
||||
if(self.onTick) self.onTick();
|
||||
}
|
||||
};
|
||||
|
||||
struct MenuCheckItem::Data : public QAction {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MenuCheckItem &self;
|
||||
|
||||
Data(MenuCheckItem &self) : self(self), QAction(0) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onTick() {
|
||||
if(self.onTick) self.onTick();
|
||||
}
|
||||
};
|
||||
|
||||
struct MenuRadioItem::Data : public QAction {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MenuRadioItem &self;
|
||||
Menu *parent;
|
||||
QActionGroup *actionGroup;
|
||||
|
||||
Data(MenuRadioItem &self) : self(self), QAction(0) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onTick() {
|
||||
if(self.object->locked == false && self.onTick && self.checked()) self.onTick();
|
||||
}
|
||||
};
|
||||
|
||||
struct Widget::Data {
|
||||
public:
|
||||
Widget &self;
|
||||
QWidget *widget;
|
||||
|
||||
Data(Widget &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Window::Data : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window &self;
|
||||
QFont *defaultFont;
|
||||
QVBoxLayout *layout;
|
||||
QMenuBar *menuBar;
|
||||
QWidget *container;
|
||||
QStatusBar *statusBar;
|
||||
|
||||
void closeEvent(QCloseEvent *event) {
|
||||
if(self.onClose) {
|
||||
bool result = self.onClose();
|
||||
if(result == false) event->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
Data(Window &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Button::Data : public QPushButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Button &self;
|
||||
|
||||
Data(Button &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onTick() {
|
||||
if(self.onTick) self.onTick();
|
||||
}
|
||||
};
|
||||
|
||||
struct Canvas::Data : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Canvas &self;
|
||||
QImage *image;
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
||||
Data(Canvas &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct CheckBox::Data : public QCheckBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CheckBox &self;
|
||||
|
||||
Data(CheckBox &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onTick() {
|
||||
if(self.onTick) self.onTick();
|
||||
}
|
||||
};
|
||||
|
||||
struct ComboBox::Data : public QComboBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ComboBox &self;
|
||||
|
||||
Data(ComboBox &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
struct EditBox::Data : public QTextEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditBox &self;
|
||||
|
||||
Data(EditBox &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
struct HorizontalSlider::Data : public QSlider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HorizontalSlider &self;
|
||||
|
||||
Data(HorizontalSlider &self) : self(self), QSlider(Qt::Horizontal) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
struct Label::Data : public QLabel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Label &self;
|
||||
|
||||
Data(Label &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct ListBox::Data : public QTreeWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ListBox &self;
|
||||
|
||||
Data(ListBox &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onActivate() {
|
||||
if(self.object->locked == false && self.onActivate) self.onActivate();
|
||||
}
|
||||
|
||||
void onChange() {
|
||||
if(self.object->locked == false && self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
struct ProgressBar::Data : public QProgressBar {
|
||||
public:
|
||||
ProgressBar &self;
|
||||
|
||||
Data(ProgressBar &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct RadioBox::Data : public QRadioButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RadioBox &self;
|
||||
Window *parent;
|
||||
QButtonGroup *buttonGroup;
|
||||
|
||||
Data(RadioBox &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onTick() {
|
||||
if(self.onTick && self.checked()) self.onTick();
|
||||
}
|
||||
};
|
||||
|
||||
struct TextBox::Data : public QLineEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TextBox &self;
|
||||
|
||||
Data(TextBox &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
struct VerticalSlider::Data : public QSlider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VerticalSlider &self;
|
||||
|
||||
Data(VerticalSlider &self) : self(self), QSlider(Qt::Vertical) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
void onChange() {
|
||||
if(self.onChange) self.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
struct Viewport::Data : public QWidget {
|
||||
public:
|
||||
Viewport &self;
|
||||
|
||||
Data(Viewport &self) : self(self) {
|
||||
}
|
||||
};
|
||||
|
||||
struct OS::Data : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OS &self;
|
||||
QApplication *application;
|
||||
|
||||
Data(OS &self) : self(self) {
|
||||
}
|
||||
|
||||
public slots:
|
||||
};
|
37
bsnes/phoenix/qt/radiobox.cpp
Executable file
37
bsnes/phoenix/qt/radiobox.cpp
Executable file
@ -0,0 +1,37 @@
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
radioBox->parent = &parent;
|
||||
radioBox->buttonGroup = new QButtonGroup;
|
||||
radioBox->buttonGroup->addButton(radioBox);
|
||||
radioBox->setParent(radioBox->parent->window->container);
|
||||
radioBox->setGeometry(x, y, width, height);
|
||||
radioBox->setText(text);
|
||||
radioBox->setChecked(true);
|
||||
if(parent.window->defaultFont) radioBox->setFont(*parent.window->defaultFont);
|
||||
radioBox->show();
|
||||
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));
|
||||
}
|
||||
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
radioBox->parent = parent.radioBox->parent;
|
||||
radioBox->buttonGroup = parent.radioBox->buttonGroup;
|
||||
radioBox->buttonGroup->addButton(radioBox);
|
||||
radioBox->setParent(radioBox->parent->window->container);
|
||||
radioBox->setGeometry(x, y, width, height);
|
||||
radioBox->setText(text);
|
||||
if(radioBox->parent->window->defaultFont) radioBox->setFont(*radioBox->parent->window->defaultFont);
|
||||
radioBox->show();
|
||||
radioBox->connect(radioBox, SIGNAL(toggled(bool)), SLOT(onTick()));
|
||||
}
|
||||
|
||||
bool RadioBox::checked() {
|
||||
return radioBox->isChecked();
|
||||
}
|
||||
|
||||
void RadioBox::setChecked() {
|
||||
radioBox->setChecked(true);
|
||||
}
|
||||
|
||||
RadioBox::RadioBox() {
|
||||
radioBox = new RadioBox::Data(*this);
|
||||
widget->widget = radioBox;
|
||||
}
|
25
bsnes/phoenix/qt/textbox.cpp
Executable file
25
bsnes/phoenix/qt/textbox.cpp
Executable file
@ -0,0 +1,25 @@
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
textBox->setParent(parent.window->container);
|
||||
textBox->setGeometry(x, y, width, height);
|
||||
textBox->setText(text);
|
||||
if(parent.window->defaultFont) textBox->setFont(*parent.window->defaultFont);
|
||||
textBox->show();
|
||||
textBox->connect(textBox, SIGNAL(textEdited(const QString&)), SLOT(onChange()));
|
||||
}
|
||||
|
||||
void TextBox::setEditable(bool editable) {
|
||||
textBox->setReadOnly(editable == false);
|
||||
}
|
||||
|
||||
string TextBox::text() {
|
||||
return textBox->text().toUtf8().constData();
|
||||
}
|
||||
|
||||
void TextBox::setText(const char *text) {
|
||||
textBox->setText(text);
|
||||
}
|
||||
|
||||
TextBox::TextBox() {
|
||||
textBox = new TextBox::Data(*this);
|
||||
widget->widget = textBox;
|
||||
}
|
24
bsnes/phoenix/qt/verticalslider.cpp
Executable file
24
bsnes/phoenix/qt/verticalslider.cpp
Executable file
@ -0,0 +1,24 @@
|
||||
void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
|
||||
length += (length == 0);
|
||||
verticalSlider->setParent(parent.window->container);
|
||||
verticalSlider->setGeometry(x, y, width, height);
|
||||
verticalSlider->setInvertedAppearance(true);
|
||||
verticalSlider->setInvertedControls(true);
|
||||
verticalSlider->setRange(0, length - 1);
|
||||
verticalSlider->setPageStep(length >> 3);
|
||||
verticalSlider->connect(verticalSlider, SIGNAL(valueChanged(int)), SLOT(onChange()));
|
||||
verticalSlider->show();
|
||||
}
|
||||
|
||||
unsigned VerticalSlider::position() {
|
||||
return verticalSlider->value();
|
||||
}
|
||||
|
||||
void VerticalSlider::setPosition(unsigned position) {
|
||||
verticalSlider->setValue(position);
|
||||
}
|
||||
|
||||
VerticalSlider::VerticalSlider() {
|
||||
verticalSlider = new VerticalSlider::Data(*this);
|
||||
widget->widget = verticalSlider;
|
||||
}
|
14
bsnes/phoenix/qt/viewport.cpp
Executable file
14
bsnes/phoenix/qt/viewport.cpp
Executable file
@ -0,0 +1,14 @@
|
||||
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
viewport->setParent(parent.window->container);
|
||||
viewport->setGeometry(x, y, width, height);
|
||||
viewport->show();
|
||||
}
|
||||
|
||||
uintptr_t Viewport::handle() {
|
||||
return (uintptr_t)viewport->winId();
|
||||
}
|
||||
|
||||
Viewport::Viewport() {
|
||||
viewport = new Viewport::Data(*this);
|
||||
widget->widget = viewport;
|
||||
}
|
35
bsnes/phoenix/qt/widget.cpp
Executable file
35
bsnes/phoenix/qt/widget.cpp
Executable file
@ -0,0 +1,35 @@
|
||||
void Widget::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
widget->widget->setGeometry(x, y, width, height);
|
||||
}
|
||||
|
||||
void Widget::setFont(Font &font) {
|
||||
widget->widget->setFont(*font.font);
|
||||
}
|
||||
|
||||
bool Widget::visible() {
|
||||
return widget->widget->isVisible();
|
||||
}
|
||||
|
||||
void Widget::setVisible(bool visible) {
|
||||
widget->widget->setVisible(visible);
|
||||
}
|
||||
|
||||
bool Widget::enabled() {
|
||||
return widget->widget->isEnabled();
|
||||
}
|
||||
|
||||
void Widget::setEnabled(bool enabled) {
|
||||
widget->widget->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool Widget::focused() {
|
||||
return widget->widget->hasFocus();
|
||||
}
|
||||
|
||||
void Widget::setFocused() {
|
||||
widget->widget->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
Widget::Widget() {
|
||||
widget = new Widget::Data(*this);
|
||||
}
|
64
bsnes/phoenix/qt/window.cpp
Executable file
64
bsnes/phoenix/qt/window.cpp
Executable file
@ -0,0 +1,64 @@
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
window->setWindowTitle(text);
|
||||
window->move(x, y);
|
||||
|
||||
window->layout = new QVBoxLayout;
|
||||
window->layout->setMargin(0);
|
||||
window->layout->setSpacing(0);
|
||||
window->layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
window->setLayout(window->layout);
|
||||
|
||||
window->menuBar = new QMenuBar;
|
||||
window->menuBar->hide();
|
||||
window->layout->addWidget(window->menuBar);
|
||||
|
||||
window->container = new QWidget;
|
||||
window->container->setFixedSize(width, height);
|
||||
window->layout->addWidget(window->container);
|
||||
|
||||
window->statusBar = new QStatusBar;
|
||||
window->statusBar->setSizeGripEnabled(false);
|
||||
window->layout->addWidget(window->statusBar);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
window->container->setFixedSize(width, height);
|
||||
window->move(x, y);
|
||||
}
|
||||
|
||||
void Window::setFont(Font &font) {
|
||||
window->defaultFont = font.font;
|
||||
window->menuBar->setFont(*font.font);
|
||||
window->statusBar->setFont(*font.font);
|
||||
}
|
||||
|
||||
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Window, QColor(red, green, blue));
|
||||
window->setPalette(palette);
|
||||
window->setAutoFillBackground(true);
|
||||
}
|
||||
|
||||
void Window::setTitle(const char *text) {
|
||||
window->setWindowTitle(text);
|
||||
}
|
||||
|
||||
void Window::setStatusText(const char *text) {
|
||||
window->statusBar->showMessage(text, 0);
|
||||
}
|
||||
|
||||
void Window::setMenuVisible(bool visible) {
|
||||
if(visible) window->menuBar->show();
|
||||
else window->menuBar->hide();
|
||||
}
|
||||
|
||||
void Window::setStatusVisible(bool visible) {
|
||||
if(visible) window->statusBar->show();
|
||||
else window->statusBar->hide();
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data(*this);
|
||||
window->defaultFont = 0;
|
||||
widget->widget = window;
|
||||
}
|
10
bsnes/phoenix/windows/button.cpp
Executable file
10
bsnes/phoenix/windows/button.cpp
Executable file
@ -0,0 +1,10 @@
|
||||
void Button::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindow(
|
||||
L"BUTTON", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE,
|
||||
x, y, width, height,
|
||||
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);
|
||||
}
|
44
bsnes/phoenix/windows/canvas.cpp
Executable file
44
bsnes/phoenix/windows/canvas.cpp
Executable file
@ -0,0 +1,44 @@
|
||||
void Canvas::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
canvas->buffer = new uint32_t[width * height]();
|
||||
canvas->pitch = width * sizeof(uint32_t);
|
||||
canvas->width = width;
|
||||
canvas->height = height;
|
||||
memset(&canvas->bmi, 0, sizeof(BITMAPINFO));
|
||||
canvas->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
canvas->bmi.bmiHeader.biPlanes = 1;
|
||||
canvas->bmi.bmiHeader.biBitCount = 32;
|
||||
canvas->bmi.bmiHeader.biCompression = BI_RGB;
|
||||
canvas->bmi.bmiHeader.biWidth = width;
|
||||
canvas->bmi.bmiHeader.biHeight = -height; //GDI stores bitmaps upside down; negative height flips bitmap
|
||||
canvas->bmi.bmiHeader.biSizeImage = canvas->pitch * canvas->height;
|
||||
|
||||
widget->window = CreateWindow(
|
||||
L"phoenix_window", L"",
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
x, y, width, height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
}
|
||||
|
||||
uint32_t* Canvas::buffer() {
|
||||
return canvas->buffer;
|
||||
}
|
||||
|
||||
void Canvas::redraw() {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(widget->window, &ps);
|
||||
SetDIBitsToDevice(ps.hdc, 0, 0, canvas->width, canvas->height, 0, 0, 0, canvas->height, (void*)canvas->buffer, &canvas->bmi, DIB_RGB_COLORS);
|
||||
EndPaint(widget->window, &ps);
|
||||
InvalidateRect(widget->window, 0, false);
|
||||
}
|
||||
|
||||
Canvas::Canvas() {
|
||||
canvas = new Canvas::Data;
|
||||
canvas->buffer = 0;
|
||||
}
|
||||
|
||||
Canvas::~Canvas() {
|
||||
delete[] canvas->buffer;
|
||||
delete canvas;
|
||||
}
|
18
bsnes/phoenix/windows/checkbox.cpp
Executable file
18
bsnes/phoenix/windows/checkbox.cpp
Executable file
@ -0,0 +1,18 @@
|
||||
void CheckBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindow(
|
||||
L"BUTTON", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
|
||||
x, y, width, height,
|
||||
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);
|
||||
}
|
||||
|
||||
bool CheckBox::checked() {
|
||||
return SendMessage(widget->window, BM_GETCHECK, 0, 0);
|
||||
}
|
||||
|
||||
void CheckBox::setChecked(bool checked) {
|
||||
SendMessage(widget->window, BM_SETCHECK, (WPARAM)checked, 0);
|
||||
}
|
46
bsnes/phoenix/windows/combobox.cpp
Executable file
46
bsnes/phoenix/windows/combobox.cpp
Executable file
@ -0,0 +1,46 @@
|
||||
void ComboBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindowEx(
|
||||
0, L"COMBOBOX", L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
x, y, width, 200,
|
||||
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);
|
||||
|
||||
//CreateWindow height parameter is the height of the expanded list box;
|
||||
//need additional code to override default ComboBox control height
|
||||
RECT rc;
|
||||
GetWindowRect(widget->window, &rc);
|
||||
unsigned adjustedHeight = height - ((rc.bottom - rc.top) - SendMessage(widget->window, CB_GETITEMHEIGHT, (WPARAM)-1, 0));
|
||||
SendMessage(widget->window, CB_SETITEMHEIGHT, (WPARAM)-1, adjustedHeight);
|
||||
|
||||
if(*text) {
|
||||
lstring list;
|
||||
list.split("\n", text);
|
||||
foreach(item, list) addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::reset() {
|
||||
SendMessage(widget->window, CB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
void ComboBox::addItem(const char *text) {
|
||||
SendMessage(widget->window, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16_t(text));
|
||||
if(SendMessage(widget->window, CB_GETCOUNT, 0, 0) == 1) setSelection(0);
|
||||
}
|
||||
|
||||
unsigned ComboBox::selection() {
|
||||
return SendMessage(widget->window, CB_GETCURSEL, 0, 0);
|
||||
}
|
||||
|
||||
void ComboBox::setSelection(unsigned row) {
|
||||
SendMessage(widget->window, CB_SETCURSEL, comboBox->selection = row, 0);
|
||||
}
|
||||
|
||||
ComboBox::ComboBox() {
|
||||
comboBox = new ComboBox::Data;
|
||||
comboBox->selection = 0;
|
||||
}
|
51
bsnes/phoenix/windows/editbox.cpp
Executable file
51
bsnes/phoenix/windows/editbox.cpp
Executable file
@ -0,0 +1,51 @@
|
||||
void EditBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE, L"EDIT", L"",
|
||||
WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN |
|
||||
(editBox->wordWrap == false ? ES_AUTOHSCROLL : 0),
|
||||
editBox->x = x, editBox->y = y, editBox->width = width, editBox->height = height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
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);
|
||||
}
|
||||
|
||||
string EditBox::getText() {
|
||||
unsigned length = SendMessage(widget->window, WM_GETTEXTLENGTH, 0, 0);
|
||||
wchar_t buffer[length + 1];
|
||||
GetWindowText(widget->window, buffer, length + 1);
|
||||
buffer[length] = 0;
|
||||
string text = utf8_t(buffer);
|
||||
text.replace("\r", "");
|
||||
return text;
|
||||
}
|
||||
|
||||
void EditBox::setText(const char *text) {
|
||||
string output = text;
|
||||
output.replace("\r", "");
|
||||
output.replace("\n", "\r\n");
|
||||
SetWindowText(widget->window, utf16_t(output));
|
||||
}
|
||||
|
||||
void EditBox::setEditable(bool editable) {
|
||||
SendMessage(widget->window, EM_SETREADONLY, editable == false, (LPARAM)0);
|
||||
}
|
||||
|
||||
void EditBox::setWordWrap(bool wordWrap) {
|
||||
editBox->wordWrap = wordWrap;
|
||||
if(widget->window == 0) return;
|
||||
|
||||
//ES_AUTOSCROLL options cannot be changed after control has been created;
|
||||
//so destroy the control and recreate it with desired options
|
||||
HWND hparent = GetParent(widget->window);
|
||||
Window *parent = (Window*)GetWindowLongPtr(hparent, GWLP_USERDATA);
|
||||
string text = getText();
|
||||
DestroyWindow(widget->window);
|
||||
create(*parent, editBox->x, editBox->y, editBox->width, editBox->height, text);
|
||||
}
|
||||
|
||||
EditBox::EditBox() {
|
||||
editBox = new EditBox::Data;
|
||||
editBox->wordWrap = true;
|
||||
}
|
26
bsnes/phoenix/windows/font.cpp
Executable file
26
bsnes/phoenix/windows/font.cpp
Executable file
@ -0,0 +1,26 @@
|
||||
static HFONT Font_createFont(const char *name, unsigned size, bool bold, bool italic) {
|
||||
return CreateFont(
|
||||
-(size * 96.0 / 72.0 + 0.5),
|
||||
0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0,
|
||||
utf16_t(name)
|
||||
);
|
||||
}
|
||||
|
||||
bool Font::create(const char *name, unsigned size, Font::Style style) {
|
||||
font->font = Font_createFont(
|
||||
name, size,
|
||||
(style & Font::Style::Bold) == Font::Style::Bold,
|
||||
(style & Font::Style::Italic) == Font::Style::Italic
|
||||
);
|
||||
return font->font;
|
||||
}
|
||||
|
||||
Font::Font() {
|
||||
font = new Font::Data;
|
||||
font->font = 0;
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
if(font->font) DeleteObject(font->font);
|
||||
delete font;
|
||||
}
|
25
bsnes/phoenix/windows/horizontalslider.cpp
Executable file
25
bsnes/phoenix/windows/horizontalslider.cpp
Executable file
@ -0,0 +1,25 @@
|
||||
void HorizontalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
|
||||
length += (length == 0);
|
||||
widget->window = CreateWindow(
|
||||
TRACKBAR_CLASS, L"",
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ,
|
||||
x, y, width, height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1));
|
||||
SendMessage(widget->window, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3));
|
||||
setPosition(0);
|
||||
}
|
||||
|
||||
unsigned HorizontalSlider::position() {
|
||||
return SendMessage(widget->window, TBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void HorizontalSlider::setPosition(unsigned position) {
|
||||
SendMessage(widget->window, TBM_SETPOS, (WPARAM)true, (LPARAM)(horizontalSlider->position = position));
|
||||
}
|
||||
|
||||
HorizontalSlider::HorizontalSlider() {
|
||||
horizontalSlider = new HorizontalSlider::Data;
|
||||
}
|
15
bsnes/phoenix/windows/label.cpp
Executable file
15
bsnes/phoenix/windows/label.cpp
Executable file
@ -0,0 +1,15 @@
|
||||
void Label::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindow(
|
||||
L"STATIC", L"",
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
x, y, width, height,
|
||||
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);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
void Label::setText(const char *text) {
|
||||
SetWindowText(widget->window, utf16_t(text));
|
||||
}
|
88
bsnes/phoenix/windows/listbox.cpp
Executable file
88
bsnes/phoenix/windows/listbox.cpp
Executable file
@ -0,0 +1,88 @@
|
||||
void ListBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
|
||||
LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER,
|
||||
x, y, width, height,
|
||||
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);
|
||||
ListView_SetExtendedListViewStyle(widget->window, LVS_EX_FULLROWSELECT);
|
||||
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
listBox->columns = list.size();
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
LVCOLUMN column;
|
||||
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
|
||||
column.fmt = LVCFMT_LEFT;
|
||||
column.iSubItem = list.size();
|
||||
utf16_t text(list[i]);
|
||||
column.pszText = text;
|
||||
ListView_InsertColumn(widget->window, i, &column);
|
||||
}
|
||||
resizeColumnsToContent();
|
||||
}
|
||||
|
||||
void ListBox::setHeaderVisible(bool headerVisible) {
|
||||
SetWindowLong(
|
||||
widget->window,
|
||||
GWL_STYLE,
|
||||
(GetWindowLong(widget->window, GWL_STYLE) & ~LVS_NOCOLUMNHEADER) |
|
||||
(headerVisible == false ? LVS_NOCOLUMNHEADER : 0)
|
||||
);
|
||||
}
|
||||
|
||||
void ListBox::resizeColumnsToContent() {
|
||||
for(unsigned i = 0; i < listBox->columns; i++) {
|
||||
ListView_SetColumnWidth(widget->window, i, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::addItem(const char *text) {
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
LVITEM item;
|
||||
unsigned row = ListView_GetItemCount(widget->window);
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = row;
|
||||
item.iSubItem = 0;
|
||||
utf16_t wtext(list[0]);
|
||||
item.pszText = wtext;
|
||||
ListView_InsertItem(widget->window, &item);
|
||||
for(unsigned i = 1; i < list.size(); i++) {
|
||||
utf16_t wtext(list[i]);
|
||||
ListView_SetItemText(widget->window, row, i, wtext);
|
||||
}
|
||||
}
|
||||
|
||||
void ListBox::setItem(unsigned row, const char *text) {
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
utf16_t wtext(list[i]);
|
||||
ListView_SetItemText(widget->window, row, i, wtext);
|
||||
}
|
||||
}
|
||||
|
||||
optional<unsigned> ListBox::selection() {
|
||||
unsigned count = ListView_GetItemCount(widget->window);
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
if(ListView_GetItemState(widget->window, i, LVIS_SELECTED)) return { true, i };
|
||||
}
|
||||
return { false, 0 };
|
||||
}
|
||||
|
||||
void ListBox::setSelection(unsigned row) {
|
||||
unsigned count = ListView_GetItemCount(widget->window);
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
ListView_SetItemState(widget->window, i, LVIS_FOCUSED, (i == row ? LVIS_FOCUSED : 0));
|
||||
ListView_SetItemState(widget->window, i, LVIS_SELECTED, (i == row ? LVIS_SELECTED : 0));
|
||||
}
|
||||
}
|
||||
|
||||
ListBox::ListBox() {
|
||||
listBox = new ListBox::Data;
|
||||
listBox->lostFocus = false;
|
||||
}
|
144
bsnes/phoenix/windows/menu.cpp
Executable file
144
bsnes/phoenix/windows/menu.cpp
Executable file
@ -0,0 +1,144 @@
|
||||
Action::Action() {
|
||||
os.objects.append(this);
|
||||
action = new Action::Data;
|
||||
}
|
||||
|
||||
void Menu::create(Window &parent, const char *text) {
|
||||
action->parentMenu = parent.window->menu;
|
||||
action->menu = CreatePopupMenu();
|
||||
AppendMenu(parent.window->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
|
||||
}
|
||||
|
||||
void Menu::create(Menu &parent, const char *text) {
|
||||
action->parentMenu = parent.action->menu;
|
||||
action->menu = CreatePopupMenu();
|
||||
AppendMenu(parent.action->menu, MF_STRING | MF_POPUP, (UINT_PTR)action->menu, utf16_t(text));
|
||||
}
|
||||
|
||||
bool Menu::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parentMenu, (UINT_PTR)action->menu, false, &info);
|
||||
return (info.fState & MFS_GRAYED) == 0;
|
||||
}
|
||||
|
||||
void Menu::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parentMenu, (UINT_PTR)action->menu, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void MenuSeparator::create(Menu &parent) {
|
||||
action->parent = &parent;
|
||||
AppendMenu(parent.action->menu, MF_SEPARATOR, object->id, L"");
|
||||
}
|
||||
|
||||
bool MenuSeparator::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
|
||||
return (info.fState & MFS_GRAYED) == 0;
|
||||
}
|
||||
|
||||
void MenuSeparator::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void MenuItem::create(Menu &parent, const char *text) {
|
||||
action->parent = &parent;
|
||||
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
|
||||
}
|
||||
|
||||
bool MenuItem::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
|
||||
return (info.fState & MFS_GRAYED) == 0;
|
||||
}
|
||||
|
||||
void MenuItem::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void MenuCheckItem::create(Menu &parent, const char *text) {
|
||||
action->parent = &parent;
|
||||
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
|
||||
}
|
||||
|
||||
bool MenuCheckItem::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
|
||||
return (info.fState & MFS_GRAYED) == 0;
|
||||
}
|
||||
|
||||
void MenuCheckItem::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
bool MenuCheckItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
|
||||
return info.fState & MFS_CHECKED;
|
||||
}
|
||||
|
||||
void MenuCheckItem::setChecked(bool checked) {
|
||||
CheckMenuItem(action->parent->action->menu, object->id, checked ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(Menu &parent, const char *text) {
|
||||
action->parent = &parent;
|
||||
action->radioParent = this;
|
||||
action->items.append(this);
|
||||
AppendMenu(parent.action->menu, MF_STRING, object->id, utf16_t(text));
|
||||
setChecked();
|
||||
}
|
||||
|
||||
void MenuRadioItem::create(MenuRadioItem &parent, const char *text) {
|
||||
action->parent = parent.action->parent;
|
||||
action->radioParent = parent.action->radioParent;
|
||||
action->radioParent->action->items.append(this);
|
||||
AppendMenu(action->parent->action->menu, MF_STRING, object->id, utf16_t(text));
|
||||
}
|
||||
|
||||
bool MenuRadioItem::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
|
||||
return (info.fState & MFS_GRAYED) == 0;
|
||||
}
|
||||
|
||||
void MenuRadioItem::setEnabled(bool enabled) {
|
||||
EnableMenuItem(action->parent->action->menu, object->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
bool MenuRadioItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof(MENUITEMINFO));
|
||||
info.cbSize = sizeof(MENUITEMINFO);
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(action->parent->action->menu, object->id, false, &info);
|
||||
return info.fState & MFS_CHECKED;
|
||||
}
|
||||
|
||||
void MenuRadioItem::setChecked() {
|
||||
MenuRadioItem *parent = action->radioParent;
|
||||
foreach(item, parent->action->items) {
|
||||
CheckMenuRadioItem(
|
||||
action->parent->action->menu,
|
||||
item->object->id, item->object->id, item->object->id + (item != this),
|
||||
MF_BYCOMMAND
|
||||
);
|
||||
}
|
||||
}
|
41
bsnes/phoenix/windows/messagewindow.cpp
Executable file
41
bsnes/phoenix/windows/messagewindow.cpp
Executable file
@ -0,0 +1,41 @@
|
||||
static MessageWindow::Response MessageWindow_response(MessageWindow::Buttons buttons, UINT response) {
|
||||
if(response == IDOK) return MessageWindow::Response::Ok;
|
||||
if(response == IDCANCEL) return MessageWindow::Response::Cancel;
|
||||
if(response == IDYES) return MessageWindow::Response::Yes;
|
||||
if(response == IDNO) return MessageWindow::Response::No;
|
||||
if(buttons == MessageWindow::Buttons::OkCancel) return MessageWindow::Response::Cancel;
|
||||
if(buttons == MessageWindow::Buttons::YesNo) return MessageWindow::Response::No;
|
||||
return MessageWindow::Response::Ok;
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::information(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONINFORMATION;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::question(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONQUESTION;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::warning(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONWARNING;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
||||
|
||||
MessageWindow::Response MessageWindow::critical(Window &parent, const char *text, MessageWindow::Buttons buttons) {
|
||||
UINT flags = MB_ICONERROR;
|
||||
if(buttons == Buttons::Ok) flags |= MB_OK;
|
||||
if(buttons == Buttons::OkCancel) flags |= MB_OKCANCEL;
|
||||
if(buttons == Buttons::YesNo) flags |= MB_YESNO;
|
||||
return MessageWindow_response(buttons, MessageBox(&parent != &Window::None ? parent.widget->window : 0, utf16_t(text), L"", flags));
|
||||
}
|
82
bsnes/phoenix/windows/object.cpp
Executable file
82
bsnes/phoenix/windows/object.cpp
Executable file
@ -0,0 +1,82 @@
|
||||
struct Object::Data {
|
||||
unsigned id;
|
||||
};
|
||||
|
||||
struct Font::Data {
|
||||
HFONT font;
|
||||
};
|
||||
|
||||
struct Action::Data {
|
||||
Menu *parent;
|
||||
HMENU parentMenu;
|
||||
HMENU menu;
|
||||
MenuRadioItem *radioParent;
|
||||
array<MenuRadioItem*> items;
|
||||
};
|
||||
|
||||
struct Widget::Data {
|
||||
HWND window;
|
||||
};
|
||||
|
||||
struct Window::Data {
|
||||
HFONT defaultFont;
|
||||
HBRUSH brush;
|
||||
COLORREF brushColor;
|
||||
HMENU menu;
|
||||
HWND status;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
||||
struct Canvas::Data {
|
||||
uint32_t *buffer;
|
||||
BITMAPINFO bmi;
|
||||
unsigned pitch;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
||||
struct ComboBox::Data {
|
||||
unsigned selection;
|
||||
};
|
||||
|
||||
struct EditBox::Data {
|
||||
bool wordWrap;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
};
|
||||
|
||||
struct HorizontalSlider::Data {
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
struct ListBox::Data {
|
||||
unsigned columns;
|
||||
bool lostFocus;
|
||||
};
|
||||
|
||||
struct RadioBox::Data {
|
||||
Window *parentWindow;
|
||||
RadioBox *parent;
|
||||
array<RadioBox*> items;
|
||||
};
|
||||
|
||||
struct VerticalSlider::Data {
|
||||
unsigned position;
|
||||
};
|
||||
|
||||
struct OS::Data {
|
||||
HFONT proportionalFont;
|
||||
HFONT monospaceFont;
|
||||
};
|
||||
|
||||
void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
static unsigned guid = 100;
|
||||
object = new Object::Data;
|
||||
object->id = guid++;
|
||||
}
|
9
bsnes/phoenix/windows/phoenix.Manifest
Executable file
9
bsnes/phoenix/windows/phoenix.Manifest
Executable file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="phoenix" version="1.0.0.0" processorArchitecture="x86"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
1
bsnes/phoenix/windows/phoenix.rc
Executable file
1
bsnes/phoenix/windows/phoenix.rc
Executable file
@ -0,0 +1 @@
|
||||
1 24 "phoenix.Manifest"
|
18
bsnes/phoenix/windows/progressbar.cpp
Executable file
18
bsnes/phoenix/windows/progressbar.cpp
Executable file
@ -0,0 +1,18 @@
|
||||
void ProgressBar::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
widget->window = CreateWindow(
|
||||
PROGRESS_CLASS, L"",
|
||||
WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
x, y, width, height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SendMessage(widget->window, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendMessage(widget->window, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
|
||||
}
|
||||
|
||||
unsigned ProgressBar::progress() {
|
||||
return SendMessage(widget->window, PBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void ProgressBar::setProgress(unsigned progress) {
|
||||
SendMessage(widget->window, PBM_SETPOS, (WPARAM)progress, 0);
|
||||
}
|
42
bsnes/phoenix/windows/radiobox.cpp
Executable file
42
bsnes/phoenix/windows/radiobox.cpp
Executable file
@ -0,0 +1,42 @@
|
||||
void RadioBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
radioBox->parentWindow = &parent;
|
||||
radioBox->parent = this;
|
||||
radioBox->parent->radioBox->items.append(this);
|
||||
widget->window = CreateWindow(
|
||||
L"BUTTON", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
x, y, width, height,
|
||||
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);
|
||||
setChecked();
|
||||
}
|
||||
|
||||
void RadioBox::create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
radioBox->parentWindow = parent.radioBox->parentWindow;
|
||||
radioBox->parent = parent.radioBox->parent;
|
||||
radioBox->parent->radioBox->items.append(this);
|
||||
widget->window = CreateWindow(
|
||||
L"BUTTON", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
x, y, width, height,
|
||||
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);
|
||||
}
|
||||
|
||||
bool RadioBox::checked() {
|
||||
return SendMessage(widget->window, BM_GETCHECK, 0, 0);
|
||||
}
|
||||
|
||||
void RadioBox::setChecked() {
|
||||
foreach(item, radioBox->parent->radioBox->items) {
|
||||
SendMessage(item->widget->window, BM_SETCHECK, (WPARAM)(item == this), 0);
|
||||
}
|
||||
}
|
||||
|
||||
RadioBox::RadioBox() {
|
||||
radioBox = new RadioBox::Data;
|
||||
}
|
14
bsnes/phoenix/windows/textbox.cpp
Executable file
14
bsnes/phoenix/windows/textbox.cpp
Executable file
@ -0,0 +1,14 @@
|
||||
void TextBox::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE, L"EDIT", utf16_t(text),
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
|
||||
x, y, width, height,
|
||||
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);
|
||||
}
|
||||
|
||||
void TextBox::setEditable(bool editable) {
|
||||
SendMessage(widget->window, EM_SETREADONLY, editable == false, (LPARAM)0);
|
||||
}
|
25
bsnes/phoenix/windows/verticalslider.cpp
Executable file
25
bsnes/phoenix/windows/verticalslider.cpp
Executable file
@ -0,0 +1,25 @@
|
||||
void VerticalSlider::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length) {
|
||||
length += (length == 0);
|
||||
widget->window = CreateWindow(
|
||||
TRACKBAR_CLASS, L"",
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_VERT,
|
||||
x, y, width, height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(widget->window, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1));
|
||||
SendMessage(widget->window, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3));
|
||||
setPosition(0);
|
||||
}
|
||||
|
||||
unsigned VerticalSlider::position() {
|
||||
return SendMessage(widget->window, TBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void VerticalSlider::setPosition(unsigned position) {
|
||||
SendMessage(widget->window, TBM_SETPOS, (WPARAM)true, (LPARAM)(verticalSlider->position = position));
|
||||
}
|
||||
|
||||
VerticalSlider::VerticalSlider() {
|
||||
verticalSlider = new VerticalSlider::Data;
|
||||
}
|
13
bsnes/phoenix/windows/viewport.cpp
Executable file
13
bsnes/phoenix/windows/viewport.cpp
Executable file
@ -0,0 +1,13 @@
|
||||
void Viewport::create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
widget->window = CreateWindow(
|
||||
L"phoenix_window", L"",
|
||||
WS_CHILD | WS_VISIBLE | WS_DISABLED,
|
||||
x, y, width, height,
|
||||
parent.widget->window, (HMENU)object->id, GetModuleHandle(0), 0
|
||||
);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
}
|
||||
|
||||
uintptr_t Viewport::handle() {
|
||||
return (uintptr_t)widget->window;
|
||||
}
|
34
bsnes/phoenix/windows/widget.cpp
Executable file
34
bsnes/phoenix/windows/widget.cpp
Executable file
@ -0,0 +1,34 @@
|
||||
void Widget::setFont(Font &font) {
|
||||
SendMessage(widget->window, WM_SETFONT, (WPARAM)font.font->font, 0);
|
||||
}
|
||||
|
||||
bool Widget::visible() {
|
||||
return GetWindowLong(widget->window, GWL_STYLE) & WS_VISIBLE;
|
||||
}
|
||||
|
||||
void Widget::setVisible(bool visible) {
|
||||
ShowWindow(widget->window, visible ? SW_SHOWNORMAL : SW_HIDE);
|
||||
}
|
||||
|
||||
bool Widget::enabled() {
|
||||
return IsWindowEnabled(widget->window);
|
||||
}
|
||||
|
||||
void Widget::setEnabled(bool enabled) {
|
||||
EnableWindow(widget->window, enabled);
|
||||
}
|
||||
|
||||
bool Widget::focused() {
|
||||
return GetDesktopWindow() == widget->window;
|
||||
}
|
||||
|
||||
void Widget::setFocused() {
|
||||
if(visible() == false) setVisible(true);
|
||||
SetFocus(widget->window);
|
||||
}
|
||||
|
||||
Widget::Widget() {
|
||||
os.objects.append(this);
|
||||
widget = new Widget::Data;
|
||||
widget->window = 0;
|
||||
}
|
81
bsnes/phoenix/windows/window.cpp
Executable file
81
bsnes/phoenix/windows/window.cpp
Executable file
@ -0,0 +1,81 @@
|
||||
void Window::create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text) {
|
||||
widget->window = CreateWindowEx(
|
||||
0, L"phoenix_window", utf16_t(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
x, y, width, height,
|
||||
0, 0, GetModuleHandle(0), 0
|
||||
);
|
||||
window->menu = CreateMenu();
|
||||
window->status = CreateWindowEx(
|
||||
0, STATUSCLASSNAME, L"",
|
||||
WS_CHILD,
|
||||
0, 0, 0, 0,
|
||||
widget->window, 0, GetModuleHandle(0), 0
|
||||
);
|
||||
//StatusBar will be capable of receiving tab focus if it is not disabled
|
||||
SetWindowLongPtr(window->status, GWL_STYLE, GetWindowLong(window->status, GWL_STYLE) | WS_DISABLED);
|
||||
resize(width, height);
|
||||
SetWindowLongPtr(widget->window, GWLP_USERDATA, (LONG_PTR)this);
|
||||
}
|
||||
|
||||
void Window::setFont(Font &font) {
|
||||
window->defaultFont = font.font->font;
|
||||
SendMessage(window->status, WM_SETFONT, (WPARAM)window->defaultFont, 0);
|
||||
}
|
||||
|
||||
void Window::setGeometry(unsigned x, unsigned y, unsigned width, unsigned height) {
|
||||
bool isVisible = visible();
|
||||
if(isVisible) setVisible(false);
|
||||
SetWindowPos(widget->window, NULL, x, y, width, height, SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
resize(width, height);
|
||||
if(isVisible) setVisible(true);
|
||||
}
|
||||
|
||||
void Window::setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue) {
|
||||
if(window->brush) DeleteObject(window->brush);
|
||||
window->brushColor = RGB(red, green, blue);
|
||||
window->brush = CreateSolidBrush(window->brushColor);
|
||||
}
|
||||
|
||||
void Window::setTitle(const char *text) {
|
||||
SetWindowText(widget->window, utf16_t(text));
|
||||
}
|
||||
|
||||
void Window::setStatusText(const char *text) {
|
||||
SendMessage(window->status, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16_t(text));
|
||||
}
|
||||
|
||||
void Window::setMenuVisible(bool visible) {
|
||||
SetMenu(widget->window, visible ? window->menu : 0);
|
||||
resize(window->width, window->height);
|
||||
}
|
||||
|
||||
void Window::setStatusVisible(bool visible) {
|
||||
ShowWindow(window->status, visible ? SW_SHOWNORMAL : SW_HIDE);
|
||||
resize(window->width, window->height);
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
window = new Window::Data;
|
||||
window->defaultFont = 0;
|
||||
window->brush = 0;
|
||||
}
|
||||
|
||||
void Window::resize(unsigned width, unsigned height) {
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
|
||||
SetWindowPos(widget->window, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
|
||||
RECT rc;
|
||||
GetClientRect(widget->window, &rc);
|
||||
width += width - (rc.right - rc.left);
|
||||
height += height - (rc.bottom - rc.top);
|
||||
|
||||
if(GetWindowLongPtr(window->status, GWL_STYLE) & WS_VISIBLE) {
|
||||
GetClientRect(window->status, &rc);
|
||||
height += rc.bottom - rc.top;
|
||||
}
|
||||
|
||||
SetWindowPos(widget->window, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
|
||||
SetWindowPos(window->status, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
}
|
390
bsnes/phoenix/windows/windows.cpp
Executable file
390
bsnes/phoenix/windows/windows.cpp
Executable file
@ -0,0 +1,390 @@
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/utf8.hpp>
|
||||
using namespace nall;
|
||||
|
||||
namespace phoenix {
|
||||
|
||||
#include "object.cpp"
|
||||
#include "font.cpp"
|
||||
#include "menu.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
#include "button.cpp"
|
||||
#include "canvas.cpp"
|
||||
#include "checkbox.cpp"
|
||||
#include "combobox.cpp"
|
||||
#include "editbox.cpp"
|
||||
#include "horizontalslider.cpp"
|
||||
#include "label.cpp"
|
||||
#include "listbox.cpp"
|
||||
#include "progressbar.cpp"
|
||||
#include "radiobox.cpp"
|
||||
#include "textbox.cpp"
|
||||
#include "verticalslider.cpp"
|
||||
#include "viewport.cpp"
|
||||
#include "messagewindow.cpp"
|
||||
|
||||
OS &os = OS::handle();
|
||||
Window Window::None;
|
||||
|
||||
OS& OS::handle() {
|
||||
static OS os;
|
||||
return os;
|
||||
}
|
||||
|
||||
bool OS::pending() {
|
||||
MSG msg;
|
||||
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
bool OS::run() {
|
||||
MSG msg;
|
||||
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
void OS::main() {
|
||||
MSG msg;
|
||||
while(GetMessage(&msg, 0, 0, 0)) {
|
||||
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OS::quit() {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
unsigned OS::desktopWidth() {
|
||||
return GetSystemMetrics(SM_CXSCREEN);
|
||||
}
|
||||
|
||||
unsigned OS::desktopHeight() {
|
||||
return GetSystemMetrics(SM_CYSCREEN);
|
||||
}
|
||||
|
||||
string OS::folderSelect(Window &parent, const char *path) {
|
||||
wchar_t wfilename[PATH_MAX + 1] = L"";
|
||||
BROWSEINFO bi;
|
||||
bi.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
|
||||
bi.pidlRoot = NULL;
|
||||
bi.pszDisplayName = wfilename;
|
||||
bi.lpszTitle = L"";
|
||||
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
|
||||
bi.lpfn = NULL;
|
||||
bi.lParam = 0;
|
||||
bi.iImage = 0;
|
||||
bool result = false;
|
||||
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
|
||||
if(pidl) {
|
||||
if(SHGetPathFromIDList(pidl, wfilename)) {
|
||||
result = true;
|
||||
IMalloc *imalloc = 0;
|
||||
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
|
||||
imalloc->Free(pidl);
|
||||
imalloc->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result == false) return "";
|
||||
return utf8_t(wfilename);
|
||||
}
|
||||
|
||||
string OS::fileOpen(Window &parent, const char *filter, const char *path) {
|
||||
string dir = path;
|
||||
dir.replace("/", "\\");
|
||||
|
||||
string filterInfo;
|
||||
lstring type;
|
||||
type.split("\n", filter);
|
||||
for(unsigned i = 0; i < type.size(); i++) {
|
||||
lstring part;
|
||||
part.split("\t", type[i]);
|
||||
if(part.size() != 2) continue;
|
||||
filterInfo.append(part[0]);
|
||||
filterInfo.append(" (");
|
||||
filterInfo.append(part[1]);
|
||||
filterInfo.append(")\t");
|
||||
part[1].replace(",", ";");
|
||||
filterInfo.append(part[1]);
|
||||
filterInfo.append("\t");
|
||||
}
|
||||
|
||||
utf16_t wfilter(filterInfo);
|
||||
utf16_t wdir(dir);
|
||||
wchar_t wfilename[PATH_MAX] = L"";
|
||||
|
||||
wchar_t *p = wfilter;
|
||||
while(*p != L'\0') {
|
||||
if(*p == L'\t') *p = L'\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
memset(&ofn, 0, sizeof(OPENFILENAME));
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
ofn.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
|
||||
ofn.lpstrFilter = wfilter;
|
||||
ofn.lpstrInitialDir = wdir;
|
||||
ofn.lpstrFile = wfilename;
|
||||
ofn.nMaxFile = PATH_MAX;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
|
||||
ofn.lpstrDefExt = L"";
|
||||
|
||||
bool result = GetOpenFileName(&ofn);
|
||||
if(result == false) return "";
|
||||
return utf8_t(wfilename);
|
||||
}
|
||||
|
||||
string OS::fileSave(Window &parent, const char *filter, const char *path) {
|
||||
string dir = path;
|
||||
dir.replace("/", "\\");
|
||||
|
||||
string filterInfo;
|
||||
lstring type;
|
||||
type.split("\n", filter);
|
||||
for(unsigned i = 0; i < type.size(); i++) {
|
||||
lstring part;
|
||||
part.split("\t", type[i]);
|
||||
if(part.size() != 2) continue;
|
||||
filterInfo.append(part[0]);
|
||||
filterInfo.append(" (");
|
||||
filterInfo.append(part[1]);
|
||||
filterInfo.append(")\t");
|
||||
part[1].replace(",", ";");
|
||||
filterInfo.append(part[1]);
|
||||
filterInfo.append("\t");
|
||||
}
|
||||
|
||||
utf16_t wfilter(filterInfo);
|
||||
utf16_t wdir(dir);
|
||||
wchar_t wfilename[PATH_MAX] = L"";
|
||||
|
||||
wchar_t *p = wfilter;
|
||||
while(*p != L'\0') {
|
||||
if(*p == L'\t') *p = L'\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
memset(&ofn, 0, sizeof(OPENFILENAME));
|
||||
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||
ofn.hwndOwner = &parent != &Window::None ? parent.widget->window : 0;
|
||||
ofn.lpstrFilter = wfilter;
|
||||
ofn.lpstrInitialDir = wdir;
|
||||
ofn.lpstrFile = wfilename;
|
||||
ofn.nMaxFile = PATH_MAX;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
|
||||
ofn.lpstrDefExt = L"";
|
||||
|
||||
bool result = GetSaveFileName(&ofn);
|
||||
if(result == false) return "";
|
||||
return utf8_t(wfilename);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
Window *window_ptr = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(!window_ptr) return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
Window &window = *window_ptr;
|
||||
|
||||
switch(msg) {
|
||||
case WM_CLOSE: {
|
||||
if(window.onClose) return window.onClose();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_ERASEBKGND: {
|
||||
if(window.window->brush == 0) break;
|
||||
RECT rc;
|
||||
GetClientRect(window.widget->window, &rc);
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(window.widget->window, &ps);
|
||||
FillRect(ps.hdc, &rc, window.window->brush);
|
||||
EndPaint(window.widget->window, &ps);
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
case WM_CTLCOLORBTN:
|
||||
case WM_CTLCOLORSTATIC: {
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
|
||||
if(object_ptr && window.window->brush) {
|
||||
HDC hdc = (HDC)wparam;
|
||||
SetBkColor((HDC)wparam, window.window->brushColor);
|
||||
return (INT_PTR)window.window->brush;
|
||||
}
|
||||
}
|
||||
|
||||
case WM_PAINT: {
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<Canvas*>(object_ptr)) {
|
||||
Canvas &canvas = (Canvas&)*object_ptr;
|
||||
canvas.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case WM_COMMAND: {
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.widget->window, id);
|
||||
if(control == 0) {
|
||||
Object *object_ptr = (Object*)os.findObject(id);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<MenuItem*>(object_ptr)) {
|
||||
MenuItem &menuItem = (MenuItem&)*object_ptr;
|
||||
if(menuItem.onTick) menuItem.onTick();
|
||||
} else if(dynamic_cast<MenuCheckItem*>(object_ptr)) {
|
||||
MenuCheckItem &menuCheckItem = (MenuCheckItem&)*object_ptr;
|
||||
menuCheckItem.setChecked(!menuCheckItem.checked());
|
||||
if(menuCheckItem.onTick) menuCheckItem.onTick();
|
||||
} else if(dynamic_cast<MenuRadioItem*>(object_ptr)) {
|
||||
MenuRadioItem &menuRadioItem = (MenuRadioItem&)*object_ptr;
|
||||
if(menuRadioItem.checked() == false) {
|
||||
menuRadioItem.setChecked();
|
||||
if(menuRadioItem.onTick) menuRadioItem.onTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<Button*>(object_ptr)) {
|
||||
Button &button = (Button&)*object_ptr;
|
||||
if(button.onTick) button.onTick();
|
||||
} else if(dynamic_cast<CheckBox*>(object_ptr)) {
|
||||
CheckBox &checkBox = (CheckBox&)*object_ptr;
|
||||
checkBox.setChecked(!checkBox.checked());
|
||||
if(checkBox.onTick) checkBox.onTick();
|
||||
} else if(dynamic_cast<ComboBox*>(object_ptr)) {
|
||||
ComboBox &comboBox = (ComboBox&)*object_ptr;
|
||||
if(HIWORD(wparam) == CBN_SELCHANGE) {
|
||||
if(comboBox.comboBox->selection != comboBox.selection()) {
|
||||
comboBox.comboBox->selection = comboBox.selection();
|
||||
if(comboBox.onChange) comboBox.onChange();
|
||||
}
|
||||
}
|
||||
} else if(dynamic_cast<EditBox*>(object_ptr)) {
|
||||
EditBox &editBox = (EditBox&)*object_ptr;
|
||||
if(HIWORD(wparam) == EN_CHANGE) {
|
||||
if(editBox.onChange) editBox.onChange();
|
||||
}
|
||||
} else if(dynamic_cast<RadioBox*>(object_ptr)) {
|
||||
RadioBox &radioBox = (RadioBox&)*object_ptr;
|
||||
if(radioBox.checked() == false) {
|
||||
radioBox.setChecked();
|
||||
if(radioBox.onTick) radioBox.onTick();
|
||||
}
|
||||
} else if(dynamic_cast<TextBox*>(object_ptr)) {
|
||||
TextBox &textBox = (TextBox&)*object_ptr;
|
||||
if(HIWORD(wparam) == EN_CHANGE) {
|
||||
if(textBox.onChange) textBox.onChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case WM_NOTIFY: {
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.widget->window, id);
|
||||
if(control) {
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<ListBox*>(object_ptr)) {
|
||||
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)) {
|
||||
listBox.listBox->lostFocus = true;
|
||||
} else {
|
||||
if(!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED)) {
|
||||
if(listBox.onChange) listBox.onChange();
|
||||
} else if(listBox.listBox->lostFocus == false && listBox.selection() == false) {
|
||||
if(listBox.onChange) listBox.onChange();
|
||||
}
|
||||
listBox.listBox->lostFocus = false;
|
||||
}
|
||||
} else if(nmhdr->code == LVN_ITEMACTIVATE) {
|
||||
if(listBox.onActivate) listBox.onActivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case WM_HSCROLL: {
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.widget->window, id);
|
||||
if(control) {
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<HorizontalSlider*>(object_ptr)) {
|
||||
HorizontalSlider &horizontalSlider = (HorizontalSlider&)*object_ptr;
|
||||
if(horizontalSlider.horizontalSlider->position != horizontalSlider.position()) {
|
||||
horizontalSlider.horizontalSlider->position = horizontalSlider.position();
|
||||
if(horizontalSlider.onChange) horizontalSlider.onChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case WM_VSCROLL: {
|
||||
unsigned id = LOWORD(wparam);
|
||||
HWND control = GetDlgItem(window.widget->window, id);
|
||||
if(control) {
|
||||
Object *object_ptr = (Object*)GetWindowLongPtr(control, GWLP_USERDATA);
|
||||
if(object_ptr) {
|
||||
if(dynamic_cast<VerticalSlider*>(object_ptr)) {
|
||||
VerticalSlider &verticalSlider = (VerticalSlider&)*object_ptr;
|
||||
if(verticalSlider.verticalSlider->position != verticalSlider.position()) {
|
||||
verticalSlider.verticalSlider->position = verticalSlider.position();
|
||||
if(verticalSlider.onChange) verticalSlider.onChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
Object* OS::findObject(unsigned id) {
|
||||
foreach(object, objects) { if(object->object->id == id) return object; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
OS::OS() {
|
||||
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(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = OS_windowProc;
|
||||
wc.lpszClassName = L"phoenix_window";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
}
|
||||
|
||||
}
|
275
bsnes/phoenix/windows/windows.hpp
Executable file
275
bsnes/phoenix/windows/windows.hpp
Executable file
@ -0,0 +1,275 @@
|
||||
namespace phoenix {
|
||||
|
||||
struct Window;
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *object;
|
||||
private:
|
||||
virtual void unused();
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *font;
|
||||
};
|
||||
|
||||
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
|
||||
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
|
||||
|
||||
struct Action : Object {
|
||||
virtual bool enabled() = 0;
|
||||
virtual void setEnabled(bool enabled = true) = 0;
|
||||
Action();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *action;
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuSeparator : Action {
|
||||
void create(Menu &parent);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
void setChecked();
|
||||
};
|
||||
|
||||
struct Widget : Object {
|
||||
virtual void setFont(Font &font);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool focused();
|
||||
void setFocused();
|
||||
Widget();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *widget;
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setFont(Font &font);
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
//private:
|
||||
void resize(unsigned width, unsigned height);
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
};
|
||||
|
||||
struct Canvas : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uint32_t* buffer();
|
||||
void redraw();
|
||||
Canvas();
|
||||
~Canvas();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *canvas;
|
||||
};
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned item);
|
||||
ComboBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *comboBox;
|
||||
};
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
nall::string getText();
|
||||
void setText(const char *text);
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
EditBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *editBox;
|
||||
};
|
||||
|
||||
struct HorizontalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
HorizontalSlider();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *horizontalSlider;
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setText(const char *text);
|
||||
};
|
||||
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *listBox;
|
||||
};
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
unsigned progress();
|
||||
void setProgress(unsigned progress);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
RadioBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *radioBox;
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setEditable(bool editable = true);
|
||||
};
|
||||
|
||||
struct VerticalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
VerticalSlider();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *verticalSlider;
|
||||
};
|
||||
|
||||
struct Viewport : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uintptr_t handle();
|
||||
};
|
||||
|
||||
struct MessageWindow : Object {
|
||||
enum class Buttons : unsigned {
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo,
|
||||
};
|
||||
enum class Response : unsigned {
|
||||
Ok,
|
||||
Cancel,
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
bool 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 = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
struct Data;
|
||||
Data *os;
|
||||
Object* findObject(unsigned id);
|
||||
nall::array<Object*> objects;
|
||||
private:
|
||||
OS();
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
};
|
@ -8,6 +8,10 @@
|
||||
#ifndef XAUDIO2_RUBY_H
|
||||
#define XAUDIO2_RUBY_H
|
||||
|
||||
//64-bit GCC fix
|
||||
#define GUID_EXT EXTERN_C
|
||||
#define GUID_SECT
|
||||
|
||||
#include <BaseTyps.h>
|
||||
|
||||
#define DEFINE_GUID_X(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
|
@ -66,7 +66,7 @@ void PPU::Background::run_mode7() {
|
||||
|
||||
//character 0 repetition outside of screen area
|
||||
case 3: {
|
||||
if((px & py) & ~1023) {
|
||||
if((px | py) & ~1023) {
|
||||
tile = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
|
@ -1,7 +1,7 @@
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "068.17";
|
||||
static const char Version[] = "068.18";
|
||||
static const unsigned SerializerVersion = 13;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,13 @@ synchronize() {
|
||||
synchronize "libco"
|
||||
synchronize "nall"
|
||||
synchronize "ruby"
|
||||
synchronize "phoenix"
|
||||
|
||||
test -d libco/doc && rm -r libco/doc
|
||||
test -d libco/test && rm -r libco/test
|
||||
test -d ruby/_test && rm -r ruby/_test
|
||||
test -d phoenix/nall && rm -r phoenix/nall
|
||||
rm -r phoenix/test*
|
||||
rm -r phoenix/*.sh
|
||||
rm -r phoenix/*.bat
|
||||
|
||||
|
64
bsnes/ui-phoenix/Makefile
Executable file
64
bsnes/ui-phoenix/Makefile
Executable file
@ -0,0 +1,64 @@
|
||||
ui_objects := ui-main ui-general ui-cartridge
|
||||
ui_objects += ruby phoenix
|
||||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
flags += -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
|
||||
link += `pkg-config --libs gtk+-2.0`
|
||||
|
||||
ruby := video.glx video.xv video.sdl
|
||||
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
|
||||
ruby += input.sdl input.x
|
||||
|
||||
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
|
||||
else ifeq ($(platform),osx)
|
||||
ruby :=
|
||||
ruby += audio.openal
|
||||
ruby += input.carbon
|
||||
|
||||
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
|
||||
else ifeq ($(platform),win)
|
||||
flags += -DPHOENIX_WINDOWS
|
||||
link +=
|
||||
|
||||
ruby := video.direct3d video.wgl video.directdraw video.gdi
|
||||
ruby += audio.directsound audio.xaudio2
|
||||
ruby += input.rawinput input.directinput
|
||||
|
||||
link += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
|
||||
endif
|
||||
|
||||
# ruby
|
||||
rubyflags := $(if $(finstring .sdl,$(ruby)),`sdl-config --cflags`)
|
||||
|
||||
link += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
|
||||
link += $(if $(findstring video.direct3d,$(ruby)),-ld3d9)
|
||||
link += $(if $(findstring video.directdraw,$(ruby)),-lddraw)
|
||||
link += $(if $(findstring video.glx,$(ruby)),-lGL)
|
||||
link += $(if $(findstring video.wgl,$(ruby)),-lopengl32)
|
||||
link += $(if $(findstring video.xv,$(ruby)),-lXv)
|
||||
link += $(if $(findstring audio.alsa,$(ruby)),-lasound)
|
||||
link += $(if $(findstring audio.ao,$(ruby)),-lao)
|
||||
link += $(if $(findstring audio.directsound,$(ruby)),-ldsound)
|
||||
link += $(if $(findstring audio.pulseaudio,$(ruby)),-lpulse)
|
||||
link += $(if $(findstring audio.pulseaudiosimple,$(ruby)),-lpulse-simple)
|
||||
link += $(if $(findstring audio.xaudio2,$(ruby)),-lole32)
|
||||
link += $(if $(findstring input.directinput,$(ruby)),-ldinput8 -ldxguid)
|
||||
link += $(if $(findstring input.rawinput,$(ruby)),-ldinput8 -ldxguid)
|
||||
|
||||
rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
|
||||
|
||||
# rules
|
||||
objects := $(ui_objects) $(objects)
|
||||
|
||||
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/*)
|
||||
obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/general/*)
|
||||
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/cartridge/*)
|
||||
obj/ruby.o: ruby/ruby.cpp $(call rwildcard,ruby/*)
|
||||
$(call compile,$(rubydef) $(rubyflags))
|
||||
obj/phoenix.o: phoenix/phoenix.cpp $(call rwildcard,phoenix/*)
|
||||
|
||||
# targets
|
||||
ui_build:;
|
||||
|
||||
ui_clean:;
|
25
bsnes/ui-phoenix/base.hpp
Executable file
25
bsnes/ui-phoenix/base.hpp
Executable file
@ -0,0 +1,25 @@
|
||||
#include <snes.hpp>
|
||||
|
||||
#include <nall/base64.hpp>
|
||||
#include <nall/config.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/ups.hpp>
|
||||
#include <nall/snes/info.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <ruby/ruby.hpp>
|
||||
using namespace ruby;
|
||||
|
||||
#include <phoenix/phoenix.hpp>
|
||||
using namespace phoenix;
|
||||
|
||||
#include "interface.hpp"
|
||||
#include "general/general.hpp"
|
||||
#include "cartridge/cartridge.hpp"
|
||||
|
||||
struct Application {
|
||||
bool quit;
|
||||
void main(int argc, char **argv);
|
||||
};
|
||||
|
||||
extern Application application;
|
34
bsnes/ui-phoenix/cartridge/cartridge.cpp
Executable file
34
bsnes/ui-phoenix/cartridge/cartridge.cpp
Executable file
@ -0,0 +1,34 @@
|
||||
#include "../base.hpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
bool Cartridge::loadNormal(string filename) {
|
||||
if(file::exists(filename) == false) return false;
|
||||
|
||||
file fp;
|
||||
if(fp.open(filename, file::mode_read) == false) return false;
|
||||
|
||||
unsigned size = fp.size();
|
||||
if((size & 0x7fff) == 512) {
|
||||
size -= 512;
|
||||
fp.seek(512);
|
||||
}
|
||||
uint8_t *data = new uint8_t[size];
|
||||
fp.read(data, size);
|
||||
fp.close();
|
||||
|
||||
SNES::memory::cartrom.copy(data, size);
|
||||
|
||||
string baseXML = snes_information(data, size).xml_memory_map;
|
||||
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, lstring() << baseXML);
|
||||
delete[] data;
|
||||
|
||||
filename = string(nall::basename(filename), ".srm");
|
||||
if(SNES::memory::cartram.size() && file::exists(filename)) {
|
||||
if(fp.open(filename, file::mode_read)) {
|
||||
fp.read(SNES::memory::cartram.data(), min(fp.size(), SNES::memory::cartram.size()));
|
||||
fp.close();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
5
bsnes/ui-phoenix/cartridge/cartridge.hpp
Executable file
5
bsnes/ui-phoenix/cartridge/cartridge.hpp
Executable file
@ -0,0 +1,5 @@
|
||||
struct Cartridge {
|
||||
bool loadNormal(string filename);
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
2
bsnes/ui-phoenix/general/general.cpp
Executable file
2
bsnes/ui-phoenix/general/general.cpp
Executable file
@ -0,0 +1,2 @@
|
||||
#include "../base.hpp"
|
||||
#include "main-window.cpp"
|
1
bsnes/ui-phoenix/general/general.hpp
Executable file
1
bsnes/ui-phoenix/general/general.hpp
Executable file
@ -0,0 +1 @@
|
||||
#include "main-window.hpp"
|
19
bsnes/ui-phoenix/general/main-window.cpp
Executable file
19
bsnes/ui-phoenix/general/main-window.cpp
Executable file
@ -0,0 +1,19 @@
|
||||
MainWindow mainWindow;
|
||||
|
||||
void MainWindow::create() {
|
||||
Window::create(256, 256, 595, 448, string(SNES::Info::Name, " v", SNES::Info::Version));
|
||||
//setBackgroundColor(0, 0, 0);
|
||||
|
||||
system.create(*this, "System");
|
||||
systemQuit.create(system, "Quit");
|
||||
systemQuit.onTick = []() { application.quit = true; };
|
||||
setMenuVisible(true);
|
||||
settings.create(*this, "Settings");
|
||||
tools.create(*this, "Tools");
|
||||
help.create(*this, "Help");
|
||||
|
||||
viewport.create(*this, 0, 0, 595, 448);
|
||||
setStatusVisible(true);
|
||||
setVisible(true);
|
||||
onClose = []() { application.quit = true; return false; };
|
||||
}
|
13
bsnes/ui-phoenix/general/main-window.hpp
Executable file
13
bsnes/ui-phoenix/general/main-window.hpp
Executable file
@ -0,0 +1,13 @@
|
||||
struct MainWindow : Window {
|
||||
Menu system;
|
||||
MenuItem systemQuit;
|
||||
Menu settings;
|
||||
Menu tools;
|
||||
Menu help;
|
||||
|
||||
Viewport viewport;
|
||||
|
||||
void create();
|
||||
};
|
||||
|
||||
extern MainWindow mainWindow;
|
85
bsnes/ui-phoenix/interface.cpp
Executable file
85
bsnes/ui-phoenix/interface.cpp
Executable file
@ -0,0 +1,85 @@
|
||||
Palette palette;
|
||||
Interface interface;
|
||||
|
||||
const uint8_t Palette::gammaRamp[32] = {
|
||||
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
|
||||
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
|
||||
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
|
||||
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff,
|
||||
};
|
||||
|
||||
void Palette::update() {
|
||||
for(unsigned i = 0; i < 32768; i++) {
|
||||
unsigned r = gammaRamp[(i >> 10) & 31];
|
||||
unsigned g = gammaRamp[(i >> 5) & 31];
|
||||
unsigned b = gammaRamp[(i >> 0) & 31];
|
||||
//r = (r << 3) | (r >> 2);
|
||||
//g = (g << 3) | (g >> 2);
|
||||
//b = (b << 3) | (b >> 2);
|
||||
color[i] = (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
}
|
||||
|
||||
Palette::Palette() {
|
||||
update();
|
||||
}
|
||||
|
||||
void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) {
|
||||
bool interlace = (height >= 240);
|
||||
bool overscan = (height == 239 || height == 478);
|
||||
unsigned inpitch = interlace ? 1024 : 2048;
|
||||
|
||||
uint32_t *buffer;
|
||||
unsigned outpitch;
|
||||
|
||||
if(video.lock(buffer, outpitch, width, height)) {
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint32_t *output = buffer + y * (outpitch >> 2);
|
||||
const uint16_t *input = data + y * (inpitch >> 1);
|
||||
for(unsigned x = 0; x < width; x++) *output++ = palette.color[*input++];
|
||||
}
|
||||
video.unlock();
|
||||
video.refresh();
|
||||
}
|
||||
|
||||
static signed frameCounter = 0;
|
||||
static time_t previous, current;
|
||||
frameCounter++;
|
||||
|
||||
time(¤t);
|
||||
if(current != previous) {
|
||||
mainWindow.setStatusText(string("FPS: ", frameCounter));
|
||||
frameCounter = 0;
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::audio_sample(uint16_t left, uint16_t right) {
|
||||
audio.sample(left, right);
|
||||
}
|
||||
|
||||
void Interface::input_poll() {
|
||||
input.poll(state);
|
||||
}
|
||||
|
||||
int16_t Interface::input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
||||
if(port == 0) {
|
||||
if(device == SNES::Input::Device::Joypad) {
|
||||
switch(id) {
|
||||
case SNES::Input::JoypadID::Up: return state[keyboard(0)[Keyboard::Up]];
|
||||
case SNES::Input::JoypadID::Down: return state[keyboard(0)[Keyboard::Down]];
|
||||
case SNES::Input::JoypadID::Left: return state[keyboard(0)[Keyboard::Left]];
|
||||
case SNES::Input::JoypadID::Right: return state[keyboard(0)[Keyboard::Right]];
|
||||
case SNES::Input::JoypadID::B: return state[keyboard(0)[Keyboard::Z]];
|
||||
case SNES::Input::JoypadID::A: return state[keyboard(0)[Keyboard::X]];
|
||||
case SNES::Input::JoypadID::Y: return state[keyboard(0)[Keyboard::A]];
|
||||
case SNES::Input::JoypadID::X: return state[keyboard(0)[Keyboard::S]];
|
||||
case SNES::Input::JoypadID::L: return state[keyboard(0)[Keyboard::D]];
|
||||
case SNES::Input::JoypadID::R: return state[keyboard(0)[Keyboard::C]];
|
||||
case SNES::Input::JoypadID::Select: return state[keyboard(0)[Keyboard::Apostrophe]];
|
||||
case SNES::Input::JoypadID::Start: return state[keyboard(0)[Keyboard::Return]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
17
bsnes/ui-phoenix/interface.hpp
Executable file
17
bsnes/ui-phoenix/interface.hpp
Executable file
@ -0,0 +1,17 @@
|
||||
struct Palette {
|
||||
static const uint8_t gammaRamp[32];
|
||||
uint32_t color[32768];
|
||||
void update();
|
||||
Palette();
|
||||
};
|
||||
|
||||
struct Interface : public SNES::Interface {
|
||||
int16_t state[Scancode::Limit];
|
||||
void video_refresh(const uint16_t *data, unsigned width, unsigned height);
|
||||
void audio_sample(uint16_t left, uint16_t right);
|
||||
void input_poll();
|
||||
int16_t input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id);
|
||||
};
|
||||
|
||||
extern Palette palette;
|
||||
extern Interface interface;
|
63
bsnes/ui-phoenix/main.cpp
Executable file
63
bsnes/ui-phoenix/main.cpp
Executable file
@ -0,0 +1,63 @@
|
||||
#include "base.hpp"
|
||||
#include "interface.cpp"
|
||||
Application application;
|
||||
|
||||
void Application::main(int argc, char **argv) {
|
||||
mainWindow.create();
|
||||
while(os.pending()) os.run();
|
||||
|
||||
video.driver("OpenGL");
|
||||
video.set(Video::Handle, mainWindow.viewport.handle());
|
||||
video.set(Video::Synchronize, false);
|
||||
video.set(Video::Filter, (unsigned)Video::FilterLinear);
|
||||
if(video.init() == false) {
|
||||
MessageWindow::critical(mainWindow, "Failed to initialize video.");
|
||||
video.driver("None");
|
||||
video.init();
|
||||
}
|
||||
|
||||
audio.driver("ALSA");
|
||||
audio.set(Audio::Handle, mainWindow.viewport.handle());
|
||||
audio.set(Audio::Synchronize, false);
|
||||
audio.set(Audio::Frequency, (unsigned)32000);
|
||||
if(audio.init() == false) {
|
||||
MessageWindow::critical(mainWindow, "Failed to initialize audio.");
|
||||
audio.driver("None");
|
||||
audio.init();
|
||||
}
|
||||
|
||||
input.driver("SDL");
|
||||
input.set(Input::Handle, mainWindow.viewport.handle());
|
||||
if(input.init() == false) {
|
||||
MessageWindow::critical(mainWindow, "Failed to initialize input.");
|
||||
input.driver("None");
|
||||
input.init();
|
||||
}
|
||||
|
||||
SNES::system.init(&interface);
|
||||
if(argc == 2) {
|
||||
cartridge.loadNormal(argv[1]);
|
||||
SNES::system.power();
|
||||
}
|
||||
|
||||
while(quit == false) {
|
||||
if(os.pending()) os.run();
|
||||
|
||||
if(SNES::cartridge.loaded()) {
|
||||
SNES::system.run();
|
||||
} else {
|
||||
usleep(20 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
mainWindow.setVisible(false);
|
||||
while(os.pending()) os.run();
|
||||
SNES::system.term();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
application.main(argc, argv);
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user