mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-13 13:02:06 +02:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b5b21a4ec2 | ||
|
2b587de04b | ||
|
1e133eeb5e | ||
|
9de4b1dea2 | ||
|
2b84d1ef37 | ||
|
e2a44195cd | ||
|
9ac912d100 | ||
|
d15092dada | ||
|
91270e504a |
18
src/Makefile
18
src/Makefile
@@ -17,8 +17,9 @@ ifneq ($(findstring gcc,$(compiler)),) # GCC family
|
||||
link = -s
|
||||
mkbin = -o$1
|
||||
mkdef = -D$1
|
||||
mkinc = -I$1
|
||||
mkincpath = -I$1
|
||||
mklib = -l$1
|
||||
mklibpath = -L$1
|
||||
|
||||
# profile-guided optimization:
|
||||
# flags += -fprofile-generate
|
||||
@@ -34,8 +35,9 @@ else ifeq ($(compiler),cl) # Visual C++
|
||||
link = /link
|
||||
mkbin = /Fe$1
|
||||
mkdef = /D$1
|
||||
mkinc = /I$1
|
||||
mkincpath = /I$1
|
||||
mklib = $1.lib
|
||||
mklibpath = /L$1
|
||||
else
|
||||
unknown_compiler: help;
|
||||
endif
|
||||
@@ -48,10 +50,13 @@ ifeq ($(platform),x) # X11
|
||||
ruby = video.glx video.xv video.sdl audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao input.sdl input.x
|
||||
delete = rm -f $1
|
||||
else ifeq ($(platform),win) # Windows
|
||||
# enable static linking to Qt for Windows build
|
||||
mingw_link_flags = -mwindows -enable-stdcall-fixup -Wl,-s -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
||||
mingw_link_flags = -mwindows
|
||||
# mingw_links_flags = -mconsole
|
||||
|
||||
ruby = video.direct3d video.wgl video.directdraw video.gdi audio.directsound input.directinput
|
||||
# enable static linking to Qt for Windows build
|
||||
mingw_link_flags += -enable-stdcall-fixup -Wl,-s -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
||||
|
||||
ruby = video.direct3d video.wgl video.directdraw video.gdi audio.directsound input.rawinput input.directinput
|
||||
delete = $(if $(findstring i586-mingw-gcc,$(compiler)),rm -f $1,del $(subst /,\,$1))
|
||||
link += $(if $(findstring mingw,$(compiler)),$(mingw_link_flags))
|
||||
link += $(call mklib,uuid)
|
||||
@@ -68,6 +73,7 @@ endif
|
||||
############
|
||||
|
||||
rubyflags = $(if $(findstring .sdl,$(ruby)),`sdl-config --cflags`)
|
||||
link += $(if $(findstring .sdl,$(ruby)),`sdl-config --libs`)
|
||||
|
||||
link += $(if $(findstring video.direct3d,$(ruby)),$(call mklib,d3d9))
|
||||
link += $(if $(findstring video.directdraw,$(ruby)),$(call mklib,ddraw))
|
||||
@@ -80,7 +86,7 @@ link += $(if $(findstring audio.directsound,$(ruby)),$(call mklib,dsound))
|
||||
link += $(if $(findstring audio.openal,$(ruby)),$(if $(call streq,$(platform),x),$(call mklib,openal),$(call mklib,openal32)))
|
||||
link += $(if $(findstring audio.pulseaudio,$(ruby)),$(call mklib,pulse-simple))
|
||||
link += $(if $(findstring input.directinput,$(ruby)),$(call mklib,dinput8) $(call mklib,dxguid))
|
||||
link += $(if $(findstring input.sdl,$(ruby)),`sdl-config --libs`)
|
||||
link += $(if $(findstring input.rawinput,$(ruby)),$(call mklib,xinput) $(call mklib,dinput8) $(call mklib,dxguid))
|
||||
|
||||
####################
|
||||
### core objects ###
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#define BSNES_VERSION "0.041"
|
||||
#define BSNES_VERSION "0.042"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define BUSCORE sBus
|
||||
|
@@ -118,7 +118,7 @@ bool Cartridge::load_bsx(const char *base, const char *slot) {
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
if(load_image(slot, data, size, patch_applied)) {
|
||||
if(load_image(slot, data, size, patch_applied) == true) {
|
||||
set(bsx_flash_loaded, true);
|
||||
if(patch_applied) set(patched, true);
|
||||
bs.ram = data;
|
||||
@@ -157,7 +157,7 @@ bool Cartridge::load_sufami_turbo(const char *base, const char *slotA, const cha
|
||||
read_header(cartinfo, cart.rom = data, cart.rom_size = size);
|
||||
set_cartinfo(cartinfo);
|
||||
|
||||
if(load_image(slotA, data, size, patch_applied)) {
|
||||
if(load_image(slotA, data, size, patch_applied) == true) {
|
||||
if(patch_applied) set(patched, true);
|
||||
stA.rom = new(zeromemory) uint8_t[stA.rom_size = 0x100000];
|
||||
memcpy(stA.rom, data, min(size, stA.rom_size));
|
||||
@@ -166,7 +166,7 @@ bool Cartridge::load_sufami_turbo(const char *base, const char *slotA, const cha
|
||||
load_ram(get_filename(slotA, "srm", snes.config.path.save), stA.ram, stA.ram_size = 0x020000, 0xff);
|
||||
}
|
||||
|
||||
if(load_image(slotB, data, size, patch_applied)) {
|
||||
if(load_image(slotB, data, size, patch_applied) == true) {
|
||||
if(patch_applied) set(patched, true);
|
||||
stB.rom = new(zeromemory) uint8_t[stB.rom_size = 0x100000];
|
||||
memcpy(stB.rom, data, min(size, stB.rom_size));
|
||||
|
@@ -1,3 +1,3 @@
|
||||
@mingw32-make platform=win compiler=mingw32-gcc
|
||||
::@mingw32-make platform=win compiler=mingw32-gcc enable_gzip=true enable_jma=true
|
||||
::@mingw32-make platform=win compiler=mingw32-gcc
|
||||
@mingw32-make platform=win compiler=mingw32-gcc enable_gzip=true enable_jma=true
|
||||
@pause
|
||||
|
@@ -56,7 +56,7 @@ public:
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
unsigned size();
|
||||
unsigned size() const;
|
||||
uint8 read(unsigned addr);
|
||||
void write(unsigned addr, uint8 data);
|
||||
|
||||
|
@@ -32,9 +32,9 @@ uint8 BSXBase::mmio_read(unsigned addr) {
|
||||
if(regs.r2192_counter >= 18) regs.r2192_counter = 0;
|
||||
|
||||
if(counter == 0) {
|
||||
time_t rawtime;
|
||||
time_t rawtime;
|
||||
time(&rawtime);
|
||||
tm *t = localtime(&rawtime);
|
||||
tm *t = localtime(&rawtime);
|
||||
|
||||
regs.r2192_hour = t->tm_hour;
|
||||
regs.r2192_minute = t->tm_min;
|
||||
@@ -42,11 +42,11 @@ uint8 BSXBase::mmio_read(unsigned addr) {
|
||||
}
|
||||
|
||||
switch(counter) {
|
||||
case 0: return 0x00; //???
|
||||
case 1: return 0x00; //???
|
||||
case 2: return 0x00; //???
|
||||
case 3: return 0x00; //???
|
||||
case 4: return 0x00; //???
|
||||
case 0: return 0x00; //???
|
||||
case 1: return 0x00; //???
|
||||
case 2: return 0x00; //???
|
||||
case 3: return 0x00; //???
|
||||
case 4: return 0x00; //???
|
||||
case 5: return 0x01;
|
||||
case 6: return 0x01;
|
||||
case 7: return 0x00;
|
||||
@@ -55,11 +55,11 @@ uint8 BSXBase::mmio_read(unsigned addr) {
|
||||
case 10: return regs.r2192_second;
|
||||
case 11: return regs.r2192_minute;
|
||||
case 12: return regs.r2192_hour;
|
||||
case 13: return 0x00; //???
|
||||
case 14: return 0x00; //???
|
||||
case 15: return 0x00; //???
|
||||
case 16: return 0x00; //???
|
||||
case 17: return 0x00; //???
|
||||
case 13: return 0x00; //???
|
||||
case 14: return 0x00; //???
|
||||
case 15: return 0x00; //???
|
||||
case 16: return 0x00; //???
|
||||
case 17: return 0x00; //???
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@@ -22,10 +22,12 @@ void BSXCart::reset() {
|
||||
void BSXCart::update_memory_map() {
|
||||
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
|
||||
|
||||
if((regs.r[0x02] & 0x80) == 0x00) { //LoROM mapping
|
||||
if((regs.r[0x02] & 0x80) == 0x00) {
|
||||
//LoROM mapping
|
||||
bus.map(Bus::MapLinear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapLinear, 0x80, 0xff, 0x8000, 0xffff, cart);
|
||||
} else { //HiROM mapping
|
||||
} else {
|
||||
//HiROM mapping
|
||||
bus.map(Bus::MapShadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
|
||||
bus.map(Bus::MapLinear, 0x40, 0x7d, 0x0000, 0xffff, cart);
|
||||
bus.map(Bus::MapShadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
|
||||
@@ -58,12 +60,12 @@ void BSXCart::update_memory_map() {
|
||||
}
|
||||
|
||||
uint8 BSXCart::mmio_read(unsigned addr) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
return regs.r[n];
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
return sram.read(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
|
||||
}
|
||||
|
||||
@@ -71,14 +73,14 @@ uint8 BSXCart::mmio_read(unsigned addr) {
|
||||
}
|
||||
|
||||
void BSXCart::mmio_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO
|
||||
uint8 n = (addr >> 16) & 15;
|
||||
regs.r[n] = data;
|
||||
if(n == 0x0e && data & 0x80) update_memory_map();
|
||||
return;
|
||||
}
|
||||
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
if((addr & 0xf8f000) == 0x105000) { //$[10-17]:[5000-5fff] SRAM
|
||||
return sram.write(((addr >> 16) & 7) * 0x1000 + (addr & 0xfff), data);
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ void BSXFlash::reset() {
|
||||
regs.write_enable = false;
|
||||
}
|
||||
|
||||
unsigned BSXFlash::size() {
|
||||
unsigned BSXFlash::size() const {
|
||||
return memory::bscram.size();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ uint8 BSXFlash::read(unsigned addr) {
|
||||
}
|
||||
|
||||
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
|
||||
//read flash cartridge vendor information
|
||||
//read flash cartridge vendor information
|
||||
switch(addr - 0xff00) {
|
||||
case 0x00: return 0x4d;
|
||||
case 0x01: return 0x00;
|
||||
@@ -39,7 +39,7 @@ uint8 BSXFlash::read(unsigned addr) {
|
||||
case 0x03: return 0x00;
|
||||
case 0x04: return 0x00;
|
||||
case 0x05: return 0x00;
|
||||
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
|
||||
case 0x06: return 0x2a; //0x2a = 8mbit, 0x2b = 16mbit (not known to exist, though BIOS recognizes ID)
|
||||
case 0x07: return 0x00;
|
||||
default: return 0x00;
|
||||
}
|
||||
@@ -49,14 +49,14 @@ uint8 BSXFlash::read(unsigned addr) {
|
||||
}
|
||||
|
||||
void BSXFlash::write(unsigned addr, uint8 data) {
|
||||
//there exist both read-only and read-write BS-X flash cartridges ...
|
||||
//unfortunately, the vendor info is not stored inside memory dumps
|
||||
//of BS-X flashcarts, so it is impossible to determine whether a
|
||||
//given flashcart is writeable.
|
||||
//however, it has been observed that LoROM-mapped BS-X carts always
|
||||
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
||||
//read-only flashcarts.
|
||||
//below is an unfortunately necessary workaround to this problem.
|
||||
//there exist both read-only and read-write BS-X flash cartridges ...
|
||||
//unfortunately, the vendor info is not stored inside memory dumps
|
||||
//of BS-X flashcarts, so it is impossible to determine whether a
|
||||
//given flashcart is writeable.
|
||||
//however, it has been observed that LoROM-mapped BS-X carts always
|
||||
//use read-write flashcarts, and HiROM-mapped BS-X carts always use
|
||||
//read-only flashcarts.
|
||||
//below is an unfortunately necessary workaround to this problem.
|
||||
if(cartridge.mapper() == Cartridge::BSCHiROM) return;
|
||||
|
||||
if((addr & 0xff0000) == 0) {
|
||||
|
@@ -1,27 +0,0 @@
|
||||
void hiro_pbutton_tick(pButton *p) {
|
||||
if(p->self.on_tick) p->self.on_tick(event_t(event_t::Tick, 0, &p->self));
|
||||
}
|
||||
|
||||
void pButton::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
button = gtk_button_new_with_label(text ? text : "");
|
||||
set_default_font(button);
|
||||
gtk_widget_set_size_request(button, width, height);
|
||||
gtk_widget_show(button);
|
||||
g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(hiro_pbutton_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pButton::set_text(const char *text) {
|
||||
if(!button) return;
|
||||
gtk_button_set_label(GTK_BUTTON(button), text ? text : "");
|
||||
set_default_font(button);
|
||||
}
|
||||
|
||||
pButton::pButton(Button &self_) : pFormControl(self_), self(self_) {
|
||||
button = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pButton::gtk_handle() {
|
||||
return button;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
class pButton : public pFormControl {
|
||||
public:
|
||||
Button &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pButton(Button&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *button;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,89 +0,0 @@
|
||||
void hiro_pcanvas_expose(pCanvas *p) {
|
||||
uint32_t *f = p->fbuffer;
|
||||
uint32_t *r = p->rbuffer;
|
||||
for(unsigned y = p->canvas->allocation.height; y; y--) {
|
||||
for(unsigned x = p->canvas->allocation.width; x; x--) {
|
||||
uint32_t p = *f++;
|
||||
*r++ = ((p << 16) & 0xff0000) + (p & 0x00ff00) + ((p >> 16) & 0x0000ff);
|
||||
}
|
||||
}
|
||||
|
||||
gdk_draw_rgb_32_image(p->canvas->window,
|
||||
p->canvas->style->fg_gc[GTK_WIDGET_STATE(p->canvas)],
|
||||
0, 0, p->canvas->allocation.width, p->canvas->allocation.height,
|
||||
GDK_RGB_DITHER_NONE, (guchar*)p->rbuffer, p->bpitch);
|
||||
}
|
||||
|
||||
gboolean hiro_pcanvas_button_press(GtkWidget *widget, GdkEventButton *event, pCanvas *p) {
|
||||
if(p->self.on_input && event->button < mouse::buttons) {
|
||||
p->self.on_input(event_t(event_t::Input, (mouse::button + event->button) + (1 << 16), &p->self));
|
||||
}
|
||||
return false; //do not propogate the event to other handlers
|
||||
}
|
||||
|
||||
gboolean hiro_pcanvas_button_release(GtkWidget *widget, GdkEventButton *event, pCanvas *p) {
|
||||
if(p->self.on_input && event->button < mouse::buttons) {
|
||||
p->self.on_input(event_t(event_t::Input, (mouse::button + event->button) + (0 << 16), &p->self));
|
||||
}
|
||||
return false; //do not propogate the event to other handlers
|
||||
}
|
||||
|
||||
void pCanvas::create(unsigned style, unsigned width, unsigned height) {
|
||||
canvas = gtk_drawing_area_new();
|
||||
resize(width, height);
|
||||
GdkColor color;
|
||||
color.pixel = color.red = color.green = color.blue = 0;
|
||||
gtk_widget_modify_bg(canvas, GTK_STATE_NORMAL, &color);
|
||||
gtk_widget_set_double_buffered(canvas, false);
|
||||
gtk_widget_add_events(canvas, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
|
||||
gtk_widget_show(canvas);
|
||||
g_signal_connect_swapped(G_OBJECT(canvas), "expose_event", G_CALLBACK(hiro_pcanvas_expose), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(canvas), "button_press_event", G_CALLBACK(hiro_pcanvas_button_press), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(canvas), "button_release_event", G_CALLBACK(hiro_pcanvas_button_release), (gpointer)this);
|
||||
}
|
||||
|
||||
void pCanvas::redraw() {
|
||||
if(!canvas || !canvas->window) return;
|
||||
|
||||
GdkRectangle rect;
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = canvas->allocation.width;
|
||||
rect.height = canvas->allocation.height;
|
||||
gdk_window_invalidate_rect(canvas->window, &rect, true);
|
||||
}
|
||||
|
||||
uint32_t* pCanvas::buffer() {
|
||||
return fbuffer;
|
||||
}
|
||||
|
||||
pCanvas::pCanvas(Canvas &self_) : pFormControl(self_), self(self_) {
|
||||
canvas = 0;
|
||||
fbuffer = 0;
|
||||
rbuffer = 0;
|
||||
bpitch = 0;
|
||||
}
|
||||
|
||||
pCanvas::~pCanvas() {
|
||||
if(fbuffer) free(fbuffer);
|
||||
if(rbuffer) free(rbuffer);
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
void pCanvas::resize(unsigned width, unsigned height) {
|
||||
if(fbuffer) free(fbuffer);
|
||||
if(rbuffer) free(rbuffer);
|
||||
|
||||
bpitch = width * sizeof(uint32_t);
|
||||
fbuffer = (uint32_t*)malloc(bpitch * height);
|
||||
rbuffer = (uint32_t*)malloc(bpitch * height);
|
||||
memset(fbuffer, 0, bpitch * height);
|
||||
memset(rbuffer, 0, bpitch * height);
|
||||
|
||||
pFormControl::resize(width, height);
|
||||
}
|
||||
|
||||
GtkWidget* pCanvas::gtk_handle() {
|
||||
return canvas;
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
class pCanvas : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height);
|
||||
void redraw();
|
||||
uint32_t* buffer();
|
||||
|
||||
Canvas &self;
|
||||
pCanvas(Canvas&);
|
||||
~pCanvas();
|
||||
|
||||
/* internal */
|
||||
GtkWidget *canvas;
|
||||
//GTK+ RGB drawing function draws in xBGR format, so two buffers are needed ...
|
||||
uint32_t *fbuffer; //one for the xRGB image
|
||||
uint32_t *rbuffer; //one for the xBGR image
|
||||
unsigned bpitch;
|
||||
void resize(unsigned width, unsigned height);
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,41 +0,0 @@
|
||||
void hiro_pcheckbox_tick(pCheckbox *p) {
|
||||
if(!p->locked && p->self.on_tick) p->self.on_tick(event_t(event_t::Tick, p->checked(), &p->self));
|
||||
}
|
||||
|
||||
void pCheckbox::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
checkbox = gtk_check_button_new_with_label(text ? text : "");
|
||||
set_default_font(checkbox);
|
||||
gtk_widget_set_size_request(checkbox, width, height);
|
||||
gtk_widget_show(checkbox);
|
||||
g_signal_connect_swapped(G_OBJECT(checkbox), "toggled", G_CALLBACK(hiro_pcheckbox_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pCheckbox::set_text(const char *text) {
|
||||
if(!checkbox) return;
|
||||
gtk_button_set_label(GTK_BUTTON(checkbox), text ? text : "");
|
||||
}
|
||||
|
||||
void pCheckbox::check(bool state) {
|
||||
locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), state ? TRUE : FALSE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void pCheckbox::uncheck() {
|
||||
check(false);
|
||||
}
|
||||
|
||||
bool pCheckbox::checked() {
|
||||
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox));
|
||||
}
|
||||
|
||||
pCheckbox::pCheckbox(Checkbox &self_) : pFormControl(self_), self(self_) {
|
||||
checkbox = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pCheckbox::gtk_handle() {
|
||||
return checkbox;
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
class pCheckbox : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void check(bool state = true);
|
||||
void uncheck();
|
||||
bool checked();
|
||||
|
||||
Checkbox &self;
|
||||
pCheckbox(Checkbox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *checkbox;
|
||||
bool locked;
|
||||
};
|
@@ -1,45 +0,0 @@
|
||||
void hiro_pcombobox_change(pCombobox *p) {
|
||||
if(p->self.on_change) p->self.on_change(event_t(event_t::Change, p->get_selection(), &p->self));
|
||||
}
|
||||
|
||||
void pCombobox::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
combobox = gtk_combo_box_new_text();
|
||||
set_default_font(combobox);
|
||||
gtk_widget_set_size_request(combobox, width, height);
|
||||
gtk_widget_show(combobox);
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(combobox), "changed", G_CALLBACK(hiro_pcombobox_change), (gpointer)this);
|
||||
}
|
||||
|
||||
void pCombobox::add_item(const char *text) {
|
||||
if(!combobox) return;
|
||||
gtk_combo_box_append_text(GTK_COMBO_BOX(combobox), text ? text : "?");
|
||||
if(counter++ == 0) set_selection(0);
|
||||
}
|
||||
|
||||
int pCombobox::get_selection() {
|
||||
return gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
|
||||
}
|
||||
|
||||
void pCombobox::set_selection(int index) {
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index);
|
||||
}
|
||||
|
||||
void pCombobox::reset() {
|
||||
if(counter == 0) return;
|
||||
for(int i = counter - 1; i >= 0; i--) {
|
||||
gtk_combo_box_remove_text(GTK_COMBO_BOX(combobox), i);
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
pCombobox::pCombobox(Combobox &self_) : pFormControl(self_), self(self_) {
|
||||
combobox = 0;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pCombobox::gtk_handle() {
|
||||
return combobox;
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
class pCombobox : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void add_item(const char *text);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
Combobox &self;
|
||||
pCombobox(Combobox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *combobox;
|
||||
unsigned counter;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,74 +0,0 @@
|
||||
static void hiro_peditbox_change(pEditbox *p) {
|
||||
if(p->self.on_change) {
|
||||
p->self.on_change(event_t(event_t::Change, 0, &p->self));
|
||||
}
|
||||
}
|
||||
|
||||
void pEditbox::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
multiline = bool(style & Editbox::Multiline);
|
||||
|
||||
if(multiline == false) {
|
||||
editbox = gtk_entry_new();
|
||||
if(style & Editbox::Readonly) { gtk_entry_set_editable(GTK_ENTRY(editbox), false); }
|
||||
gtk_entry_set_text(GTK_ENTRY(editbox), text ? text : "");
|
||||
gtk_widget_set_size_request(editbox, width, height);
|
||||
gtk_widget_show(editbox);
|
||||
g_signal_connect_swapped(G_OBJECT(editbox), "changed", G_CALLBACK(hiro_peditbox_change), (gpointer)this);
|
||||
} else {
|
||||
GtkPolicyType hscroll = (style & Editbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Editbox::HorizontalScrollNever ) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
GtkPolicyType vscroll = (style & Editbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Editbox::VerticalScrollNever ) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
scrollbox = gtk_scrolled_window_new(0, 0);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN);
|
||||
gtk_widget_set_size_request(scrollbox, width, height);
|
||||
editbox = gtk_text_view_new();
|
||||
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(editbox),
|
||||
(hscroll == GTK_POLICY_NEVER ? GTK_WRAP_WORD_CHAR : GTK_WRAP_NONE));
|
||||
gtk_container_add(GTK_CONTAINER(scrollbox), editbox);
|
||||
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(editbox));
|
||||
if(style & Editbox::Readonly) { gtk_text_view_set_editable(GTK_TEXT_VIEW(editbox), false); }
|
||||
gtk_text_buffer_set_text(buffer, text ? text : "", -1);
|
||||
gtk_widget_show(editbox);
|
||||
gtk_widget_show(scrollbox);
|
||||
g_signal_connect_swapped(G_OBJECT(buffer), "changed", G_CALLBACK(hiro_peditbox_change), (gpointer)this);
|
||||
}
|
||||
|
||||
set_default_font(editbox);
|
||||
}
|
||||
|
||||
void pEditbox::set_text(const char *text) {
|
||||
if(multiline == false) {
|
||||
gtk_entry_set_text(GTK_ENTRY(editbox), text);
|
||||
} else {
|
||||
gtk_text_buffer_set_text(buffer, text, -1);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned pEditbox::get_text(char *text, unsigned length) {
|
||||
if(multiline == false) {
|
||||
const char *temp = gtk_entry_get_text(GTK_ENTRY(editbox));
|
||||
return strlcpy(text, temp ? temp : "", length);
|
||||
} else {
|
||||
GtkTextIter start, end;
|
||||
gtk_text_buffer_get_start_iter(buffer, &start);
|
||||
gtk_text_buffer_get_end_iter(buffer, &end);
|
||||
return strlcpy(text, gtk_text_buffer_get_text(buffer, &start, &end, true), length);
|
||||
}
|
||||
}
|
||||
|
||||
pEditbox::pEditbox(Editbox &self_) : pFormControl(self_), self(self_) {
|
||||
scrollbox = 0;
|
||||
editbox = 0;
|
||||
buffer = 0;
|
||||
multiline = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pEditbox::gtk_handle() {
|
||||
return multiline ? scrollbox : editbox;
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
class pEditbox : public pFormControl {
|
||||
public:
|
||||
Editbox &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
unsigned get_text(char *text, unsigned length = -1U);
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pEditbox(Editbox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *scrollbox;
|
||||
GtkWidget *editbox;
|
||||
GtkTextBuffer *buffer;
|
||||
bool multiline;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,32 +0,0 @@
|
||||
void pFormControl::resize(unsigned width, unsigned height) {
|
||||
gtk_widget_set_size_request(gtk_handle(), width, height);
|
||||
}
|
||||
|
||||
void pFormControl::focus() {
|
||||
gtk_widget_grab_focus(gtk_handle());
|
||||
}
|
||||
|
||||
bool pFormControl::focused() {
|
||||
return GTK_WIDGET_HAS_FOCUS(gtk_handle());
|
||||
}
|
||||
|
||||
void pFormControl::enable(bool state) {
|
||||
gtk_widget_set_sensitive(gtk_handle(), state);
|
||||
}
|
||||
|
||||
void pFormControl::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pFormControl::enabled() {
|
||||
return GTK_WIDGET_SENSITIVE(gtk_handle());
|
||||
}
|
||||
|
||||
pFormControl::pFormControl(FormControl &self_) : pWidget(self_), self(self_) {
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pFormControl::gtk_handle() {
|
||||
return 0;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
class pFormControl : public pWidget {
|
||||
public:
|
||||
virtual void resize(unsigned width, unsigned height);
|
||||
void focus();
|
||||
bool focused();
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
FormControl &self;
|
||||
pFormControl(FormControl&);
|
||||
|
||||
/* internal */
|
||||
virtual GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,20 +0,0 @@
|
||||
void pFrame::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
frame = gtk_frame_new(text ? text : "");
|
||||
set_default_font(frame);
|
||||
gtk_widget_set_size_request(frame, width, height);
|
||||
gtk_widget_show(frame);
|
||||
}
|
||||
|
||||
void pFrame::set_text(const char *text) {
|
||||
gtk_frame_set_label(GTK_FRAME(frame), text ? text : "");
|
||||
}
|
||||
|
||||
pFrame::pFrame(Frame &self_) : pFormControl(self_), self(self_) {
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pFrame::gtk_handle() {
|
||||
return frame;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
class pFrame : public pFormControl {
|
||||
public:
|
||||
Frame &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pFrame(Frame&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *frame;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,270 +0,0 @@
|
||||
#include "hiro.hpp"
|
||||
#include "port.cpp"
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
using nall::min;
|
||||
using nall::max;
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
static void set_font(GtkWidget *widget, gpointer font) {
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)set_font, font);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_default_font(GtkWidget *widget) {
|
||||
set_font(widget, phiro().font);
|
||||
}
|
||||
|
||||
#include "keymap.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
#include "menucontrol.cpp"
|
||||
#include "menugroup.cpp"
|
||||
#include "menuitem.cpp"
|
||||
#include "menucheckitem.cpp"
|
||||
#include "menuradioitem.cpp"
|
||||
#include "menuseparator.cpp"
|
||||
#include "formcontrol.cpp"
|
||||
#include "frame.cpp"
|
||||
#include "canvas.cpp"
|
||||
#include "label.cpp"
|
||||
#include "button.cpp"
|
||||
#include "checkbox.cpp"
|
||||
#include "radiobox.cpp"
|
||||
#include "editbox.cpp"
|
||||
#include "listbox.cpp"
|
||||
#include "combobox.cpp"
|
||||
#include "progressbar.cpp"
|
||||
#include "slider.cpp"
|
||||
|
||||
void pHiro::init() {
|
||||
is_composited = false;
|
||||
*default_path = 0;
|
||||
screen = gdk_screen_get_default();
|
||||
if(gdk_screen_is_composited(screen)) {
|
||||
colormap = gdk_screen_get_rgba_colormap(screen);
|
||||
if(colormap) is_composited = true;
|
||||
else colormap = gdk_screen_get_rgb_colormap(screen); //fallback
|
||||
} else {
|
||||
colormap = gdk_screen_get_rgb_colormap(screen);
|
||||
}
|
||||
|
||||
font = pango_font_description_new();
|
||||
pango_font_description_set_family(font, "Sans");
|
||||
pango_font_description_set_absolute_size(font, 11.0 * PANGO_SCALE);
|
||||
pango_font_description_set_style(font, PANGO_STYLE_NORMAL);
|
||||
|
||||
//apply custom GTK+-2.0 stylesheet.
|
||||
//it's obviously not ideal to override the global GTK+ theme settings;
|
||||
//however it is necessary to ensure consistency between ports of hiro.
|
||||
//without this, it would be impossible to develop a hiro application
|
||||
//on one platform, and be assured text wouldn't clipped off, etc on
|
||||
//another platform.
|
||||
gtk_rc_parse_string(
|
||||
"style \"ruby-gtk\"\n"
|
||||
"{\n"
|
||||
" GtkComboBox::appears-as-list = 1\n" //text tends to get cut off in some themes otherwise
|
||||
" GtkTreeView::vertical-separator = 0\n" //GTK+ lists tend to have way more space than on Windows
|
||||
"}\n"
|
||||
"\n"
|
||||
"class \"GtkComboBox\" style \"ruby-gtk\"\n"
|
||||
"class \"GtkTreeView\" style \"ruby-gtk\"\n"
|
||||
);
|
||||
}
|
||||
|
||||
void pHiro::term() {
|
||||
pango_font_description_free(font);
|
||||
enable_screensaver();
|
||||
}
|
||||
|
||||
bool pHiro::run() {
|
||||
if(is_screensaver_enabled == false) screensaver_tick();
|
||||
gtk_main_iteration_do(false);
|
||||
return pending();
|
||||
}
|
||||
|
||||
bool pHiro::pending() {
|
||||
return gtk_events_pending();
|
||||
}
|
||||
|
||||
bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
|
||||
if(!filename) return false;
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Select Folder",
|
||||
focus ? GTK_WINDOW(focus->p.gtk_handle()) : (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 && *path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
else if(*default_path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), default_path);
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
strcpy(filename, fn);
|
||||
set_default_path(fn);
|
||||
g_free(fn);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return strcmp(filename, ""); //return true if filename exists
|
||||
}
|
||||
|
||||
bool pHiro::file_open(Window *focus, char *filename, const char *path, const char *filter) {
|
||||
if(!filename) return false;
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Open File",
|
||||
focus ? GTK_WINDOW(focus->p.gtk_handle()) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
|
||||
(const gchar*)0);
|
||||
|
||||
if(path && *path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
else if(*default_path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), default_path);
|
||||
|
||||
if(filter && *filter) {
|
||||
lstring filterlist;
|
||||
filterlist.split("\n", filter);
|
||||
for(unsigned i = 0; i < filterlist.size(); i++) {
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
lstring filterpart;
|
||||
filterpart.split("\t", filterlist[i]);
|
||||
gtk_file_filter_set_name(filter, string() << filterpart[0] << " (" << filterpart[1] << ")");
|
||||
lstring patternlist;
|
||||
patternlist.split(",", filterpart[1]);
|
||||
for(unsigned l = 0; l < patternlist.size(); l++) {
|
||||
gtk_file_filter_add_pattern(filter, patternlist[l]);
|
||||
}
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
}
|
||||
}
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
strcpy(filename, fn);
|
||||
set_default_path(fn);
|
||||
g_free(fn);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return strcmp(filename, ""); //return true if filename exists
|
||||
}
|
||||
|
||||
bool pHiro::file_save(Window *focus, char *filename, const char *path, const char *filter) {
|
||||
if(!filename) return false;
|
||||
strcpy(filename, "");
|
||||
|
||||
GtkWidget *dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
focus ? GTK_WINDOW(focus->p.gtk_handle()) : (GtkWindow*)0,
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
||||
(const gchar*)0);
|
||||
|
||||
if(path && *path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path);
|
||||
else if(*default_path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), default_path);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||
|
||||
if(filter && *filter) {
|
||||
lstring filterlist;
|
||||
filterlist.split("\n", filter);
|
||||
for(unsigned i = 0; i < filterlist.size(); i++) {
|
||||
GtkFileFilter *filter = gtk_file_filter_new();
|
||||
lstring filterpart;
|
||||
filterpart.split("\t", filterlist[i]);
|
||||
gtk_file_filter_set_name(filter, string() << filterpart[0] << " (" << filterpart[1] << ")");
|
||||
lstring patternlist;
|
||||
patternlist.split(",", filterpart[1]);
|
||||
for(unsigned l = 0; l < patternlist.size(); l++) {
|
||||
gtk_file_filter_add_pattern(filter, patternlist[l]);
|
||||
}
|
||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||
}
|
||||
}
|
||||
|
||||
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *fn = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
strcpy(filename, fn);
|
||||
set_default_path(fn);
|
||||
g_free(fn);
|
||||
}
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
return strcmp(filename, ""); //return true if filename exists
|
||||
}
|
||||
|
||||
unsigned pHiro::screen_width() {
|
||||
return gdk_screen_width();
|
||||
}
|
||||
|
||||
unsigned pHiro::screen_height() {
|
||||
return gdk_screen_height();
|
||||
}
|
||||
|
||||
void pHiro::enable_screensaver() {
|
||||
if(is_screensaver_enabled == true) return;
|
||||
is_screensaver_enabled = true;
|
||||
DPMSDisable(GDK_DISPLAY());
|
||||
}
|
||||
|
||||
void pHiro::disable_screensaver() {
|
||||
if(is_screensaver_enabled == false) return;
|
||||
is_screensaver_enabled = false;
|
||||
DPMSEnable(GDK_DISPLAY());
|
||||
}
|
||||
|
||||
pHiro& pHiro::handle() {
|
||||
return hiro().p;
|
||||
}
|
||||
|
||||
pHiro::pHiro(Hiro &self_) : self(self_) {
|
||||
is_screensaver_enabled = true;
|
||||
}
|
||||
|
||||
pHiro& phiro() {
|
||||
return pHiro::handle();
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
//GTK+ does not save the most recent path to a file.
|
||||
//Strip trailing filename / folder to save path for next file dialog request.
|
||||
//This is only called when file dialog filename / folder is accepted, not when dialog cancelled.
|
||||
void pHiro::set_default_path(const char *p) {
|
||||
strcpy(default_path, p);
|
||||
for(int i = strlen(default_path) - 1; i >= 0; i--) {
|
||||
if(default_path[i] == '/' || default_path[i] == '\\') {
|
||||
default_path[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pHiro::screensaver_tick() {
|
||||
static clock_t delta_x = 0, delta_y = 0;
|
||||
|
||||
delta_y = clock();
|
||||
if(delta_y - delta_x < CLOCKS_PER_SEC * 20) return;
|
||||
|
||||
//XSetScreenSaver(timeout = 0) does not work
|
||||
//XResetScreenSaver() does not work
|
||||
//XScreenSaverSuspend() does not work
|
||||
//DPMSDisable() does not work
|
||||
//XSendEvent(KeyPressMask) does not work
|
||||
//use XTest extension to send fake keypress every ~20 seconds.
|
||||
//keycode of 255 does not map to any actual key, but it will block screensaver.
|
||||
delta_x = delta_y;
|
||||
XTestFakeKeyEvent(GDK_DISPLAY(), 255, True, 0);
|
||||
XSync(GDK_DISPLAY(), False);
|
||||
XTestFakeKeyEvent(GDK_DISPLAY(), 255, False, 0);
|
||||
XSync(GDK_DISPLAY(), False);
|
||||
}
|
||||
|
||||
} //namespace libhiro
|
@@ -1,78 +0,0 @@
|
||||
#ifndef HIRO_GTK_H
|
||||
#define HIRO_GTK_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <cairo.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <X11/extensions/dpms.h>
|
||||
#include <X11/extensions/XTest.h>
|
||||
|
||||
extern int hiromain(int argc, const char *const argv[]);
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
#include "widget.hpp"
|
||||
#include "window.hpp"
|
||||
#include "menucontrol.hpp"
|
||||
#include "menugroup.hpp"
|
||||
#include "menuitem.hpp"
|
||||
#include "menucheckitem.hpp"
|
||||
#include "menuradioitem.hpp"
|
||||
#include "menuseparator.hpp"
|
||||
#include "formcontrol.hpp"
|
||||
#include "frame.hpp"
|
||||
#include "canvas.hpp"
|
||||
#include "label.hpp"
|
||||
#include "button.hpp"
|
||||
#include "checkbox.hpp"
|
||||
#include "radiobox.hpp"
|
||||
#include "editbox.hpp"
|
||||
#include "listbox.hpp"
|
||||
#include "combobox.hpp"
|
||||
#include "progressbar.hpp"
|
||||
#include "slider.hpp"
|
||||
|
||||
class pHiro {
|
||||
public:
|
||||
Hiro &self;
|
||||
void init();
|
||||
void term();
|
||||
bool run();
|
||||
bool pending();
|
||||
|
||||
bool folder_select(Window *focus, char *filename, const char *path = "");
|
||||
bool file_open(Window *focus, char *filename, const char *path = "", const char *filter = "");
|
||||
bool file_save(Window *focus, char *filename, const char *path = "", const char *filter = "");
|
||||
|
||||
unsigned screen_width();
|
||||
unsigned screen_height();
|
||||
|
||||
void enable_screensaver();
|
||||
void disable_screensaver();
|
||||
|
||||
static pHiro& handle();
|
||||
pHiro(Hiro&);
|
||||
|
||||
/* internal */
|
||||
GdkScreen *screen;
|
||||
GdkColormap *colormap;
|
||||
PangoFontDescription *font;
|
||||
bool is_composited;
|
||||
char default_path[PATH_MAX];
|
||||
|
||||
void set_default_path(const char*);
|
||||
bool is_screensaver_enabled;
|
||||
void screensaver_tick();
|
||||
uint16_t translate_key(unsigned key);
|
||||
};
|
||||
|
||||
pHiro& phiro();
|
||||
|
||||
} //namespace libhiro
|
||||
|
||||
#endif //ifndef HIRO_GTK_H
|
@@ -1,188 +0,0 @@
|
||||
uint16_t pHiro::translate_key(unsigned key) {
|
||||
switch(key) {
|
||||
case GDK_Escape: return keyboard::escape;
|
||||
|
||||
case GDK_F1: return keyboard::f1;
|
||||
case GDK_F2: return keyboard::f2;
|
||||
case GDK_F3: return keyboard::f3;
|
||||
case GDK_F4: return keyboard::f4;
|
||||
case GDK_F5: return keyboard::f5;
|
||||
case GDK_F6: return keyboard::f6;
|
||||
case GDK_F7: return keyboard::f7;
|
||||
case GDK_F8: return keyboard::f8;
|
||||
case GDK_F9: return keyboard::f9;
|
||||
case GDK_F10: return keyboard::f10;
|
||||
case GDK_F11: return keyboard::f11;
|
||||
case GDK_F12: return keyboard::f12;
|
||||
|
||||
case GDK_Print: return keyboard::print_screen;
|
||||
case GDK_Sys_Req: return keyboard::print_screen;
|
||||
case GDK_Scroll_Lock: return keyboard::scroll_lock;
|
||||
case GDK_Pause: return keyboard::pause;
|
||||
case GDK_Break: return keyboard::pause;
|
||||
|
||||
case GDK_grave: return keyboard::tilde;
|
||||
case GDK_asciitilde: return keyboard::tilde;
|
||||
|
||||
case GDK_1: return keyboard::num_1;
|
||||
case GDK_2: return keyboard::num_2;
|
||||
case GDK_3: return keyboard::num_3;
|
||||
case GDK_4: return keyboard::num_4;
|
||||
case GDK_5: return keyboard::num_5;
|
||||
case GDK_6: return keyboard::num_6;
|
||||
case GDK_7: return keyboard::num_7;
|
||||
case GDK_8: return keyboard::num_8;
|
||||
case GDK_9: return keyboard::num_9;
|
||||
case GDK_0: return keyboard::num_0;
|
||||
|
||||
case GDK_exclam: return keyboard::num_1;
|
||||
case GDK_at: return keyboard::num_2;
|
||||
case GDK_numbersign: return keyboard::num_3;
|
||||
case GDK_dollar: return keyboard::num_4;
|
||||
case GDK_percent: return keyboard::num_5;
|
||||
case GDK_asciicircum: return keyboard::num_6;
|
||||
case GDK_ampersand: return keyboard::num_7;
|
||||
case GDK_asterisk: return keyboard::num_8;
|
||||
case GDK_parenleft: return keyboard::num_9;
|
||||
case GDK_parenright: return keyboard::num_0;
|
||||
|
||||
case GDK_minus: return keyboard::dash;
|
||||
case GDK_underscore: return keyboard::dash;
|
||||
case GDK_equal: return keyboard::equal;
|
||||
case GDK_plus: return keyboard::equal;
|
||||
case GDK_BackSpace: return keyboard::backspace;
|
||||
|
||||
case GDK_Insert: return keyboard::insert;
|
||||
case GDK_Delete: return keyboard::delete_;
|
||||
case GDK_Home: return keyboard::home;
|
||||
case GDK_End: return keyboard::end;
|
||||
case GDK_Page_Up: return keyboard::page_up;
|
||||
case GDK_Page_Down: return keyboard::page_down;
|
||||
|
||||
case GDK_a: return keyboard::a;
|
||||
case GDK_b: return keyboard::b;
|
||||
case GDK_c: return keyboard::c;
|
||||
case GDK_d: return keyboard::d;
|
||||
case GDK_e: return keyboard::e;
|
||||
case GDK_f: return keyboard::f;
|
||||
case GDK_g: return keyboard::g;
|
||||
case GDK_h: return keyboard::h;
|
||||
case GDK_i: return keyboard::i;
|
||||
case GDK_j: return keyboard::j;
|
||||
case GDK_k: return keyboard::k;
|
||||
case GDK_l: return keyboard::l;
|
||||
case GDK_m: return keyboard::m;
|
||||
case GDK_n: return keyboard::n;
|
||||
case GDK_o: return keyboard::o;
|
||||
case GDK_p: return keyboard::p;
|
||||
case GDK_q: return keyboard::q;
|
||||
case GDK_r: return keyboard::r;
|
||||
case GDK_s: return keyboard::s;
|
||||
case GDK_t: return keyboard::t;
|
||||
case GDK_u: return keyboard::u;
|
||||
case GDK_v: return keyboard::v;
|
||||
case GDK_w: return keyboard::w;
|
||||
case GDK_x: return keyboard::x;
|
||||
case GDK_y: return keyboard::y;
|
||||
case GDK_z: return keyboard::z;
|
||||
|
||||
case GDK_A: return keyboard::a;
|
||||
case GDK_B: return keyboard::b;
|
||||
case GDK_C: return keyboard::c;
|
||||
case GDK_D: return keyboard::d;
|
||||
case GDK_E: return keyboard::e;
|
||||
case GDK_F: return keyboard::f;
|
||||
case GDK_G: return keyboard::g;
|
||||
case GDK_H: return keyboard::h;
|
||||
case GDK_I: return keyboard::i;
|
||||
case GDK_J: return keyboard::j;
|
||||
case GDK_K: return keyboard::k;
|
||||
case GDK_L: return keyboard::l;
|
||||
case GDK_M: return keyboard::m;
|
||||
case GDK_N: return keyboard::n;
|
||||
case GDK_O: return keyboard::o;
|
||||
case GDK_P: return keyboard::p;
|
||||
case GDK_Q: return keyboard::q;
|
||||
case GDK_R: return keyboard::r;
|
||||
case GDK_S: return keyboard::s;
|
||||
case GDK_T: return keyboard::t;
|
||||
case GDK_U: return keyboard::u;
|
||||
case GDK_V: return keyboard::v;
|
||||
case GDK_W: return keyboard::w;
|
||||
case GDK_X: return keyboard::x;
|
||||
case GDK_Y: return keyboard::y;
|
||||
case GDK_Z: return keyboard::z;
|
||||
|
||||
case GDK_bracketleft: return keyboard::lbracket;
|
||||
case GDK_bracketright: return keyboard::rbracket;
|
||||
case GDK_backslash: return keyboard::backslash;
|
||||
case GDK_semicolon: return keyboard::semicolon;
|
||||
case GDK_apostrophe: return keyboard::apostrophe;
|
||||
case GDK_comma: return keyboard::comma;
|
||||
case GDK_period: return keyboard::period;
|
||||
case GDK_slash: return keyboard::slash;
|
||||
|
||||
case GDK_braceleft: return keyboard::lbracket;
|
||||
case GDK_braceright: return keyboard::rbracket;
|
||||
case GDK_bar: return keyboard::backslash;
|
||||
case GDK_colon: return keyboard::semicolon;
|
||||
case GDK_quotedbl: return keyboard::apostrophe;
|
||||
case GDK_less: return keyboard::comma;
|
||||
case GDK_greater: return keyboard::period;
|
||||
case GDK_question: return keyboard::slash;
|
||||
|
||||
case GDK_KP_1: return keyboard::pad_1;
|
||||
case GDK_KP_2: return keyboard::pad_2;
|
||||
case GDK_KP_3: return keyboard::pad_3;
|
||||
case GDK_KP_4: return keyboard::pad_4;
|
||||
case GDK_KP_5: return keyboard::pad_5;
|
||||
case GDK_KP_6: return keyboard::pad_6;
|
||||
case GDK_KP_7: return keyboard::pad_7;
|
||||
case GDK_KP_8: return keyboard::pad_8;
|
||||
case GDK_KP_9: return keyboard::pad_9;
|
||||
case GDK_KP_0: return keyboard::pad_0;
|
||||
case GDK_KP_Decimal: return keyboard::point;
|
||||
|
||||
case GDK_KP_End: return keyboard::pad_1;
|
||||
case GDK_KP_Down: return keyboard::pad_2;
|
||||
case GDK_KP_Page_Down: return keyboard::pad_3;
|
||||
case GDK_KP_Left: return keyboard::pad_4;
|
||||
case GDK_KP_Begin: return keyboard::pad_5;
|
||||
case GDK_KP_Right: return keyboard::pad_6;
|
||||
case GDK_KP_Home: return keyboard::pad_7;
|
||||
case GDK_KP_Up: return keyboard::pad_8;
|
||||
case GDK_KP_Page_Up: return keyboard::pad_9;
|
||||
case GDK_KP_Insert: return keyboard::pad_0;
|
||||
case GDK_KP_Delete: return keyboard::point;
|
||||
|
||||
case GDK_KP_Add: return keyboard::add;
|
||||
case GDK_KP_Subtract: return keyboard::subtract;
|
||||
case GDK_KP_Multiply: return keyboard::multiply;
|
||||
case GDK_KP_Divide: return keyboard::divide;
|
||||
case GDK_KP_Enter: return keyboard::enter;
|
||||
|
||||
case GDK_Num_Lock: return keyboard::num_lock;
|
||||
case GDK_Caps_Lock: return keyboard::caps_lock;
|
||||
|
||||
case GDK_Up: return keyboard::up;
|
||||
case GDK_Down: return keyboard::down;
|
||||
case GDK_Left: return keyboard::left;
|
||||
case GDK_Right: return keyboard::right;
|
||||
|
||||
case GDK_Tab: return keyboard::tab;
|
||||
case GDK_Return: return keyboard::return_;
|
||||
case GDK_space: return keyboard::spacebar;
|
||||
|
||||
case GDK_Control_L: return keyboard::lctrl;
|
||||
case GDK_Control_R: return keyboard::rctrl;
|
||||
case GDK_Alt_L: return keyboard::lalt;
|
||||
case GDK_Alt_R: return keyboard::ralt;
|
||||
case GDK_Shift_L: return keyboard::lshift;
|
||||
case GDK_Shift_R: return keyboard::rshift;
|
||||
case GDK_Super_L: return keyboard::lsuper;
|
||||
case GDK_Super_R: return keyboard::rsuper;
|
||||
case GDK_Menu: return keyboard::menu;
|
||||
}
|
||||
|
||||
return keyboard::none;
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
void pLabel::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
label = gtk_label_new(text ? text : "");
|
||||
set_default_font(label);
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
|
||||
gtk_widget_set_size_request(label, width, height);
|
||||
gtk_widget_show(label);
|
||||
}
|
||||
|
||||
void pLabel::set_text(const char *text) {
|
||||
if(!label) return;
|
||||
gtk_label_set_label(GTK_LABEL(label), text ? text : "");
|
||||
}
|
||||
|
||||
pLabel::pLabel(Label &self_) : pFormControl(self_), self(self_) {
|
||||
label = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pLabel::gtk_handle() {
|
||||
return label;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
class pLabel : public pFormControl {
|
||||
public:
|
||||
Label &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pLabel(Label&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *label;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,160 +0,0 @@
|
||||
static void hiro_plistbox_change(pListbox *p) {
|
||||
//only send message when active item changes
|
||||
if(p->listbox_selection == p->get_selection()) return;
|
||||
|
||||
p->listbox_selection = p->get_selection();
|
||||
if(p->self.on_change) {
|
||||
p->self.on_change(event_t(event_t::Change, p->listbox_selection, &p->self));
|
||||
}
|
||||
}
|
||||
|
||||
static void hiro_plistbox_activate(pListbox *p) {
|
||||
p->listbox_selection = p->get_selection();
|
||||
if(p->self.on_activate) {
|
||||
p->self.on_activate(event_t(event_t::Activate, p->listbox_selection, &p->self));
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::create(unsigned style, unsigned width, unsigned height, const char *columns, const char *text) {
|
||||
bool header = style & Listbox::Header;
|
||||
GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Listbox::HorizontalScrollNever ) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Listbox::VerticalScrollNever ) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
|
||||
scrollbox = gtk_scrolled_window_new(0, 0);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN);
|
||||
|
||||
lstring list;
|
||||
list.split("\t", columns);
|
||||
|
||||
GType *v = (GType*)malloc(list.size() * sizeof(GType));
|
||||
for(unsigned i = 0; i < list.size(); i++) v[i] = G_TYPE_STRING;
|
||||
store = gtk_list_store_newv(list.size(), v);
|
||||
free(v);
|
||||
|
||||
listbox = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
|
||||
gtk_container_add(GTK_CONTAINER(scrollbox), listbox);
|
||||
g_object_unref(G_OBJECT(store));
|
||||
gtk_widget_set_size_request(scrollbox, width, height);
|
||||
gtk_widget_show(listbox);
|
||||
gtk_widget_show(scrollbox);
|
||||
|
||||
//alternate colors for each listbox entry if there are multiple columns
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(listbox), list.size() >= 2 ? true : false);
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
unsigned i = column.size();
|
||||
column[i].renderer = gtk_cell_renderer_text_new();
|
||||
column[i].column = gtk_tree_view_column_new_with_attributes(
|
||||
list[i], column[i].renderer, "text", i, (void*)0
|
||||
);
|
||||
//default header widget is GtkLabel with stock font size;
|
||||
//only way to assign a custom font to header widget is to create custom GtkLabel widget.
|
||||
column[i].label = gtk_label_new(list[i]);
|
||||
set_default_font(column[i].label);
|
||||
gtk_widget_show(column[i].label);
|
||||
gtk_tree_view_column_set_widget(GTK_TREE_VIEW_COLUMN(column[i].column), column[i].label);
|
||||
gtk_tree_view_append_column(GTK_TREE_VIEW(listbox), column[i].column);
|
||||
}
|
||||
|
||||
if(text && *text) {
|
||||
list.split("\n", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) add_item(list[i]);
|
||||
}
|
||||
|
||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(listbox), header);
|
||||
autosize_columns();
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(listbox), "cursor-changed", G_CALLBACK(hiro_plistbox_change), (gpointer)this);
|
||||
g_signal_connect_swapped(G_OBJECT(listbox), "row-activated", G_CALLBACK(hiro_plistbox_activate), (gpointer)this);
|
||||
|
||||
set_default_font(listbox);
|
||||
}
|
||||
|
||||
void pListbox::autosize_columns() {
|
||||
gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listbox));
|
||||
}
|
||||
|
||||
void pListbox::set_column_width(unsigned index, unsigned width) {
|
||||
gtk_tree_view_column_set_min_width(column[index].column, width);
|
||||
gtk_tree_view_column_set_max_width(column[index].column, width);
|
||||
}
|
||||
|
||||
void pListbox::add_item(const char *text) {
|
||||
lstring list;
|
||||
list.split("\t", text);
|
||||
gtk_list_store_append(store, &iter);
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
gtk_list_store_set(store, &iter, i, (const char*)list[i], -1);
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::set_item(unsigned index, const char *text) {
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(listbox));
|
||||
for(unsigned i = 0; i <= index; i++) {
|
||||
i == 0 ?
|
||||
gtk_tree_model_get_iter_first(model, &iter) :
|
||||
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(store, &iter, i, (const char*)list[i], -1);
|
||||
}
|
||||
}
|
||||
|
||||
int pListbox::get_selection() {
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listbox));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(listbox));
|
||||
if(gtk_tree_model_get_iter_first(model, &iter) == false) return -1;
|
||||
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return 0;
|
||||
for(unsigned i = 1; i < 100000; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) return -1;
|
||||
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pListbox::set_selection(int index) {
|
||||
int current = get_selection();
|
||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listbox));
|
||||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(listbox));
|
||||
gtk_tree_selection_unselect_all(selection);
|
||||
if(index < 0) return; //nothing to select?
|
||||
|
||||
if(gtk_tree_model_get_iter_first(model, &iter)) {
|
||||
if(index == 0) {
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
} else {
|
||||
for(unsigned i = 1; i < 100000; i++) {
|
||||
if(gtk_tree_model_iter_next(model, &iter) == false) break;
|
||||
if(index == i) {
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::reset() {
|
||||
listbox_selection = -1;
|
||||
gtk_list_store_clear(GTK_LIST_STORE(store));
|
||||
gtk_tree_view_set_model(GTK_TREE_VIEW(listbox), GTK_TREE_MODEL(store));
|
||||
}
|
||||
|
||||
pListbox::pListbox(Listbox &self_) : pFormControl(self_), self(self_) {
|
||||
scrollbox = 0;
|
||||
listbox = 0;
|
||||
listbox_selection = -1;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pListbox::gtk_handle() {
|
||||
return scrollbox;
|
||||
}
|
@@ -1,28 +0,0 @@
|
||||
class pListbox : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *columns = "", const char *text = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(unsigned column, unsigned width);
|
||||
void add_item(const char *text);
|
||||
void set_item(unsigned index, const char *text);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
Listbox &self;
|
||||
pListbox(Listbox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *scrollbox;
|
||||
GtkWidget *listbox;
|
||||
GtkListStore *store;
|
||||
struct GtkColumn {
|
||||
GtkCellRenderer *renderer;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkWidget *label;
|
||||
};
|
||||
vector<GtkColumn> column;
|
||||
GtkTreeIter iter;
|
||||
int listbox_selection;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,35 +0,0 @@
|
||||
void hiro_pmenucheckitem_tick(pMenuCheckItem *p) {
|
||||
if(!p->locked && p->self.on_tick) p->self.on_tick(event_t(event_t::Tick, p->checked(), &p->self));
|
||||
}
|
||||
|
||||
void pMenuCheckItem::create(const char *text) {
|
||||
item = gtk_check_menu_item_new_with_label(text ? text : "?");
|
||||
set_default_font(item);
|
||||
gtk_widget_show(item);
|
||||
g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(hiro_pmenucheckitem_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pMenuCheckItem::check(bool state) {
|
||||
locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), state ? TRUE : FALSE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void pMenuCheckItem::uncheck() {
|
||||
check(false);
|
||||
}
|
||||
|
||||
bool pMenuCheckItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
|
||||
}
|
||||
|
||||
pMenuCheckItem::pMenuCheckItem(MenuCheckItem &self_) : pMenuControl(self_), self(self_) {
|
||||
item = 0;
|
||||
locked = true;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pMenuCheckItem::gtk_handle() {
|
||||
return item;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
class pMenuCheckItem : public pMenuControl {
|
||||
public:
|
||||
void create(const char *text = "");
|
||||
void check(bool state = true);
|
||||
void uncheck();
|
||||
bool checked();
|
||||
|
||||
MenuCheckItem &self;
|
||||
pMenuCheckItem(MenuCheckItem&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *item;
|
||||
bool locked;
|
||||
};
|
@@ -1,20 +0,0 @@
|
||||
void pMenuControl::enable(bool state) {
|
||||
gtk_widget_set_sensitive(gtk_handle(), state);
|
||||
}
|
||||
|
||||
void pMenuControl::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pMenuControl::enabled() {
|
||||
return GTK_WIDGET_SENSITIVE(gtk_handle());
|
||||
}
|
||||
|
||||
pMenuControl::pMenuControl(MenuControl &self_) : pWidget(self_), self(self_) {
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pMenuControl::gtk_handle() {
|
||||
return 0;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
class pMenuControl : public pWidget {
|
||||
public:
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
MenuControl &self;
|
||||
pMenuControl(MenuControl&);
|
||||
|
||||
/* internal */
|
||||
virtual GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,22 +0,0 @@
|
||||
void pMenuGroup::create(const char *text) {
|
||||
group = gtk_menu_new();
|
||||
item = gtk_menu_item_new_with_label(text ? text : "");
|
||||
set_default_font(item);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), group);
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
|
||||
void pMenuGroup::attach(MenuControl &menucontrol) {
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(group), menucontrol.p.gtk_handle());
|
||||
}
|
||||
|
||||
pMenuGroup::pMenuGroup(MenuGroup &self_) : pMenuControl(self_), self(self_) {
|
||||
group = 0;
|
||||
item = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pMenuGroup::gtk_handle() {
|
||||
return item;
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
class pMenuGroup : public pMenuControl {
|
||||
public:
|
||||
MenuGroup &self;
|
||||
void create(const char *text);
|
||||
void attach(MenuControl &menucontrol);
|
||||
|
||||
pMenuGroup(MenuGroup&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *group;
|
||||
GtkWidget *item;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,20 +0,0 @@
|
||||
void hiro_pmenuitem_tick(pMenuItem *p) {
|
||||
if(p->self.on_tick) p->self.on_tick(event_t(event_t::Tick, 0, &p->self));
|
||||
}
|
||||
|
||||
void pMenuItem::create(const char *text) {
|
||||
item = gtk_menu_item_new_with_label(text ? text : "");
|
||||
set_default_font(item);
|
||||
g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(hiro_pmenuitem_tick), (gpointer)this);
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
|
||||
pMenuItem::pMenuItem(MenuItem &self_) : pMenuControl(self_), self(self_) {
|
||||
item = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pMenuItem::gtk_handle() {
|
||||
return item;
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
class pMenuItem : public pMenuControl {
|
||||
public:
|
||||
void create(const char *text = "");
|
||||
|
||||
MenuItem &self;
|
||||
pMenuItem(MenuItem&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *item;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,37 +0,0 @@
|
||||
void hiro_pmenuradioitem_tick(pMenuRadioItem *p) {
|
||||
//GTK+ sends two messages: one for the activated radio item,
|
||||
//and one for the deactivated radio item. ignore the latter.
|
||||
if(!p->locked && p->checked() && p->self.on_tick) p->self.on_tick(event_t(event_t::Tick, 0, &p->self));
|
||||
}
|
||||
|
||||
void pMenuRadioItem::create(MenuRadioItemGroup &group, const char *text) {
|
||||
if(group.size() == 0 || group[0] == &self) {
|
||||
item = gtk_radio_menu_item_new_with_label(0, text ? text : "?");
|
||||
} else {
|
||||
item = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(group[0]->p.gtk_handle()), text ? text : "");
|
||||
}
|
||||
set_default_font(item);
|
||||
gtk_widget_show(item);
|
||||
g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(hiro_pmenuradioitem_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pMenuRadioItem::check() {
|
||||
locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool pMenuRadioItem::checked() {
|
||||
return gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
|
||||
}
|
||||
|
||||
pMenuRadioItem::pMenuRadioItem(MenuRadioItem &self_) : pMenuControl(self_), self(self_) {
|
||||
item = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pMenuRadioItem::gtk_handle() {
|
||||
return item;
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
class pMenuRadioItem : public pMenuControl {
|
||||
public:
|
||||
void create(MenuRadioItemGroup &group, const char *text = "");
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
MenuRadioItem &self;
|
||||
pMenuRadioItem(MenuRadioItem&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *item;
|
||||
bool locked;
|
||||
};
|
@@ -1,14 +0,0 @@
|
||||
void pMenuSeparator::create() {
|
||||
item = gtk_separator_menu_item_new();
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
|
||||
pMenuSeparator::pMenuSeparator(MenuSeparator &self_) : pMenuControl(self_), self(self_) {
|
||||
item = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pMenuSeparator::gtk_handle() {
|
||||
return item;
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
class pMenuSeparator : public pMenuControl {
|
||||
public:
|
||||
MenuSeparator &self;
|
||||
void create();
|
||||
|
||||
pMenuSeparator(MenuSeparator&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *item;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,17 +0,0 @@
|
||||
char* userpath(char *output) {
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
if(userinfo) { strcpy(output, userinfo->pw_dir); }
|
||||
return output;
|
||||
}
|
||||
|
||||
int mkdir(const char *path) {
|
||||
return mkdir(path, 0755);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
gtk_init(&argc, &argv);
|
||||
libhiro::hiro().init();
|
||||
int result = hiromain(argc, argv);
|
||||
libhiro::hiro().term();
|
||||
return result;
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
void pProgressbar::create(unsigned style, unsigned width, unsigned height) {
|
||||
progressbar = gtk_progress_bar_new();
|
||||
gtk_widget_set_size_request(progressbar, width, height);
|
||||
gtk_widget_show(progressbar);
|
||||
}
|
||||
|
||||
unsigned pProgressbar::get_progress() {
|
||||
unsigned progress = (unsigned)(gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(progressbar)) * 100.0);
|
||||
return max(0U, min(progress, 100U));
|
||||
}
|
||||
|
||||
void pProgressbar::set_progress(unsigned progress) {
|
||||
progress = max(0U, min(progress, 100U));
|
||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressbar), (double)progress / 100.0);
|
||||
}
|
||||
|
||||
pProgressbar::pProgressbar(Progressbar &self_) : pFormControl(self_), self(self_) {
|
||||
progressbar = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pProgressbar::gtk_handle() {
|
||||
return progressbar;
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
class pProgressbar : public pFormControl {
|
||||
public:
|
||||
Progressbar &self;
|
||||
void create(unsigned style, unsigned width, unsigned height);
|
||||
unsigned get_progress();
|
||||
void set_progress(unsigned progress);
|
||||
|
||||
pProgressbar(Progressbar&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *progressbar;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,43 +0,0 @@
|
||||
void hiro_pradiobox_tick(pRadiobox *p) {
|
||||
//GTK+ sends two messages: one for the activated radiobox,
|
||||
//and one for the deactivated radiobox. ignore the latter.
|
||||
if(!p->locked && p->checked() && p->self.on_tick) p->self.on_tick(event_t(event_t::Tick, 0, &p->self));
|
||||
}
|
||||
|
||||
void pRadiobox::create(RadioboxGroup &group, unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
if(group.size() == 0 || group[0] == &self) {
|
||||
radiobox = gtk_radio_button_new_with_label(0, text ? text : "");
|
||||
} else {
|
||||
radiobox = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(group[0]->p.gtk_handle()), text ? text : "");
|
||||
}
|
||||
set_default_font(radiobox);
|
||||
gtk_widget_set_size_request(radiobox, width, height);
|
||||
gtk_widget_show(radiobox);
|
||||
g_signal_connect_swapped(G_OBJECT(radiobox), "toggled", G_CALLBACK(hiro_pradiobox_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pRadiobox::set_text(const char *text) {
|
||||
if(!radiobox) return;
|
||||
gtk_button_set_label(GTK_BUTTON(radiobox), text ? text : "");
|
||||
}
|
||||
|
||||
void pRadiobox::check() {
|
||||
locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radiobox), TRUE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool pRadiobox::checked() {
|
||||
return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radiobox));
|
||||
}
|
||||
|
||||
pRadiobox::pRadiobox(Radiobox &self_) : pFormControl(self), self(self_) {
|
||||
radiobox = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pRadiobox::gtk_handle() {
|
||||
return radiobox;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
class pRadiobox : public pFormControl {
|
||||
public:
|
||||
void create(RadioboxGroup &group, unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
Radiobox &self;
|
||||
pRadiobox(Radiobox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *radiobox;
|
||||
bool locked;
|
||||
};
|
@@ -1,36 +0,0 @@
|
||||
void hiro_pslider_change(pSlider *p) {
|
||||
if(p->slider_position == p->get_position()) return;
|
||||
if(p->self.on_change) p->self.on_change(event_t(event_t::Change, p->slider_position = p->get_position(), &p->self));
|
||||
}
|
||||
|
||||
void pSlider::create(unsigned style, unsigned width, unsigned height, unsigned length) {
|
||||
if(length < 1) length = 1;
|
||||
if(style & Slider::Vertical) {
|
||||
slider = gtk_vscale_new_with_range(0, length - 1, 1);
|
||||
} else {
|
||||
slider = gtk_hscale_new_with_range(0, length - 1, 1);
|
||||
}
|
||||
gtk_scale_set_draw_value(GTK_SCALE(slider), FALSE);
|
||||
gtk_widget_set_size_request(slider, width, height);
|
||||
gtk_widget_show(slider);
|
||||
g_signal_connect_swapped(G_OBJECT(slider), "value-changed", G_CALLBACK(hiro_pslider_change), (gpointer)this);
|
||||
}
|
||||
|
||||
unsigned pSlider::get_position() {
|
||||
return (unsigned)gtk_range_get_value(GTK_RANGE(slider));
|
||||
}
|
||||
|
||||
void pSlider::set_position(unsigned position) {
|
||||
gtk_range_set_value(GTK_RANGE(slider), position);
|
||||
}
|
||||
|
||||
pSlider::pSlider(Slider &self_) : pFormControl(self_), self(self_) {
|
||||
slider = 0;
|
||||
slider_position = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pSlider::gtk_handle() {
|
||||
return slider;
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
class pSlider : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, unsigned length);
|
||||
unsigned get_position();
|
||||
void set_position(unsigned position);
|
||||
|
||||
Slider &self;
|
||||
pSlider(Slider&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *slider;
|
||||
unsigned slider_position;
|
||||
GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,24 +0,0 @@
|
||||
void pWidget::show(bool state) {
|
||||
state ? gtk_widget_show(gtk_handle()) : gtk_widget_hide(gtk_handle());
|
||||
}
|
||||
|
||||
void pWidget::hide() {
|
||||
show(false);
|
||||
}
|
||||
|
||||
bool pWidget::visible() {
|
||||
return GTK_WIDGET_VISIBLE(gtk_handle());
|
||||
}
|
||||
|
||||
uintptr_t pWidget::handle() {
|
||||
return GDK_WINDOW_XID(gtk_handle()->window);
|
||||
}
|
||||
|
||||
pWidget::pWidget(Widget &self_) : self(self_) {
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pWidget::gtk_handle() {
|
||||
return 0;
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
class pWidget {
|
||||
public:
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
uintptr_t handle();
|
||||
|
||||
Widget &self;
|
||||
pWidget(Widget&);
|
||||
|
||||
/* internal */
|
||||
virtual GtkWidget* gtk_handle();
|
||||
};
|
@@ -1,325 +0,0 @@
|
||||
static gint hiro_pwindow_close(pWindow *p) {
|
||||
uintptr_t r = p->self.on_close ? p->self.on_close(event_t(event_t::Close, 0, &p->self)) : true;
|
||||
return !bool(r);
|
||||
}
|
||||
|
||||
static gboolean hiro_pwindow_expose(pWindow *p) {
|
||||
cairo_t *context = gdk_cairo_create(p->window->window);
|
||||
GtkStyle *style = gtk_widget_get_style(p->window);
|
||||
|
||||
double red = double(style->bg[GTK_STATE_NORMAL].red) / 65536.0;
|
||||
double green = double(style->bg[GTK_STATE_NORMAL].green) / 65536.0;
|
||||
double blue = double(style->bg[GTK_STATE_NORMAL].blue) / 65536.0;
|
||||
double alpha = double(p->state.alpha) / 256.0;
|
||||
|
||||
if(phiro().is_composited == true) {
|
||||
cairo_set_source_rgba(context, red, green, blue, alpha);
|
||||
} else {
|
||||
cairo_set_source_rgb(context, red, green, blue);
|
||||
}
|
||||
|
||||
cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_paint(context);
|
||||
cairo_destroy(context);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint hiro_pwindow_keydown(GtkWidget *w, GdkEventKey *key, pWindow *p) {
|
||||
if(p && p->self.on_input) {
|
||||
p->self.on_input(event_t(event_t::Input,
|
||||
phiro().translate_key(key->keyval) + (1 << 16),
|
||||
&p->self));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint hiro_pwindow_keyup(GtkWidget *w, GdkEventKey *key, pWindow *p) {
|
||||
if(p && p->self.on_input) {
|
||||
p->self.on_input(event_t(event_t::Input,
|
||||
phiro().translate_key(key->keyval) + (0 << 16),
|
||||
&p->self));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void pWindow::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_widget_set_colormap(window, phiro().colormap);
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(window), text ? text : "");
|
||||
gtk_window_set_resizable(GTK_WINDOW(window), false);
|
||||
gtk_widget_set_app_paintable(window, true);
|
||||
if(style & Window::AutoCenter) gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ALWAYS);
|
||||
g_signal_connect_swapped(G_OBJECT(window), "delete_event", G_CALLBACK(hiro_pwindow_close), (gpointer)this);
|
||||
g_signal_connect_swapped(G_OBJECT(window), "expose_event", G_CALLBACK(hiro_pwindow_expose), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(hiro_pwindow_keydown), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(hiro_pwindow_keyup), (gpointer)this);
|
||||
|
||||
menucontainer = gtk_vbox_new(false, 0);
|
||||
gtk_container_add(GTK_CONTAINER(window), menucontainer);
|
||||
gtk_widget_show(menucontainer);
|
||||
|
||||
menubar = gtk_menu_bar_new();
|
||||
gtk_box_pack_start(GTK_BOX(menucontainer), menubar, false, false, 0);
|
||||
|
||||
formcontainer = gtk_fixed_new();
|
||||
gtk_widget_set_size_request(formcontainer, width, height);
|
||||
gtk_box_pack_start(GTK_BOX(menucontainer), formcontainer, true, true, 0);
|
||||
gtk_widget_show(formcontainer);
|
||||
|
||||
//GTK+ statusbar background can be transparent, depending upon GTK+ theme
|
||||
//therefore, pack statusbar inside an event box, which always has a background
|
||||
//this allows pWindow::set_background_color() to change the window color,
|
||||
//without affecting the statusbar color
|
||||
statuscontainer = gtk_event_box_new();
|
||||
statusbar = gtk_statusbar_new();
|
||||
set_default_font(statusbar);
|
||||
gtk_container_add(GTK_CONTAINER(statuscontainer), statusbar);
|
||||
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), false);
|
||||
gtk_box_pack_start(GTK_BOX(menucontainer), statuscontainer, false, false, 0);
|
||||
gtk_widget_show(statuscontainer);
|
||||
|
||||
gtk_widget_realize(window);
|
||||
state.is_fullscreen = false;
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
}
|
||||
|
||||
void pWindow::close() {
|
||||
gtk_widget_destroy(window);
|
||||
}
|
||||
|
||||
void pWindow::move(unsigned x, unsigned y) {
|
||||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
|
||||
gtk_window_move(GTK_WINDOW(window), x, y);
|
||||
}
|
||||
|
||||
void pWindow::resize(unsigned width, unsigned height) {
|
||||
gtk_widget_set_size_request(formcontainer, width, height);
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
}
|
||||
|
||||
void pWindow::focus() {
|
||||
gtk_window_present(GTK_WINDOW(window));
|
||||
}
|
||||
|
||||
bool pWindow::focused() {
|
||||
return gtk_window_is_active(GTK_WINDOW(window));
|
||||
}
|
||||
|
||||
//gtk_window_(un/)fullscreen() alone does not work well on certain WMs, such as Openbox.
|
||||
//sometimes, the window will not resize (but will move to the top left.)
|
||||
//sometimes, the window decorations will not disappear.
|
||||
//therefore, to be safe, perform some manual window adjustments as well
|
||||
|
||||
void pWindow::fullscreen() {
|
||||
if(state.is_fullscreen == true) return;
|
||||
state.is_fullscreen = true;
|
||||
|
||||
gtk_window_fullscreen(GTK_WINDOW(window));
|
||||
gtk_window_set_decorated(GTK_WINDOW(window), false);
|
||||
gtk_widget_set_size_request(window, gdk_screen_width(), gdk_screen_height());
|
||||
}
|
||||
|
||||
//note that the size of the window is bound to be at least the size of the formcontainer.
|
||||
//this is why the window size is set to -1, -1 below, so that it becomes the minimum
|
||||
//needed to display all of the formcontainer.
|
||||
|
||||
void pWindow::unfullscreen() {
|
||||
if(state.is_fullscreen == false) return;
|
||||
state.is_fullscreen = false;
|
||||
|
||||
gtk_widget_set_size_request(formcontainer, state.width, state.height);
|
||||
gtk_widget_set_size_request(window, -1, -1);
|
||||
gtk_window_set_decorated(GTK_WINDOW(window), true);
|
||||
gtk_window_unfullscreen(GTK_WINDOW(window));
|
||||
}
|
||||
|
||||
//gtk_widget_size_request() on a window immediately after gtk_window_(un/)fullscreen()
|
||||
//is unreliable, as it will usually report the previous window size.
|
||||
//therefore, calculate it manually by using state information.
|
||||
|
||||
unsigned pWindow::get_width() {
|
||||
if(state.is_fullscreen == false) return state.width;
|
||||
return gdk_screen_width();
|
||||
}
|
||||
|
||||
unsigned pWindow::get_height() {
|
||||
if(state.is_fullscreen == false) return state.height;
|
||||
unsigned height = gdk_screen_height();
|
||||
|
||||
//do not include menubar height in client area height
|
||||
if(menu.visible()) {
|
||||
GtkRequisition req;
|
||||
gtk_widget_size_request(menubar, &req);
|
||||
height -= req.height;
|
||||
}
|
||||
|
||||
//do not include statusbar height in client area height
|
||||
if(status.visible()) {
|
||||
GtkRequisition req;
|
||||
gtk_widget_size_request(statusbar, &req);
|
||||
height -= req.height;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
void pWindow::set_opacity(uint8_t opacity) {
|
||||
state.alpha = opacity;
|
||||
if(window) gtk_widget_queue_draw(window);
|
||||
}
|
||||
|
||||
void pWindow::set_background_color(uint8_t r, uint8_t g, uint8_t b) {
|
||||
GdkColor color;
|
||||
color.pixel = (r << 16) | (g << 8) | b;
|
||||
color.red = (r << 8) | r;
|
||||
color.green = (g << 8) | g;
|
||||
color.blue = (b << 8) | b;
|
||||
gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color);
|
||||
}
|
||||
|
||||
void pWindow::set_icon(unsigned width, unsigned height, const uint32_t *data) {
|
||||
uint8_t *temp = (uint8_t*)malloc(width * height * 4);
|
||||
memcpy(temp, data, width * height * 4);
|
||||
for(unsigned i = 0; i < width * height; i++) {
|
||||
//ABGR -> ARGB
|
||||
uint8_t t = temp[i * 4 + 0];
|
||||
temp[i * 4 + 0] = temp[i * 4 + 2];
|
||||
temp[i * 4 + 2] = t;
|
||||
}
|
||||
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(
|
||||
(const guchar*)temp, GDK_COLORSPACE_RGB,
|
||||
/* has_alpha = */ TRUE, /* bits_per_sample = */ 8,
|
||||
width, height, /* rowstride = */ width * 4,
|
||||
/* destroy_fn = */ NULL, /* destroy_fn_data = */ NULL
|
||||
);
|
||||
gtk_window_set_icon(GTK_WINDOW(window), pixbuf);
|
||||
|
||||
g_object_unref(pixbuf);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
void pWindow::set_text(const char *text) {
|
||||
gtk_window_set_title(GTK_WINDOW(window), text ? text : "");
|
||||
}
|
||||
|
||||
void pWindow::attach(Window &window, unsigned x, unsigned y) {
|
||||
window.p.owner = this;
|
||||
|
||||
//GTK+ does not support attaching a window to another window,
|
||||
//so instead reparent the container from the child window to
|
||||
//the parent window, and reposition the child window's container
|
||||
gtk_widget_hide(window.p.window);
|
||||
gtk_widget_hide(window.p.formcontainer);
|
||||
gtk_widget_reparent(window.p.formcontainer, formcontainer);
|
||||
gtk_fixed_move(GTK_FIXED(formcontainer), window.p.formcontainer, x, y);
|
||||
gtk_widget_show(window.p.formcontainer);
|
||||
}
|
||||
|
||||
void pWindow::attach(MenuGroup &menugroup) {
|
||||
gtk_menu_bar_append(menubar, menugroup.p.item);
|
||||
gtk_widget_show(menubar);
|
||||
}
|
||||
|
||||
void pWindow::attach(FormControl &formcontrol, unsigned x, unsigned y) {
|
||||
gtk_fixed_put(GTK_FIXED(formcontainer), formcontrol.p.gtk_handle(), x, y);
|
||||
}
|
||||
|
||||
void pWindow::move(Window &window, unsigned x, unsigned y) {
|
||||
gtk_fixed_move(GTK_FIXED(formcontainer), window.p.gtk_handle(), x, y);
|
||||
}
|
||||
|
||||
void pWindow::move(FormControl &formcontrol, unsigned x, unsigned y) {
|
||||
gtk_fixed_move(GTK_FIXED(formcontainer), formcontrol.p.gtk_handle(), x, y);
|
||||
}
|
||||
|
||||
/* pWindow -> Menubar */
|
||||
|
||||
void pWindow::Menubar::show(bool state) {
|
||||
p.menu_show(state);
|
||||
}
|
||||
|
||||
void pWindow::Menubar::hide() {
|
||||
p.menu_hide();
|
||||
}
|
||||
|
||||
bool pWindow::Menubar::visible() {
|
||||
return p.menu_visible();
|
||||
}
|
||||
|
||||
pWindow::Menubar::Menubar(pWindow &p_) : p(p_) {
|
||||
}
|
||||
|
||||
/* pWindow -> Statusbar */
|
||||
|
||||
void pWindow::Statusbar::set_text(const char *text) {
|
||||
p.status_set_text(text);
|
||||
}
|
||||
|
||||
void pWindow::Statusbar::show(bool state) {
|
||||
p.status_show(state);
|
||||
}
|
||||
|
||||
void pWindow::Statusbar::hide() {
|
||||
p.status_hide();
|
||||
}
|
||||
|
||||
bool pWindow::Statusbar::visible() {
|
||||
return p.status_visible();
|
||||
}
|
||||
|
||||
pWindow::Statusbar::Statusbar(pWindow &p_) : p(p_) {
|
||||
}
|
||||
|
||||
pWindow::pWindow(Window &self_) : pWidget(self_), self(self_), menu(*this), status(*this) {
|
||||
owner = 0;
|
||||
window = 0;
|
||||
menubar = 0;
|
||||
statusbar = 0;
|
||||
menucontainer = 0;
|
||||
formcontainer = 0;
|
||||
statuscontainer = 0;
|
||||
|
||||
state.is_fullscreen = false;
|
||||
state.width = 0;
|
||||
state.height = 0;
|
||||
state.alpha = 255;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
GtkWidget* pWindow::gtk_handle() {
|
||||
return owner ? formcontainer : window;
|
||||
}
|
||||
|
||||
void pWindow::menu_show(bool state) {
|
||||
state ? gtk_widget_show(menubar) : gtk_widget_hide(menubar);
|
||||
}
|
||||
|
||||
void pWindow::menu_hide() {
|
||||
menu_show(false);
|
||||
}
|
||||
|
||||
bool pWindow::menu_visible() {
|
||||
return GTK_WIDGET_VISIBLE(menubar);
|
||||
}
|
||||
|
||||
void pWindow::status_set_text(const char *text) {
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 1);
|
||||
gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, text ? text : "");
|
||||
}
|
||||
|
||||
void pWindow::status_show(bool state) {
|
||||
state ? gtk_widget_show(statusbar) : gtk_widget_hide(statusbar);
|
||||
}
|
||||
|
||||
void pWindow::status_hide() {
|
||||
status_show(false);
|
||||
}
|
||||
|
||||
bool pWindow::status_visible() {
|
||||
return GTK_WIDGET_VISIBLE(statusbar);
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
class pWindow : public pWidget {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void close();
|
||||
void move(unsigned x, unsigned y);
|
||||
void resize(unsigned width, unsigned height);
|
||||
void focus();
|
||||
bool focused();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
unsigned get_width();
|
||||
unsigned get_height();
|
||||
void set_opacity(uint8_t opacity);
|
||||
void set_background_color(uint8_t r, uint8_t g, uint8_t b);
|
||||
void set_icon(unsigned width, unsigned height, const uint32_t *data);
|
||||
void set_text(const char *text = "");
|
||||
void attach(Window &window, unsigned x, unsigned y);
|
||||
void attach(MenuGroup &menugroup);
|
||||
void attach(FormControl &formcontrol, unsigned x, unsigned y);
|
||||
void move(Window &window, unsigned x, unsigned y);
|
||||
void move(FormControl &formcontrol, unsigned x, unsigned y);
|
||||
|
||||
class Statusbar {
|
||||
public:
|
||||
void set_text(const char *text = "");
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
pWindow &p;
|
||||
Statusbar(pWindow&);
|
||||
} status;
|
||||
|
||||
class Menubar {
|
||||
public:
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
pWindow &p;
|
||||
Menubar(pWindow&);
|
||||
} menu;
|
||||
|
||||
Window &self;
|
||||
pWindow(Window&);
|
||||
|
||||
/* internal */
|
||||
pWindow *owner; //0 = no owner (default)
|
||||
GtkWidget *window;
|
||||
GtkWidget *menubar;
|
||||
GtkWidget *statusbar;
|
||||
GtkWidget *menucontainer;
|
||||
GtkWidget *formcontainer;
|
||||
GtkWidget *statuscontainer;
|
||||
GtkWidget* gtk_handle();
|
||||
struct {
|
||||
bool is_fullscreen;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned alpha;
|
||||
} state;
|
||||
|
||||
void menu_show(bool = true);
|
||||
void menu_hide();
|
||||
bool menu_visible();
|
||||
|
||||
void status_set_text(const char *text = "");
|
||||
void status_show(bool = true);
|
||||
void status_hide();
|
||||
bool status_visible();
|
||||
};
|
@@ -1,274 +0,0 @@
|
||||
#include "hiro.hpp"
|
||||
using namespace nall;
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "win/hiro.cpp"
|
||||
#else
|
||||
#include "gtk/hiro.cpp"
|
||||
#endif
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
/* Hiro (singleton) */
|
||||
|
||||
void Hiro::init() { p.init(); }
|
||||
void Hiro::term() { p.term(); }
|
||||
bool Hiro::run() { return p.run(); }
|
||||
bool Hiro::pending() { return p.pending(); }
|
||||
bool Hiro::folder_select(Window *focus, char *filename, const char *path) { return p.folder_select(focus, filename, path); }
|
||||
bool Hiro::file_open(Window *focus, char *filename, const char *path, const char *filter) { return p.file_open(focus, filename, path, filter); }
|
||||
bool Hiro::file_save(Window *focus, char *filename, const char *path, const char *filter) { return p.file_save(focus, filename, path, filter); }
|
||||
unsigned Hiro::screen_width() { return p.screen_width(); }
|
||||
unsigned Hiro::screen_height() { return p.screen_height(); }
|
||||
void Hiro::enable_screensaver() { p.enable_screensaver(); }
|
||||
void Hiro::disable_screensaver() { p.disable_screensaver(); }
|
||||
Hiro& Hiro::handle() { static Hiro hiro; return hiro; }
|
||||
Hiro::Hiro() : p(*new pHiro(*this)) {}
|
||||
Hiro::~Hiro() { delete &p; }
|
||||
Hiro& hiro() { return Hiro::handle(); }
|
||||
|
||||
/* Widget */
|
||||
|
||||
void Widget::show(bool state) { p.show(state); }
|
||||
void Widget::hide() { p.hide(); }
|
||||
bool Widget::visible() { return p.visible(); }
|
||||
uintptr_t Widget::handle() { return p.handle(); }
|
||||
Widget::Widget() : p(*new pWidget(*this)) { type = WidgetType; }
|
||||
Widget::Widget(pWidget &p_) : p(p_) { type = WidgetType; }
|
||||
Widget::~Widget() { delete &p; }
|
||||
|
||||
/* Widget -> Window */
|
||||
|
||||
void Window::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
void Window::close() { p.close(); }
|
||||
void Window::move(unsigned x, unsigned y) { p.move(x, y); }
|
||||
void Window::resize(unsigned width, unsigned height) { p.resize(width, height); }
|
||||
void Window::focus() { p.focus(); }
|
||||
bool Window::focused() { return p.focused(); }
|
||||
void Window::fullscreen() { p.fullscreen(); }
|
||||
void Window::unfullscreen() { p.unfullscreen(); }
|
||||
unsigned Window::get_width() { return p.get_width(); }
|
||||
unsigned Window::get_height() { return p.get_height(); }
|
||||
void Window::set_opacity(uint8_t opacity) { p.set_opacity(opacity); }
|
||||
void Window::set_background_color(uint8_t r, uint8_t g, uint8_t b) { p.set_background_color(r, g, b); }
|
||||
void Window::set_icon(unsigned width, unsigned height, const uint32_t *data) { p.set_icon(width, height, data); }
|
||||
void Window::set_text(const char *text) { p.set_text(text); }
|
||||
void Window::attach(Window &window, unsigned x, unsigned y) { p.attach(window, x, y); }
|
||||
void Window::attach(MenuGroup &menugroup) { p.attach(menugroup); }
|
||||
void Window::attach(FormControl &formcontrol, unsigned x, unsigned y) { p.attach(formcontrol, x, y); }
|
||||
void Window::move(Window &window, unsigned x, unsigned y) { p.move(window, x, y); }
|
||||
void Window::move(FormControl &formcontrol, unsigned x, unsigned y) { p.move(formcontrol, x, y); }
|
||||
|
||||
void Window::Menubar::show(bool state) { p.menu.show(state); }
|
||||
void Window::Menubar::hide() { p.menu.hide(); }
|
||||
bool Window::Menubar::visible() { return p.menu.visible(); }
|
||||
Window::Menubar::Menubar(pWindow &p_) : p(p_) {}
|
||||
|
||||
void Window::Statusbar::set_text(const char *text) { p.status.set_text(text); }
|
||||
void Window::Statusbar::show(bool state) { p.status.show(state); }
|
||||
void Window::Statusbar::hide() { p.status.hide(); }
|
||||
bool Window::Statusbar::visible() { return p.status.visible(); }
|
||||
Window::Statusbar::Statusbar(pWindow &p_) : p(p_) {}
|
||||
|
||||
Window::Window() :
|
||||
base_from_member<pWindow&>(*new pWindow(*this)),
|
||||
Widget(base_from_member<pWindow&>::value),
|
||||
p(base_from_member<pWindow&>::value),
|
||||
menu(base_from_member<pWindow&>::value),
|
||||
status(base_from_member<pWindow&>::value) { type = WindowType; }
|
||||
|
||||
/* Widget -> MenuControl */
|
||||
|
||||
void MenuControl::enable(bool state) { p.enable(state); }
|
||||
void MenuControl::disable() { p.disable(); }
|
||||
bool MenuControl::enabled() { return p.enabled(); }
|
||||
MenuControl::MenuControl() :
|
||||
base_from_member<pMenuControl&>(*new pMenuControl(*this)),
|
||||
Widget(base_from_member<pMenuControl&>::value),
|
||||
p(base_from_member<pMenuControl&>::value) { type = MenuControlType; }
|
||||
MenuControl::MenuControl(pMenuControl &p_) :
|
||||
base_from_member<pMenuControl&>(p_),
|
||||
Widget(base_from_member<pMenuControl&>::value),
|
||||
p(base_from_member<pMenuControl&>::value) { type = MenuControlType; }
|
||||
|
||||
/* Widget -> MenuControl -> MenuGroup */
|
||||
|
||||
MenuGroup& MenuGroup::create(const char *text) { p.create(text); return *this; }
|
||||
void MenuGroup::attach(MenuControl &menucontrol) { p.attach(menucontrol); }
|
||||
MenuGroup::MenuGroup() :
|
||||
base_from_member<pMenuGroup&>(*new pMenuGroup(*this)),
|
||||
MenuControl(base_from_member<pMenuGroup&>::value),
|
||||
p(base_from_member<pMenuGroup&>::value) { type = MenuGroupType; }
|
||||
|
||||
/* Widget -> MenuControl -> MenuItem */
|
||||
|
||||
MenuItem& MenuItem::create(const char *text) { p.create(text); return *this; }
|
||||
MenuItem::MenuItem() :
|
||||
base_from_member<pMenuItem&>(*new pMenuItem(*this)),
|
||||
MenuControl(base_from_member<pMenuItem&>::value),
|
||||
p(base_from_member<pMenuItem&>::value) { type = MenuItemType; }
|
||||
|
||||
/* Widget -> MenuControl -> MenuCheckItem */
|
||||
|
||||
MenuCheckItem& MenuCheckItem::create(const char *text) { p.create(text); return *this; }
|
||||
void MenuCheckItem::check(bool state) { state ? p.check() : p.uncheck(); }
|
||||
void MenuCheckItem::uncheck() { p.uncheck(); }
|
||||
bool MenuCheckItem::checked() { return p.checked(); }
|
||||
MenuCheckItem::MenuCheckItem() :
|
||||
base_from_member<pMenuCheckItem&>(*new pMenuCheckItem(*this)),
|
||||
MenuControl(base_from_member<pMenuCheckItem&>::value),
|
||||
p(base_from_member<pMenuCheckItem&>::value) { type = MenuCheckItemType; }
|
||||
|
||||
/* Widget -> MenuControl -> MenuRadioItem */
|
||||
|
||||
MenuRadioItem& MenuRadioItem::create(MenuRadioItemGroup &group, const char *text) { p.create(group, text); return *this; }
|
||||
void MenuRadioItem::check() { p.check(); }
|
||||
bool MenuRadioItem::checked() { return p.checked(); }
|
||||
MenuRadioItem::MenuRadioItem() :
|
||||
base_from_member<pMenuRadioItem&>(*new pMenuRadioItem(*this)),
|
||||
MenuControl(base_from_member<pMenuRadioItem&>::value),
|
||||
p(base_from_member<pMenuRadioItem&>::value) { type = MenuRadioItemType; }
|
||||
|
||||
/* Widget -> MenuControl -> MenuSeparator */
|
||||
|
||||
MenuSeparator& MenuSeparator::create() { p.create(); return *this; }
|
||||
MenuSeparator::MenuSeparator() :
|
||||
base_from_member<pMenuSeparator&>(*new pMenuSeparator(*this)),
|
||||
MenuControl(base_from_member<pMenuSeparator&>::value),
|
||||
p(base_from_member<pMenuSeparator&>::value) { type = MenuSeparatorType; }
|
||||
|
||||
/* Widget -> FormControl */
|
||||
|
||||
void FormControl::resize(unsigned width, unsigned height) { p.resize(width, height); }
|
||||
void FormControl::focus() { p.focus(); }
|
||||
bool FormControl::focused() { return p.focused(); }
|
||||
void FormControl::enable(bool state) { p.enable(state); }
|
||||
void FormControl::disable() { p.disable(); }
|
||||
bool FormControl::enabled() { return p.enabled(); }
|
||||
FormControl::FormControl() :
|
||||
base_from_member<pFormControl&>(*new pFormControl(*this)),
|
||||
Widget(base_from_member<pFormControl&>::value),
|
||||
p(base_from_member<pFormControl&>::value) { type = FormControlType; }
|
||||
FormControl::FormControl(pFormControl &p_) :
|
||||
base_from_member<pFormControl&>(p_),
|
||||
Widget(base_from_member<pFormControl&>::value),
|
||||
p(base_from_member<pFormControl&>::value) { type = FormControlType; }
|
||||
|
||||
/* Widget -> FormControl -> Frame */
|
||||
|
||||
void Frame::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
void Frame::set_text(const char *text) { p.set_text(text); }
|
||||
Frame::Frame() :
|
||||
base_from_member<pFrame&>(*new pFrame(*this)),
|
||||
FormControl(base_from_member<pFrame&>::value),
|
||||
p(base_from_member<pFrame&>::value) { type = FrameType; }
|
||||
|
||||
/* Widget -> FormControl -> Canvas */
|
||||
|
||||
void Canvas::create(unsigned style, unsigned width, unsigned height) { p.create(style, width, height); }
|
||||
void Canvas::redraw() { p.redraw(); }
|
||||
uint32_t* Canvas::buffer() { return p.buffer(); }
|
||||
Canvas::Canvas() :
|
||||
base_from_member<pCanvas&>(*new pCanvas(*this)),
|
||||
FormControl(base_from_member<pCanvas&>::value),
|
||||
p(base_from_member<pCanvas&>::value) { type = CanvasType; }
|
||||
|
||||
/* Widget -> FormControl -> Label */
|
||||
|
||||
void Label::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
void Label::set_text(const char *text) { p.set_text(text); }
|
||||
Label::Label() :
|
||||
base_from_member<pLabel&>(*new pLabel(*this)),
|
||||
FormControl(base_from_member<pLabel&>::value),
|
||||
p(base_from_member<pLabel&>::value) { type = LabelType; }
|
||||
|
||||
/* Widget -> FormControl -> Button */
|
||||
|
||||
void Button::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
void Button::set_text(const char *text) { p.set_text(text); }
|
||||
Button::Button() :
|
||||
base_from_member<pButton&>(*new pButton(*this)),
|
||||
FormControl(base_from_member<pButton&>::value),
|
||||
p(base_from_member<pButton&>::value) { type = ButtonType; }
|
||||
|
||||
/* Widget -> FormControl -> Checkbox */
|
||||
|
||||
void Checkbox::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
void Checkbox::set_text(const char *text) { p.set_text(text); }
|
||||
void Checkbox::check(bool state) { state ? p.check() : p.uncheck(); }
|
||||
void Checkbox::uncheck() { p.uncheck(); }
|
||||
bool Checkbox::checked() { return p.checked(); }
|
||||
Checkbox::Checkbox() :
|
||||
base_from_member<pCheckbox&>(*new pCheckbox(*this)),
|
||||
FormControl(base_from_member<pCheckbox&>::value),
|
||||
p(base_from_member<pCheckbox&>::value) { type = CheckboxType; }
|
||||
|
||||
/* Widget -> FormControl -> Radiobox */
|
||||
|
||||
void Radiobox::create(RadioboxGroup &group, unsigned style, unsigned width, unsigned height, const char *text) { p.create(group, style, width, height, text); }
|
||||
void Radiobox::set_text(const char *text) { p.set_text(text); }
|
||||
void Radiobox::check() { p.check(); }
|
||||
bool Radiobox::checked() { return p.checked(); }
|
||||
Radiobox::Radiobox() :
|
||||
base_from_member<pRadiobox&>(*new pRadiobox(*this)),
|
||||
FormControl(base_from_member<pRadiobox&>::value),
|
||||
p(base_from_member<pRadiobox&>::value) { type = RadioboxType; }
|
||||
|
||||
/* Widget -> FormControl -> Editbox */
|
||||
|
||||
void Editbox::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
unsigned Editbox::get_text(char *text, unsigned length) { return p.get_text(text, length); }
|
||||
void Editbox::set_text(const char *text) { p.set_text(text); }
|
||||
Editbox::Editbox() :
|
||||
base_from_member<pEditbox&>(*new pEditbox(*this)),
|
||||
FormControl(base_from_member<pEditbox&>::value),
|
||||
p(base_from_member<pEditbox&>::value) { type = EditboxType; }
|
||||
|
||||
/* Widget -> FormControl -> Listbox */
|
||||
|
||||
void Listbox::create(unsigned style, unsigned width, unsigned height, const char *columns, const char *text) { p.create(style, width, height, columns, text); }
|
||||
void Listbox::autosize_columns() { p.autosize_columns(); }
|
||||
void Listbox::set_column_width(unsigned column, unsigned width) { p.set_column_width(column, width); }
|
||||
void Listbox::add_item(const char *text) { p.add_item(text); }
|
||||
void Listbox::set_item(unsigned index, const char *text) { p.set_item(index, text); }
|
||||
int Listbox::get_selection() { return p.get_selection(); }
|
||||
void Listbox::set_selection(int index) { p.set_selection(index); }
|
||||
void Listbox::reset() { p.reset(); }
|
||||
Listbox::Listbox() :
|
||||
base_from_member<pListbox&>(*new pListbox(*this)),
|
||||
FormControl(base_from_member<pListbox&>::value),
|
||||
p(base_from_member<pListbox&>::value) { type = ListboxType; }
|
||||
|
||||
/* Widget -> FormControl -> Combobox */
|
||||
|
||||
void Combobox::create(unsigned style, unsigned width, unsigned height, const char *text) { p.create(style, width, height, text); }
|
||||
void Combobox::add_item(const char *text) { p.add_item(text); }
|
||||
int Combobox::get_selection() { return p.get_selection(); }
|
||||
void Combobox::set_selection(int index) { p.set_selection(index); }
|
||||
void Combobox::reset() { p.reset(); }
|
||||
Combobox::Combobox() :
|
||||
base_from_member<pCombobox&>(*new pCombobox(*this)),
|
||||
FormControl(base_from_member<pCombobox&>::value),
|
||||
p(base_from_member<pCombobox&>::value) { type = ComboboxType; }
|
||||
|
||||
/* Widget -> FormControl -> Progressbar */
|
||||
|
||||
void Progressbar::create(unsigned style, unsigned width, unsigned height) { p.create(style, width, height); }
|
||||
unsigned Progressbar::get_progress() { return p.get_progress(); }
|
||||
void Progressbar::set_progress(unsigned progress) { p.set_progress(progress); }
|
||||
Progressbar::Progressbar() :
|
||||
base_from_member<pProgressbar&>(*new pProgressbar(*this)),
|
||||
FormControl(base_from_member<pProgressbar&>::value),
|
||||
p(base_from_member<pProgressbar&>::value) { type = ProgressbarType; }
|
||||
|
||||
/* Widget -> FormControl -> Slider */
|
||||
|
||||
void Slider::create(unsigned style, unsigned width, unsigned height, unsigned length) { p.create(style, width, height, length); }
|
||||
unsigned Slider::get_position() { return p.get_position(); }
|
||||
void Slider::set_position(unsigned position) { p.set_position(position); }
|
||||
Slider::Slider() :
|
||||
base_from_member<pSlider&>(*new pSlider(*this)),
|
||||
FormControl(base_from_member<pSlider&>::value),
|
||||
p(base_from_member<pSlider&>::value) { type = SliderType; }
|
||||
|
||||
} //namespace libhiro
|
@@ -1,538 +0,0 @@
|
||||
/*
|
||||
hiro
|
||||
version: 0.008.1 (2008-11-02)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#ifndef HIRO_H
|
||||
#define HIRO_H
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/new.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
extern char* realpath(const char*, char*);
|
||||
extern char* userpath(char*);
|
||||
int mkdir(const char*);
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
class pHiro;
|
||||
class pWidget;
|
||||
class pWindow;
|
||||
class pMenuControl;
|
||||
class pMenuGroup;
|
||||
class pMenuItem;
|
||||
class pMenuCheckItem;
|
||||
class pMenuRadioItem;
|
||||
class pMenuSeparator;
|
||||
class pFormControl;
|
||||
class pFrame;
|
||||
class pCanvas;
|
||||
class pLabel;
|
||||
class pButton;
|
||||
class pCheckbox;
|
||||
class pRadiobox;
|
||||
class pEditbox;
|
||||
class pListbox;
|
||||
class pCombobox;
|
||||
class pProgressbar;
|
||||
class pSlider;
|
||||
|
||||
#define pFriends \
|
||||
friend class pHiro; \
|
||||
friend class pWidget; \
|
||||
friend class pWindow; \
|
||||
friend class pMenuControl; \
|
||||
friend class pMenuGroup; \
|
||||
friend class pMenuItem; \
|
||||
friend class pMenuCheckItem; \
|
||||
friend class pMenuRadioItem; \
|
||||
friend class pMenuSeparator; \
|
||||
friend class pFormControl; \
|
||||
friend class pFrame; \
|
||||
friend class pCanvas; \
|
||||
friend class pLabel; \
|
||||
friend class pButton; \
|
||||
friend class pCheckbox; \
|
||||
friend class pRadiobox; \
|
||||
friend class pEditbox; \
|
||||
friend class pListbox; \
|
||||
friend class pCombobox; \
|
||||
friend class pProgressbar; \
|
||||
friend class pSlider
|
||||
|
||||
class Hiro;
|
||||
class Widget;
|
||||
class Window;
|
||||
class MenuControl;
|
||||
class MenuGroup;
|
||||
class MenuItem;
|
||||
class MenuCheckItem;
|
||||
class MenuRadioItem;
|
||||
class MenuSeparator;
|
||||
class FormControl;
|
||||
class Frame;
|
||||
class Canvas;
|
||||
class Label;
|
||||
class Button;
|
||||
class Checkbox;
|
||||
class Radiobox;
|
||||
class Editbox;
|
||||
class Listbox;
|
||||
class Combobox;
|
||||
class Progressbar;
|
||||
class Slider;
|
||||
|
||||
typedef nall::array<MenuRadioItem*> MenuRadioItemGroup;
|
||||
typedef nall::array<Radiobox*> RadioboxGroup;
|
||||
|
||||
struct event_t {
|
||||
enum type_t {
|
||||
Close,
|
||||
Block,
|
||||
Input,
|
||||
Change,
|
||||
Tick,
|
||||
Activate,
|
||||
} type;
|
||||
uintptr_t param;
|
||||
Widget *widget;
|
||||
|
||||
event_t(type_t type_, uintptr_t param_ = 0, Widget *widget_ = 0) :
|
||||
type(type_), param(param_), widget(widget_) {}
|
||||
};
|
||||
|
||||
class Hiro : nall::noncopyable {
|
||||
public:
|
||||
void init();
|
||||
void term();
|
||||
bool run();
|
||||
bool pending();
|
||||
|
||||
bool folder_select(Window *focus, char *filename, const char *path = "");
|
||||
bool file_open(Window *focus, char *filename, const char *path = "", const char *filter = "");
|
||||
bool file_save(Window *focus, char *filename, const char *path = "", const char *filter = "");
|
||||
|
||||
unsigned screen_width();
|
||||
unsigned screen_height();
|
||||
|
||||
void enable_screensaver();
|
||||
void disable_screensaver();
|
||||
|
||||
static Hiro& handle();
|
||||
Hiro();
|
||||
~Hiro();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pHiro &p;
|
||||
};
|
||||
|
||||
Hiro& hiro();
|
||||
|
||||
class Widget : nall::noncopyable {
|
||||
public:
|
||||
enum Type {
|
||||
WidgetType,
|
||||
WindowType,
|
||||
MenuControlType,
|
||||
MenuGroupType,
|
||||
MenuItemType,
|
||||
MenuCheckItemType,
|
||||
MenuRadioItemType,
|
||||
MenuSeparatorType,
|
||||
FormControlType,
|
||||
FrameType,
|
||||
CanvasType,
|
||||
LabelType,
|
||||
ButtonType,
|
||||
CheckboxType,
|
||||
RadioboxType,
|
||||
EditboxType,
|
||||
ListboxType,
|
||||
ComboboxType,
|
||||
ProgressbarType,
|
||||
SliderType,
|
||||
} type;
|
||||
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
uintptr_t handle();
|
||||
|
||||
Widget();
|
||||
~Widget();
|
||||
|
||||
protected:
|
||||
Widget(pWidget&);
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pWidget &p;
|
||||
};
|
||||
|
||||
class Window : private nall::base_from_member<pWindow&>, public Widget {
|
||||
public:
|
||||
enum Style {
|
||||
AutoCenter = 1 << 1,
|
||||
};
|
||||
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void close();
|
||||
void move(unsigned x, unsigned y);
|
||||
void resize(unsigned width, unsigned height);
|
||||
void focus();
|
||||
bool focused();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
unsigned get_width();
|
||||
unsigned get_height();
|
||||
void set_opacity(uint8_t opacity);
|
||||
void set_background_color(uint8_t r, uint8_t g, uint8_t b);
|
||||
void set_icon(unsigned width, unsigned height, const uint32_t *data);
|
||||
void set_status_text(const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void attach(Window &window, unsigned x, unsigned y);
|
||||
void attach(MenuGroup &menugroup);
|
||||
void attach(FormControl &formcontrol, unsigned x, unsigned y);
|
||||
void move(Window &window, unsigned x, unsigned y);
|
||||
void move(FormControl &formcontrol, unsigned x, unsigned y);
|
||||
|
||||
class Menubar {
|
||||
public:
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
pWindow &p;
|
||||
Menubar(pWindow&);
|
||||
} menu;
|
||||
|
||||
class Statusbar {
|
||||
public:
|
||||
void set_text(const char *text = "");
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
pWindow &p;
|
||||
Statusbar(pWindow&);
|
||||
} status;
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_close;
|
||||
nall::function<uintptr_t (event_t)> on_block;
|
||||
nall::function<uintptr_t (event_t)> on_input;
|
||||
|
||||
Window();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pWindow &p;
|
||||
};
|
||||
|
||||
class MenuControl : public nall::base_from_member<pMenuControl&>, public Widget {
|
||||
public:
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
MenuControl();
|
||||
|
||||
protected:
|
||||
MenuControl(pMenuControl&);
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pMenuControl &p;
|
||||
};
|
||||
|
||||
class MenuGroup : public nall::base_from_member<pMenuGroup&>, public MenuControl {
|
||||
public:
|
||||
MenuGroup& create(const char *text);
|
||||
void attach(MenuControl &menucontrol);
|
||||
MenuGroup();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pMenuGroup &p;
|
||||
};
|
||||
|
||||
class MenuItem : public nall::base_from_member<pMenuItem&>, public MenuControl {
|
||||
public:
|
||||
MenuItem& create(const char *text);
|
||||
MenuItem();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_tick;
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pMenuItem &p;
|
||||
};
|
||||
|
||||
class MenuCheckItem : public nall::base_from_member<pMenuCheckItem&>, public MenuControl {
|
||||
public:
|
||||
MenuCheckItem& create(const char *text);
|
||||
void check(bool = true);
|
||||
void uncheck();
|
||||
bool checked();
|
||||
MenuCheckItem();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_tick;
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pMenuCheckItem &p;
|
||||
};
|
||||
|
||||
class MenuRadioItem : public nall::base_from_member<pMenuRadioItem&>, public MenuControl {
|
||||
public:
|
||||
MenuRadioItem& create(MenuRadioItemGroup &group, const char *text);
|
||||
void check();
|
||||
bool checked();
|
||||
MenuRadioItem();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_tick;
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pMenuRadioItem &p;
|
||||
};
|
||||
|
||||
class MenuSeparator : public nall::base_from_member<pMenuSeparator&>, public MenuControl {
|
||||
public:
|
||||
MenuSeparator& create();
|
||||
MenuSeparator();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pMenuSeparator &p;
|
||||
};
|
||||
|
||||
class FormControl : private nall::base_from_member<pFormControl&>, public Widget {
|
||||
public:
|
||||
void resize(unsigned width, unsigned height);
|
||||
void focus();
|
||||
bool focused();
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
FormControl();
|
||||
|
||||
protected:
|
||||
FormControl(pFormControl&);
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pFormControl &p;
|
||||
};
|
||||
|
||||
class Frame : private nall::base_from_member<pFrame&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
Frame();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pFrame &p;
|
||||
};
|
||||
|
||||
class Canvas : private nall::base_from_member<pCanvas&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height);
|
||||
void redraw();
|
||||
uint32_t* buffer();
|
||||
|
||||
Canvas();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_input;
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pCanvas &p;
|
||||
};
|
||||
|
||||
class Label : private nall::base_from_member<pLabel&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
Label();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pLabel &p;
|
||||
};
|
||||
|
||||
class Button : private nall::base_from_member<pButton&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_tick;
|
||||
|
||||
Button();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pButton &p;
|
||||
};
|
||||
|
||||
class Checkbox : private nall::base_from_member<pCheckbox&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void check(bool = true);
|
||||
void uncheck();
|
||||
bool checked();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_tick;
|
||||
|
||||
Checkbox();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pCheckbox &p;
|
||||
};
|
||||
|
||||
class Radiobox : private nall::base_from_member<pRadiobox&>, public FormControl {
|
||||
public:
|
||||
void create(RadioboxGroup &group, unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_tick;
|
||||
|
||||
Radiobox();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pRadiobox &p;
|
||||
};
|
||||
|
||||
class Editbox : private nall::base_from_member<pEditbox&>, public FormControl {
|
||||
public:
|
||||
enum Style {
|
||||
Multiline = 1 << 1,
|
||||
Readonly = 1 << 2,
|
||||
|
||||
HorizontalScrollAuto = 0,
|
||||
HorizontalScrollAlways = 1 << 3,
|
||||
HorizontalScrollNever = 1 << 4,
|
||||
|
||||
VerticalScrollAuto = 0,
|
||||
VerticalScrollAlways = 1 << 5,
|
||||
VerticalScrollNever = 1 << 6,
|
||||
};
|
||||
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
unsigned get_text(char *text, unsigned length = -1U);
|
||||
void set_text(const char *text = "");
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_change;
|
||||
|
||||
Editbox();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pEditbox &p;
|
||||
};
|
||||
|
||||
class Listbox : private nall::base_from_member<pListbox&>, public FormControl {
|
||||
public:
|
||||
enum Style {
|
||||
Header = 1 << 1,
|
||||
|
||||
HorizontalScrollAuto = 0,
|
||||
HorizontalScrollAlways = 1 << 2,
|
||||
HorizontalScrollNever = 1 << 3,
|
||||
|
||||
VerticalScrollAuto = 0,
|
||||
VerticalScrollAlways = 1 << 4,
|
||||
VerticalScrollNever = 1 << 5,
|
||||
};
|
||||
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *columns = "", const char *text = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(unsigned column, unsigned width);
|
||||
void add_item(const char *text);
|
||||
void set_item(unsigned index, const char *text);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_change;
|
||||
nall::function<uintptr_t (event_t)> on_activate;
|
||||
|
||||
Listbox();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pListbox &p;
|
||||
};
|
||||
|
||||
class Combobox : private nall::base_from_member<pCombobox&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void add_item(const char *text);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_change;
|
||||
|
||||
Combobox();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pCombobox &p;
|
||||
};
|
||||
|
||||
class Progressbar : private nall::base_from_member<pProgressbar&>, public FormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height);
|
||||
unsigned get_progress();
|
||||
void set_progress(unsigned progress);
|
||||
|
||||
Progressbar();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pProgressbar &p;
|
||||
};
|
||||
|
||||
class Slider : private nall::base_from_member<pSlider&>, public FormControl {
|
||||
public:
|
||||
enum Style {
|
||||
Horizontal = 0,
|
||||
Vertical = 1 << 1,
|
||||
};
|
||||
|
||||
void create(unsigned style, unsigned width, unsigned height, unsigned length);
|
||||
unsigned get_position();
|
||||
void set_position(unsigned position);
|
||||
|
||||
nall::function<uintptr_t (event_t)> on_change;
|
||||
|
||||
Slider();
|
||||
|
||||
private:
|
||||
pFriends;
|
||||
pSlider &p;
|
||||
};
|
||||
|
||||
#undef pFriends
|
||||
|
||||
} //namespace libhiro
|
||||
|
||||
#endif //ifndef HIRO_H
|
@@ -1,14 +0,0 @@
|
||||
void pButton::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pButton::set_text(const char *text) {
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
pButton::pButton(Button &self_) : pFormControl(self_), self(self_) {
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
class pButton : public pFormControl {
|
||||
public:
|
||||
Button &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pButton(Button&);
|
||||
};
|
@@ -1,52 +0,0 @@
|
||||
void pCanvas::create(unsigned style, unsigned width, unsigned height) {
|
||||
hwnd = CreateWindow(L"hiro_window", L"", WS_CHILD,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
resize(width, height);
|
||||
ShowWindow(hwnd, SW_NORMAL);
|
||||
}
|
||||
|
||||
void pCanvas::redraw() {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS);
|
||||
EndPaint(hwnd, &ps);
|
||||
InvalidateRect(hwnd, 0, FALSE);
|
||||
}
|
||||
|
||||
uint32_t* pCanvas::buffer() {
|
||||
return ibuffer;
|
||||
}
|
||||
|
||||
pCanvas::pCanvas(Canvas &self_) : pFormControl(self_), self(self_) {
|
||||
ibuffer = 0;
|
||||
ipitch = 0;
|
||||
memset(&bmi, 0, sizeof(BITMAPINFO));
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
}
|
||||
|
||||
pCanvas::~pCanvas() {
|
||||
if(ibuffer) free(ibuffer);
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
void pCanvas::resize(unsigned width, unsigned height) {
|
||||
if(ibuffer) free(ibuffer);
|
||||
|
||||
ipitch = width * sizeof(uint32_t);
|
||||
iwidth = width;
|
||||
iheight = height;
|
||||
ibuffer = (uint32_t*)malloc(ipitch * height);
|
||||
memset(ibuffer, 0, ipitch * height);
|
||||
|
||||
bmi.bmiHeader.biWidth = width;
|
||||
bmi.bmiHeader.biHeight = -height; //use negative height to tell GDI not to flip bitmap vertically
|
||||
bmi.bmiHeader.biSizeImage = ipitch * height;
|
||||
|
||||
pFormControl::resize(width, height);
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
class pCanvas : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height);
|
||||
void redraw();
|
||||
uint32_t* buffer();
|
||||
|
||||
Canvas &self;
|
||||
pCanvas(Canvas&);
|
||||
~pCanvas();
|
||||
|
||||
/* internal */
|
||||
BITMAPINFO bmi;
|
||||
uint32_t *ibuffer;
|
||||
unsigned ipitch, iwidth, iheight;
|
||||
void resize(unsigned width, unsigned height);
|
||||
};
|
@@ -1,25 +0,0 @@
|
||||
void pCheckbox::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pCheckbox::set_text(const char *text) {
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
void pCheckbox::check(bool state) {
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)(state ? TRUE : FALSE), 0);
|
||||
}
|
||||
|
||||
void pCheckbox::uncheck() {
|
||||
check(false);
|
||||
}
|
||||
|
||||
bool pCheckbox::checked() {
|
||||
return SendMessage(hwnd, BM_GETCHECK, 0, 0);
|
||||
}
|
||||
|
||||
pCheckbox::pCheckbox(Checkbox &self_) : pFormControl(self_), self(self_) {
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
class pCheckbox : public pFormControl {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void check(bool state = true);
|
||||
void uncheck();
|
||||
bool checked();
|
||||
|
||||
Checkbox &self;
|
||||
pCheckbox(Checkbox&);
|
||||
};
|
@@ -1,38 +0,0 @@
|
||||
void pCombobox::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
0, 0, width, 200,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
|
||||
//fix combobox height
|
||||
//CreateWindow height parameter represents dropdown window height; auto-sizes control based on current font setting
|
||||
//GetWindowRect returns true height (~22px), CB_GETITEMHEIGHT returns text height (~16px)
|
||||
//difference = WindowHeight - CB_GETITEMHEIGHT
|
||||
//CB_SETITEMHEIGHT to height - difference, so that height matches requested height perfectly
|
||||
RECT rc;
|
||||
GetWindowRect(hwnd, &rc);
|
||||
unsigned adjusted_height = height - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0));
|
||||
SendMessage(hwnd, CB_SETITEMHEIGHT, (WPARAM)-1, adjusted_height);
|
||||
}
|
||||
|
||||
void pCombobox::add_item(const char *text) {
|
||||
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16(text));
|
||||
if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) set_selection(0);
|
||||
}
|
||||
|
||||
int pCombobox::get_selection() {
|
||||
return SendMessage(hwnd, CB_GETCURSEL, 0, 0);
|
||||
}
|
||||
|
||||
void pCombobox::set_selection(int index) {
|
||||
SendMessage(hwnd, CB_SETCURSEL, combobox_selection = index, 0);
|
||||
}
|
||||
|
||||
void pCombobox::reset() {
|
||||
SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
pCombobox::pCombobox(Combobox &self_) : pFormControl(self_), self(self_) {
|
||||
combobox_selection = 0;
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
class pCombobox : public pFormControl {
|
||||
public:
|
||||
Combobox &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void add_item(const char *text);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
pCombobox(Combobox&);
|
||||
|
||||
/* internal */
|
||||
int combobox_selection;
|
||||
};
|
@@ -1,84 +0,0 @@
|
||||
void pEditbox::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
bool multiline = style & Editbox::Multiline;
|
||||
bool readonly = style & Editbox::Readonly;
|
||||
unsigned vscroll = (style & Editbox::VerticalScrollAlways) ? WS_VSCROLL :
|
||||
(style & Editbox::VerticalScrollNever ) ? 0 :
|
||||
ES_AUTOVSCROLL;
|
||||
unsigned hscroll = (style & Editbox::HorizontalScrollAlways) ? WS_HSCROLL :
|
||||
(style & Editbox::HorizontalScrollNever ) ? 0 :
|
||||
ES_AUTOHSCROLL;
|
||||
|
||||
autovscroll = (vscroll == ES_AUTOVSCROLL);
|
||||
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
|
||||
WS_CHILD | WS_VISIBLE | vscroll | hscroll |
|
||||
(multiline == true ? ES_MULTILINE | ES_WANTRETURN : WS_TABSTOP) |
|
||||
(readonly == true ? ES_READONLY : 0),
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
set_text(text);
|
||||
update();
|
||||
}
|
||||
|
||||
void pEditbox::resize(unsigned width, unsigned height) {
|
||||
pFormControl::resize(width, height);
|
||||
update();
|
||||
}
|
||||
|
||||
void pEditbox::set_text(const char *text) {
|
||||
string temp = text ? text : "";
|
||||
temp.replace("\r", "");
|
||||
temp.replace("\n", "\r\n");
|
||||
SetWindowText(hwnd, utf16(temp));
|
||||
update();
|
||||
}
|
||||
|
||||
unsigned pEditbox::get_text(char *text, unsigned length) {
|
||||
wchar_t *buffer = new wchar_t[length + 1];
|
||||
GetWindowText(hwnd, buffer, length);
|
||||
string temp = (const char*)utf8(buffer);
|
||||
delete[] buffer;
|
||||
temp.replace("\r", "");
|
||||
strlcpy(text, temp, length);
|
||||
return strlen(text);
|
||||
}
|
||||
|
||||
pEditbox::pEditbox(Editbox &self_) : pFormControl(self_), self(self_) {
|
||||
autovscroll = false;
|
||||
}
|
||||
|
||||
//========
|
||||
//internal
|
||||
//========
|
||||
|
||||
//WS_VSCROLL always shows the scrollbar;
|
||||
//ES_AUTOVSCROLL never shows the scrollbar but allows unlimited text;
|
||||
//no style disallows more text than what fits in the window.
|
||||
//
|
||||
//below routine simulates the effect of allowing unlimited text, but only
|
||||
//showing the scrollbar when it is needed. not sure how to simulate this effect
|
||||
//for horizontal scrolling at this time.
|
||||
//
|
||||
//below routine should be called whenever the font, text or window size is
|
||||
//modified.
|
||||
void pEditbox::update() {
|
||||
if(autovscroll == true) {
|
||||
//determine how many lines of text this control allows
|
||||
RECT rect;
|
||||
SendMessage(hwnd, EM_GETRECT, 0, (LPARAM)&rect);
|
||||
unsigned height = rect.bottom - rect.top;
|
||||
|
||||
//determine the height of a single line of text
|
||||
HDC hdc = GetDC(hwnd);
|
||||
SelectObject(hdc, phiro().default_font);
|
||||
DrawText(hdc, L"byuu", -1, &rect, DT_CALCRECT);
|
||||
ReleaseDC(hwnd, hdc);
|
||||
unsigned lineheight = rect.bottom - rect.top;
|
||||
|
||||
//only show the scrollbar when there are more lines of text
|
||||
//than the control can show at once.
|
||||
unsigned linecount = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0);
|
||||
ShowScrollBar(hwnd, SB_VERT, linecount > (height / lineheight));
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
class pEditbox : public pFormControl {
|
||||
public:
|
||||
Editbox &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void resize(unsigned width, unsigned height);
|
||||
unsigned get_text(char *text, unsigned length = -1U);
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pEditbox(Editbox&);
|
||||
|
||||
//private:
|
||||
bool autovscroll;
|
||||
void update();
|
||||
};
|
@@ -1,45 +0,0 @@
|
||||
void pFormControl::resize(unsigned width, unsigned height) {
|
||||
SetWindowPos(hwnd, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE);
|
||||
}
|
||||
|
||||
void pFormControl::focus() {
|
||||
SetFocus(hwnd);
|
||||
}
|
||||
|
||||
bool pFormControl::focused() {
|
||||
return true; //fixme
|
||||
}
|
||||
|
||||
void pFormControl::enable(bool state) {
|
||||
EnableWindow(hwnd, state);
|
||||
}
|
||||
|
||||
void pFormControl::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pFormControl::enabled() {
|
||||
return !(GetWindowLong(hwnd, GWL_STYLE) & WS_DISABLED);
|
||||
}
|
||||
|
||||
uintptr_t pFormControl::handle() {
|
||||
return (uintptr_t)hwnd;
|
||||
}
|
||||
|
||||
pFormControl::pFormControl(FormControl &self_) : pWidget(self_), self(self_) {
|
||||
hwnd = 0;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
void pFormControl::show(bool state) {
|
||||
ShowWindow(hwnd, state ? SW_NORMAL : SW_HIDE);
|
||||
}
|
||||
|
||||
void pFormControl::hide() {
|
||||
show(false);
|
||||
}
|
||||
|
||||
bool pFormControl::visible() {
|
||||
return GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE;
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
class pFormControl : public pWidget {
|
||||
public:
|
||||
virtual void resize(unsigned width, unsigned height);
|
||||
void focus();
|
||||
bool focused();
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
uintptr_t handle();
|
||||
|
||||
virtual void show(bool = true);
|
||||
virtual void hide();
|
||||
virtual bool visible();
|
||||
|
||||
FormControl &self;
|
||||
pFormControl(FormControl&);
|
||||
|
||||
/* internal */
|
||||
HWND hwnd;
|
||||
};
|
@@ -1,13 +0,0 @@
|
||||
void pFrame::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pFrame::set_text(const char *text) {
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
pFrame::pFrame(Frame &self_) : pFormControl(self_), self(self_) {
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
class pFrame : public pFormControl {
|
||||
public:
|
||||
Frame &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pFrame(Frame&);
|
||||
};
|
@@ -1,444 +0,0 @@
|
||||
#include "hiro.hpp"
|
||||
#include "port.cpp"
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
LRESULT CALLBACK phiro_wndproc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
#include "keymap.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
#include "menucontrol.cpp"
|
||||
#include "menugroup.cpp"
|
||||
#include "menuitem.cpp"
|
||||
#include "menucheckitem.cpp"
|
||||
#include "menuradioitem.cpp"
|
||||
#include "menuseparator.cpp"
|
||||
#include "formcontrol.cpp"
|
||||
#include "frame.cpp"
|
||||
#include "canvas.cpp"
|
||||
#include "label.cpp"
|
||||
#include "button.cpp"
|
||||
#include "checkbox.cpp"
|
||||
#include "radiobox.cpp"
|
||||
#include "editbox.cpp"
|
||||
#include "listbox.cpp"
|
||||
#include "combobox.cpp"
|
||||
#include "progressbar.cpp"
|
||||
#include "slider.cpp"
|
||||
|
||||
void pHiro::init() {
|
||||
memset(&osversioninfo, 0, sizeof(OSVERSIONINFO));
|
||||
osversioninfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&osversioninfo);
|
||||
|
||||
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 = phiro_wndproc;
|
||||
wc.lpszClassName = L"hiro_window";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
InitCommonControls();
|
||||
default_hwnd = CreateWindow(L"hiro_window", L"", WS_POPUP, 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0);
|
||||
default_font = create_font("Tahoma", 8);
|
||||
black_brush = CreateSolidBrush(RGB(0, 0, 0));
|
||||
}
|
||||
|
||||
void pHiro::term() {
|
||||
DeleteObject(black_brush);
|
||||
}
|
||||
|
||||
bool pHiro::run() {
|
||||
MSG msg;
|
||||
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||
//TODO: IsDialogMessage() does not clear keyboard buffer, but is required for tab key to work ...
|
||||
#if defined(HIRO_WIN_TABSTOP)
|
||||
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
|
||||
#endif
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
#if defined(HIRO_WIN_TABSTOP)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return pending();
|
||||
}
|
||||
|
||||
bool pHiro::pending() {
|
||||
MSG msg;
|
||||
return PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE);
|
||||
}
|
||||
|
||||
bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
|
||||
wchar_t wfilename[_MAX_PATH] = L"";
|
||||
strcpy(filename, "");
|
||||
BROWSEINFO bi;
|
||||
bi.hwndOwner = focus ? focus->p.hwnd : 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
strcpy(filename, utf8(wfilename));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool pHiro::file_open(Window *focus, char *filename, const char *path, const char *filter) {
|
||||
string dir, f;
|
||||
dir = path ? path : "";
|
||||
dir.replace("/", "\\");
|
||||
|
||||
lstring type, part;
|
||||
type.split("\n", filter);
|
||||
for(int i = 0; i < type.size(); i++) {
|
||||
part.split("\t", type[i]);
|
||||
if(part.size() != 2) continue;
|
||||
|
||||
f.append(part[0]);
|
||||
f.append(" (");
|
||||
f.append(part[1]);
|
||||
f.append(")\t");
|
||||
part[1].replace(",", ";");
|
||||
f.append(part[1]);
|
||||
f.append("\t");
|
||||
}
|
||||
|
||||
utf16 wfilter(f);
|
||||
utf16 wdir(dir);
|
||||
wchar_t wfilename[_MAX_PATH] = L"";
|
||||
|
||||
wchar_t *p = wfilter;
|
||||
while(*p != L'\0') {
|
||||
if(*p == L'\t') *p = L'\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
strcpy(filename, "");
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = focus ? focus->p.hwnd : 0;
|
||||
ofn.lpstrFilter = wfilter;
|
||||
ofn.lpstrInitialDir = wdir;
|
||||
ofn.lpstrFile = wfilename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
|
||||
ofn.lpstrDefExt = L"";
|
||||
|
||||
bool result = GetOpenFileName(&ofn);
|
||||
strcpy(filename, utf8(wfilename));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool pHiro::file_save(Window *focus, char *filename, const char *path, const char *filter) {
|
||||
string dir, f;
|
||||
dir = path ? path : "";
|
||||
dir.replace("/", "\\");
|
||||
|
||||
lstring type, part;
|
||||
type.split("\n", filter);
|
||||
for(int i = 0; i < type.size(); i++) {
|
||||
part.split("\t", type[i]);
|
||||
if(part.size() != 2) continue;
|
||||
|
||||
f.append(part[0]);
|
||||
f.append(" (");
|
||||
f.append(part[1]);
|
||||
f.append(")\t");
|
||||
part[1].replace(",", ";");
|
||||
f.append(part[1]);
|
||||
f.append("\t");
|
||||
}
|
||||
|
||||
utf16 wfilter(f);
|
||||
utf16 wdir(dir);
|
||||
wchar_t wfilename[_MAX_PATH] = L"";
|
||||
|
||||
wchar_t *p = wfilter;
|
||||
while(*p != L'\0') {
|
||||
if(*p == L'\t') *p = L'\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
strcpy(filename, "");
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = focus ? focus->p.hwnd : 0;
|
||||
ofn.lpstrFilter = wfilter;
|
||||
ofn.lpstrInitialDir = wdir;
|
||||
ofn.lpstrFile = wfilename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
|
||||
ofn.lpstrDefExt = L"";
|
||||
|
||||
bool result = GetSaveFileName(&ofn);
|
||||
strcpy(filename, utf8(wfilename));
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned pHiro::screen_width() {
|
||||
return GetSystemMetrics(SM_CXSCREEN);
|
||||
}
|
||||
|
||||
unsigned pHiro::screen_height() {
|
||||
return GetSystemMetrics(SM_CYSCREEN);
|
||||
}
|
||||
|
||||
void pHiro::enable_screensaver() {
|
||||
is_screensaver_enabled = true;
|
||||
}
|
||||
|
||||
void pHiro::disable_screensaver() {
|
||||
is_screensaver_enabled = false;
|
||||
}
|
||||
|
||||
pHiro& pHiro::handle() {
|
||||
return hiro().p;
|
||||
}
|
||||
|
||||
pHiro::pHiro(Hiro &self_) : self(self_) {
|
||||
is_screensaver_enabled = true;
|
||||
}
|
||||
|
||||
pHiro& phiro() {
|
||||
return pHiro::handle();
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
HFONT pHiro::create_font(const char *name, unsigned size) {
|
||||
return CreateFont(
|
||||
-(size * 96.0 / 72.0 + 0.5), //96 = DPI
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
utf16(name)
|
||||
);
|
||||
}
|
||||
|
||||
Widget* pHiro::get_widget(unsigned instance) {
|
||||
Widget *widget = 0;
|
||||
for(unsigned i = 0; i < widget_list.size(); i++) {
|
||||
if(widget_list[i]->p.instance != instance) continue;
|
||||
widget = widget_list[i];
|
||||
break;
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK phiro_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return phiro().wndproc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
pWidget *p = (pWidget*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
switch(msg) {
|
||||
case WM_SYSCOMMAND: {
|
||||
switch(wparam) {
|
||||
case SC_SCREENSAVE:
|
||||
case SC_MONITORPOWER: {
|
||||
if(is_screensaver_enabled == false) return FALSE;
|
||||
//fallthrough to DefWindowProc()
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_SIZE: {
|
||||
if(!p || p->self.type != Widget::WindowType) break;
|
||||
SendMessage(((pWindow*)p)->hstatus, WM_SIZE, 0, 0); //the control itself auto-sizes after receiving WM_SIZE
|
||||
} break;
|
||||
|
||||
case WM_CLOSE: {
|
||||
if(!p || p->self.type != Widget::WindowType) break;
|
||||
Window &w = ((pWindow*)p)->self;
|
||||
if(w.on_close) return (bool)w.on_close(event_t(event_t::Close, 0, &w));
|
||||
return TRUE; //true = destroy window
|
||||
} break;
|
||||
|
||||
case WM_ENTERMENULOOP: {
|
||||
if(!p || p->self.type != Widget::WindowType) break;
|
||||
Window &w = ((pWindow*)p)->self;
|
||||
if(w.on_block) w.on_block(event_t(event_t::Block, 0, &w));
|
||||
} break;
|
||||
|
||||
case WM_KEYDOWN: {
|
||||
if(!p || p->self.type != Widget::WindowType) break;
|
||||
Window &w = ((pWindow*)p)->self;
|
||||
if(w.on_input) w.on_input(event_t(event_t::Input, translate_key(wparam) + (1 << 16), &w));
|
||||
} break;
|
||||
|
||||
case WM_KEYUP: {
|
||||
if(!p || p->self.type != Widget::WindowType) break;
|
||||
Window &w = ((pWindow*)p)->self;
|
||||
if(w.on_input) w.on_input(event_t(event_t::Input, translate_key(wparam) + (0 << 16), &w));
|
||||
} break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN: {
|
||||
if(!p || p->self.type != Widget::CanvasType) break;
|
||||
Canvas &canvas = ((pCanvas*)p)->self;
|
||||
uintptr_t param = (msg == WM_LBUTTONDOWN ? mouse::button + 0 : mouse::button + 1) + (1 << 16);
|
||||
if(canvas.on_input) canvas.on_input(event_t(event_t::Input, param, &canvas));
|
||||
} break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP: {
|
||||
if(!p || p->self.type != Widget::CanvasType) break;
|
||||
Canvas &canvas = ((pCanvas*)p)->self;
|
||||
uintptr_t param = (msg == WM_LBUTTONUP ? mouse::button + 0 : mouse::button + 1) + (0 << 16);
|
||||
if(canvas.on_input) canvas.on_input(event_t(event_t::Input, param, &canvas));
|
||||
} break;
|
||||
|
||||
case WM_ERASEBKGND: {
|
||||
if(!p) break;
|
||||
HBRUSH brush = 0;
|
||||
if(p->self.type == Widget::WindowType) brush = ((pWindow*)p)->background;
|
||||
if(p->self.type == Widget::CanvasType) brush = phiro().black_brush;
|
||||
if(!brush) break;
|
||||
RECT rc;
|
||||
GetClientRect(hwnd, &rc);
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
FillRect(ps.hdc, &rc, brush);
|
||||
EndPaint(hwnd, &ps);
|
||||
return TRUE;
|
||||
} break;
|
||||
|
||||
case WM_PAINT: {
|
||||
if(p && p->self.type == Widget::CanvasType) ((pCanvas*)p)->redraw();
|
||||
} break;
|
||||
|
||||
case WM_COMMAND: {
|
||||
Widget *widget = get_widget(LOWORD(wparam));
|
||||
if(!widget) break;
|
||||
|
||||
switch(widget->type) {
|
||||
case Widget::MenuItemType: {
|
||||
MenuItem &w = (MenuItem&)*widget;
|
||||
if(w.on_tick) w.on_tick(event_t(event_t::Tick, 0, &w));
|
||||
} break;
|
||||
|
||||
case Widget::MenuCheckItemType: {
|
||||
MenuCheckItem &w = (MenuCheckItem&)*widget;
|
||||
w.check(!w.checked()); //invert check state
|
||||
if(w.on_tick) w.on_tick(event_t(event_t::Tick, w.checked(), &w));
|
||||
} break;
|
||||
|
||||
case Widget::MenuRadioItemType: {
|
||||
MenuRadioItem &w = (MenuRadioItem&)*widget;
|
||||
bool checked = w.checked();
|
||||
w.check();
|
||||
if(!checked && w.on_tick) w.on_tick(event_t(event_t::Tick, w.checked(), &w));
|
||||
} break;
|
||||
|
||||
case Widget::ButtonType: {
|
||||
Button &w = (Button&)*widget;
|
||||
if(w.on_tick) w.on_tick(event_t(event_t::Tick, 0, &w));
|
||||
} break;
|
||||
|
||||
case Widget::CheckboxType: {
|
||||
Checkbox &w = (Checkbox&)*widget;
|
||||
w.check(!w.checked()); //invert check state
|
||||
if(w.on_tick) w.on_tick(event_t(event_t::Tick, w.checked(), &w));
|
||||
} break;
|
||||
|
||||
case Widget::RadioboxType: {
|
||||
Radiobox &w = (Radiobox&)*widget;
|
||||
bool checked = w.checked();
|
||||
w.check();
|
||||
if(!checked && w.on_tick) w.on_tick(event_t(event_t::Tick, w.checked(), &w));
|
||||
} break;
|
||||
|
||||
case Widget::EditboxType: {
|
||||
Editbox &editbox = (Editbox&)*widget;
|
||||
if(HIWORD(wparam) == EN_CHANGE) {
|
||||
editbox.p.update(); //called to dynamically display vertical scrollbar if needed
|
||||
if(editbox.on_change) editbox.on_change(event_t(event_t::Change, 0, &editbox));
|
||||
}
|
||||
} break;
|
||||
|
||||
case Widget::ComboboxType: {
|
||||
Combobox &combobox = (Combobox&)*widget;
|
||||
if(HIWORD(wparam) == CBN_SELCHANGE) {
|
||||
if(combobox.p.combobox_selection == combobox.get_selection()) break;
|
||||
if(combobox.on_change) combobox.on_change(event_t(event_t::Change, combobox.p.combobox_selection = combobox.get_selection(), &combobox));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_HSCROLL:
|
||||
case WM_VSCROLL: {
|
||||
Widget *widget = get_widget(GetDlgCtrlID((HWND)lparam));
|
||||
if(!widget) break;
|
||||
|
||||
switch(widget->type) {
|
||||
case Widget::SliderType: {
|
||||
Slider &slider = (Slider&)*widget;
|
||||
if(slider.p.slider_position == slider.get_position()) break;
|
||||
if(slider.on_change) slider.on_change(event_t(event_t::Change, slider.p.slider_position = slider.get_position(), &slider));
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case WM_NOTIFY: {
|
||||
Widget *widget = get_widget(LOWORD(wparam));
|
||||
if(!widget) break;
|
||||
|
||||
switch(widget->type) {
|
||||
case Widget::ListboxType: {
|
||||
Listbox &listbox = (Listbox&)*widget;
|
||||
LPNMHDR nmhdr = (LPNMHDR)lparam;
|
||||
LPNMLISTVIEW nmlistview = (LPNMLISTVIEW)lparam;
|
||||
|
||||
if(nmhdr->code == LVN_ITEMCHANGED && (nmlistview->uChanged & LVIF_STATE)) {
|
||||
//LVN_ITEMCHANGED is sent whenever an item gains or loses either focus or selection;
|
||||
//it does not send a special message to indicate that no items are focused or selected.
|
||||
//it will send two messages when a different item gains selection -- the first to remove
|
||||
//focus from the old item, the second to set selection to the new item.
|
||||
//hiro sends only one message whenever an item changed (eg gained selection),
|
||||
//including for deselection of all items. below code adapts win32 model to hiro model.
|
||||
//(focused means an item has a dotted outline box around it, but is not highlighted.)
|
||||
//(selected means an item is highlighted.)
|
||||
if((nmlistview->uOldState & LVIS_FOCUSED) && !(nmlistview->uNewState & LVIS_FOCUSED)) {
|
||||
listbox.p.lostfocus = true;
|
||||
} else {
|
||||
if((!(nmlistview->uOldState & LVIS_SELECTED) && (nmlistview->uNewState & LVIS_SELECTED))
|
||||
|| (listbox.p.lostfocus == false && listbox.get_selection() == -1)) {
|
||||
if(listbox.on_change) listbox.on_change(event_t(event_t::Change, listbox.get_selection(), &listbox));
|
||||
}
|
||||
listbox.p.lostfocus = false;
|
||||
}
|
||||
} else if(nmhdr->code == LVN_ITEMACTIVATE) {
|
||||
if(listbox.on_activate) listbox.on_activate(event_t(event_t::Activate, listbox.get_selection(), &listbox));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
} //namespace libhiro
|
@@ -1,97 +0,0 @@
|
||||
#ifndef HIRO_WIN_H
|
||||
#define HIRO_WIN_H
|
||||
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#undef _WIN32_IE
|
||||
#undef NOMINMAX
|
||||
#undef _NO_OLDNAMES
|
||||
|
||||
#define WINVER 0x0501
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#define _WIN32_IE 0x0600
|
||||
#define NOMINMAX
|
||||
#define _NO_OLDNAMES
|
||||
|
||||
#define mkdir _mkdir
|
||||
#define UNICODE
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
#undef mkdir
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
using nall::min;
|
||||
using nall::max;
|
||||
|
||||
#include <nall/utf8.hpp>
|
||||
#define utf8 nall::utf8_t
|
||||
#define utf16 nall::utf16_t
|
||||
|
||||
extern int hiromain(int argc, const char *const argv[]);
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
#include "widget.hpp"
|
||||
#include "window.hpp"
|
||||
#include "menucontrol.hpp"
|
||||
#include "menugroup.hpp"
|
||||
#include "menuitem.hpp"
|
||||
#include "menucheckitem.hpp"
|
||||
#include "menuradioitem.hpp"
|
||||
#include "menuseparator.hpp"
|
||||
#include "formcontrol.hpp"
|
||||
#include "frame.hpp"
|
||||
#include "canvas.hpp"
|
||||
#include "label.hpp"
|
||||
#include "button.hpp"
|
||||
#include "checkbox.hpp"
|
||||
#include "radiobox.hpp"
|
||||
#include "editbox.hpp"
|
||||
#include "listbox.hpp"
|
||||
#include "combobox.hpp"
|
||||
#include "progressbar.hpp"
|
||||
#include "slider.hpp"
|
||||
|
||||
class pHiro {
|
||||
public:
|
||||
Hiro &self;
|
||||
void init();
|
||||
void term();
|
||||
bool run();
|
||||
bool pending();
|
||||
|
||||
bool folder_select(Window *focus, char *filename, const char *path = "");
|
||||
bool file_open(Window *focus, char *filename, const char *path = "", const char *filter = "");
|
||||
bool file_save(Window *focus, char *filename, const char *path = "", const char *filter = "");
|
||||
|
||||
unsigned screen_width();
|
||||
unsigned screen_height();
|
||||
|
||||
void enable_screensaver();
|
||||
void disable_screensaver();
|
||||
|
||||
static pHiro& handle();
|
||||
pHiro(Hiro&);
|
||||
|
||||
/* internal */
|
||||
OSVERSIONINFO osversioninfo;
|
||||
bool is_screensaver_enabled;
|
||||
HWND default_hwnd; //default parent window for all windowless controls
|
||||
HFONT default_font; //default font for all controls
|
||||
HBRUSH black_brush; //used for Canvas background
|
||||
HFONT create_font(const char *name, unsigned size);
|
||||
|
||||
array<Widget*> widget_list;
|
||||
Widget* get_widget(unsigned instance);
|
||||
LRESULT wndproc(HWND, UINT, WPARAM, LPARAM);
|
||||
uint16_t translate_key(unsigned key);
|
||||
};
|
||||
|
||||
pHiro& phiro();
|
||||
|
||||
} //namsepace libhiro
|
||||
|
||||
#endif //ifndef HIRO_WIN_H
|
@@ -1,74 +0,0 @@
|
||||
uint16_t pHiro::translate_key(unsigned key) {
|
||||
switch(key) {
|
||||
case VK_ESCAPE: return keyboard::escape;
|
||||
|
||||
case VK_F1: return keyboard::f1;
|
||||
case VK_F2: return keyboard::f2;
|
||||
case VK_F3: return keyboard::f3;
|
||||
case VK_F4: return keyboard::f4;
|
||||
case VK_F5: return keyboard::f5;
|
||||
case VK_F6: return keyboard::f6;
|
||||
case VK_F7: return keyboard::f7;
|
||||
case VK_F8: return keyboard::f8;
|
||||
case VK_F9: return keyboard::f9;
|
||||
case VK_F10: return keyboard::f10;
|
||||
case VK_F11: return keyboard::f11;
|
||||
case VK_F12: return keyboard::f12;
|
||||
|
||||
case VK_TAB: return keyboard::tab;
|
||||
case VK_RETURN: return keyboard::return_;
|
||||
case VK_SPACE: return keyboard::spacebar;
|
||||
|
||||
case '0': return keyboard::num_0;
|
||||
case '1': return keyboard::num_1;
|
||||
case '2': return keyboard::num_2;
|
||||
case '3': return keyboard::num_3;
|
||||
case '4': return keyboard::num_4;
|
||||
case '5': return keyboard::num_5;
|
||||
case '6': return keyboard::num_6;
|
||||
case '7': return keyboard::num_7;
|
||||
case '8': return keyboard::num_8;
|
||||
case '9': return keyboard::num_9;
|
||||
|
||||
case VK_INSERT: return keyboard::insert;
|
||||
case VK_DELETE: return keyboard::delete_;
|
||||
case VK_HOME: return keyboard::home;
|
||||
case VK_END: return keyboard::end;
|
||||
case VK_PRIOR: return keyboard::page_up;
|
||||
case VK_NEXT: return keyboard::page_down;
|
||||
|
||||
case 'A': return keyboard::a;
|
||||
case 'B': return keyboard::b;
|
||||
case 'C': return keyboard::c;
|
||||
case 'D': return keyboard::d;
|
||||
case 'E': return keyboard::e;
|
||||
case 'F': return keyboard::f;
|
||||
case 'G': return keyboard::g;
|
||||
case 'H': return keyboard::h;
|
||||
case 'I': return keyboard::i;
|
||||
case 'J': return keyboard::j;
|
||||
case 'K': return keyboard::k;
|
||||
case 'L': return keyboard::l;
|
||||
case 'M': return keyboard::m;
|
||||
case 'N': return keyboard::n;
|
||||
case 'O': return keyboard::o;
|
||||
case 'P': return keyboard::p;
|
||||
case 'Q': return keyboard::q;
|
||||
case 'R': return keyboard::r;
|
||||
case 'S': return keyboard::s;
|
||||
case 'T': return keyboard::t;
|
||||
case 'U': return keyboard::u;
|
||||
case 'V': return keyboard::v;
|
||||
case 'W': return keyboard::w;
|
||||
case 'X': return keyboard::x;
|
||||
case 'Y': return keyboard::y;
|
||||
case 'Z': return keyboard::z;
|
||||
|
||||
case VK_UP: return keyboard::up;
|
||||
case VK_DOWN: return keyboard::down;
|
||||
case VK_LEFT: return keyboard::left;
|
||||
case VK_RIGHT: return keyboard::right;
|
||||
}
|
||||
|
||||
return keyboard::none;
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
void pLabel::create(unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
hwnd = CreateWindow(L"STATIC", utf16(text), WS_CHILD | WS_VISIBLE,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pLabel::set_text(const char *text) {
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
pLabel::pLabel(Label &self_) : pFormControl(self_), self(self_) {
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
class pLabel : public pFormControl {
|
||||
public:
|
||||
Label &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
|
||||
pLabel(Label&);
|
||||
};
|
@@ -1,98 +0,0 @@
|
||||
void pListbox::create(unsigned style, unsigned width, unsigned height, const char *columns, const char *text) {
|
||||
bool header = style & Listbox::Header;
|
||||
unsigned hscroll = (style & Listbox::HorizontalScrollAlways) ? WS_HSCROLL :
|
||||
(style & Listbox::HorizontalScrollNever) ? 0 :
|
||||
0;
|
||||
unsigned vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
|
||||
(style & Listbox::VerticalScrollNever) ? 0 :
|
||||
0;
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
|
||||
LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll |
|
||||
(header ? 0 : LVS_NOCOLUMNHEADER),
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
|
||||
|
||||
lstring list;
|
||||
list.split("\t", columns ? columns : "");
|
||||
column_count = 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 ulist(list[i]);
|
||||
column.pszText = ulist;
|
||||
ListView_InsertColumn(hwnd, i, &column);
|
||||
}
|
||||
|
||||
if(text && *text) {
|
||||
list.split("\n", text);
|
||||
for(unsigned i = 0; i < list.size(); i++) add_item(list[i]);
|
||||
}
|
||||
autosize_columns();
|
||||
}
|
||||
|
||||
void pListbox::autosize_columns() {
|
||||
for(unsigned i = 0; i < column_count; i++) {
|
||||
ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::set_column_width(unsigned column, unsigned width) {
|
||||
ListView_SetColumnWidth(hwnd, column, width);
|
||||
}
|
||||
|
||||
void pListbox::add_item(const char *text) {
|
||||
lstring list;
|
||||
list.split("\t", text ? text : "");
|
||||
LVITEM item;
|
||||
unsigned pos = ListView_GetItemCount(hwnd);
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = pos;
|
||||
item.iSubItem = 0;
|
||||
utf16 wtext(list[0]);
|
||||
item.pszText = wtext;
|
||||
ListView_InsertItem(hwnd, &item);
|
||||
|
||||
for(unsigned i = 1; i < list.size(); i++) {
|
||||
utf16 wtext(list[i]);
|
||||
ListView_SetItemText(hwnd, pos, i, wtext);
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::set_item(unsigned index, const char *text) {
|
||||
lstring list;
|
||||
list.split("\t", text ? text : "");
|
||||
for(unsigned i = 0; i < list.size(); i++) {
|
||||
utf16 wtext(list[i]);
|
||||
ListView_SetItemText(hwnd, index, i, wtext);
|
||||
}
|
||||
}
|
||||
|
||||
int pListbox::get_selection() {
|
||||
unsigned count = ListView_GetItemCount(hwnd);
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
if(ListView_GetItemState(hwnd, i, LVIS_SELECTED)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pListbox::set_selection(int index) {
|
||||
unsigned count = ListView_GetItemCount(hwnd);
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0);
|
||||
ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::reset() {
|
||||
ListView_DeleteAllItems(hwnd);
|
||||
}
|
||||
|
||||
pListbox::pListbox(Listbox &self_) : pFormControl(self_), self(self_) {
|
||||
column_count = 0;
|
||||
lostfocus = false; //used for message parsing
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
class pListbox : public pFormControl {
|
||||
public:
|
||||
Listbox &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *columns = "", const char *text = "");
|
||||
void autosize_columns();
|
||||
void set_column_width(unsigned column, unsigned width);
|
||||
void add_item(const char *text);
|
||||
void set_item(unsigned index, const char *text);
|
||||
int get_selection();
|
||||
void set_selection(int index);
|
||||
void reset();
|
||||
|
||||
pListbox(Listbox&);
|
||||
|
||||
/* internal */
|
||||
unsigned column_count;
|
||||
bool lostfocus;
|
||||
};
|
@@ -1,40 +0,0 @@
|
||||
void pMenuCheckItem::create(const char *text_) {
|
||||
text = strdup(text_);
|
||||
}
|
||||
|
||||
void pMenuCheckItem::check(bool state) {
|
||||
CheckMenuItem(parent, instance, state ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
|
||||
void pMenuCheckItem::uncheck() {
|
||||
check(false);
|
||||
}
|
||||
|
||||
bool pMenuCheckItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, instance, false, &info);
|
||||
return info.fState & MFS_CHECKED;
|
||||
}
|
||||
|
||||
void pMenuCheckItem::enable(bool state) {
|
||||
EnableMenuItem(parent, instance, MF_BYCOMMAND | (state ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void pMenuCheckItem::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pMenuCheckItem::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, instance, false, &info);
|
||||
return info.fState & MFS_ENABLED;
|
||||
}
|
||||
|
||||
pMenuCheckItem::pMenuCheckItem(MenuCheckItem &self_) : pMenuControl(self_), self(self_) {
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
class pMenuCheckItem : public pMenuControl {
|
||||
public:
|
||||
void create(const char *text = "");
|
||||
void check(bool state = true);
|
||||
void uncheck();
|
||||
bool checked();
|
||||
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
MenuCheckItem &self;
|
||||
pMenuCheckItem(MenuCheckItem&);
|
||||
};
|
@@ -1,18 +0,0 @@
|
||||
void pMenuControl::enable(bool) {
|
||||
}
|
||||
|
||||
void pMenuControl::disable() {
|
||||
}
|
||||
|
||||
bool pMenuControl::enabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
pMenuControl::pMenuControl(MenuControl &self_) : pWidget(self_), self(self_) {
|
||||
parent = 0;
|
||||
text = 0;
|
||||
}
|
||||
|
||||
pMenuControl::~pMenuControl() {
|
||||
if(text) free(text);
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
class pMenuControl : public pWidget {
|
||||
public:
|
||||
virtual void enable(bool = true);
|
||||
virtual void disable();
|
||||
virtual bool enabled();
|
||||
|
||||
MenuControl &self;
|
||||
pMenuControl(MenuControl&);
|
||||
virtual ~pMenuControl();
|
||||
|
||||
/* internal */
|
||||
HMENU parent;
|
||||
char *text;
|
||||
};
|
@@ -1,48 +0,0 @@
|
||||
void pMenuGroup::create(const char *text_) {
|
||||
group = CreatePopupMenu();
|
||||
text = strdup(text_);
|
||||
}
|
||||
|
||||
void pMenuGroup::attach(MenuControl &menucontrol) {
|
||||
switch(menucontrol.type) {
|
||||
case Widget::MenuGroupType: {
|
||||
AppendMenu(group, MF_STRING | MF_POPUP, (unsigned)((MenuGroup&)menucontrol).p.group, utf16(menucontrol.p.text));
|
||||
} break;
|
||||
|
||||
case Widget::MenuItemType:
|
||||
case Widget::MenuCheckItemType:
|
||||
case Widget::MenuRadioItemType: {
|
||||
AppendMenu(group, MF_STRING, menucontrol.p.instance, utf16(menucontrol.p.text));
|
||||
if(menucontrol.type == Widget::MenuRadioItemType && ((MenuRadioItem&)menucontrol).p.create_checked) {
|
||||
CheckMenuItem(group, menucontrol.p.instance, MF_CHECKED);
|
||||
}
|
||||
} break;
|
||||
|
||||
case Widget::MenuSeparatorType: {
|
||||
AppendMenu(group, MF_SEPARATOR, menucontrol.p.instance, L"");
|
||||
} break;
|
||||
}
|
||||
|
||||
menucontrol.p.parent = group;
|
||||
}
|
||||
|
||||
void pMenuGroup::enable(bool state) {
|
||||
EnableMenuItem(parent, (unsigned)group, MF_BYCOMMAND | (state ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void pMenuGroup::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pMenuGroup::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, (unsigned)group, false, &info);
|
||||
return info.fState & MFS_ENABLED;
|
||||
}
|
||||
|
||||
pMenuGroup::pMenuGroup(MenuGroup &self_) : pMenuControl(self_), self(self_) {
|
||||
group = 0;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
class pMenuGroup : public pMenuControl {
|
||||
public:
|
||||
MenuGroup &self;
|
||||
void create(const char *text);
|
||||
void attach(MenuControl &menucontrol);
|
||||
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
pMenuGroup(MenuGroup&);
|
||||
|
||||
/* internal */
|
||||
HMENU group;
|
||||
};
|
@@ -1,23 +0,0 @@
|
||||
void pMenuItem::create(const char *text_) {
|
||||
text = strdup(text_);
|
||||
}
|
||||
|
||||
void pMenuItem::enable(bool state) {
|
||||
EnableMenuItem(parent, instance, MF_BYCOMMAND | (state ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void pMenuItem::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pMenuItem::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, instance, false, &info);
|
||||
return info.fState & MFS_ENABLED;
|
||||
}
|
||||
|
||||
pMenuItem::pMenuItem(MenuItem &self_) : pMenuControl(self_), self(self_) {
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
class pMenuItem : public pMenuControl {
|
||||
public:
|
||||
void create(const char *text = "");
|
||||
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
MenuItem &self;
|
||||
pMenuItem(MenuItem&);
|
||||
};
|
@@ -1,41 +0,0 @@
|
||||
void pMenuRadioItem::create(MenuRadioItemGroup &group_, const char *text_) {
|
||||
group = group_;
|
||||
text = strdup(text_);
|
||||
create_checked = (group[0] == &self);
|
||||
}
|
||||
|
||||
void pMenuRadioItem::check() {
|
||||
for(unsigned i = 0; i < group.size(); i++) {
|
||||
CheckMenuItem(parent, group[i]->p.instance, (group[i] == &self) ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
}
|
||||
|
||||
bool pMenuRadioItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, instance, false, &info);
|
||||
return info.fState & MFS_CHECKED;
|
||||
}
|
||||
|
||||
void pMenuRadioItem::enable(bool state) {
|
||||
EnableMenuItem(parent, instance, MF_BYCOMMAND | (state ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void pMenuRadioItem::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pMenuRadioItem::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, instance, false, &info);
|
||||
return info.fState & MFS_ENABLED;
|
||||
}
|
||||
|
||||
pMenuRadioItem::pMenuRadioItem(MenuRadioItem &self_) : pMenuControl(self_), self(self_) {
|
||||
create_checked = false;
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
class pMenuRadioItem : public pMenuControl {
|
||||
public:
|
||||
void create(MenuRadioItemGroup &group, const char *text = "");
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
MenuRadioItem &self;
|
||||
pMenuRadioItem(MenuRadioItem&);
|
||||
|
||||
/* internal */
|
||||
MenuRadioItemGroup group;
|
||||
bool create_checked;
|
||||
};
|
@@ -1,22 +0,0 @@
|
||||
void pMenuSeparator::create() {
|
||||
}
|
||||
|
||||
void pMenuSeparator::enable(bool state) {
|
||||
EnableMenuItem(parent, instance, MF_BYCOMMAND | (state ? MF_ENABLED : MF_GRAYED));
|
||||
}
|
||||
|
||||
void pMenuSeparator::disable() {
|
||||
enable(false);
|
||||
}
|
||||
|
||||
bool pMenuSeparator::enabled() {
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
GetMenuItemInfo(parent, instance, false, &info);
|
||||
return info.fState & MFS_ENABLED;
|
||||
}
|
||||
|
||||
pMenuSeparator::pMenuSeparator(MenuSeparator &self_) : pMenuControl(self_), self(self_) {
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
class pMenuSeparator : public pMenuControl {
|
||||
public:
|
||||
MenuSeparator &self;
|
||||
void create();
|
||||
|
||||
void enable(bool = true);
|
||||
void disable();
|
||||
bool enabled();
|
||||
|
||||
pMenuSeparator(MenuSeparator&);
|
||||
};
|
@@ -1,40 +0,0 @@
|
||||
char* realpath(const char *file_name, char *resolved_name) {
|
||||
wchar_t filename[_MAX_PATH] = L"";
|
||||
_wfullpath(filename, utf16(file_name), _MAX_PATH);
|
||||
strcpy(resolved_name, utf8(filename));
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
char* userpath(char *output) {
|
||||
wchar_t path[_MAX_PATH] = L"";
|
||||
SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, path);
|
||||
strcpy(output, utf8(path));
|
||||
return output;
|
||||
}
|
||||
|
||||
int mkdir(const char *path) {
|
||||
return _wmkdir(utf16(path));
|
||||
}
|
||||
|
||||
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
//argv[] is in 7-bit ANSI format; Unicode characters are converted to '?'s.
|
||||
//this needs to be converted to UTF-8, eg for realpath(argv[0]) to work.
|
||||
int argc;
|
||||
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
char **argv = new char*[argc];
|
||||
for(unsigned i = 0; i < argc; i++) {
|
||||
argv[i] = new char[_MAX_PATH];
|
||||
strcpy(argv[i], utf8(wargv[i]));
|
||||
}
|
||||
|
||||
libhiro::hiro().init();
|
||||
int result = hiromain(argc, argv);
|
||||
libhiro::hiro().term();
|
||||
|
||||
for(unsigned i = 0; i < argc; i++) {
|
||||
delete[] argv[i];
|
||||
}
|
||||
delete[] argv;
|
||||
|
||||
return result;
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
void pProgressbar::create(unsigned style, unsigned width, unsigned height) {
|
||||
hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0);
|
||||
}
|
||||
|
||||
unsigned pProgressbar::get_progress() {
|
||||
unsigned progress = SendMessage(hwnd, PBM_GETPOS, 0, 0);
|
||||
return max(0U, min(progress, 100U));
|
||||
}
|
||||
|
||||
void pProgressbar::set_progress(unsigned progress) {
|
||||
progress = max(0U, min(progress, 100U));
|
||||
SendMessage(hwnd, PBM_SETPOS, (WPARAM)progress, 0);
|
||||
}
|
||||
|
||||
pProgressbar::pProgressbar(Progressbar &self_) : pFormControl(self_), self(self_) {
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
class pProgressbar : public pFormControl {
|
||||
public:
|
||||
Progressbar &self;
|
||||
void create(unsigned style, unsigned width, unsigned height);
|
||||
unsigned get_progress();
|
||||
void set_progress(unsigned progress);
|
||||
|
||||
pProgressbar(Progressbar&);
|
||||
};
|
@@ -1,24 +0,0 @@
|
||||
void pRadiobox::create(RadioboxGroup &group_, unsigned style, unsigned width, unsigned height, const char *text) {
|
||||
group = group_;
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
if(group[0] == &self) check();
|
||||
}
|
||||
|
||||
void pRadiobox::set_text(const char *text) {
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
void pRadiobox::check() {
|
||||
for(unsigned i = 0; i < group.size(); i++) {
|
||||
SendMessage(group[i]->p.hwnd, BM_SETCHECK, (WPARAM)(group[i] == &self), 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool pRadiobox::checked() {
|
||||
return SendMessage(hwnd, BM_GETCHECK, 0, 0);
|
||||
}
|
||||
|
||||
pRadiobox::pRadiobox(Radiobox &self_) : pFormControl(self_), self(self_) {
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
class pRadiobox : public pFormControl {
|
||||
public:
|
||||
void create(RadioboxGroup &group, unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void set_text(const char *text = "");
|
||||
void check();
|
||||
bool checked();
|
||||
|
||||
Radiobox &self;
|
||||
pRadiobox(Radiobox&);
|
||||
|
||||
/* internal */
|
||||
RadioboxGroup group;
|
||||
};
|
@@ -1,24 +0,0 @@
|
||||
void pSlider::create(unsigned style, unsigned width, unsigned height, unsigned length) {
|
||||
if(length < 1) length = 1;
|
||||
|
||||
hwnd = CreateWindow(TRACKBAR_CLASS, L"",
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH |
|
||||
(style & Slider::Vertical ? TBS_VERT : TBS_HORZ),
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, TBM_SETRANGE, (WPARAM)true, (LPARAM)MAKELONG(0, length - 1));
|
||||
SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)(length >> 3));
|
||||
SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)0);
|
||||
}
|
||||
|
||||
unsigned pSlider::get_position() {
|
||||
return SendMessage(hwnd, TBM_GETPOS, 0, 0);
|
||||
}
|
||||
|
||||
void pSlider::set_position(unsigned position) {
|
||||
SendMessage(hwnd, TBM_SETPOS, (WPARAM)true, (LPARAM)(slider_position = position));
|
||||
}
|
||||
|
||||
pSlider::pSlider(Slider &self_) : pFormControl(self_), self(self_) {
|
||||
slider_position = 0;
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
class pSlider : public pFormControl {
|
||||
public:
|
||||
Slider &self;
|
||||
void create(unsigned style, unsigned width, unsigned height, unsigned length);
|
||||
unsigned get_position();
|
||||
void set_position(unsigned position);
|
||||
|
||||
pSlider(Slider&);
|
||||
|
||||
/* internal */
|
||||
unsigned slider_position;
|
||||
};
|
@@ -1,27 +0,0 @@
|
||||
void pWidget::show(bool state) {
|
||||
}
|
||||
|
||||
void pWidget::hide() {
|
||||
}
|
||||
|
||||
bool pWidget::visible() {
|
||||
return true;
|
||||
}
|
||||
|
||||
uintptr_t pWidget::handle() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pWidget::pWidget(Widget &self_) : self(self_) {
|
||||
instance = instance_counter++;
|
||||
phiro().widget_list.add(&self);
|
||||
}
|
||||
|
||||
pWidget::~pWidget() {
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
//100 is the standard start index for control IDs in the Windows API
|
||||
//avoids duplicate IDs when they are not explicitly set (and are thus 0)
|
||||
unsigned pWidget::instance_counter = 100;
|
@@ -1,19 +0,0 @@
|
||||
class pWidget {
|
||||
public:
|
||||
Widget &self;
|
||||
virtual void show(bool = true);
|
||||
virtual void hide();
|
||||
virtual bool visible();
|
||||
virtual uintptr_t handle();
|
||||
|
||||
pWidget(Widget&);
|
||||
virtual ~pWidget();
|
||||
|
||||
/* internal */
|
||||
|
||||
//Windows API controls often require a unique ID for each control to identify it.
|
||||
//Simulate this with an instance counter, so that each Widget has a unique ID.
|
||||
//In each pWidget() constructor, instance = instance_counter++; is called.
|
||||
static unsigned instance_counter;
|
||||
unsigned instance;
|
||||
};
|
@@ -1,334 +0,0 @@
|
||||
void pWindow::create(unsigned style, unsigned width_, unsigned height_, const char *text) {
|
||||
auto_center = style & Window::AutoCenter;
|
||||
|
||||
RECT rc;
|
||||
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
|
||||
hwnd = CreateWindowEx(0, L"hiro_window", utf16(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
rc.left, rc.top, width_, height_,
|
||||
0, 0, GetModuleHandle(0), 0);
|
||||
hwndr = CreateWindowEx(0, L"hiro_window", utf16(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
rc.left, rc.top, width_, height_,
|
||||
0, 0, GetModuleHandle(0), 0);
|
||||
hmenu = CreateMenu();
|
||||
hstatus = CreateWindowEx(0, STATUSCLASSNAME, L"",
|
||||
WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
|
||||
resize(width_, height_);
|
||||
}
|
||||
|
||||
void pWindow::close() {
|
||||
CloseWindow(hwnd);
|
||||
}
|
||||
|
||||
void pWindow::move(unsigned x, unsigned y) {
|
||||
if(is_fullscreen == true) return;
|
||||
SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
void pWindow::resize(unsigned width_, unsigned height_) {
|
||||
int screen_width = GetSystemMetrics(SM_CXSCREEN);
|
||||
int screen_height = GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
if(is_fullscreen == true) {
|
||||
SetWindowPos(hwnd, 0, 0, 0, screen_width, screen_height, SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
return;
|
||||
}
|
||||
|
||||
width = width_;
|
||||
height = height_;
|
||||
|
||||
//set requested window size to hidden window, calculate the difference between
|
||||
//requested and actual client size area, and then adjust width so that new
|
||||
//width, height values will set requested client area size.
|
||||
//AdjustWindowRect() does not properly calculate the height of multi-line menus,
|
||||
//and thusly is not used.
|
||||
SetWindowPos(hwndr, 0, 0, 0, width_, height_, SWP_NOMOVE | SWP_NOZORDER);
|
||||
RECT rc;
|
||||
GetClientRect(hwndr, &rc);
|
||||
width_ += width_ - (rc.right - rc.left);
|
||||
height_ += height_ - (rc.bottom - rc.top);
|
||||
|
||||
if(status.visible()) {
|
||||
//statusbar does not count as part of window client area width, height
|
||||
GetClientRect(hstatus, &rc);
|
||||
height_ += rc.bottom - rc.top;
|
||||
}
|
||||
|
||||
//if window is larger than the screen size, Windows will hide the window entirely.
|
||||
//therefore, window must be constrained to fit within the current screen size.
|
||||
|
||||
int x, y;
|
||||
if(width_ <= screen_width) {
|
||||
x = (screen_width - width_) >> 1;
|
||||
} else {
|
||||
x = 0;
|
||||
width_ = screen_width;
|
||||
}
|
||||
|
||||
if(height_ <= screen_height) {
|
||||
y = (screen_height - height_) >> 1;
|
||||
} else {
|
||||
y = 0;
|
||||
height_ = screen_height;
|
||||
}
|
||||
|
||||
SetWindowPos(hwnd, 0, x, y, width_, height_, (auto_center ? 0 : SWP_NOMOVE) | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
void pWindow::focus() {
|
||||
if(visible() == false) show();
|
||||
SetFocus(hwnd);
|
||||
}
|
||||
|
||||
bool pWindow::focused() {
|
||||
return GetForegroundWindow() == hwnd;
|
||||
}
|
||||
|
||||
void pWindow::show(bool state) {
|
||||
if(state == true) {
|
||||
ShowWindow(hwnd, SW_NORMAL);
|
||||
SetFocus(hwnd);
|
||||
} else {
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
void pWindow::hide() {
|
||||
show(false);
|
||||
}
|
||||
|
||||
bool pWindow::visible() {
|
||||
return GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE;
|
||||
}
|
||||
|
||||
void pWindow::fullscreen() {
|
||||
if(is_fullscreen == true) return;
|
||||
is_fullscreen = true;
|
||||
SetWindowLong(hwnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
|
||||
resize(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
|
||||
}
|
||||
|
||||
void pWindow::unfullscreen() {
|
||||
if(is_fullscreen == false) return;
|
||||
is_fullscreen = false;
|
||||
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE);
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
unsigned pWindow::get_width() {
|
||||
RECT rc;
|
||||
GetClientRect(hwnd, &rc);
|
||||
return rc.right - rc.left;
|
||||
}
|
||||
|
||||
unsigned pWindow::get_height() {
|
||||
RECT rc;
|
||||
GetClientRect(hwnd, &rc);
|
||||
if(status.visible() == false) return rc.bottom - rc.top;
|
||||
//do not include statusbar in client area height
|
||||
RECT src;
|
||||
GetClientRect(hstatus, &src);
|
||||
return (rc.bottom - rc.top) - (src.bottom - src.top);
|
||||
}
|
||||
|
||||
void pWindow::set_opacity(uint8_t opacity_) {
|
||||
opacity = opacity_;
|
||||
if(!hwnd) return;
|
||||
|
||||
if(opacity != 255) {
|
||||
//enable translucency
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
|
||||
SetLayeredWindowAttributes(hwnd, 0, opacity, LWA_ALPHA);
|
||||
} else {
|
||||
//disable transluceny
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
|
||||
SetLayeredWindowAttributes(hwnd, 0, 0, 0);
|
||||
}
|
||||
|
||||
InvalidateRect(hwnd, 0, TRUE);
|
||||
}
|
||||
|
||||
void pWindow::set_background_color(uint8_t r, uint8_t g, uint8_t b) {
|
||||
if(background) DeleteObject(background);
|
||||
background = CreateSolidBrush(RGB(r, g, b));
|
||||
}
|
||||
|
||||
void pWindow::set_icon(unsigned width, unsigned height, const uint32_t *data) {
|
||||
if(hicon) DestroyIcon(hicon);
|
||||
|
||||
uint8_t *mask = (uint8_t*)malloc(width * height / 8);
|
||||
memset(mask, 0, width * height / 8);
|
||||
uint8_t *icon = (uint8_t*)malloc(width * height * 4);
|
||||
memcpy(icon, data, width * height * 4);
|
||||
|
||||
if((phiro().osversioninfo.dwMajorVersion < 5)
|
||||
|| (phiro().osversioninfo.dwMajorVersion == 5 && phiro().osversioninfo.dwMinorVersion < 1)) {
|
||||
//5.1 and above represents Windows XP or later, which supports 32-bit icons.
|
||||
//5.0 and below represents Windows 2000 or earlier, which does not support 32-bit icons.
|
||||
//if running Win2k or prior, alpha channel will be ignored;
|
||||
//so scale color intensity by alpha level, which gives icons a black background.
|
||||
//this is because an alpha of 0 (fully transparent) results in a color of 0 (black).
|
||||
//without this step and alpha ignored, icons lose appearance of anti-aliasing.
|
||||
for(unsigned i = 0; i < width * height; i++) {
|
||||
uint8_t a = icon[i * 4 + 3];
|
||||
uint8_t r = uint8_t(1.0 / 256.0 * a * icon[i * 4 + 2]);
|
||||
uint8_t g = uint8_t(1.0 / 256.0 * a * icon[i * 4 + 1]);
|
||||
uint8_t b = uint8_t(1.0 / 256.0 * a * icon[i * 4 + 0]);
|
||||
icon[i * 4 + 3] = 0xff; //ignored anyway, but just to be safe ...
|
||||
icon[i * 4 + 2] = max(0, min(255, r)); //clamp 0 <= color <= 255 ...
|
||||
icon[i * 4 + 1] = max(0, min(255, g)); //not required, but again ...
|
||||
icon[i * 4 + 0] = max(0, min(255, b)); //it's better to be safe.
|
||||
}
|
||||
}
|
||||
|
||||
hicon = CreateIcon(GetModuleHandle(0), width, height, 1, 32, (const BYTE*)mask, (const BYTE*)icon);
|
||||
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
|
||||
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
|
||||
|
||||
free(mask);
|
||||
free(icon);
|
||||
}
|
||||
|
||||
void pWindow::set_text(const char *text) {
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
void pWindow::attach(Window &window, unsigned x, unsigned y) {
|
||||
if(!window.p.hwnd) return;
|
||||
|
||||
//toplevel window size is larger, because it includes window borders
|
||||
//read size of window without window borders, and resize upon attach
|
||||
RECT rc;
|
||||
GetClientRect(window.p.hwnd, &rc);
|
||||
|
||||
ShowWindow(window.p.hwnd, SW_HIDE);
|
||||
SetWindowLong(window.p.hwnd, GWL_STYLE, WS_CHILD);
|
||||
SetWindowLong(window.p.hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT);
|
||||
SetParent(window.p.hwnd, hwnd);
|
||||
SetWindowPos(window.p.hwnd, 0, x, y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
ShowWindow(window.p.hwnd, SW_NORMAL);
|
||||
}
|
||||
|
||||
void pWindow::attach(MenuGroup &menugroup) {
|
||||
AppendMenu(hmenu, MF_STRING | MF_POPUP, (unsigned)menugroup.p.group, utf16(menugroup.p.text));
|
||||
if(menu_visible() == false) menu_show();
|
||||
}
|
||||
|
||||
void pWindow::attach(FormControl &formcontrol, unsigned x, unsigned y) {
|
||||
SetWindowPos(formcontrol.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
SetParent(formcontrol.p.hwnd, hwnd);
|
||||
//SetParent() sets Z-order to topmost ...
|
||||
//this causes WS_TABSTOP property to run through controls "backward"
|
||||
//by inverting this, the later a control is attached, the later the tab key moves to it
|
||||
SetWindowPos(formcontrol.p.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||
}
|
||||
|
||||
void pWindow::move(Window &window, unsigned x, unsigned y) {
|
||||
SetWindowPos(window.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
void pWindow::move(FormControl &formcontrol, unsigned x, unsigned y) {
|
||||
SetWindowPos(formcontrol.p.hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
/* pWindow -> Menubar */
|
||||
|
||||
void pWindow::Menubar::show(bool state) {
|
||||
p.menu_show(state);
|
||||
}
|
||||
|
||||
void pWindow::Menubar::hide() {
|
||||
p.menu_hide();
|
||||
}
|
||||
|
||||
bool pWindow::Menubar::visible() {
|
||||
return p.menu_visible();
|
||||
}
|
||||
|
||||
pWindow::Menubar::Menubar(pWindow &p_) : p(p_) {
|
||||
}
|
||||
|
||||
/* pWindow -> Statusbar */
|
||||
|
||||
void pWindow::Statusbar::set_text(const char *text) {
|
||||
p.status_set_text(text);
|
||||
}
|
||||
|
||||
void pWindow::Statusbar::show(bool state) {
|
||||
p.status_show(state);
|
||||
}
|
||||
|
||||
void pWindow::Statusbar::hide() {
|
||||
p.status_hide();
|
||||
}
|
||||
|
||||
bool pWindow::Statusbar::visible() {
|
||||
return p.status_visible();
|
||||
}
|
||||
|
||||
pWindow::Statusbar::Statusbar(pWindow &p_) : p(p_) {
|
||||
}
|
||||
|
||||
pWindow::pWindow(Window &self_) : pWidget(self_), self(self_), menu(*this), status(*this) {
|
||||
hwnd = 0;
|
||||
hwndr = 0;
|
||||
hicon = 0;
|
||||
hmenu = 0;
|
||||
background = 0;
|
||||
opacity = 255;
|
||||
is_fullscreen = false;
|
||||
auto_center = false;
|
||||
width = 0;
|
||||
height = 0;
|
||||
}
|
||||
|
||||
pWindow::~pWindow() {
|
||||
if(hicon) DestroyIcon(hicon);
|
||||
if(background) DeleteObject(background);
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
||||
uintptr_t pWindow::handle() {
|
||||
return (uintptr_t)hwnd;
|
||||
}
|
||||
|
||||
void pWindow::menu_show(bool state) {
|
||||
if(state) {
|
||||
SetMenu(hwnd, hmenu);
|
||||
SetMenu(hwndr, hmenu);
|
||||
} else {
|
||||
SetMenu(hwnd, 0);
|
||||
SetMenu(hwndr, 0);
|
||||
}
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
void pWindow::menu_hide() {
|
||||
menu_show(false);
|
||||
}
|
||||
|
||||
bool pWindow::menu_visible() {
|
||||
return GetMenu(hwnd);
|
||||
}
|
||||
|
||||
void pWindow::status_set_text(const char *text) {
|
||||
SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16(text));
|
||||
}
|
||||
|
||||
void pWindow::status_show(bool state) {
|
||||
ShowWindow(hstatus, state ? SW_SHOWNORMAL : SW_HIDE);
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
void pWindow::status_hide() {
|
||||
status_show(false);
|
||||
}
|
||||
|
||||
bool pWindow::status_visible() {
|
||||
return GetWindowLong(hstatus, GWL_STYLE) & WS_VISIBLE;
|
||||
}
|
@@ -1,74 +0,0 @@
|
||||
class pWindow : public pWidget {
|
||||
public:
|
||||
void create(unsigned style, unsigned width, unsigned height, const char *text = "");
|
||||
void close();
|
||||
void move(unsigned x, unsigned y);
|
||||
void resize(unsigned width, unsigned height);
|
||||
void focus();
|
||||
bool focused();
|
||||
void fullscreen();
|
||||
void unfullscreen();
|
||||
unsigned get_width();
|
||||
unsigned get_height();
|
||||
void set_opacity(uint8_t opacity);
|
||||
void set_background_color(uint8_t r, uint8_t g, uint8_t b);
|
||||
void set_icon(unsigned width, unsigned height, const uint32_t *data);
|
||||
void set_text(const char *text = "");
|
||||
void attach(Window &window, unsigned x, unsigned y);
|
||||
void attach(MenuGroup &menugroup);
|
||||
void attach(FormControl &formcontrol, unsigned x, unsigned y);
|
||||
void move(Window &window, unsigned x, unsigned y);
|
||||
void move(FormControl &formcontrol, unsigned x, unsigned y);
|
||||
|
||||
class Statusbar {
|
||||
public:
|
||||
void set_text(const char *text = "");
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
pWindow &p;
|
||||
Statusbar(pWindow&);
|
||||
} status;
|
||||
|
||||
class Menubar {
|
||||
public:
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
pWindow &p;
|
||||
Menubar(pWindow&);
|
||||
} menu;
|
||||
|
||||
Window &self;
|
||||
pWindow(Window&);
|
||||
~pWindow();
|
||||
|
||||
/* internal */
|
||||
HWND hwnd;
|
||||
HWND hwndr; //hidden window, used as resize assistant
|
||||
HICON hicon;
|
||||
HMENU hmenu;
|
||||
HWND hstatus;
|
||||
HBRUSH background;
|
||||
uint8_t opacity;
|
||||
bool is_fullscreen;
|
||||
bool auto_center;
|
||||
unsigned width, height;
|
||||
|
||||
uintptr_t handle();
|
||||
|
||||
void show(bool = true);
|
||||
void hide();
|
||||
bool visible();
|
||||
|
||||
void menu_show(bool = true);
|
||||
void menu_hide();
|
||||
bool menu_visible();
|
||||
|
||||
void status_set_text(const char *text = "");
|
||||
void status_show(bool = true);
|
||||
void status_hide();
|
||||
bool status_visible();
|
||||
};
|
@@ -8,9 +8,11 @@
|
||||
#include <nall/stdint.hpp>
|
||||
|
||||
namespace nall {
|
||||
struct keyboard {
|
||||
enum { input_none = 0 };
|
||||
|
||||
template<int number = -1> struct keyboard {
|
||||
enum {
|
||||
none,
|
||||
none = keyboard<number - 1>::limit,
|
||||
escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
|
||||
print_screen, scroll_lock, pause, tilde,
|
||||
num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
|
||||
@@ -29,54 +31,92 @@ namespace nall {
|
||||
};
|
||||
};
|
||||
|
||||
struct mouse {
|
||||
enum { buttons = 8 };
|
||||
|
||||
template<> struct keyboard<-1> {
|
||||
enum { count = 16 };
|
||||
enum {
|
||||
none = keyboard::limit,
|
||||
none,
|
||||
escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
|
||||
print_screen, scroll_lock, pause, tilde,
|
||||
num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
|
||||
dash, equal, backspace,
|
||||
insert, delete_, home, end, page_up, page_down,
|
||||
a, b, c, d, e, f, g, h, i, j, k, l, m,
|
||||
n, o, p, q, r, s, t, u, v, w, x, y, z,
|
||||
lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash,
|
||||
pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0,
|
||||
point, enter, add, subtract, multiply, divide,
|
||||
num_lock, caps_lock,
|
||||
up, down, left, right,
|
||||
tab, return_, spacebar,
|
||||
lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu,
|
||||
length, //number of syms per keyboard
|
||||
limit = 0,
|
||||
};
|
||||
|
||||
static uint16_t index(unsigned keyboard_number, unsigned keyboard_enum) {
|
||||
if(keyboard_number >= count) return input_none;
|
||||
return limit + keyboard_number * length + keyboard_enum;
|
||||
}
|
||||
};
|
||||
|
||||
template<int number = -1> struct mouse {
|
||||
enum { buttons = 8 };
|
||||
enum {
|
||||
none = mouse<number - 1>::limit,
|
||||
x, y, z,
|
||||
button,
|
||||
limit = button + buttons,
|
||||
};
|
||||
};
|
||||
|
||||
template<int number = -1> struct joypad {
|
||||
enum { axes = 8 };
|
||||
enum { buttons = 96 };
|
||||
template<> struct mouse<-1> {
|
||||
enum { count = 16, buttons = 8 };
|
||||
enum {
|
||||
none,
|
||||
x, y, z,
|
||||
button,
|
||||
length = button + buttons - none, //number of syms per mouse
|
||||
limit = keyboard<keyboard<>::count - 1>::limit,
|
||||
};
|
||||
|
||||
static uint16_t index(unsigned mouse_number, unsigned mouse_enum) {
|
||||
if(mouse_number >= count) return input_none;
|
||||
return limit + mouse_number * length + mouse_enum;
|
||||
}
|
||||
};
|
||||
|
||||
template<int number = -1> struct joypad {
|
||||
enum { hats = 8, axes = 32, buttons = 96 };
|
||||
enum {
|
||||
none = joypad<number - 1>::limit,
|
||||
up, down, left, right,
|
||||
axis,
|
||||
hat,
|
||||
axis = hat + hats,
|
||||
button = axis + axes,
|
||||
limit = button + buttons,
|
||||
};
|
||||
};
|
||||
|
||||
template<> struct joypad<-1> {
|
||||
enum { count = 16 };
|
||||
enum { axes = 8 };
|
||||
enum { buttons = 96 };
|
||||
|
||||
enum { count = 16, hats = 8, axes = 32, buttons = 96 };
|
||||
enum { hat_center = 0, hat_up = 1, hat_right = 2, hat_down = 4, hat_left = 8 };
|
||||
enum {
|
||||
none,
|
||||
up, down, left, right,
|
||||
axis,
|
||||
hat,
|
||||
axis = hat + hats,
|
||||
button = axis + axes,
|
||||
length = button + buttons - none, //number of syms per joypad
|
||||
limit = mouse::limit,
|
||||
limit = mouse<mouse<>::count - 1>::limit,
|
||||
};
|
||||
|
||||
static uint16_t index(unsigned joypad_number, unsigned joypad_enum) {
|
||||
if(joypad_number >= count) return keyboard::none;
|
||||
if(joypad_number >= count) return input_none;
|
||||
return limit + joypad_number * length + joypad_enum;
|
||||
}
|
||||
};
|
||||
|
||||
enum { input_limit = joypad<joypad<>::count - 1>::limit };
|
||||
|
||||
static const char sym_table[][64] = {
|
||||
//keyboard
|
||||
static const char keysym[][64] = {
|
||||
"none",
|
||||
"escape", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
|
||||
"print_screen", "scroll_lock", "pause", "tilde",
|
||||
@@ -92,24 +132,37 @@ namespace nall {
|
||||
"up", "down", "left", "right",
|
||||
"tab", "return", "spacebar",
|
||||
"lctrl", "rctrl", "lalt", "ralt", "lshift", "rshift", "lsuper", "rsuper", "menu",
|
||||
"keyboard.limit",
|
||||
|
||||
//mouse
|
||||
"mouse.x", "mouse.y", "mouse.z",
|
||||
"mouse.button00", "mouse.button01", "mouse.button02", "mouse.button03",
|
||||
"mouse.button04", "mouse.button05", "mouse.button06", "mouse.button07",
|
||||
"mouse.limit",
|
||||
"limit",
|
||||
};
|
||||
|
||||
static const char* input_find(uint16_t key) {
|
||||
if(key < mouse::limit) return sym_table[key];
|
||||
|
||||
static char buffer[64];
|
||||
for(unsigned j = 0; j < 16; j++) {
|
||||
if(key == joypad<>::index(j, joypad<>::up)) { sprintf(buffer, "joypad%.2d.up", j); return buffer; }
|
||||
if(key == joypad<>::index(j, joypad<>::down)) { sprintf(buffer, "joypad%.2d.down", j); return buffer; }
|
||||
if(key == joypad<>::index(j, joypad<>::left)) { sprintf(buffer, "joypad%.2d.left", j); return buffer; }
|
||||
if(key == joypad<>::index(j, joypad<>::right)) { sprintf(buffer, "joypad%.2d.right", j); return buffer; }
|
||||
|
||||
for(unsigned k = 0; k < keyboard<>::count; k++) {
|
||||
if(key >= keyboard<>::index(k, keyboard<>::none) && key < keyboard<>::index(k, keyboard<>::length)) {
|
||||
sprintf(buffer, "keyboard%.2d.%s", k, keysym[key - keyboard<>::index(k, keyboard<>::none)]);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned m = 0; m < mouse<>::count; m++) {
|
||||
if(key == mouse<>::index(m, mouse<>::x)) { sprintf(buffer, "mouse%.2d.x", m); return buffer; }
|
||||
if(key == mouse<>::index(m, mouse<>::y)) { sprintf(buffer, "mouse%.2d.y", m); return buffer; }
|
||||
if(key == mouse<>::index(m, mouse<>::z)) { sprintf(buffer, "mouse%.2d.z", m); return buffer; }
|
||||
|
||||
if(key >= mouse<>::index(m, mouse<>::button + 0)
|
||||
&& key < mouse<>::index(m, mouse<>::button + mouse<>::buttons)) {
|
||||
sprintf(buffer, "mouse%.2d.button%.2d", m, key - mouse<>::index(m, mouse<>::button));
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned j = 0; j < joypad<>::count; j++) {
|
||||
if(key >= joypad<>::index(j, joypad<>::hat + 0)
|
||||
&& key < joypad<>::index(j, joypad<>::hat + joypad<>::hats)) {
|
||||
sprintf(buffer, "joypad%.2d.hat%.2d", j, key - joypad<>::index(j, joypad<>::hat));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
if(key >= joypad<>::index(j, joypad<>::axis + 0)
|
||||
&& key < joypad<>::index(j, joypad<>::axis + joypad<>::axes)) {
|
||||
@@ -133,39 +186,77 @@ namespace nall {
|
||||
}
|
||||
|
||||
static uint16_t input_find(const char *key) {
|
||||
for(unsigned i = 0; i < mouse::limit; i++) {
|
||||
if(!strcmp(sym_table[i], key)) return i;
|
||||
if(!memcmp(key, "keyboard", 8)) {
|
||||
key += 8;
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t k = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(k >= keyboard<>::count) return input_none;
|
||||
key += 2;
|
||||
|
||||
if(*key++ != '.') return input_none;
|
||||
|
||||
for(unsigned i = 0; i < keyboard<>::length; i++) {
|
||||
if(!strcmp(key, keysym[i])) return keyboard<>::index(k, i);
|
||||
}
|
||||
}
|
||||
|
||||
if(memcmp(key, "joypad", 6)) return keyboard::none;
|
||||
key += 6;
|
||||
if(!*key || !*(key + 1)) return keyboard::none;
|
||||
uint8_t j = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(j > 15) return keyboard::none;
|
||||
|
||||
key += 2;
|
||||
if(!strcmp(key, ".up")) return joypad<>::index(j, joypad<>::up);
|
||||
if(!strcmp(key, ".down")) return joypad<>::index(j, joypad<>::down);
|
||||
if(!strcmp(key, ".left")) return joypad<>::index(j, joypad<>::left);
|
||||
if(!strcmp(key, ".right")) return joypad<>::index(j, joypad<>::right);
|
||||
|
||||
if(!memcmp(key, ".axis", 5)) {
|
||||
if(!memcmp(key, "mouse", 5)) {
|
||||
key += 5;
|
||||
if(!*key || !*(key + 1)) return keyboard::none;
|
||||
uint8_t axis = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(axis >= joypad<>::axes) return keyboard::none;
|
||||
return joypad<>::index(j, joypad<>::axis + axis);
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t m = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(m >= mouse<>::count) return input_none;
|
||||
key += 2;
|
||||
|
||||
if(!strcmp(key, ".x")) return mouse<>::index(m, mouse<>::x);
|
||||
if(!strcmp(key, ".y")) return mouse<>::index(m, mouse<>::y);
|
||||
if(!strcmp(key, ".z")) return mouse<>::index(m, mouse<>::z);
|
||||
|
||||
if(!memcmp(key, ".button", 7)) {
|
||||
key += 7;
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(button >= mouse<>::buttons) return input_none;
|
||||
return mouse<>::index(m, mouse<>::button + button);
|
||||
}
|
||||
|
||||
return input_none;
|
||||
}
|
||||
|
||||
if(!memcmp(key, ".button", 7)) {
|
||||
key += 7;
|
||||
if(!*key || !*(key + 1)) return keyboard::none;
|
||||
uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(button >= joypad<>::buttons) return keyboard::none;
|
||||
return joypad<>::index(j, joypad<>::button + button);
|
||||
if(!memcmp(key, "joypad", 6)) {
|
||||
key += 6;
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t j = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(j >= joypad<>::count) return input_none;
|
||||
key += 2;
|
||||
|
||||
if(!memcmp(key, ".hat", 4)) {
|
||||
key += 4;
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t hat = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(hat >= joypad<>::hats) return input_none;
|
||||
return joypad<>::index(j, joypad<>::hat + hat);
|
||||
}
|
||||
|
||||
if(!memcmp(key, ".axis", 5)) {
|
||||
key += 5;
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t axis = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(axis >= joypad<>::axes) return input_none;
|
||||
return joypad<>::index(j, joypad<>::axis + axis);
|
||||
}
|
||||
|
||||
if(!memcmp(key, ".button", 7)) {
|
||||
key += 7;
|
||||
if(!*key || !*(key + 1)) return input_none;
|
||||
uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
|
||||
if(button >= joypad<>::buttons) return input_none;
|
||||
return joypad<>::index(j, joypad<>::button + button);
|
||||
}
|
||||
|
||||
return input_none;
|
||||
}
|
||||
|
||||
return keyboard::none;
|
||||
return input_none;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,7 +5,6 @@ public:
|
||||
KeyboardSupport,
|
||||
MouseSupport,
|
||||
JoypadSupport,
|
||||
AnalogAxisResistance,
|
||||
};
|
||||
|
||||
virtual bool cap(Setting) { return false; }
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user