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:
Tim Allen 2010-10-20 22:47:14 +11:00
parent 92ab697f8c
commit b671e49644
195 changed files with 4567 additions and 7 deletions

View File

@ -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:;

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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;
}

View 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
View 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;
}

View 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
View 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
View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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);
}

View 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
View File

@ -0,0 +1,6 @@
void Object::unused() {
}
Object::Object() {
object = new Object::Data(*this);
}

View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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;
}

View 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);
}

View 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;
}

View 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);
}

View 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;
}

View 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
View 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;
}

View 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
View 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));
}

View 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
View 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
);
}
}

View 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));
}

View 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++;
}

View 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>

View File

@ -0,0 +1 @@
1 24 "phoenix.Manifest"

View 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);
}

View 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;
}

View 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);
}

View 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;
}

View 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;
}

View 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;
}

View 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
View 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
View 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;
};

View File

@ -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}}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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
View 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
View 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;

View 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;
}

View File

@ -0,0 +1,5 @@
struct Cartridge {
bool loadNormal(string filename);
};
extern Cartridge cartridge;

View File

@ -0,0 +1,2 @@
#include "../base.hpp"
#include "main-window.cpp"

View File

@ -0,0 +1 @@
#include "main-window.hpp"

View 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; };
}

View 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
View 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(&current);
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
View 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
View 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