mirror of https://github.com/bsnes-emu/bsnes.git
Update to v068r18 release.
byuu says: This WIP fixes the Mode7 repeat issue in the accuracy core. More importantly, it's the first build to include phoenix. There is a stub GUI that does basically nothing right now. It will give you a window, a command to close the emulator, and an FPS meter so you can tell how fast it is. To load a ROM, you have to drag the ROM on top of the binary. I don't know if it will work if the filename+path has spaces in it or not, so avoid that to be safe. [...] For some reason, the 64-bit binary sometimes crashes on start, maybe 1:6 times. So just keep trying. I don't know what's up with that, I'd appreciate if someone here wanted to debug that for me though :D One really good bit of news, there was that old hiro bug where keyboard input would cause the main window to beep. I spied on the main event loop and, as suspected, the status bar was getting focus and rejecting key presses. What. The. Fuck. Why would a status bar ever need focus? So I set WM_DISABLED on it, which luckily leaves the font color alone. I also had to use WM_DISABLED on the Viewport widget that I use for video output. These two combined let me have my main window with no keyboard beeping AND allow tab+shift-tab to work as you'd expect on other windows, so hooray. Now, at the moment there's no Manifest included, because Microsoft for some reason includes the processorArcitecture in the file. So I can't use the same manifest for 32-bit and 64-bit mode, or the binary will crash on one or the other. Fuck. So the status bar may look old-school or something, whatever, it's only temporary. Next up, my goal is to avoid the hiro icon corruption bullshit by making phoenix itself try and use an internal resource icon. So just compile your app with that resource icon and voila, perfect icon. Not in there yet so you get the white box. Input is hard-coded, up/down/left/right/z/x/a/s/d/c/apostrophe/return. Lastly, compilation is ... in a serious state of flux. The code is set to compile bsnes/phoenix-gtk right now. Try it at your own risk. Give me a few WIPs to get everything nice and refined. Ubuntu users will need gcc-4.5, which you can get by adding the Maverick Meerkat repository, updating apt, installing the gcc-4.5 + g++-4.5 packages, and then removing and re-updating your apt/sources.list file so you don't end up fucking your whole system when you run apt again in the future. For anyone who can work with all of that, great! Please post a framerate comparison between 32-bit and 64-bit builds. Any game, any screen, so long as the FPS is not fluctuating when you measure it (eg don't do it during an attract sequence.) If anyone complains about the 64-bit binary not working and it turns out they are on 32-bit Windows, they are going to be removed from this WIP forum :P
This commit is contained in:
parent
92ab697f8c
commit
b671e49644
|
@ -1,7 +1,7 @@
|
|||
include nall/Makefile
|
||||
snes := snes
|
||||
profile := performance
|
||||
ui := qt
|
||||
ui := ui-phoenix
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
|
@ -88,6 +88,6 @@ clean: ui_clean
|
|||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 launcher libco nall obj out qt ruby snes Makefile sync.sh cc.bat clean.bat
|
||||
tar -cjf bsnes.tar.bz2 launcher libco nall obj out phoenix ruby snes ui-phoenix ui-qt Makefile cc.bat clean.bat sync.sh
|
||||
|
||||
help:;
|
||||
|
|
|
@ -29,10 +29,12 @@ ifeq ($(platform),)
|
|||
endif
|
||||
|
||||
ifeq ($(compiler),)
|
||||
ifeq ($(platform),osx)
|
||||
compiler := gcc-mp-4.4
|
||||
else
|
||||
ifeq ($(platform),win)
|
||||
compiler := gcc
|
||||
else ifeq ($(platform),osx)
|
||||
compiler := gcc-mp-4.5
|
||||
else
|
||||
compiler := gcc-4.5
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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))
|
||||
);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
void Object::unused() {
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
object = new Object::Data(*this);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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:
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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++;
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1 @@
|
|||
1 24 "phoenix.Manifest"
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
namespace phoenix {
|
||||
|
||||
struct Window;
|
||||
|
||||
struct Object {
|
||||
Object();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *object;
|
||||
private:
|
||||
virtual void unused();
|
||||
};
|
||||
|
||||
struct Font : Object {
|
||||
enum class Style : unsigned {
|
||||
None = 0,
|
||||
Bold = 1,
|
||||
Italic = 2,
|
||||
};
|
||||
bool create(const char *name, unsigned size, Font::Style style = Style::None);
|
||||
Font();
|
||||
~Font();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *font;
|
||||
};
|
||||
|
||||
inline Font::Style operator|(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a | (unsigned)b); }
|
||||
inline Font::Style operator&(Font::Style a, Font::Style b) { return (Font::Style)((unsigned)a & (unsigned)b); }
|
||||
|
||||
struct Action : Object {
|
||||
virtual bool enabled() = 0;
|
||||
virtual void setEnabled(bool enabled = true) = 0;
|
||||
Action();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *action;
|
||||
};
|
||||
|
||||
struct Menu : Action {
|
||||
void create(Window &parent, const char *text);
|
||||
void create(Menu &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuSeparator : Action {
|
||||
void create(Menu &parent);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
};
|
||||
|
||||
struct MenuCheckItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct MenuRadioItem : Action {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Menu &parent, const char *text);
|
||||
void create(MenuRadioItem &parent, const char *text);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool checked();
|
||||
void setChecked();
|
||||
};
|
||||
|
||||
struct Widget : Object {
|
||||
virtual void setFont(Font &font);
|
||||
bool visible();
|
||||
void setVisible(bool visible = true);
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
bool focused();
|
||||
void setFocused();
|
||||
Widget();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *widget;
|
||||
};
|
||||
|
||||
struct Window : Widget {
|
||||
static Window None;
|
||||
nall::function<bool ()> onClose;
|
||||
void create(unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setFont(Font &font);
|
||||
void setGeometry(unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
void setBackgroundColor(uint8_t red, uint8_t green, uint8_t blue);
|
||||
void setTitle(const char *text);
|
||||
void setStatusText(const char *text);
|
||||
void setMenuVisible(bool visible = true);
|
||||
void setStatusVisible(bool visible = true);
|
||||
Window();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *window;
|
||||
//private:
|
||||
void resize(unsigned width, unsigned height);
|
||||
};
|
||||
|
||||
struct Button : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
};
|
||||
|
||||
struct Canvas : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uint32_t* buffer();
|
||||
void redraw();
|
||||
Canvas();
|
||||
~Canvas();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *canvas;
|
||||
};
|
||||
|
||||
struct CheckBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked(bool checked = true);
|
||||
};
|
||||
|
||||
struct ComboBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void reset();
|
||||
void addItem(const char *text);
|
||||
unsigned selection();
|
||||
void setSelection(unsigned item);
|
||||
ComboBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *comboBox;
|
||||
};
|
||||
|
||||
struct EditBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
nall::string getText();
|
||||
void setText(const char *text);
|
||||
void setEditable(bool editable = true);
|
||||
void setWordWrap(bool wordWrap = true);
|
||||
EditBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *editBox;
|
||||
};
|
||||
|
||||
struct HorizontalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
HorizontalSlider();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *horizontalSlider;
|
||||
};
|
||||
|
||||
struct Label : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setText(const char *text);
|
||||
};
|
||||
|
||||
struct ListBox : Widget {
|
||||
nall::function<void ()> onActivate;
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setHeaderVisible(bool headerVisible = true);
|
||||
void reset();
|
||||
void resizeColumnsToContent();
|
||||
void addItem(const char *text);
|
||||
void setItem(unsigned row, const char *text);
|
||||
nall::optional<unsigned> selection();
|
||||
void setSelection(unsigned row);
|
||||
ListBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *listBox;
|
||||
};
|
||||
|
||||
struct ProgressBar : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
unsigned progress();
|
||||
void setProgress(unsigned progress);
|
||||
};
|
||||
|
||||
struct RadioBox : Widget {
|
||||
nall::function<void ()> onTick;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void create(RadioBox &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
bool checked();
|
||||
void setChecked();
|
||||
RadioBox();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *radioBox;
|
||||
};
|
||||
|
||||
struct TextBox : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, const char *text = "");
|
||||
void setEditable(bool editable = true);
|
||||
};
|
||||
|
||||
struct VerticalSlider : Widget {
|
||||
nall::function<void ()> onChange;
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height, unsigned length);
|
||||
unsigned position();
|
||||
void setPosition(unsigned position);
|
||||
VerticalSlider();
|
||||
//private:
|
||||
struct Data;
|
||||
Data *verticalSlider;
|
||||
};
|
||||
|
||||
struct Viewport : Widget {
|
||||
void create(Window &parent, unsigned x, unsigned y, unsigned width, unsigned height);
|
||||
uintptr_t handle();
|
||||
};
|
||||
|
||||
struct MessageWindow : Object {
|
||||
enum class Buttons : unsigned {
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo,
|
||||
};
|
||||
enum class Response : unsigned {
|
||||
Ok,
|
||||
Cancel,
|
||||
Yes,
|
||||
No,
|
||||
};
|
||||
static Response information(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response question(Window &parent, const char *text, Buttons = Buttons::YesNo);
|
||||
static Response warning(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
static Response critical(Window &parent, const char *text, Buttons = Buttons::Ok);
|
||||
};
|
||||
|
||||
struct OS : Object {
|
||||
bool pending();
|
||||
bool run();
|
||||
void main();
|
||||
void quit();
|
||||
unsigned desktopWidth();
|
||||
unsigned desktopHeight();
|
||||
nall::string folderSelect(Window &parent, const char *path = "");
|
||||
nall::string fileOpen(Window &parent, const char *filter, const char *path = "");
|
||||
nall::string fileSave(Window &parent, const char *filter, const char *path = "");
|
||||
//private:
|
||||
static OS& handle();
|
||||
struct Data;
|
||||
Data *os;
|
||||
Object* findObject(unsigned id);
|
||||
nall::array<Object*> objects;
|
||||
private:
|
||||
OS();
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
extern OS &os;
|
||||
|
||||
};
|
|
@ -8,6 +8,10 @@
|
|||
#ifndef XAUDIO2_RUBY_H
|
||||
#define XAUDIO2_RUBY_H
|
||||
|
||||
//64-bit GCC fix
|
||||
#define GUID_EXT EXTERN_C
|
||||
#define GUID_SECT
|
||||
|
||||
#include <BaseTyps.h>
|
||||
|
||||
#define DEFINE_GUID_X(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) GUID_EXT const GUID n GUID_SECT = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
|
|
|
@ -66,7 +66,7 @@ void PPU::Background::run_mode7() {
|
|||
|
||||
//character 0 repetition outside of screen area
|
||||
case 3: {
|
||||
if((px & py) & ~1023) {
|
||||
if((px | py) & ~1023) {
|
||||
tile = 0;
|
||||
} else {
|
||||
px &= 1023;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "068.17";
|
||||
static const char Version[] = "068.18";
|
||||
static const unsigned SerializerVersion = 13;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,13 @@ synchronize() {
|
|||
synchronize "libco"
|
||||
synchronize "nall"
|
||||
synchronize "ruby"
|
||||
synchronize "phoenix"
|
||||
|
||||
test -d libco/doc && rm -r libco/doc
|
||||
test -d libco/test && rm -r libco/test
|
||||
test -d ruby/_test && rm -r ruby/_test
|
||||
test -d phoenix/nall && rm -r phoenix/nall
|
||||
rm -r phoenix/test*
|
||||
rm -r phoenix/*.sh
|
||||
rm -r phoenix/*.bat
|
||||
|
||||
|
|
|
@ -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:;
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
struct Cartridge {
|
||||
bool loadNormal(string filename);
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
|
@ -0,0 +1,2 @@
|
|||
#include "../base.hpp"
|
||||
#include "main-window.cpp"
|
|
@ -0,0 +1 @@
|
|||
#include "main-window.hpp"
|
|
@ -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; };
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
struct MainWindow : Window {
|
||||
Menu system;
|
||||
MenuItem systemQuit;
|
||||
Menu settings;
|
||||
Menu tools;
|
||||
Menu help;
|
||||
|
||||
Viewport viewport;
|
||||
|
||||
void create();
|
||||
};
|
||||
|
||||
extern MainWindow mainWindow;
|
|
@ -0,0 +1,85 @@
|
|||
Palette palette;
|
||||
Interface interface;
|
||||
|
||||
const uint8_t Palette::gammaRamp[32] = {
|
||||
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
|
||||
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
|
||||
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
|
||||
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff,
|
||||
};
|
||||
|
||||
void Palette::update() {
|
||||
for(unsigned i = 0; i < 32768; i++) {
|
||||
unsigned r = gammaRamp[(i >> 10) & 31];
|
||||
unsigned g = gammaRamp[(i >> 5) & 31];
|
||||
unsigned b = gammaRamp[(i >> 0) & 31];
|
||||
//r = (r << 3) | (r >> 2);
|
||||
//g = (g << 3) | (g >> 2);
|
||||
//b = (b << 3) | (b >> 2);
|
||||
color[i] = (r << 16) | (g << 8) | (b << 0);
|
||||
}
|
||||
}
|
||||
|
||||
Palette::Palette() {
|
||||
update();
|
||||
}
|
||||
|
||||
void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned height) {
|
||||
bool interlace = (height >= 240);
|
||||
bool overscan = (height == 239 || height == 478);
|
||||
unsigned inpitch = interlace ? 1024 : 2048;
|
||||
|
||||
uint32_t *buffer;
|
||||
unsigned outpitch;
|
||||
|
||||
if(video.lock(buffer, outpitch, width, height)) {
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
uint32_t *output = buffer + y * (outpitch >> 2);
|
||||
const uint16_t *input = data + y * (inpitch >> 1);
|
||||
for(unsigned x = 0; x < width; x++) *output++ = palette.color[*input++];
|
||||
}
|
||||
video.unlock();
|
||||
video.refresh();
|
||||
}
|
||||
|
||||
static signed frameCounter = 0;
|
||||
static time_t previous, current;
|
||||
frameCounter++;
|
||||
|
||||
time(¤t);
|
||||
if(current != previous) {
|
||||
mainWindow.setStatusText(string("FPS: ", frameCounter));
|
||||
frameCounter = 0;
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::audio_sample(uint16_t left, uint16_t right) {
|
||||
audio.sample(left, right);
|
||||
}
|
||||
|
||||
void Interface::input_poll() {
|
||||
input.poll(state);
|
||||
}
|
||||
|
||||
int16_t Interface::input_poll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
||||
if(port == 0) {
|
||||
if(device == SNES::Input::Device::Joypad) {
|
||||
switch(id) {
|
||||
case SNES::Input::JoypadID::Up: return state[keyboard(0)[Keyboard::Up]];
|
||||
case SNES::Input::JoypadID::Down: return state[keyboard(0)[Keyboard::Down]];
|
||||
case SNES::Input::JoypadID::Left: return state[keyboard(0)[Keyboard::Left]];
|
||||
case SNES::Input::JoypadID::Right: return state[keyboard(0)[Keyboard::Right]];
|
||||
case SNES::Input::JoypadID::B: return state[keyboard(0)[Keyboard::Z]];
|
||||
case SNES::Input::JoypadID::A: return state[keyboard(0)[Keyboard::X]];
|
||||
case SNES::Input::JoypadID::Y: return state[keyboard(0)[Keyboard::A]];
|
||||
case SNES::Input::JoypadID::X: return state[keyboard(0)[Keyboard::S]];
|
||||
case SNES::Input::JoypadID::L: return state[keyboard(0)[Keyboard::D]];
|
||||
case SNES::Input::JoypadID::R: return state[keyboard(0)[Keyboard::C]];
|
||||
case SNES::Input::JoypadID::Select: return state[keyboard(0)[Keyboard::Apostrophe]];
|
||||
case SNES::Input::JoypadID::Start: return state[keyboard(0)[Keyboard::Return]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -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;
|
|
@ -0,0 +1,63 @@
|
|||
#include "base.hpp"
|
||||
#include "interface.cpp"
|
||||
Application application;
|
||||
|
||||
void Application::main(int argc, char **argv) {
|
||||
mainWindow.create();
|
||||
while(os.pending()) os.run();
|
||||
|
||||
video.driver("OpenGL");
|
||||
video.set(Video::Handle, mainWindow.viewport.handle());
|
||||
video.set(Video::Synchronize, false);
|
||||
video.set(Video::Filter, (unsigned)Video::FilterLinear);
|
||||
if(video.init() == false) {
|
||||
MessageWindow::critical(mainWindow, "Failed to initialize video.");
|
||||
video.driver("None");
|
||||
video.init();
|
||||
}
|
||||
|
||||
audio.driver("ALSA");
|
||||
audio.set(Audio::Handle, mainWindow.viewport.handle());
|
||||
audio.set(Audio::Synchronize, false);
|
||||
audio.set(Audio::Frequency, (unsigned)32000);
|
||||
if(audio.init() == false) {
|
||||
MessageWindow::critical(mainWindow, "Failed to initialize audio.");
|
||||
audio.driver("None");
|
||||
audio.init();
|
||||
}
|
||||
|
||||
input.driver("SDL");
|
||||
input.set(Input::Handle, mainWindow.viewport.handle());
|
||||
if(input.init() == false) {
|
||||
MessageWindow::critical(mainWindow, "Failed to initialize input.");
|
||||
input.driver("None");
|
||||
input.init();
|
||||
}
|
||||
|
||||
SNES::system.init(&interface);
|
||||
if(argc == 2) {
|
||||
cartridge.loadNormal(argv[1]);
|
||||
SNES::system.power();
|
||||
}
|
||||
|
||||
while(quit == false) {
|
||||
if(os.pending()) os.run();
|
||||
|
||||
if(SNES::cartridge.loaded()) {
|
||||
SNES::system.run();
|
||||
} else {
|
||||
usleep(20 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
mainWindow.setVisible(false);
|
||||
while(os.pending()) os.run();
|
||||
SNES::system.term();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
application.main(argc, argv);
|
||||
return 0;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue