diff --git a/bsnes/gameboy/apu/apu.cpp b/bsnes/gameboy/apu/apu.cpp index 87c90d95..eaf5916e 100755 --- a/bsnes/gameboy/apu/apu.cpp +++ b/bsnes/gameboy/apu/apu.cpp @@ -80,10 +80,10 @@ uint8 APU::mmio_read(uint16 addr) { if(addr == 0xff26) { uint8 data = master.enable << 7; - if(square1.counter && square1.length) data |= 0x01; - if(square2.counter && square2.length) data |= 0x02; - if( wave.counter && wave.length) data |= 0x04; - if( noise.counter && noise.length) data |= 0x08; + if(square1.enable) data |= 0x01; + if(square2.enable) data |= 0x02; + if( wave.enable) data |= 0x04; + if( noise.enable) data |= 0x08; return data | table[addr - 0xff10]; } diff --git a/bsnes/gameboy/apu/master/master.cpp b/bsnes/gameboy/apu/master/master.cpp index 30d8f65f..02df2dc1 100755 --- a/bsnes/gameboy/apu/master/master.cpp +++ b/bsnes/gameboy/apu/master/master.cpp @@ -16,12 +16,6 @@ void APU::Master::run() { sample >>= 2; center = sclamp<16>(sample); - if(left_enable == false && right_enable == false) { - left = center; - right = center; - return; - } - sample = 0; channels = 0; if(channel1_left_enable) { sample += apu.square1.output; channels++; } @@ -41,7 +35,6 @@ void APU::Master::run() { case 6: left -= (left >> 3); break; // 87.5% //case 7: break; //100.0% } - if(left_enable == false) left = 0; sample = 0; channels = 0; @@ -62,18 +55,17 @@ void APU::Master::run() { case 6: right -= (right >> 3); break; // 87.5% //case 7: break; //100.0% } - if(right_enable == false) right = 0; } void APU::Master::write(unsigned r, uint8 data) { - if(r == 0) { - left_enable = data & 0x80; - left_volume = (data >> 4) & 7; - right_enable = data & 0x08; - right_volume = (data >> 0) & 7; + if(r == 0) { //$ff24 NR50 + left_in_enable = data & 0x80; + left_volume = (data >> 4) & 7; + right_in_enable = data & 0x08; + right_volume = (data >> 0) & 7; } - if(r == 1) { + if(r == 1) { //$ff25 NR51 channel4_left_enable = data & 0x80; channel3_left_enable = data & 0x40; channel2_left_enable = data & 0x20; @@ -84,15 +76,15 @@ void APU::Master::write(unsigned r, uint8 data) { channel1_right_enable = data & 0x01; } - if(r == 2) { + if(r == 2) { //$ff26 NR52 enable = data & 0x80; } } void APU::Master::power() { - left_enable = 0; + left_in_enable = 0; left_volume = 0; - right_enable = 0; + right_in_enable = 0; right_volume = 0; channel4_left_enable = 0; channel3_left_enable = 0; @@ -110,9 +102,9 @@ void APU::Master::power() { } void APU::Master::serialize(serializer &s) { - s.integer(left_enable); + s.integer(left_in_enable); s.integer(left_volume); - s.integer(right_enable); + s.integer(right_in_enable); s.integer(right_volume); s.integer(channel4_left_enable); s.integer(channel3_left_enable); diff --git a/bsnes/gameboy/apu/master/master.hpp b/bsnes/gameboy/apu/master/master.hpp index fb079891..a2785966 100755 --- a/bsnes/gameboy/apu/master/master.hpp +++ b/bsnes/gameboy/apu/master/master.hpp @@ -1,7 +1,7 @@ struct Master { - bool left_enable; + bool left_in_enable; unsigned left_volume; - bool right_enable; + bool right_in_enable; unsigned right_volume; bool channel4_left_enable; bool channel3_left_enable; diff --git a/bsnes/gameboy/apu/noise/noise.cpp b/bsnes/gameboy/apu/noise/noise.cpp index 45278322..4a0258e4 100755 --- a/bsnes/gameboy/apu/noise/noise.cpp +++ b/bsnes/gameboy/apu/noise/noise.cpp @@ -1,5 +1,9 @@ #ifdef APU_CPP +bool APU::Noise::dac_enable() { + return (envelope_volume || envelope_direction); +} + void APU::Noise::run() { if(period && --period == 0) { period = divisor << frequency; @@ -10,36 +14,39 @@ void APU::Noise::run() { } uint4 sample = (lfsr & 1) ? 0 : volume; - if(counter && length == 0) sample = 0; + if(enable == false) sample = 0; output = (sample * 4369) - 32768; } void APU::Noise::clock_length() { - if(counter && length) length--; + if(counter && length) { + if(--length == 0) enable = false; + } } void APU::Noise::clock_envelope() { if(envelope_period && --envelope_period == 0) { envelope_period = envelope_frequency; + if(envelope_period == 0) envelope_period = 8; if(envelope_direction == 0 && volume > 0) volume--; if(envelope_direction == 1 && volume < 15) volume++; } } void APU::Noise::write(unsigned r, uint8 data) { - if(r == 1) { - initial_length = 64 - (data & 0x3f); - length = initial_length; + if(r == 1) { //$ff20 NR41 + length = 64 - (data & 0x3f); } - if(r == 2) { + if(r == 2) { //$ff21 NR42 envelope_volume = data >> 4; envelope_direction = data & 0x08; envelope_frequency = data & 0x07; + if(dac_enable() == false) enable = false; } - if(r == 3) { + if(r == 3) { //$ff22 NR43 frequency = data >> 4; narrow_lfsr = data & 0x08; divisor = (data & 0x07) << 4; @@ -47,20 +54,23 @@ void APU::Noise::write(unsigned r, uint8 data) { period = divisor << frequency; } - if(r == 4) { + if(r == 4) { //$ff34 NR44 bool initialize = data & 0x80; counter = data & 0x40; if(initialize) { + enable = dac_enable(); lfsr = ~0U; - length = initial_length; envelope_period = envelope_frequency; volume = envelope_volume; + if(length == 0) length = 64; } } } void APU::Noise::power() { + enable = 0; + envelope_volume = 0; envelope_direction = 0; envelope_frequency = 0; @@ -70,7 +80,6 @@ void APU::Noise::power() { counter = 0; output = 0; - initial_length = 0; length = 0; envelope_period = 0; volume = 0; @@ -79,6 +88,8 @@ void APU::Noise::power() { } void APU::Noise::serialize(serializer &s) { + s.integer(enable); + s.integer(envelope_volume); s.integer(envelope_direction); s.integer(envelope_frequency); @@ -88,7 +99,6 @@ void APU::Noise::serialize(serializer &s) { s.integer(counter); s.integer(output); - s.integer(initial_length); s.integer(length); s.integer(envelope_period); s.integer(volume); diff --git a/bsnes/gameboy/apu/noise/noise.hpp b/bsnes/gameboy/apu/noise/noise.hpp index 19c4df38..199d380e 100755 --- a/bsnes/gameboy/apu/noise/noise.hpp +++ b/bsnes/gameboy/apu/noise/noise.hpp @@ -1,4 +1,6 @@ struct Noise { + bool enable; + unsigned envelope_volume; bool envelope_direction; unsigned envelope_frequency; @@ -8,13 +10,14 @@ struct Noise { bool counter; int16 output; - unsigned initial_length; unsigned length; unsigned envelope_period; unsigned volume; unsigned period; uint15 lfsr; + bool dac_enable(); + void run(); void clock_length(); void clock_envelope(); diff --git a/bsnes/gameboy/apu/square1/square1.cpp b/bsnes/gameboy/apu/square1/square1.cpp index a78ccf80..09afefd5 100755 --- a/bsnes/gameboy/apu/square1/square1.cpp +++ b/bsnes/gameboy/apu/square1/square1.cpp @@ -1,5 +1,9 @@ #ifdef APU_CPP +bool APU::Square1::dac_enable() { + return (envelope_volume || envelope_direction); +} + void APU::Square1::run() { if(period && --period == 0) { period = 4 * (2048 - frequency); @@ -13,86 +17,92 @@ void APU::Square1::run() { } uint4 sample = (duty_output ? volume : 0); - if(counter && length == 0) sample = 0; + if(enable == false) sample = 0; output = (sample * 4369) - 32768; } -void APU::Square1::sweep() { - if(enable == false) return; +void APU::Square1::sweep(bool update) { + if(sweep_enable == false) return; - signed offset = frequency_shadow >> sweep_shift; - if(sweep_direction) offset = -offset; - frequency_shadow += offset; + sweep_negate = sweep_direction; + unsigned delta = frequency_shadow >> sweep_shift; + signed freq = frequency_shadow + (sweep_negate ? -delta : delta); - if(frequency_shadow < 0) { - frequency_shadow = 0; - } else if(frequency_shadow > 2047) { - frequency_shadow = 2048; + if(freq > 2047) { enable = false; - } - - if(frequency_shadow <= 2047 && sweep_shift) { - frequency = frequency_shadow; + } else if(sweep_shift && update) { + frequency_shadow = freq; + frequency = freq & 2047; period = 4 * (2048 - frequency); } } void APU::Square1::clock_length() { - if(counter && length) length--; + if(counter && length) { + if(--length == 0) enable = false; + } } void APU::Square1::clock_sweep() { - if(sweep_frequency && sweep_period && --sweep_period == 0) { + if(enable && --sweep_period == 0) { sweep_period = sweep_frequency; - sweep(); + if(sweep_period == 0) sweep_period = 8; + if(sweep_frequency) { + sweep(1); + sweep(0); + } } } void APU::Square1::clock_envelope() { if(envelope_period && --envelope_period == 0) { envelope_period = envelope_frequency; + if(envelope_period == 0) envelope_period = 8; if(envelope_direction == 0 && volume > 0) volume--; if(envelope_direction == 1 && volume < 15) volume++; } } void APU::Square1::write(unsigned r, uint8 data) { - if(r == 0) { + if(r == 0) { //$ff10 NR10 + if(sweep_negate && sweep_direction && !(data & 0x08)) enable = false; sweep_frequency = (data >> 4) & 7; sweep_direction = data & 0x08; sweep_shift = data & 0x07; } - if(r == 1) { + if(r == 1) { //$ff11 NR11 duty = data >> 6; - initial_length = 64 - (data & 0x3f); - length = initial_length; + length = 64 - (data & 0x3f); } - if(r == 2) { + if(r == 2) { //$ff12 NR12 envelope_volume = data >> 4; envelope_direction = data & 0x08; envelope_frequency = data & 0x07; + if(dac_enable() == false) enable = false; } - if(r == 3) { + if(r == 3) { //$ff13 NR13 frequency = (frequency & 0x0700) | data; } - if(r == 4) { + if(r == 4) { //$ff14 NR14 bool initialize = data & 0x80; counter = data & 0x40; frequency = ((data & 7) << 8) | (frequency & 0x00ff); if(initialize) { - length = initial_length; + enable = dac_enable(); envelope_period = envelope_frequency; volume = envelope_volume; frequency_shadow = frequency; sweep_period = sweep_frequency; - enable = sweep_period || sweep_shift; - if(sweep_shift) sweep(); + sweep_enable = sweep_period || sweep_shift; + sweep_negate = false; + if(sweep_shift) sweep(0); + if(length == 0) length = 64; } } @@ -100,11 +110,13 @@ void APU::Square1::write(unsigned r, uint8 data) { } void APU::Square1::power() { + enable = 0; + sweep_frequency = 0; sweep_direction = 0; sweep_shift = 0; + sweep_negate = 0; duty = 0; - initial_length = 0; length = 0; envelope_volume = 0; envelope_direction = 0; @@ -119,16 +131,18 @@ void APU::Square1::power() { envelope_period = 0; sweep_period = 0; frequency_shadow = 0; - enable = 0; + sweep_enable = 0; volume = 0; } void APU::Square1::serialize(serializer &s) { + s.integer(enable); + s.integer(sweep_frequency); s.integer(sweep_direction); s.integer(sweep_shift); + s.integer(sweep_negate); s.integer(duty); - s.integer(initial_length); s.integer(length); s.integer(envelope_volume); s.integer(envelope_direction); @@ -143,7 +157,7 @@ void APU::Square1::serialize(serializer &s) { s.integer(envelope_period); s.integer(sweep_period); s.integer(frequency_shadow); - s.integer(enable); + s.integer(sweep_enable); s.integer(volume); } diff --git a/bsnes/gameboy/apu/square1/square1.hpp b/bsnes/gameboy/apu/square1/square1.hpp index 7f6513fa..36048fb8 100755 --- a/bsnes/gameboy/apu/square1/square1.hpp +++ b/bsnes/gameboy/apu/square1/square1.hpp @@ -1,9 +1,11 @@ struct Square1 { + bool enable; + unsigned sweep_frequency; unsigned sweep_direction; unsigned sweep_shift; + bool sweep_negate; unsigned duty; - unsigned initial_length; unsigned length; unsigned envelope_volume; unsigned envelope_direction; @@ -18,11 +20,13 @@ struct Square1 { unsigned envelope_period; unsigned sweep_period; signed frequency_shadow; - bool enable; + bool sweep_enable; unsigned volume; + bool dac_enable(); + void run(); - void sweep(); + void sweep(bool update); void clock_length(); void clock_sweep(); void clock_envelope(); diff --git a/bsnes/gameboy/apu/square2/square2.cpp b/bsnes/gameboy/apu/square2/square2.cpp index d005d97d..7e29e24a 100755 --- a/bsnes/gameboy/apu/square2/square2.cpp +++ b/bsnes/gameboy/apu/square2/square2.cpp @@ -1,5 +1,9 @@ #ifdef APU_CPP +bool APU::Square2::dac_enable() { + return (envelope_volume || envelope_direction); +} + void APU::Square2::run() { if(period && --period == 0) { period = 4 * (2048 - frequency); @@ -13,49 +17,53 @@ void APU::Square2::run() { } uint4 sample = (duty_output ? volume : 0); - if(counter && length == 0) sample = 0; + if(enable == false) sample = 0; output = (sample * 4369) - 32768; } void APU::Square2::clock_length() { - if(counter && length) length--; + if(counter && length) { + if(--length == 0) enable = false; + } } void APU::Square2::clock_envelope() { if(envelope_period && --envelope_period == 0) { envelope_period = envelope_frequency; + if(envelope_period == 0) envelope_period = 8; if(envelope_direction == 0 && volume > 0) volume--; if(envelope_direction == 1 && volume < 15) volume++; } } void APU::Square2::write(unsigned r, uint8 data) { - if(r == 1) { + if(r == 1) { //$ff16 NR21 duty = data >> 6; - initial_length = 64 - (data & 0x3f); - length = initial_length; + length = 64 - (data & 0x3f); } - if(r == 2) { + if(r == 2) { //$ff17 NR22 envelope_volume = data >> 4; envelope_direction = data & 0x08; envelope_frequency = data & 0x07; + if(dac_enable() == false) enable = false; } - if(r == 3) { + if(r == 3) { //$ff18 NR23 frequency = (frequency & 0x0700) | data; } - if(r == 4) { + if(r == 4) { //$ff19 NR24 bool initialize = data & 0x80; counter = data & 0x40; frequency = ((data & 7) << 8) | (frequency & 0x00ff); if(initialize) { - length = initial_length; + enable = dac_enable(); envelope_period = envelope_frequency; volume = envelope_volume; + if(length == 0) length = 64; } } @@ -63,8 +71,9 @@ void APU::Square2::write(unsigned r, uint8 data) { } void APU::Square2::power() { + enable = 0; + duty = 0; - initial_length = 0; length = 0; envelope_volume = 0; envelope_direction = 0; @@ -81,8 +90,9 @@ void APU::Square2::power() { } void APU::Square2::serialize(serializer &s) { + s.integer(enable); + s.integer(duty); - s.integer(initial_length); s.integer(length); s.integer(envelope_volume); s.integer(envelope_direction); diff --git a/bsnes/gameboy/apu/square2/square2.hpp b/bsnes/gameboy/apu/square2/square2.hpp index 8a67835d..f32ac5f9 100755 --- a/bsnes/gameboy/apu/square2/square2.hpp +++ b/bsnes/gameboy/apu/square2/square2.hpp @@ -1,6 +1,7 @@ struct Square2 { + bool enable; + unsigned duty; - unsigned initial_length; unsigned length; unsigned envelope_volume; unsigned envelope_direction; @@ -15,6 +16,8 @@ struct Square2 { unsigned envelope_period; unsigned volume; + bool dac_enable(); + void run(); void clock_length(); void clock_envelope(); diff --git a/bsnes/gameboy/apu/wave/wave.cpp b/bsnes/gameboy/apu/wave/wave.cpp index b4fedf06..65d6a9dd 100755 --- a/bsnes/gameboy/apu/wave/wave.cpp +++ b/bsnes/gameboy/apu/wave/wave.cpp @@ -8,7 +8,6 @@ void APU::Wave::run() { } uint4 sample = pattern_sample; - if(counter && length == 0) sample = 0; if(enable == false) sample = 0; output = (sample * 4369) - 32768; @@ -16,22 +15,22 @@ void APU::Wave::run() { } void APU::Wave::clock_length() { - if(counter && length) length--; + if(counter && length) { + if(--length == 0) enable = false; + } } void APU::Wave::write(unsigned r, uint8 data) { - if(r == 0) { + if(r == 0) { //$ff1a NR30 dac_enable = data & 0x80; - if(dac_enable == false) enable = false; } - if(r == 1) { - initial_length = 256 - data; - length = initial_length; + if(r == 1) { //$ff1b NR31 + length = 256 - data; } - if(r == 2) { + if(r == 2) { //$ff1c NR32 switch((data >> 5) & 3) { case 0: volume = 16; break; // 0% case 1: volume = 0; break; //100% @@ -40,19 +39,19 @@ void APU::Wave::write(unsigned r, uint8 data) { } } - if(r == 3) { + if(r == 3) { //$ff1d NR33 frequency = (frequency & 0x0700) | data; } - if(r == 4) { + if(r == 4) { //$ff1e NR34 bool initialize = data & 0x80; counter = data & 0x40; frequency = ((data & 7) << 8) | (frequency & 0x00ff); - if(initialize && dac_enable) { - enable = true; + if(initialize) { + enable = dac_enable; pattern_offset = 0; - length = initial_length; + if(length == 0) length = 256; } } @@ -66,6 +65,8 @@ void APU::Wave::write_pattern(unsigned p, uint8 data) { } void APU::Wave::power() { + enable = 0; + dac_enable = 0; volume = 0; frequency = 0; @@ -75,8 +76,6 @@ void APU::Wave::power() { foreach(n, pattern) n = r() & 15; output = 0; - enable = 0; - initial_length = 0; length = 0; period = 0; pattern_offset = 0; @@ -84,6 +83,8 @@ void APU::Wave::power() { } void APU::Wave::serialize(serializer &s) { + s.integer(enable); + s.integer(dac_enable); s.integer(volume); s.integer(frequency); @@ -91,8 +92,6 @@ void APU::Wave::serialize(serializer &s) { s.array(pattern); s.integer(output); - s.integer(enable); - s.integer(initial_length); s.integer(length); s.integer(period); s.integer(pattern_offset); diff --git a/bsnes/gameboy/apu/wave/wave.hpp b/bsnes/gameboy/apu/wave/wave.hpp index bbfb7ee2..20b24441 100755 --- a/bsnes/gameboy/apu/wave/wave.hpp +++ b/bsnes/gameboy/apu/wave/wave.hpp @@ -1,4 +1,6 @@ struct Wave { + bool enable; + bool dac_enable; unsigned volume; unsigned frequency; @@ -6,8 +8,6 @@ struct Wave { uint8 pattern[32]; int16 output; - bool enable; - unsigned initial_length; unsigned length; unsigned period; unsigned pattern_offset; diff --git a/bsnes/gameboy/gameboy.hpp b/bsnes/gameboy/gameboy.hpp index 6981796d..b96d7fc9 100755 --- a/bsnes/gameboy/gameboy.hpp +++ b/bsnes/gameboy/gameboy.hpp @@ -5,7 +5,7 @@ namespace GameBoy { namespace Info { static const char Name[] = "bgameboy"; - static const char Version[] = "000.21"; + static const char Version[] = "000.22"; static unsigned SerializerVersion = 2; } } diff --git a/bsnes/nall/png.hpp b/bsnes/nall/png.hpp index ba6f05f8..025044b2 100755 --- a/bsnes/nall/png.hpp +++ b/bsnes/nall/png.hpp @@ -46,9 +46,9 @@ protected: IEND = 0x49454e44, }; - static const unsigned interlace[7][4]; unsigned bitpos; + inline unsigned interlace(unsigned pass, unsigned index); inline unsigned inflateSize(); inline bool deinterlace(const uint8_t *&inputData, unsigned pass); inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height); @@ -172,16 +172,19 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) { return true; } -const unsigned png::interlace[7][4] = { - //x-distance, y-distance, x-origin, y-origin - { 8, 8, 0, 0 }, - { 8, 8, 4, 0 }, - { 4, 8, 0, 4 }, - { 4, 4, 2, 0 }, - { 2, 4, 0, 2 }, - { 2, 2, 1, 0 }, - { 1, 2, 0, 1 }, -}; +unsigned png::interlace(unsigned pass, unsigned index) { + static const unsigned data[7][4] = { + //x-distance, y-distance, x-origin, y-origin + { 8, 8, 0, 0 }, + { 8, 8, 4, 0 }, + { 4, 8, 0, 4 }, + { 4, 4, 2, 0 }, + { 2, 4, 0, 2 }, + { 2, 2, 1, 0 }, + { 1, 2, 0, 1 }, + }; + return data[pass][index]; +} unsigned png::inflateSize() { if(info.interlaceMethod == 0) { @@ -190,8 +193,8 @@ unsigned png::inflateSize() { unsigned size = 0; for(unsigned pass = 0; pass < 7; pass++) { - unsigned xd = interlace[pass][0], yd = interlace[pass][1]; - unsigned xo = interlace[pass][2], yo = interlace[pass][3]; + unsigned xd = interlace(pass, 0), yd = interlace(pass, 1); + unsigned xo = interlace(pass, 2), yo = interlace(pass, 3); unsigned width = (info.width + (xd - xo - 1)) / xd; unsigned height = (info.height + (yd - yo - 1)) / yd; if(width == 0 || height == 0) continue; @@ -201,8 +204,8 @@ unsigned png::inflateSize() { } bool png::deinterlace(const uint8_t *&inputData, unsigned pass) { - unsigned xd = interlace[pass][0], yd = interlace[pass][1]; - unsigned xo = interlace[pass][2], yo = interlace[pass][3]; + unsigned xd = interlace(pass, 0), yd = interlace(pass, 1); + unsigned xo = interlace(pass, 2), yo = interlace(pass, 3); unsigned width = (info.width + (xd - xo - 1)) / xd; unsigned height = (info.height + (yd - yo - 1)) / yd; if(width == 0 || height == 0) return true; diff --git a/bsnes/nall/reference_array.hpp b/bsnes/nall/reference_array.hpp index ac47c32b..77d06d86 100755 --- a/bsnes/nall/reference_array.hpp +++ b/bsnes/nall/reference_array.hpp @@ -36,10 +36,26 @@ namespace nall { buffersize = newsize; } - void append(const T data) { + bool append(const T data) { + for(unsigned index = 0; index < buffersize; index++) { + if(pool[index] == &data) return false; + } + unsigned index = buffersize++; if(index >= poolsize) resize(index + 1); pool[index] = &data; + return true; + } + + bool remove(const T data) { + for(unsigned index = 0; index < buffersize; index++) { + if(pool[index] == &data) { + for(unsigned i = index; i < buffersize - 1; i++) pool[i] = pool[i + 1]; + resize(buffersize - 1); + return true; + } + } + return false; } template reference_array(Args&... args) : pool(0), poolsize(0), buffersize(0) { diff --git a/bsnes/phoenix/core/core.cpp b/bsnes/phoenix/core/core.cpp index 39512f4f..4cdee332 100755 --- a/bsnes/phoenix/core/core.cpp +++ b/bsnes/phoenix/core/core.cpp @@ -4,192 +4,1130 @@ #include "layout/vertical-layout.cpp" #if defined(PHOENIX_WINDOWS) - #include "../windows/windows.cpp" + #include "../windows/platform.cpp" #elif defined(PHOENIX_QT) - #include "../qt/qt.cpp" + #include "../qt/platform.cpp" #elif defined(PHOENIX_GTK) - #include "../gtk/gtk.cpp" + #include "../gtk/platform.cpp" #elif defined(PHOENIX_REFERENCE) - #include "../reference/reference.cpp" + #include "../reference/platform.cpp" #endif -Object::Object() { OS::initialize(); } - -Geometry OS::availableGeometry() { return pOS::availableGeometry(); } -Geometry OS::desktopGeometry() { return pOS::desktopGeometry(); } -string OS::fileLoad_(Window &parent, const string &path, const lstring &filter_) { auto filter = filter_; if(filter.size() == 0) filter.append("All files (*)"); return pOS::fileLoad(parent, path, filter); } -string OS::fileSave_(Window &parent, const string &path, const lstring &filter_) { auto filter = filter_; if(filter.size() == 0) filter.append("All files (*)"); return pOS::fileSave(parent, path, filter); } -string OS::folderSelect(Window &parent, const string &path) { return pOS::folderSelect(parent, path); } -void OS::main() { return pOS::main(); } -bool OS::pendingEvents() { return pOS::pendingEvents(); } -void OS::processEvents() { return pOS::processEvents(); } -void OS::quit() { return pOS::quit(); } -void OS::initialize() { static bool initialized = false; if(initialized == false) { initialized = true; return pOS::initialize(); } } - -Geometry Font::geometry(const string &text) { return p.geometry(text); } -void Font::setBold(bool bold) { state.bold = bold; return p.setBold(bold); } -void Font::setFamily(const string &family) { state.family = family; return p.setFamily(family); } -void Font::setItalic(bool italic) { state.italic = italic; return p.setItalic(italic); } -void Font::setSize(unsigned size) { state.size = size; return p.setSize(size); } -void Font::setUnderline(bool underline) { state.underline = underline; return p.setUnderline(underline); } -Font::Font() : state(*new State), p(*new pFont(*this)) { p.constructor(); } - -void Timer::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); } -void Timer::setInterval(unsigned milliseconds) { state.milliseconds = milliseconds; return p.setInterval(milliseconds); } -Timer::Timer() : state(*new State), p(*new pTimer(*this)) { p.constructor(); } - -MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::information(parent, text, buttons); } -MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::question(parent, text, buttons); } -MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::warning(parent, text, buttons); } -MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { return pMessageWindow::critical(parent, text, buttons); } - Window Window::None; -void Window::append(Layout &layout) { state.layout.append(layout); return p.append(layout); } -void Window::append(Menu &menu) { state.menu.append(menu); ((Action&)menu).state.parent = this; return p.append(menu); } -void Window::append(Widget &widget) { state.widget.append(widget); return p.append(widget); } -Color Window::backgroundColor() { return p.backgroundColor(); } -Geometry Window::frameGeometry() { Geometry geometry = p.geometry(), margin = p.frameMargin(); return { geometry.x - margin.x, geometry.y - margin.y, geometry.width + margin.width, geometry.height + margin.height }; } -Geometry Window::frameMargin() { return p.frameMargin(); } -bool Window::focused() { return p.focused(); } -Geometry Window::geometry() { return p.geometry(); } -void Window::setBackgroundColor(const Color &color) { state.backgroundColorOverride = true; state.backgroundColor = color; return p.setBackgroundColor(color); } -void Window::setFrameGeometry(const Geometry &geometry) { Geometry margin = p.frameMargin(); return setGeometry({ geometry.x + margin.x, geometry.y + margin.y, geometry.width - margin.width, geometry.height - margin.height }); } -void Window::setFocused() { return p.setFocused(); } -void Window::setFullScreen(bool fullScreen) { state.fullScreen = fullScreen; return p.setFullScreen(fullScreen); } -void Window::setGeometry(const Geometry &geometry) { state.geometry = geometry; return p.setGeometry(geometry); } -void Window::setMenuFont(Font &font) { state.menuFont = &font; return p.setMenuFont(font); } -void Window::setMenuVisible(bool visible) { state.menuVisible = visible; return p.setMenuVisible(visible); } -void Window::setResizable(bool resizable) { state.resizable = resizable; return p.setResizable(resizable); } -void Window::setStatusFont(Font &font) { state.statusFont = &font; return p.setStatusFont(font); } -void Window::setStatusText(const string &text) { state.statusText = text; return p.setStatusText(text); } -void Window::setStatusVisible(bool visible) { state.statusVisible = visible; return p.setStatusVisible(visible); } -void Window::setTitle(const string &text) { state.title = text; return p.setTitle(text); } -void Window::setVisible(bool visible) { state.visible = visible; return p.setVisible(visible); } -void Window::setWidgetFont(Font &font) { state.widgetFont = &font; return p.setWidgetFont(font); } -Window::Window() : state(*new State), p(*new pWindow(*this)) { p.constructor(); } -void Action::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); } -void Action::setVisible(bool visible) { state.visible = visible; return p.setVisible(visible); } -Action::Action(pAction &p) : state(*new State), p(p) { p.constructor(); } +//Font +//==== -void Menu::append(Action &action) { state.action.append(action); return p.append(action); } -void Menu::setText(const string &text) { state.text = text; return p.setText(text); } -Menu::Menu() : state(*new State), base_from_member(*new pMenu(*this)), Action(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Geometry Font::geometry(const string &text) { + return pFont::geometry(description, text); +} -Separator::Separator() : base_from_member(*new pSeparator(*this)), Action(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Font::Font(const string &description): +description(description) { +} -void Item::setText(const string &text) { state.text = text; return p.setText(text); } -Item::Item() : state(*new State), base_from_member(*new pItem(*this)), Action(base_from_member::value), p(base_from_member::value) { p.constructor(); } +//Object +//====== -bool CheckItem::checked() { return p.checked(); } -void CheckItem::setChecked(bool checked) { state.checked = checked; return p.setChecked(checked); } -void CheckItem::setText(const string &text) { state.text = text; return p.setText(text); } -CheckItem::CheckItem() : state(*new State), base_from_member(*new pCheckItem(*this)), Action(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Object::Object(pObject &p): +p(p) { + OS::initialize(); + p.constructor(); +} -void RadioItem::group(const reference_array &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); } -bool RadioItem::checked() { return p.checked(); } -void RadioItem::setChecked() { foreach(item, state.group) item.state.checked = false; state.checked = true; return p.setChecked(); } -void RadioItem::setText(const string &text) { state.text = text; return p.setText(text); } -RadioItem::RadioItem() : state(*new State), base_from_member(*new pRadioItem(*this)), Action(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Object::~Object() { + p.destructor(); + delete &p; +} -bool Widget::enabled() { return state.enabled; } -Font& Widget::font() { return p.font(); } -Geometry Widget::geometry() { return state.geometry; } -Geometry Widget::minimumGeometry() { return p.minimumGeometry(); } -void Widget::setEnabled(bool enabled) { state.enabled = enabled; return p.setEnabled(enabled); } -void Widget::setFocused() { return p.setFocused(); } -void Widget::setFont(Font &font) { state.font = &font; return p.setFont(font); } -void Widget::setGeometry(const Geometry &geometry) { state.geometry = geometry; return p.setGeometry(geometry); } -void Widget::setLayout(Layout &layout) { state.layout = &layout; } -void Widget::setParent(Window &parent) { state.parent = &parent; return p.setParent(parent); } -void Widget::setVisible(bool visible) { state.visible = visible; return p.setVisible(visible); } -bool Widget::visible() { return state.visible; } -Widget::Widget() : state(*new State), p(*new pWidget(*this)) { state.abstract = true; p.constructor(); } -Widget::Widget(pWidget &p) : state(*new State), p(p) { p.constructor(); } +//OS +//== -void Button::setText(const string &text) { state.text = text; return p.setText(text); } -Button::Button() : state(*new State), base_from_member(*new pButton(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Geometry OS::availableGeometry() { + return pOS::availableGeometry(); +} -uint32_t* Canvas::buffer() { return p.buffer(); } -void Canvas::update() { return p.update(); } -Canvas::Canvas() : base_from_member(*new pCanvas(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Geometry OS::desktopGeometry() { + return pOS::desktopGeometry(); +} -bool CheckBox::checked() { return p.checked(); } -void CheckBox::setChecked(bool checked) { state.checked = checked; return p.setChecked(checked); } -void CheckBox::setText(const string &text) { state.text = text; return p.setText(text); } -CheckBox::CheckBox() : state(*new State), base_from_member(*new pCheckBox(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +string OS::fileLoad_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pOS::fileLoad(parent, path, filter); +} -void ComboBox::append(const string &text) { state.text.append(text); return p.append(text); } -void ComboBox::reset() { state.selection = 0; state.text.reset(); return p.reset(); } -unsigned ComboBox::selection() { return p.selection(); } -void ComboBox::setSelection(unsigned row) { state.selection = row; return p.setSelection(row); } -ComboBox::ComboBox() : state(*new State), base_from_member(*new pComboBox(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +string OS::fileSave_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pOS::fileSave(parent, path, filter); +} -void HexEdit::setColumns(unsigned columns) { state.columns = columns; return p.setColumns(columns); } -void HexEdit::setLength(unsigned length) { state.length = length; return p.setLength(length); } -void HexEdit::setOffset(unsigned offset) { state.offset = offset; return p.setOffset(offset); } -void HexEdit::setRows(unsigned rows) { state.rows = rows; return p.setRows(rows); } -void HexEdit::update() { return p.update(); } -HexEdit::HexEdit() : state(*new State), base_from_member(*new pHexEdit(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +string OS::folderSelect(Window &parent, const string &path) { + return pOS::folderSelect(parent, path); +} -unsigned HorizontalScrollBar::position() { return p.position(); } -void HorizontalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); } -void HorizontalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); } -HorizontalScrollBar::HorizontalScrollBar() : state(*new State), base_from_member(*new pHorizontalScrollBar(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +void OS::main() { + return pOS::main(); +} -unsigned HorizontalSlider::position() { return p.position(); } -void HorizontalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); } -void HorizontalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); } -HorizontalSlider::HorizontalSlider() : state(*new State), base_from_member(*new pHorizontalSlider(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +bool OS::pendingEvents() { + return pOS::pendingEvents(); +} -void Label::setText(const string &text) { state.text = text; return p.setText(text); } -Label::Label() : state(*new State), base_from_member(*new pLabel(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +void OS::processEvents() { + return pOS::processEvents(); +} -void LineEdit::setEditable(bool editable) { state.editable = editable; return p.setEditable(editable); } -void LineEdit::setText(const string &text) { state.text = text; return p.setText(text); } -string LineEdit::text() { return p.text(); } -LineEdit::LineEdit() : state(*new State), base_from_member(*new pLineEdit(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +void OS::quit() { + return pOS::quit(); +} -void ListView::append_(const lstring &text) { state.checked.append(false); state.text.append(text); return p.append(text); } -void ListView::autoSizeColumns() { return p.autoSizeColumns(); } -bool ListView::checked(unsigned row) { return p.checked(row); } -void ListView::modify_(unsigned row, const lstring &text) { state.text[row] = text; return p.modify(row, text); } -void ListView::reset() { state.checked.reset(); state.text.reset(); return p.reset(); } -bool ListView::selected() { return p.selected(); } -unsigned ListView::selection() { return p.selection(); } -void ListView::setCheckable(bool checkable) { state.checkable = checkable; return p.setCheckable(checkable); } -void ListView::setChecked(unsigned row, bool checked) { state.checked[row] = checked; return p.setChecked(row, checked); } -void ListView::setHeaderText_(const lstring &text) { state.headerText = text; return p.setHeaderText(text); } -void ListView::setHeaderVisible(bool visible) { state.headerVisible = visible; return p.setHeaderVisible(visible); } -void ListView::setSelected(bool selected) { state.selected = selected; return p.setSelected(selected); } -void ListView::setSelection(unsigned row) { state.selected = true; state.selection = row; return p.setSelection(row); } -ListView::ListView() : state(*new State), base_from_member(*new pListView(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +void OS::initialize() { + static bool initialized = false; + if(initialized == false) { + initialized = true; + return pOS::initialize(); + } +} -void ProgressBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); } -ProgressBar::ProgressBar() : state(*new State), base_from_member(*new pProgressBar(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +//Timer +//===== -void RadioBox::group(const reference_array &list) { foreach(item, list) item.p.setGroup(item.state.group = list); if(list.size()) list[0].setChecked(); } -bool RadioBox::checked() { return p.checked(); } -void RadioBox::setChecked() { foreach(item, state.group) item.state.checked = false; state.checked = true; return p.setChecked(); } -void RadioBox::setText(const string &text) { state.text = text; return p.setText(text); } -RadioBox::RadioBox() : state(*new State), base_from_member(*new pRadioBox(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +void Timer::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} -void TextEdit::setCursorPosition(unsigned position) { state.cursorPosition = position; return p.setCursorPosition(position); } -void TextEdit::setEditable(bool editable) { state.editable = editable; return p.setEditable(editable); } -void TextEdit::setText(const string &text) { state.text = text; return p.setText(text); } -void TextEdit::setWordWrap(bool wordWrap) { state.wordWrap = wordWrap; return p.setWordWrap(wordWrap); } -string TextEdit::text() { return p.text(); } -TextEdit::TextEdit() : state(*new State), base_from_member(*new pTextEdit(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +void Timer::setInterval(unsigned milliseconds) { + state.milliseconds = milliseconds; + return p.setInterval(milliseconds); +} -unsigned VerticalScrollBar::position() { return p.position(); } -void VerticalScrollBar::setLength(unsigned length) { state.length = length; return p.setLength(length); } -void VerticalScrollBar::setPosition(unsigned position) { state.position = position; return p.setPosition(position); } -VerticalScrollBar::VerticalScrollBar() : state(*new State), base_from_member(*new pVerticalScrollBar(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Timer::Timer(): +state(*new State), +base_from_member(*new pTimer(*this)), +Object(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} -unsigned VerticalSlider::position() { return p.position(); } -void VerticalSlider::setLength(unsigned length) { state.length = length; return p.setLength(length); } -void VerticalSlider::setPosition(unsigned position) { state.position = position; return p.setPosition(position); } -VerticalSlider::VerticalSlider() : state(*new State), base_from_member(*new pVerticalSlider(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +Timer::~Timer() { + p.destructor(); + delete &state; +} -uintptr_t Viewport::handle() { return p.handle(); } -Viewport::Viewport() : base_from_member(*new pViewport(*this)), Widget(base_from_member::value), p(base_from_member::value) { p.constructor(); } +//MessageWindow +//============= + +MessageWindow::Response MessageWindow::information(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::information(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::question(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::question(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::warning(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::warning(parent, text, buttons); +} + +MessageWindow::Response MessageWindow::critical(Window &parent, const string &text, MessageWindow::Buttons buttons) { + return pMessageWindow::critical(parent, text, buttons); +} + +//Window +//====== + +void Window::append(Layout &layout) { + if(state.layout.append(layout)) { + ((Sizable&)layout).state.window = this; + ((Sizable&)layout).state.layout = 0; + p.append(layout); + layout.synchronize(); + } +} + +void Window::append(Menu &menu) { + if(state.menu.append(menu)) { + ((Action&)menu).state.window = this; + p.append(menu); + } +} + +void Window::append(Widget &widget) { + if(state.widget.append(widget)) { + ((Sizable&)widget).state.window = this; + p.append(widget); + synchronize(); + } +} + +Color Window::backgroundColor() { + return p.backgroundColor(); +} + +Geometry Window::frameGeometry() { + Geometry geometry = p.geometry(); + Geometry margin = p.frameMargin(); + return { + geometry.x - margin.x, geometry.y - margin.y, + geometry.width + margin.width, geometry.height + margin.height + }; +} + +Geometry Window::frameMargin() { + return p.frameMargin(); +} + +bool Window::focused() { + return p.focused(); +} + +Geometry Window::geometry() { + return p.geometry(); +} + +void Window::ignore() { + state.ignore = true; +} + +void Window::remove(Layout &layout) { + if(state.layout.remove(layout)) { + p.remove(layout); + ((Sizable&)layout).state.window = 0; + } +} + +void Window::remove(Menu &menu) { + if(state.menu.remove(menu)) { + p.remove(menu); + ((Action&)menu).state.window = 0; + } +} + +void Window::remove(Widget &widget) { + if(state.widget.remove(widget)) { + p.remove(widget); + ((Sizable&)widget).state.window = 0; + } +} + +void Window::setBackgroundColor(const Color &color) { + state.backgroundColorOverride = true; + state.backgroundColor = color; + return p.setBackgroundColor(color); +} + +void Window::setFrameGeometry(const Geometry &geometry) { + Geometry margin = p.frameMargin(); + return setGeometry({ + geometry.x + margin.x, geometry.y + margin.y, + geometry.width - margin.width, geometry.height - margin.height + }); +} + +void Window::setFocused() { + return p.setFocused(); +} + +void Window::setFullScreen(bool fullScreen) { + state.fullScreen = fullScreen; + return p.setFullScreen(fullScreen); +} + +void Window::setGeometry(const Geometry &geometry) { + state.geometry = geometry; + return p.setGeometry(geometry); +} + +void Window::setMenuFont(const string &font) { + state.menuFont = font; + return p.setMenuFont(font); +} + +void Window::setMenuVisible(bool visible) { + state.menuVisible = visible; + return p.setMenuVisible(visible); +} + +void Window::setResizable(bool resizable) { + state.resizable = resizable; + return p.setResizable(resizable); +} + +void Window::setStatusFont(const string &font) { + state.statusFont = font; + return p.setStatusFont(font); +} + +void Window::setStatusText(const string &text) { + state.statusText = text; + return p.setStatusText(text); +} + +void Window::setStatusVisible(bool visible) { + state.statusVisible = visible; + return p.setStatusVisible(visible); +} + +void Window::setTitle(const string &text) { + state.title = text; + return p.setTitle(text); +} + +void Window::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +void Window::setWidgetFont(const string &font) { + state.widgetFont = font; + return p.setWidgetFont(font); +} + +void Window::synchronize() { + setGeometry(geometry()); +} + +Window::Window(): +state(*new State), +base_from_member(*new pWindow(*this)), +Object(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Window::~Window() { + p.destructor(); + delete &state; +} + +//Action +//====== + +void Action::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Action::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +Action::Action(pAction &p): +state(*new State), +Object(p), +p(p) { + p.constructor(); +} + +Action::~Action() { + p.destructor(); + delete &state; +} + +//Menu +//==== + +void Menu::append(Action &action) { + if(state.action.append(action)) { + action.state.menu = this; + return p.append(action); + } +} + +void Menu::remove(Action &action) { + if(state.action.remove(action)) { + action.state.menu = 0; + return p.remove(action); + } +} + +void Menu::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Menu::Menu(): +state(*new State), +base_from_member(*new pMenu(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Menu::~Menu() { + p.destructor(); + delete &state; +} + +//Separator +//========= + +Separator::Separator(): +base_from_member(*new pSeparator(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Separator::~Separator() { + p.destructor(); +} + +//Item +//==== + +void Item::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Item::Item(): +state(*new State), +base_from_member(*new pItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Item::~Item() { + p.destructor(); + delete &state; +} + +//CheckItem +//========= + +bool CheckItem::checked() { + return p.checked(); +} + +void CheckItem::setChecked(bool checked) { + state.checked = checked; + return p.setChecked(checked); +} + +void CheckItem::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +CheckItem::CheckItem(): +state(*new State), +base_from_member(*new pCheckItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +CheckItem::~CheckItem() { + p.destructor(); + delete &state; +} + +//RadioItem +//========= + +void RadioItem::group(const reference_array &list) { + foreach(item, list) item.p.setGroup(item.state.group = list); + if(list.size()) list[0].setChecked(); +} + +bool RadioItem::checked() { + return p.checked(); +} + +void RadioItem::setChecked() { + foreach(item, state.group) item.state.checked = false; + state.checked = true; + return p.setChecked(); +} + +void RadioItem::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +RadioItem::RadioItem(): +state(*new State), +base_from_member(*new pRadioItem(*this)), +Action(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +RadioItem::~RadioItem() { + foreach(item, state.group) { + if(&item != this) item.state.group.remove(*this); + } + p.destructor(); + delete &state; +} + +//Sizable +//======= + +Layout* Sizable::layout() { + return state.layout; +} + +Window* Sizable::window() { + if(state.layout) return state.layout->window(); + return state.window; +} + +Sizable::Sizable(pSizable &p): +state(*new State), +Object(p), +p(p) { + p.constructor(); +} + +Sizable::~Sizable() { + if(layout()) layout()->remove(*this); + p.destructor(); + delete &state; +} + +//Layout +//====== + +void Layout::append(Sizable &sizable) { + sizable.state.layout = this; + sizable.state.window = 0; + + if(dynamic_cast(&sizable)) { + Layout &layout = (Layout&)sizable; + layout.synchronize(); + } + + if(dynamic_cast(&sizable)) { + Widget &widget = (Widget&)sizable; + if(sizable.window()) sizable.window()->append(widget); + } + + if(window()) window()->synchronize(); +} + +void Layout::remove(Sizable &sizable) { + if(dynamic_cast(&sizable)) { + Widget &widget = (Widget&)sizable; + if(sizable.window()) sizable.window()->remove(widget); + } + + sizable.state.layout = 0; + sizable.state.window = 0; + + if(window()) window()->synchronize(); +} + +Layout::Layout(): +state(*new State), +base_from_member(*new pLayout(*this)), +Sizable(base_from_member::value), +p(base_from_member::value) { +} + +Layout::Layout(pLayout &p): +state(*new State), +base_from_member(p), +Sizable(p), +p(p) { +} + +Layout::~Layout() { + if(layout()) layout()->remove(*this); + else if(window()) window()->remove(*this); + p.destructor(); + delete &state; +} + +//Widget +//====== + +bool Widget::enabled() { + return state.enabled; +} + +string Widget::font() { + return state.font; +} + +Geometry Widget::geometry() { + return state.geometry; +} + +Geometry Widget::minimumGeometry() { + return p.minimumGeometry(); +} + +void Widget::setEnabled(bool enabled) { + state.enabled = enabled; + return p.setEnabled(enabled); +} + +void Widget::setFocused() { + return p.setFocused(); +} + +void Widget::setFont(const string &font) { + state.font = font; + return p.setFont(font); +} + +void Widget::setGeometry(const Geometry &geometry) { + state.geometry = geometry; + return p.setGeometry(geometry); +} + +void Widget::setVisible(bool visible) { + state.visible = visible; + return p.setVisible(visible); +} + +bool Widget::visible() { + return state.visible; +} + +Widget::Widget(): +state(*new State), +base_from_member(*new pWidget(*this)), +Sizable(base_from_member::value), +p(base_from_member::value) { + state.abstract = true; + p.constructor(); +} + +Widget::Widget(pWidget &p): +state(*new State), +base_from_member(p), +Sizable(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Widget::~Widget() { + p.destructor(); + delete &state; +} + +//Button +//====== + +void Button::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Button::Button(): +state(*new State), +base_from_member(*new pButton(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Button::~Button() { + p.destructor(); + delete &state; +} + +//Canvas +//====== + +uint32_t* Canvas::buffer() { + return p.buffer(); +} + +void Canvas::update() { + return p.update(); +} + +Canvas::Canvas(): +base_from_member(*new pCanvas(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Canvas::~Canvas() { + p.destructor(); +} + +//CheckBox +//======== + +bool CheckBox::checked() { + return p.checked(); +} + +void CheckBox::setChecked(bool checked) { + state.checked = checked; + return p.setChecked(checked); +} + +void CheckBox::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +CheckBox::CheckBox(): +state(*new State), +base_from_member(*new pCheckBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +CheckBox::~CheckBox() { + p.destructor(); + delete &state; +} + +//ComboBox +//======== + +void ComboBox::append(const string &text) { + state.text.append(text); + return p.append(text); +} + +void ComboBox::reset() { + state.selection = 0; + state.text.reset(); + return p.reset(); +} + +unsigned ComboBox::selection() { + return p.selection(); +} + +void ComboBox::setSelection(unsigned row) { + state.selection = row; + return p.setSelection(row); +} + +ComboBox::ComboBox(): +state(*new State), +base_from_member(*new pComboBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ComboBox::~ComboBox() { + p.destructor(); + delete &state; +} + +//HexEdit +//======= + +void HexEdit::setColumns(unsigned columns) { + state.columns = columns; + return p.setColumns(columns); +} + +void HexEdit::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HexEdit::setOffset(unsigned offset) { + state.offset = offset; + return p.setOffset(offset); +} + +void HexEdit::setRows(unsigned rows) { + state.rows = rows; + return p.setRows(rows); +} + +void HexEdit::update() { + return p.update(); +} + +HexEdit::HexEdit(): +state(*new State), +base_from_member(*new pHexEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HexEdit::~HexEdit() { + p.destructor(); + delete &state; +} + +//HorizontalScrollBar +//=================== + +unsigned HorizontalScrollBar::position() { + return p.position(); +} + +void HorizontalScrollBar::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HorizontalScrollBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +HorizontalScrollBar::HorizontalScrollBar(): +state(*new State), +base_from_member(*new pHorizontalScrollBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HorizontalScrollBar::~HorizontalScrollBar() { + p.destructor(); + delete &state; +} + +//HorizontalSlider +//================ + +unsigned HorizontalSlider::position() { + return p.position(); +} + +void HorizontalSlider::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void HorizontalSlider::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +HorizontalSlider::HorizontalSlider(): +state(*new State), +base_from_member(*new pHorizontalSlider(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +HorizontalSlider::~HorizontalSlider() { + p.destructor(); + delete &state; +} + +//Label +//===== + +void Label::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +Label::Label(): +state(*new State), +base_from_member(*new pLabel(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Label::~Label() { + p.destructor(); + delete &state; +} + +//LineEdit +//======== + +void LineEdit::setEditable(bool editable) { + state.editable = editable; + return p.setEditable(editable); +} + +void LineEdit::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +string LineEdit::text() { + return p.text(); +} + +LineEdit::LineEdit(): +state(*new State), +base_from_member(*new pLineEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +LineEdit::~LineEdit() { + p.destructor(); + delete &state; +} + +//ListView +//======== + +void ListView::append_(const lstring &text) { + state.checked.append(false); + state.text.append(text); + return p.append(text); +} + +void ListView::autoSizeColumns() { + return p.autoSizeColumns(); +} + +bool ListView::checked(unsigned row) { + return p.checked(row); +} + +void ListView::modify_(unsigned row, const lstring &text) { + state.text[row] = text; + return p.modify(row, text); +} + +void ListView::reset() { + state.checked.reset(); + state.text.reset(); + return p.reset(); +} + +bool ListView::selected() { + return p.selected(); +} + +unsigned ListView::selection() { + return p.selection(); +} + +void ListView::setCheckable(bool checkable) { + state.checkable = checkable; + return p.setCheckable(checkable); +} + +void ListView::setChecked(unsigned row, bool checked) { + state.checked[row] = checked; + return p.setChecked(row, checked); +} + +void ListView::setHeaderText_(const lstring &text) { + state.headerText = text; + return p.setHeaderText(text); +} + +void ListView::setHeaderVisible(bool visible) { + state.headerVisible = visible; + return p.setHeaderVisible(visible); +} + +void ListView::setSelected(bool selected) { + state.selected = selected; + return p.setSelected(selected); +} + +void ListView::setSelection(unsigned row) { + state.selected = true; + state.selection = row; + return p.setSelection(row); +} + +ListView::ListView(): +state(*new State), +base_from_member(*new pListView(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ListView::~ListView() { + p.destructor(); + delete &state; +} + +//ProgressBar +//=========== + +void ProgressBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +ProgressBar::ProgressBar(): +state(*new State), +base_from_member(*new pProgressBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +ProgressBar::~ProgressBar() { + p.destructor(); + delete &state; +} + +//RadioBox +//======== + +void RadioBox::group(const reference_array &list) { + foreach(item, list) item.p.setGroup(item.state.group = list); + if(list.size()) list[0].setChecked(); +} + +bool RadioBox::checked() { + return p.checked(); +} + +void RadioBox::setChecked() { + foreach(item, state.group) item.state.checked = false; + state.checked = true; + return p.setChecked(); +} + +void RadioBox::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +RadioBox::RadioBox(): +state(*new State), +base_from_member(*new pRadioBox(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +RadioBox::~RadioBox() { + foreach(item, state.group) { + if(&item != this) item.state.group.remove(*this); + } + p.destructor(); + delete &state; +} + +//TextEdit +//======== + +void TextEdit::setCursorPosition(unsigned position) { + state.cursorPosition = position; + return p.setCursorPosition(position); +} + +void TextEdit::setEditable(bool editable) { + state.editable = editable; + return p.setEditable(editable); +} + +void TextEdit::setText(const string &text) { + state.text = text; + return p.setText(text); +} + +void TextEdit::setWordWrap(bool wordWrap) { + state.wordWrap = wordWrap; + return p.setWordWrap(wordWrap); +} + +string TextEdit::text() { + return p.text(); +} + +TextEdit::TextEdit(): +state(*new State), +base_from_member(*new pTextEdit(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +TextEdit::~TextEdit() { + p.destructor(); + delete &state; +} + +//VerticalScrollBar +//================= + +unsigned VerticalScrollBar::position() { + return p.position(); +} + +void VerticalScrollBar::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void VerticalScrollBar::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +VerticalScrollBar::VerticalScrollBar(): +state(*new State), +base_from_member(*new pVerticalScrollBar(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +VerticalScrollBar::~VerticalScrollBar() { + p.destructor(); + delete &state; +} + +//VerticalSlider +//============== + +unsigned VerticalSlider::position() { + return p.position(); +} + +void VerticalSlider::setLength(unsigned length) { + state.length = length; + return p.setLength(length); +} + +void VerticalSlider::setPosition(unsigned position) { + state.position = position; + return p.setPosition(position); +} + +VerticalSlider::VerticalSlider(): +state(*new State), +base_from_member(*new pVerticalSlider(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +VerticalSlider::~VerticalSlider() { + p.destructor(); + delete &state; +} + +//Viewport +//======== + +uintptr_t Viewport::handle() { + return p.handle(); +} + +Viewport::Viewport(): +base_from_member(*new pViewport(*this)), +Widget(base_from_member::value), +p(base_from_member::value) { + p.constructor(); +} + +Viewport::~Viewport() { + p.destructor(); +} diff --git a/bsnes/phoenix/core/core.hpp b/bsnes/phoenix/core/core.hpp index a57328f1..cca25992 100755 --- a/bsnes/phoenix/core/core.hpp +++ b/bsnes/phoenix/core/core.hpp @@ -1,11 +1,13 @@ struct Font; struct Window; struct Menu; +struct Sizable; struct Layout; struct Widget; -struct pOS; struct pFont; +struct pObject; +struct pOS; struct pTimer; struct pWindow; struct pAction; @@ -14,6 +16,7 @@ struct pSeparator; struct pItem; struct pCheckItem; struct pRadioItem; +struct pSizable; struct pLayout; struct pWidget; struct pButton; @@ -45,6 +48,12 @@ struct Geometry { inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {} }; +struct Font { + nall::string description; + Geometry geometry(const nall::string &text); + Font(const nall::string &description = ""); +}; + struct Color { uint8_t red, green, blue, alpha; inline Color() : red(0), green(0), blue(0), alpha(255) {} @@ -52,10 +61,11 @@ struct Color { }; struct Object { - Object(); + Object(pObject &p); Object& operator=(const Object&) = delete; Object(const Object&) = delete; - virtual void unused() {} //allows dynamic_cast<> on Object + virtual ~Object(); + pObject &p; }; struct OS : Object { @@ -77,27 +87,14 @@ private: static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter); }; -struct Font : Object { - Geometry geometry(const nall::string &text); - void setBold(bool bold = true); - void setFamily(const nall::string &family); - void setItalic(bool italic = true); - void setSize(unsigned size); - void setUnderline(bool underline = true); - - Font(); - struct State; - State &state; - pFont &p; -}; - -struct Timer : Object { +struct Timer : private nall::base_from_member, Object { nall::function onTimeout; void setEnabled(bool enabled = true); void setInterval(unsigned milliseconds); Timer(); + ~Timer(); struct State; State &state; pTimer &p; @@ -123,7 +120,7 @@ struct MessageWindow : Object { static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok); }; -struct Window : Object { +struct Window : private nall::base_from_member, Object { static Window None; nall::function onClose; nall::function onMove; @@ -137,22 +134,28 @@ struct Window : Object { Geometry frameMargin(); bool focused(); Geometry geometry(); + void ignore(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); void setBackgroundColor(const Color &color); void setFrameGeometry(const Geometry &geometry); void setFocused(); void setFullScreen(bool fullScreen = true); void setGeometry(const Geometry &geometry); - void setMenuFont(Font &font); + void setMenuFont(const nall::string &font); void setMenuVisible(bool visible = true); void setResizable(bool resizable = true); - void setStatusFont(Font &font); + void setStatusFont(const nall::string &font); void setStatusText(const nall::string &text); void setStatusVisible(bool visible = true); void setTitle(const nall::string &text); void setVisible(bool visible = true); - void setWidgetFont(Font &font); + void setWidgetFont(const nall::string &font); + void synchronize(); Window(); + ~Window(); struct State; State &state; pWindow &p; @@ -163,6 +166,7 @@ struct Action : Object { void setVisible(bool visible = true); Action(pAction &p); + ~Action(); struct State; State &state; pAction &p; @@ -170,9 +174,11 @@ struct Action : Object { struct Menu : private nall::base_from_member, Action { void append(Action &action); + void remove(Action &action); void setText(const nall::string &text); Menu(); + ~Menu(); struct State; State &state; pMenu &p; @@ -180,6 +186,7 @@ struct Menu : private nall::base_from_member, Action { struct Separator : private nall::base_from_member, Action { Separator(); + ~Separator(); pSeparator &p; }; @@ -189,6 +196,7 @@ struct Item : private nall::base_from_member, Action { void setText(const nall::string &text); Item(); + ~Item(); struct State; State &state; pItem &p; @@ -202,6 +210,7 @@ struct CheckItem : private nall::base_from_member, Action { void setText(const nall::string &text); CheckItem(); + ~CheckItem(); struct State; State &state; pCheckItem &p; @@ -218,41 +227,58 @@ struct RadioItem : private nall::base_from_member, Action { void setText(const nall::string &text); RadioItem(); + ~RadioItem(); struct State; State &state; pRadioItem &p; }; -struct Layout; - struct Sizable : Object { + virtual bool enabled() = 0; + Layout* layout(); virtual Geometry minimumGeometry() = 0; + virtual void setEnabled(bool enabled = true) = 0; virtual void setGeometry(const Geometry &geometry) = 0; - virtual void setLayout(Layout &layout) = 0; - virtual void setParent(Window &parent) = 0; virtual void setVisible(bool visible = true) = 0; virtual bool visible() = 0; + Window* window(); + + Sizable(pSizable &p); + ~Sizable(); + struct State; + State &state; + pSizable &p; }; -struct Layout : Sizable { +struct Layout : private nall::base_from_member, Sizable { + virtual void append(Sizable &sizable); + virtual void remove(Sizable &sizable); + virtual void reset() {} + virtual void synchronize() = 0; + + Layout(); + Layout(pLayout &p); + ~Layout(); + struct State; + State &state; + pLayout &p; }; -struct Widget : Sizable { +struct Widget : private nall::base_from_member, Sizable { bool enabled(); - Font& font(); + nall::string font(); Geometry geometry(); Geometry minimumGeometry(); void setEnabled(bool enabled = true); void setFocused(); - void setFont(Font &font); + void setFont(const nall::string &font); void setGeometry(const Geometry &geometry); - void setLayout(Layout &layout); - void setParent(Window &parent); void setVisible(bool visible = true); bool visible(); Widget(); Widget(pWidget &p); + ~Widget(); struct State; State &state; pWidget &p; @@ -264,6 +290,7 @@ struct Button : private nall::base_from_member, Widget { void setText(const nall::string &text); Button(); + ~Button(); struct State; State &state; pButton &p; @@ -274,6 +301,7 @@ struct Canvas : private nall::base_from_member, Widget { void update(); Canvas(); + ~Canvas(); pCanvas &p; }; @@ -285,6 +313,7 @@ struct CheckBox : private nall::base_from_member, Widget { void setText(const nall::string &text); CheckBox(); + ~CheckBox(); struct State; State &state; pCheckBox &p; @@ -299,6 +328,7 @@ struct ComboBox : private nall::base_from_member, Widget { void setSelection(unsigned row); ComboBox(); + ~ComboBox(); struct State; State &state; pComboBox &p; @@ -315,6 +345,7 @@ struct HexEdit : private nall::base_from_member, Widget { void update(); HexEdit(); + ~HexEdit(); struct State; State &state; pHexEdit &p; @@ -328,6 +359,7 @@ struct HorizontalScrollBar : private nall::base_from_member, Wi void setPosition(unsigned position); HorizontalSlider(); + ~HorizontalSlider(); struct State; State &state; pHorizontalSlider &p; @@ -350,6 +383,7 @@ struct Label : private nall::base_from_member, Widget { void setText(const nall::string &text); Label(); + ~Label(); struct State; State &state; pLabel &p; @@ -364,6 +398,7 @@ struct LineEdit : private nall::base_from_member, Widget { nall::string text(); LineEdit(); + ~LineEdit(); struct State; State &state; pLineEdit &p; @@ -389,6 +424,7 @@ struct ListView : private nall::base_from_member, Widget { void setSelection(unsigned row); ListView(); + ~ListView(); struct State; State &state; pListView &p; @@ -403,6 +439,7 @@ struct ProgressBar : private nall::base_from_member, Widget { void setPosition(unsigned position); ProgressBar(); + ~ProgressBar(); struct State; State &state; pProgressBar &p; @@ -419,6 +456,7 @@ struct RadioBox : private nall::base_from_member, Widget { void setText(const nall::string &text); RadioBox(); + ~RadioBox(); struct State; State &state; pRadioBox &p; @@ -434,6 +472,7 @@ struct TextEdit : private nall::base_from_member, Widget { nall::string text(); TextEdit(); + ~TextEdit(); struct State; State &state; pTextEdit &p; @@ -447,6 +486,7 @@ struct VerticalScrollBar : private nall::base_from_member, void setPosition(unsigned position); VerticalScrollBar(); + ~VerticalScrollBar(); struct State; State &state; pVerticalScrollBar &p; @@ -460,6 +500,7 @@ struct VerticalSlider : private nall::base_from_member, Widget void setPosition(unsigned position); VerticalSlider(); + ~VerticalSlider(); struct State; State &state; pVerticalSlider &p; @@ -469,6 +510,7 @@ struct Viewport : private nall::base_from_member, Widget { uintptr_t handle(); Viewport(); + ~Viewport(); pViewport &p; }; diff --git a/bsnes/phoenix/core/layout/fixed-layout.cpp b/bsnes/phoenix/core/layout/fixed-layout.cpp index 5a28e9f5..ca3131dd 100755 --- a/bsnes/phoenix/core/layout/fixed-layout.cpp +++ b/bsnes/phoenix/core/layout/fixed-layout.cpp @@ -1,12 +1,16 @@ -void FixedLayout::setParent(Window &parent) { - foreach(child, children) { - child.sizable->setParent(parent); - child.sizable->setGeometry(child.geometry); - } -} - void FixedLayout::append(Sizable &sizable, const Geometry &geometry) { children.append({ &sizable, geometry }); + synchronize(); +} + +void FixedLayout::append(Sizable &sizable) { + foreach(child, children) if(child.sizable == &sizable) return; + Layout::append(sizable); +} + +bool FixedLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; } Geometry FixedLayout::minimumGeometry() { @@ -18,27 +22,56 @@ Geometry FixedLayout::minimumGeometry() { return { 0, 0, width, height }; } +void FixedLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + children.remove(n); + Layout::remove(sizable); + break; + } + } +} + +void FixedLayout::reset() { + foreach(child, children) { + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); + } +} + +void FixedLayout::setEnabled(bool enabled) { + state.enabled = enabled; + foreach(child, children) { + child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } +} + void FixedLayout::setGeometry(const Geometry &geometry) { } -void FixedLayout::setLayout(Layout &layout) { - this->layout = &layout; -} - void FixedLayout::setVisible(bool visible) { - visible_ = visible; + state.visible = visible; foreach(child, children) { child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); } } +void FixedLayout::synchronize() { + foreach(child, children) { + Layout::append(*child.sizable); + child.sizable->setGeometry(child.geometry); + } +} + bool FixedLayout::visible() { - if(layout) return visible_ && layout->visible(); - return visible_; + if(layout()) return state.visible && layout()->visible(); + return state.visible; } FixedLayout::FixedLayout() { - layout = 0; - parent = 0; - visible_ = true; + state.enabled = true; + state.visible = true; +} + +FixedLayout::~FixedLayout() { + while(children.size()) remove(*children[0].sizable); } diff --git a/bsnes/phoenix/core/layout/fixed-layout.hpp b/bsnes/phoenix/core/layout/fixed-layout.hpp index f0dc7e23..840e3a2e 100755 --- a/bsnes/phoenix/core/layout/fixed-layout.hpp +++ b/bsnes/phoenix/core/layout/fixed-layout.hpp @@ -1,17 +1,24 @@ struct FixedLayout : Layout { void append(Sizable &sizable, const Geometry &geometry); + void append(Sizable &sizable); + bool enabled(); Geometry minimumGeometry(); + void remove(Sizable &sizable); + void reset(); + void setEnabled(bool enabled = true); void setGeometry(const Geometry &geometry); - void setLayout(Layout &layout); - void setParent(Window &parent); - void setVisible(bool visible); + void setVisible(bool visible = true); + void synchronize(); bool visible(); FixedLayout(); + ~FixedLayout(); //private: - Layout *layout; - Window *parent; - bool visible_; + struct State { + bool enabled; + bool visible; + } state; + struct Children { Sizable *sizable; Geometry geometry; diff --git a/bsnes/phoenix/core/layout/horizontal-layout.cpp b/bsnes/phoenix/core/layout/horizontal-layout.cpp index c80ea997..2ed53fe9 100755 --- a/bsnes/phoenix/core/layout/horizontal-layout.cpp +++ b/bsnes/phoenix/core/layout/horizontal-layout.cpp @@ -1,6 +1,18 @@ void HorizontalLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) { - sizable.setLayout(*this); + foreach(child, children) if(child.sizable == &sizable) return; children.append({ &sizable, width, height, spacing }); + synchronize(); +} + +void HorizontalLayout::append(Sizable &sizable) { + foreach(child, children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronize(); +} + +bool HorizontalLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; } Geometry HorizontalLayout::minimumGeometry() { @@ -23,47 +35,34 @@ Geometry HorizontalLayout::minimumGeometry() { height = max(height, child.height); } - return { 0, 0, margin * 2 + width, margin * 2 + height }; + return { 0, 0, state.margin * 2 + width, state.margin * 2 + height }; } -Geometry HorizontalLayout::minimumLayoutGeometry() { - unsigned width = 0, height = 0; - bool maximumWidth = false; - bool maximumHeight = false; - - foreach(child, children) { - if(child.width == MaximumSize) { - maximumWidth = true; +void HorizontalLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + children.remove(n); + Layout::remove(sizable); break; } - - if(child.width == MinimumSize) { - width += child.sizable->minimumGeometry().width; - continue; - } - - width += child.width; } +} +void HorizontalLayout::reset() { foreach(child, children) { - if(child.height == MaximumSize) { - maximumHeight = true; - break; - } - - if(child.height == MinimumSize) { - height = max(height, child.sizable->minimumGeometry().height); - continue; - } - - height = max(height, child.height); + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); } - - return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height }; } void HorizontalLayout::setAlignment(double alignment) { - this->alignment = max(0.0, min(1.0, alignment)); + state.alignment = max(0.0, min(1.0, alignment)); +} + +void HorizontalLayout::setEnabled(bool enabled) { + state.enabled = enabled; + foreach(child, children) { + child.sizable->setEnabled(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } } void HorizontalLayout::setGeometry(const Geometry &containerGeometry) { @@ -74,10 +73,10 @@ void HorizontalLayout::setGeometry(const Geometry &containerGeometry) { } Geometry geometry = containerGeometry; - geometry.x += margin; - geometry.y += margin; - geometry.width -= margin * 2; - geometry.height -= margin * 2; + geometry.x += state.margin; + geometry.y += state.margin; + geometry.width -= state.margin * 2; + geometry.height -= state.margin * 2; unsigned minimumWidth = 0, maximumWidthCounter = 0; foreach(child, children) { @@ -95,7 +94,7 @@ void HorizontalLayout::setGeometry(const Geometry &containerGeometry) { foreach(child, children) maximumHeight = max(maximumHeight, child.height); foreach(child, children) { - unsigned pivot = (maximumHeight - child.height) * alignment; + unsigned pivot = (maximumHeight - child.height) * state.alignment; Geometry childGeometry = { geometry.x, geometry.y + pivot, child.width, child.height }; child.sizable->setGeometry(childGeometry); @@ -104,35 +103,33 @@ void HorizontalLayout::setGeometry(const Geometry &containerGeometry) { } } -void HorizontalLayout::setLayout(Layout &layout) { - this->layout = &layout; -} - void HorizontalLayout::setMargin(unsigned margin) { - this->margin = margin; -} - -void HorizontalLayout::setParent(Window &parent) { - foreach(child, children) { - child.sizable->setParent(parent); - } + state.margin = margin; } void HorizontalLayout::setVisible(bool visible) { - visible_ = visible; + state.visible = visible; foreach(child, children) { child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); } } +void HorizontalLayout::synchronize() { + foreach(child, children) Layout::append(*child.sizable); +} + bool HorizontalLayout::visible() { - if(layout) return visible_ && layout->visible(); - return visible_; + if(layout()) return state.visible && layout()->visible(); + return state.visible; } HorizontalLayout::HorizontalLayout() { - alignment = 0.5; - layout = 0; - margin = 0; - visible_ = true; + state.alignment = 0.5; + state.enabled = true; + state.margin = 0; + state.visible = true; +} + +HorizontalLayout::~HorizontalLayout() { + while(children.size()) remove(*children[0].sizable); } diff --git a/bsnes/phoenix/core/layout/horizontal-layout.hpp b/bsnes/phoenix/core/layout/horizontal-layout.hpp index fa46a727..b3f08626 100755 --- a/bsnes/phoenix/core/layout/horizontal-layout.hpp +++ b/bsnes/phoenix/core/layout/horizontal-layout.hpp @@ -1,23 +1,28 @@ -struct VerticalLayout; - struct HorizontalLayout : public Layout { void append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing = 0); + void append(Sizable &sizable); + bool enabled(); Geometry minimumGeometry(); - Geometry minimumLayoutGeometry(); + void remove(Sizable &sizable); + void reset(); void setAlignment(double alignment); + void setEnabled(bool enabled = true); void setGeometry(const Geometry &geometry); - void setLayout(Layout &layout); void setMargin(unsigned margin); - void setParent(Window &parent); - void setVisible(bool visible); + void setVisible(bool visible = true); + void synchronize(); bool visible(); HorizontalLayout(); + ~HorizontalLayout(); //private: - double alignment; - Layout *layout; - unsigned margin; - bool visible_; + struct State { + double alignment; + bool enabled; + unsigned margin; + bool visible; + } state; + struct Children { Sizable *sizable; unsigned width, height, spacing; diff --git a/bsnes/phoenix/core/layout/vertical-layout.cpp b/bsnes/phoenix/core/layout/vertical-layout.cpp index 7e5d4528..1f238bec 100755 --- a/bsnes/phoenix/core/layout/vertical-layout.cpp +++ b/bsnes/phoenix/core/layout/vertical-layout.cpp @@ -1,6 +1,18 @@ void VerticalLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) { - sizable.setLayout(*this); + foreach(child, children) if(child.sizable == &sizable) return; children.append({ &sizable, width, height, spacing }); + synchronize(); +} + +void VerticalLayout::append(Sizable &sizable) { + foreach(child, children) if(child.sizable == &sizable) return; + Layout::append(sizable); + if(window()) window()->synchronize(); +} + +bool VerticalLayout::enabled() { + if(layout()) return state.enabled && layout()->enabled(); + return state.enabled; } Geometry VerticalLayout::minimumGeometry() { @@ -23,61 +35,52 @@ Geometry VerticalLayout::minimumGeometry() { height += child.height; } - return { 0, 0, margin * 2 + width, margin * 2 + height }; + return { 0, 0, state.margin * 2 + width, state.margin * 2 + height }; } -Geometry VerticalLayout::minimumLayoutGeometry() { - unsigned width = 0, height = 0; - bool maximumWidth = false; - bool maximumHeight = false; - - foreach(child, children) { - if(child.width == MaximumSize) { - maximumWidth = true; +void VerticalLayout::remove(Sizable &sizable) { + for(unsigned n = 0; n < children.size(); n++) { + if(children[n].sizable == &sizable) { + if(dynamic_cast(children[n].sizable)) { + Layout *layout = (Layout*)children[n].sizable; + layout->reset(); + } + children.remove(n); + Layout::remove(sizable); break; } - - if(child.width == MinimumSize) { - width = max(width, child.sizable->minimumGeometry().width); - continue; - } - - width = max(width, child.width); } +} +void VerticalLayout::reset() { foreach(child, children) { - if(child.height == MaximumSize) { - maximumHeight = true; - break; - } - - if(child.height == MinimumSize) { - height += child.sizable->minimumGeometry().height; - continue; - } - - height += child.height; + if(window() && dynamic_cast(child.sizable)) window()->remove((Widget&)*child.sizable); } - - return { 0, 0, maximumWidth ? MaximumSize : margin * 2 + width, maximumHeight ? MaximumSize : margin * 2 + height }; } void VerticalLayout::setAlignment(double alignment) { - this->alignment = max(0.0, min(1.0, alignment)); + state.alignment = max(0.0, min(1.0, alignment)); +} + +void VerticalLayout::setEnabled(bool enabled) { + state.enabled = enabled; + foreach(child, children) { + child.sizable->setEnabled(dynamic_cast(child.sizable) ? child.sizable->enabled() : enabled); + } } void VerticalLayout::setGeometry(const Geometry &containerGeometry) { auto children = this->children; foreach(child, children) { - if(child.width == MinimumSize) child.width = child.sizable->minimumGeometry().width; - if(child.height == MinimumSize) child.height = child.sizable->minimumGeometry().height; + if(child.width == MinimumSize) child.width = child.sizable->minimumGeometry().width; + if(child.height == MinimumSize) child.height = child.sizable->minimumGeometry().height; } Geometry geometry = containerGeometry; - geometry.x += margin; - geometry.y += margin; - geometry.width -= margin * 2; - geometry.height -= margin * 2; + geometry.x += state.margin; + geometry.y += state.margin; + geometry.width -= state.margin * 2; + geometry.height -= state.margin * 2; unsigned minimumHeight = 0, maximumHeightCounter = 0; foreach(child, children) { @@ -95,7 +98,7 @@ void VerticalLayout::setGeometry(const Geometry &containerGeometry) { foreach(child, children) maximumWidth = max(maximumWidth, child.width); foreach(child, children) { - unsigned pivot = (maximumWidth - child.width) * alignment; + unsigned pivot = (maximumWidth - child.width) * state.alignment; Geometry childGeometry = { geometry.x + pivot, geometry.y, child.width, child.height }; child.sizable->setGeometry(childGeometry); @@ -104,35 +107,33 @@ void VerticalLayout::setGeometry(const Geometry &containerGeometry) { } } -void VerticalLayout::setLayout(Layout &layout) { - this->layout = &layout; -} - void VerticalLayout::setMargin(unsigned margin) { - this->margin = margin; -} - -void VerticalLayout::setParent(Window &parent) { - foreach(child, children) { - child.sizable->setParent(parent); - } + state.margin = margin; } void VerticalLayout::setVisible(bool visible) { - visible_ = visible; + state.visible = visible; foreach(child, children) { child.sizable->setVisible(dynamic_cast(child.sizable) ? child.sizable->visible() : visible); } } +void VerticalLayout::synchronize() { + foreach(child, children) Layout::append(*child.sizable); +} + bool VerticalLayout::visible() { - if(layout) return visible_ && layout->visible(); - return visible_; + if(layout()) return state.visible && layout()->visible(); + return state.visible; } VerticalLayout::VerticalLayout() { - alignment = 0.0; - layout = 0; - margin = 0; - visible_ = true; + state.alignment = 0.0; + state.enabled = true; + state.margin = 0; + state.visible = true; +} + +VerticalLayout::~VerticalLayout() { + while(children.size()) remove(*children[0].sizable); } diff --git a/bsnes/phoenix/core/layout/vertical-layout.hpp b/bsnes/phoenix/core/layout/vertical-layout.hpp index 5c9dd95d..6be1fbe4 100755 --- a/bsnes/phoenix/core/layout/vertical-layout.hpp +++ b/bsnes/phoenix/core/layout/vertical-layout.hpp @@ -1,23 +1,28 @@ -struct HorizontalLayout; - struct VerticalLayout : public Layout { void append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing = 0); + void append(Sizable &sizable); + bool enabled(); Geometry minimumGeometry(); - Geometry minimumLayoutGeometry(); + void remove(Sizable &sizable); + void reset(); void setAlignment(double alignment); + void setEnabled(bool enabled = true); void setGeometry(const Geometry &geometry); - void setLayout(Layout &layout); void setMargin(unsigned margin); - void setParent(Window &parent); - void setVisible(bool visible); + void setVisible(bool visible = true); + void synchronize(); bool visible(); VerticalLayout(); + ~VerticalLayout(); //private: - double alignment; - Layout *layout; - unsigned margin; - bool visible_; + struct State { + double alignment; + bool enabled; + unsigned margin; + bool visible; + } state; + struct Children { Sizable *sizable; unsigned width, height, spacing; diff --git a/bsnes/phoenix/core/state.hpp b/bsnes/phoenix/core/state.hpp index 37eb01b2..6fb24ed6 100755 --- a/bsnes/phoenix/core/state.hpp +++ b/bsnes/phoenix/core/state.hpp @@ -1,18 +1,3 @@ -struct Font::State { - bool bold; - string family; - bool italic; - unsigned size; - bool underline; - - State() { - bold = false; - italic = false; - size = 8; - underline = false; - } -}; - struct Timer::State { bool enabled; unsigned milliseconds; @@ -28,42 +13,44 @@ struct Window::State { Color backgroundColor; bool fullScreen; Geometry geometry; + bool ignore; reference_array layout; reference_array menu; - Font *menuFont; + string menuFont; bool menuVisible; bool resizable; - Font *statusFont; + string statusFont; string statusText; bool statusVisible; string title; bool visible; reference_array widget; - Font *widgetFont; + string widgetFont; State() { backgroundColorOverride = false; backgroundColor = { 0, 0, 0, 255 }; fullScreen = false; geometry = { 128, 128, 256, 256 }; - menuFont = 0; + ignore = false; menuVisible = false; resizable = true; statusVisible = false; visible = false; - widgetFont = 0; } }; struct Action::State { bool enabled; - Window *parent; + Menu *menu; bool visible; + Window *window; State() { enabled = true; - parent = 0; + menu = 0; visible = true; + window = 0; } }; @@ -95,22 +82,32 @@ struct RadioItem::State { } }; +struct Sizable::State { + Layout *layout; + Window *window; + + State() { + layout = 0; + window = 0; + } +}; + +struct Layout::State { + State() { + } +}; + struct Widget::State { bool abstract; bool enabled; - Font *font; + string font; Geometry geometry; - Layout *layout; - Window *parent; bool visible; State() { abstract = false; enabled = true; - font = 0; geometry = { 0, 0, 0, 0 }; - layout = 0; - parent = 0; visible = true; } }; diff --git a/bsnes/phoenix/gtk/action/action.cpp b/bsnes/phoenix/gtk/action/action.cpp index 4fd12f0a..6c47e068 100755 --- a/bsnes/phoenix/gtk/action/action.cpp +++ b/bsnes/phoenix/gtk/action/action.cpp @@ -1,17 +1,9 @@ -static void Action_setFont(GtkWidget *widget, gpointer font) { - if(font == 0) return; - gtk_widget_modify_font(widget, (PangoFontDescription*)font); - if(GTK_IS_CONTAINER(widget)) { - gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Action_setFont, (PangoFontDescription*)font); - } -} - void pAction::setEnabled(bool enabled) { gtk_widget_set_sensitive(widget, enabled); } -void pAction::setFont(Font &font) { - Action_setFont(widget, font.p.gtkFont); +void pAction::setFont(const string &font) { + pFont::setFont(widget, font); } void pAction::setVisible(bool visible) { @@ -20,3 +12,6 @@ void pAction::setVisible(bool visible) { void pAction::constructor() { } + +void pAction::orphan() { +} diff --git a/bsnes/phoenix/gtk/action/check-item.cpp b/bsnes/phoenix/gtk/action/check-item.cpp index c3278c1a..92beb3cb 100755 --- a/bsnes/phoenix/gtk/action/check-item.cpp +++ b/bsnes/phoenix/gtk/action/check-item.cpp @@ -17,6 +17,16 @@ void pCheckItem::setText(const string &text) { } void pCheckItem::constructor() { - widget = gtk_check_menu_item_new_with_label(""); + widget = gtk_check_menu_item_new_with_label(checkItem.state.text); + setChecked(checkItem.state.checked); g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_tick), (gpointer)&checkItem); } + +void pCheckItem::destructor() { + gtk_widget_destroy(widget); +} + +void pCheckItem::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/action/item.cpp b/bsnes/phoenix/gtk/action/item.cpp index 7afaac37..ae442a13 100755 --- a/bsnes/phoenix/gtk/action/item.cpp +++ b/bsnes/phoenix/gtk/action/item.cpp @@ -7,6 +7,15 @@ void pItem::setText(const string &text) { } void pItem::constructor() { - widget = gtk_menu_item_new_with_label(""); + widget = gtk_menu_item_new_with_label(item.state.text); g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_tick), (gpointer)&item); } + +void pItem::destructor() { + gtk_widget_destroy(widget); +} + +void pItem::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/action/menu.cpp b/bsnes/phoenix/gtk/action/menu.cpp index 27e0936c..9f71f4bb 100755 --- a/bsnes/phoenix/gtk/action/menu.cpp +++ b/bsnes/phoenix/gtk/action/menu.cpp @@ -1,11 +1,16 @@ void pMenu::append(Action &action) { - gtk_menu_shell_append(GTK_MENU_SHELL(submenu), action.p.widget); + action.state.window = this->action.state.window; + + gtk_menu_shell_append(GTK_MENU_SHELL(gtkMenu), action.p.widget); + if(action.state.window && action.state.window->state.menuFont != "") { + action.p.setFont(action.state.window->state.menuFont); + } gtk_widget_show(action.p.widget); } -void pMenu::setFont(Font &font) { - pAction::setFont(font); - foreach(item, menu.state.action) item.p.setFont(font); +void pMenu::remove(Action &action) { + action.p.orphan(); + action.state.window = 0; } void pMenu::setText(const string &text) { @@ -13,7 +18,24 @@ void pMenu::setText(const string &text) { } void pMenu::constructor() { - submenu = gtk_menu_new(); - widget = gtk_menu_item_new_with_label(""); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), submenu); + gtkMenu = gtk_menu_new(); + widget = gtk_menu_item_new_with_label(menu.state.text); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), gtkMenu); +} + +void pMenu::destructor() { + gtk_widget_destroy(gtkMenu); + gtk_widget_destroy(widget); +} + +void pMenu::orphan() { + foreach(action, menu.state.action) action.p.orphan(); + destructor(); + constructor(); + foreach(action, menu.state.action) append(action); +} + +void pMenu::setFont(const string &font) { + pAction::setFont(font); + foreach(item, menu.state.action) item.p.setFont(font); } diff --git a/bsnes/phoenix/gtk/action/radio-item.cpp b/bsnes/phoenix/gtk/action/radio-item.cpp index d25262b9..e01b5a86 100755 --- a/bsnes/phoenix/gtk/action/radio-item.cpp +++ b/bsnes/phoenix/gtk/action/radio-item.cpp @@ -1,4 +1,5 @@ static void RadioItem_tick(RadioItem *self) { + foreach(item, self->state.group) item.state.checked = (&item == self); if(self->p.locked == false && self->checked() && self->onTick) self->onTick(); } @@ -28,6 +29,19 @@ void pRadioItem::setText(const string &text) { } void pRadioItem::constructor() { - widget = gtk_radio_menu_item_new_with_label(0, ""); + widget = gtk_radio_menu_item_new_with_label(0, radioItem.state.text); + setGroup(radioItem.state.group); + foreach(item, radioItem.state.group, n) { + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), item.state.checked); + } g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_tick), (gpointer)&radioItem); } + +void pRadioItem::destructor() { + gtk_widget_destroy(widget); +} + +void pRadioItem::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/action/separator.cpp b/bsnes/phoenix/gtk/action/separator.cpp index 982ba86d..8b7a1a6b 100755 --- a/bsnes/phoenix/gtk/action/separator.cpp +++ b/bsnes/phoenix/gtk/action/separator.cpp @@ -1,3 +1,12 @@ void pSeparator::constructor() { widget = gtk_separator_menu_item_new(); } + +void pSeparator::destructor() { + gtk_widget_destroy(widget); +} + +void pSeparator::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/font.cpp b/bsnes/phoenix/gtk/font.cpp index 9f4f840b..df330867 100755 --- a/bsnes/phoenix/gtk/font.cpp +++ b/bsnes/phoenix/gtk/font.cpp @@ -1,34 +1,55 @@ -Geometry pFont::geometry(const string &text) { - pango_layout_set_font_description(gtkLayout, gtkFont); - pango_layout_set_text(gtkLayout, text, -1); +Geometry pFont::geometry(const string &description, const string &text) { + PangoFontDescription *font = create(description); + Geometry geometry = pFont::geometry(font, text); + free(font); + return geometry; +} + +PangoFontDescription* pFont::create(const string &description) { + lstring part; + part.split(",", description); + foreach(item, part) item.trim(" "); + + string family = part[0]; + unsigned size = decimal(part[1]); + bool bold = part[2].position("Bold"); + bool italic = part[2].position("Italic"); + if(family == "") family = "Sans"; + if(size == 0) size = 8; + + PangoFontDescription *font = pango_font_description_new(); + pango_font_description_set_family(font, family); + pango_font_description_set_size(font, size * PANGO_SCALE); + pango_font_description_set_weight(font, !bold ? PANGO_WEIGHT_NORMAL : PANGO_WEIGHT_BOLD); + pango_font_description_set_style(font, !italic ? PANGO_STYLE_NORMAL : PANGO_STYLE_OBLIQUE); + return font; +} + +void pFont::free(PangoFontDescription *font) { + pango_font_description_free(font); +} + +Geometry pFont::geometry(PangoFontDescription *font, const string &text) { + PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); + PangoLayout *layout = pango_layout_new(context); + pango_layout_set_font_description(layout, font); + pango_layout_set_text(layout, text, -1); int width = 0, height = 0; - pango_layout_get_pixel_size(gtkLayout, &width, &height); + pango_layout_get_pixel_size(layout, &width, &height); + g_object_unref((gpointer)layout); return { 0, 0, width, height }; } -void pFont::setBold(bool bold) { - pango_font_description_set_weight(gtkFont, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); +void pFont::setFont(GtkWidget *widget, const string &font) { + auto gtkFont = pFont::create(font); + pFont::setFont(widget, (gpointer)gtkFont); + pFont::free(gtkFont); } -void pFont::setFamily(const string &family) { - pango_font_description_set_family(gtkFont, family); -} - -void pFont::setItalic(bool italic) { - pango_font_description_set_style(gtkFont, italic ? PANGO_STYLE_OBLIQUE : PANGO_STYLE_NORMAL); -} - -void pFont::setSize(unsigned size) { - pango_font_description_set_size(gtkFont, size * PANGO_SCALE); -} - -void pFont::setUnderline(bool underline) { -} - -void pFont::constructor() { - gtkFont = pango_font_description_new(); - PangoContext *context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); - gtkLayout = pango_layout_new(context); - font.setFamily("Sans"); - font.setSize(8); +void pFont::setFont(GtkWidget *widget, gpointer font) { + if(font == 0) return; + gtk_widget_modify_font(widget, (PangoFontDescription*)font); + if(GTK_IS_CONTAINER(widget)) { + gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)pFont::setFont, font); + } } diff --git a/bsnes/phoenix/gtk/gtk.cpp b/bsnes/phoenix/gtk/platform.cpp similarity index 99% rename from bsnes/phoenix/gtk/gtk.cpp rename to bsnes/phoenix/gtk/platform.cpp index de35e588..d62edfab 100755 --- a/bsnes/phoenix/gtk/gtk.cpp +++ b/bsnes/phoenix/gtk/platform.cpp @@ -1,4 +1,4 @@ -#include "gtk.hpp" +#include "platform.hpp" #include "settings.cpp" #include "font.cpp" diff --git a/bsnes/phoenix/gtk/gtk.hpp b/bsnes/phoenix/gtk/platform.hpp similarity index 80% rename from bsnes/phoenix/gtk/gtk.hpp rename to bsnes/phoenix/gtk/platform.hpp index dffc7c1d..0173eccb 100755 --- a/bsnes/phoenix/gtk/gtk.hpp +++ b/bsnes/phoenix/gtk/platform.hpp @@ -11,18 +11,30 @@ struct Settings : public configuration { Settings(); }; -struct pFont; struct pWindow; struct pMenu; struct pLayout; struct pWidget; +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static PangoFontDescription* create(const string &description); + static void free(PangoFontDescription *font); + static Geometry geometry(PangoFontDescription *font, const string &text); + static void setFont(GtkWidget *widget, const string &font); + static void setFont(GtkWidget *widget, gpointer font); +}; + struct pObject { + Object &object; bool locked; - pObject() { - locked = false; - } + pObject(Object &object) : object(object), locked(false) {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} }; struct pOS : public pObject { @@ -41,29 +53,13 @@ struct pOS : public pObject { static void initialize(); }; -struct pFont : public pObject { - Font &font; - PangoFontDescription *gtkFont; - PangoLayout *gtkLayout; - - Geometry geometry(const string &text); - void setBold(bool bold); - void setFamily(const string &family); - void setItalic(bool italic); - void setSize(unsigned size); - void setUnderline(bool underline); - - pFont(Font &font) : font(font) {} - void constructor(); -}; - struct pTimer : public pObject { Timer &timer; void setEnabled(bool enabled); void setInterval(unsigned milliseconds); - pTimer(Timer &timer) : timer(timer) {} + pTimer(Timer &timer) : pObject(timer), timer(timer) {} void constructor(); }; @@ -91,21 +87,24 @@ struct pWindow : public pObject { bool focused(); Geometry frameMargin(); Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); void setBackgroundColor(const Color &color); void setFocused(); void setFullScreen(bool fullScreen); void setGeometry(const Geometry &geometry); - void setMenuFont(Font &font); + void setMenuFont(const string &font); void setMenuVisible(bool visible); void setResizable(bool resizable); - void setStatusFont(Font &font); + void setStatusFont(const string &font); void setStatusText(const string &text); void setStatusVisible(bool visible); void setTitle(const string &text); void setVisible(bool visible); - void setWidgetFont(Font &font); + void setWidgetFont(const string &font); - pWindow(Window &window) : window(window) {} + pWindow(Window &window) : pObject(window), window(window) {} void constructor(); unsigned menuHeight(); unsigned statusHeight(); @@ -118,21 +117,25 @@ struct pAction : public pObject { void setEnabled(bool enabled); void setVisible(bool visible); - pAction(Action &action) : action(action) {} + pAction(Action &action) : pObject(action), action(action) {} void constructor(); - virtual void setFont(Font &font); + virtual void orphan(); + virtual void setFont(const string &font); }; struct pMenu : public pAction { Menu &menu; - GtkWidget *submenu; + GtkWidget *gtkMenu; void append(Action &action); + void remove(Action &action); void setText(const string &text); pMenu(Menu &menu) : pAction(menu), menu(menu) {} void constructor(); - void setFont(Font &font); + void destructor(); + void orphan(); + void setFont(const string &font); }; struct pSeparator : public pAction { @@ -140,6 +143,8 @@ struct pSeparator : public pAction { pSeparator(Separator &separator) : pAction(separator), separator(separator) {} void constructor(); + void destructor(); + void orphan(); }; struct pItem : public pAction { @@ -149,6 +154,8 @@ struct pItem : public pAction { pItem(Item &item) : pAction(item), item(item) {} void constructor(); + void destructor(); + void orphan(); }; struct pCheckItem : public pAction { @@ -160,6 +167,8 @@ struct pCheckItem : public pAction { pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} void constructor(); + void destructor(); + void orphan(); }; struct pRadioItem : public pAction { @@ -172,25 +181,38 @@ struct pRadioItem : public pAction { pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} void constructor(); + void destructor(); + void orphan(); }; -struct pWidget : public pObject { +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { Widget &widget; GtkWidget *gtkWidget; - pWindow *parentWindow; bool enabled(); - Font& font(); virtual Geometry minimumGeometry(); void setEnabled(bool enabled); virtual void setFocused(); - virtual void setFont(Font &font); + virtual void setFont(const string &font); virtual void setGeometry(const Geometry &geometry); - void setParent(Window &parent); void setVisible(bool visible); - pWidget(Widget &widget) : widget(widget) {} + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} void constructor(); + void destructor(); + virtual void orphan(); }; struct pButton : public pWidget { @@ -201,6 +223,8 @@ struct pButton : public pWidget { pButton(Button &button) : pWidget(button), button(button) {} void constructor(); + void destructor(); + void orphan(); }; struct pCanvas : public pWidget { @@ -213,6 +237,8 @@ struct pCanvas : public pWidget { pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} void constructor(); + void destructor(); + void orphan(); }; struct pCheckBox : public pWidget { @@ -225,6 +251,8 @@ struct pCheckBox : public pWidget { pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} void constructor(); + void destructor(); + void orphan(); }; struct pComboBox : public pWidget { @@ -239,6 +267,8 @@ struct pComboBox : public pWidget { pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} void constructor(); + void destructor(); + void orphan(); }; struct pHexEdit : public pWidget { @@ -257,6 +287,8 @@ struct pHexEdit : public pWidget { pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} void constructor(); + void destructor(); + void orphan(); unsigned cursorPosition(); bool keyPress(unsigned scancode); void scroll(unsigned position); @@ -275,6 +307,8 @@ struct pHorizontalScrollBar : public pWidget { pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} void constructor(); + void destructor(); + void orphan(); }; struct pHorizontalSlider : public pWidget { @@ -287,6 +321,8 @@ struct pHorizontalSlider : public pWidget { pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} void constructor(); + void destructor(); + void orphan(); }; struct pLabel : public pWidget { @@ -297,6 +333,8 @@ struct pLabel : public pWidget { pLabel(Label &label) : pWidget(label), label(label) {} void constructor(); + void destructor(); + void orphan(); }; struct pLineEdit : public pWidget { @@ -309,6 +347,8 @@ struct pLineEdit : public pWidget { pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} void constructor(); + void destructor(); + void orphan(); }; struct pListView : public pWidget { @@ -338,9 +378,10 @@ struct pListView : public pWidget { pListView(ListView &listView) : pWidget(listView), listView(listView) {} void constructor(); - void create(); + void destructor(); + void orphan(); void setFocused(); - void setFont(Font &font); + void setFont(const string &font); }; struct pProgressBar : public pWidget { @@ -351,6 +392,8 @@ struct pProgressBar : public pWidget { pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} void constructor(); + void destructor(); + void orphan(); }; struct pRadioBox : public pWidget { @@ -364,6 +407,8 @@ struct pRadioBox : public pWidget { pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} void constructor(); + void destructor(); + void orphan(); }; struct pTextEdit : public pWidget { @@ -379,6 +424,8 @@ struct pTextEdit : public pWidget { pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} void constructor(); + void destructor(); + void orphan(); }; struct pVerticalScrollBar : public pWidget { @@ -391,6 +438,8 @@ struct pVerticalScrollBar : public pWidget { pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} void constructor(); + void destructor(); + void orphan(); }; struct pVerticalSlider : public pWidget { @@ -403,6 +452,8 @@ struct pVerticalSlider : public pWidget { pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} void constructor(); + void destructor(); + void orphan(); }; struct pViewport : public pWidget { @@ -412,4 +463,6 @@ struct pViewport : public pWidget { pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} void constructor(); + void destructor(); + void orphan(); }; diff --git a/bsnes/phoenix/gtk/widget/button.cpp b/bsnes/phoenix/gtk/widget/button.cpp index 35802d4f..5b554fc8 100755 --- a/bsnes/phoenix/gtk/widget/button.cpp +++ b/bsnes/phoenix/gtk/widget/button.cpp @@ -3,8 +3,7 @@ static void Button_tick(Button *self) { } Geometry pButton::minimumGeometry() { - Font &font = pWidget::font(); - Geometry geometry = font.geometry(button.state.text); + Geometry geometry = pFont::geometry(widget.state.font, button.state.text); return { 0, 0, geometry.width + 24, geometry.height + 12 }; } @@ -15,5 +14,15 @@ void pButton::setText(const string &text) { void pButton::constructor() { gtkWidget = gtk_button_new(); g_signal_connect_swapped(G_OBJECT(gtkWidget), "clicked", G_CALLBACK(Button_tick), (gpointer)&button); -//g_object_ref((gpointer)gtkWidget); + + setText(button.state.text); +} + +void pButton::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pButton::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/canvas.cpp b/bsnes/phoenix/gtk/widget/canvas.cpp index c2261d17..9991f93f 100755 --- a/bsnes/phoenix/gtk/widget/canvas.cpp +++ b/bsnes/phoenix/gtk/widget/canvas.cpp @@ -36,3 +36,13 @@ void pCanvas::constructor() { gtk_widget_add_events(gtkWidget, GDK_EXPOSURE_MASK); g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this); } + +void pCanvas::destructor() { + gtk_widget_destroy(gtkWidget); + cairo_surface_destroy(surface); +} + +void pCanvas::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/widget/check-box.cpp b/bsnes/phoenix/gtk/widget/check-box.cpp index 4169c68b..a4a7874c 100755 --- a/bsnes/phoenix/gtk/widget/check-box.cpp +++ b/bsnes/phoenix/gtk/widget/check-box.cpp @@ -1,4 +1,5 @@ static void CheckBox_tick(CheckBox *self) { + self->state.checked = self->checked(); if(self->p.locked == false && self->onTick) self->onTick(); } @@ -7,8 +8,7 @@ bool pCheckBox::checked() { } Geometry pCheckBox::minimumGeometry() { - Font &font = pWidget::font(); - Geometry geometry = font.geometry(checkBox.state.text); + Geometry geometry = pFont::geometry(widget.state.font, checkBox.state.text); return { 0, 0, geometry.width + 28, geometry.height + 4 }; } @@ -25,4 +25,16 @@ void pCheckBox::setText(const string &text) { void pCheckBox::constructor() { gtkWidget = gtk_check_button_new_with_label(""); g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)&checkBox); + + setChecked(checkBox.state.checked); + setText(checkBox.state.text); +} + +void pCheckBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pCheckBox::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/combo-box.cpp b/bsnes/phoenix/gtk/widget/combo-box.cpp index 348e95d0..fb878aae 100755 --- a/bsnes/phoenix/gtk/widget/combo-box.cpp +++ b/bsnes/phoenix/gtk/widget/combo-box.cpp @@ -1,5 +1,8 @@ static void ComboBox_change(ComboBox *self) { - if(self->p.locked == false && self->onChange) self->onChange(); + if(self->p.locked == false) { + self->state.selection = self->selection(); + if(self->onChange) self->onChange(); + } } void pComboBox::append(const string &text) { @@ -8,11 +11,10 @@ void pComboBox::append(const string &text) { } Geometry pComboBox::minimumGeometry() { - Font &font = pWidget::font(); unsigned maximumWidth = 0; - foreach(item, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(item).width); + foreach(item, comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(widget.state.font, item).width); - Geometry geometry = font.geometry(" "); + Geometry geometry = pFont::geometry(widget.state.font, " "); return { 0, 0, maximumWidth + 44, geometry.height + 12 }; } @@ -37,4 +39,18 @@ void pComboBox::constructor() { itemCounter = 0; gtkWidget = gtk_combo_box_new_text(); g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(ComboBox_change), (gpointer)&comboBox); + + locked = true; + foreach(text, comboBox.state.text) append(text); + locked = false; + setSelection(comboBox.state.selection); +} + +void pComboBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pComboBox::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/hex-edit.cpp b/bsnes/phoenix/gtk/widget/hex-edit.cpp index 7aa61a07..9187d33f 100755 --- a/bsnes/phoenix/gtk/widget/hex-edit.cpp +++ b/bsnes/phoenix/gtk/widget/hex-edit.cpp @@ -96,6 +96,24 @@ void pHexEdit::constructor() { gtk_widget_show(scrollBar); gtk_widget_show(subWidget); gtk_widget_show(container); + + setColumns(hexEdit.state.columns); + setRows(hexEdit.state.rows); + setLength(hexEdit.state.length); + setOffset(hexEdit.state.offset); + update(); +} + +void pHexEdit::destructor() { + gtk_widget_destroy(scrollBar); + gtk_widget_destroy(subWidget); + gtk_widget_destroy(container); + gtk_widget_destroy(gtkWidget); +} + +void pHexEdit::orphan() { + destructor(); + constructor(); } unsigned pHexEdit::cursorPosition() { diff --git a/bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp index f260cb58..4e265f4c 100755 --- a/bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp +++ b/bsnes/phoenix/gtk/widget/horizontal-scroll-bar.cpp @@ -24,6 +24,17 @@ void pHorizontalScrollBar::setPosition(unsigned position) { void pHorizontalScrollBar::constructor() { gtkWidget = gtk_hscrollbar_new(0); - setLength(101); g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalScrollBar_change), (gpointer)&horizontalScrollBar); + + setLength(horizontalScrollBar.state.length); + setPosition(horizontalScrollBar.state.position); +} + +void pHorizontalScrollBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/horizontal-slider.cpp b/bsnes/phoenix/gtk/widget/horizontal-slider.cpp index 4541b6fd..9913d72d 100755 --- a/bsnes/phoenix/gtk/widget/horizontal-slider.cpp +++ b/bsnes/phoenix/gtk/widget/horizontal-slider.cpp @@ -25,6 +25,17 @@ void pHorizontalSlider::setPosition(unsigned position) { void pHorizontalSlider::constructor() { gtkWidget = gtk_hscale_new_with_range(0, 100, 1); gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); - setLength(101); g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(HorizontalSlider_change), (gpointer)&horizontalSlider); + + setLength(horizontalSlider.state.length); + setPosition(horizontalSlider.state.position); +} + +void pHorizontalSlider::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/label.cpp b/bsnes/phoenix/gtk/widget/label.cpp index 645abdbf..8b5cec4f 100755 --- a/bsnes/phoenix/gtk/widget/label.cpp +++ b/bsnes/phoenix/gtk/widget/label.cpp @@ -1,6 +1,5 @@ Geometry pLabel::minimumGeometry() { - Font &font = pWidget::font(); - Geometry geometry = font.geometry(label.state.text); + Geometry geometry = pFont::geometry(widget.state.font, label.state.text); return { 0, 0, geometry.width, geometry.height }; } @@ -11,4 +10,15 @@ void pLabel::setText(const string &text) { void pLabel::constructor() { gtkWidget = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(gtkWidget), 0.0, 0.5); + + setText(label.state.text); +} + +void pLabel::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pLabel::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/line-edit.cpp b/bsnes/phoenix/gtk/widget/line-edit.cpp index e630b3f5..8dbe9ef4 100755 --- a/bsnes/phoenix/gtk/widget/line-edit.cpp +++ b/bsnes/phoenix/gtk/widget/line-edit.cpp @@ -3,12 +3,12 @@ static void LineEdit_activate(LineEdit *self) { } static void LineEdit_change(LineEdit *self) { + self->state.text = self->text(); if(self->p.locked == false && self->onChange) self->onChange(); } Geometry pLineEdit::minimumGeometry() { - Font &font = pWidget::font(); - Geometry geometry = font.geometry(lineEdit.state.text); + Geometry geometry = pFont::geometry(widget.state.font, lineEdit.state.text); return { 0, 0, geometry.width + 10, geometry.height + 10 }; } @@ -30,4 +30,16 @@ void pLineEdit::constructor() { gtkWidget = gtk_entry_new(); g_signal_connect_swapped(G_OBJECT(gtkWidget), "activate", G_CALLBACK(LineEdit_activate), (gpointer)&lineEdit); g_signal_connect_swapped(G_OBJECT(gtkWidget), "changed", G_CALLBACK(LineEdit_change), (gpointer)&lineEdit); + + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); +} + +void pLineEdit::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pLineEdit::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/list-view.cpp b/bsnes/phoenix/gtk/widget/list-view.cpp index 9a56fbdc..e2b707be 100755 --- a/bsnes/phoenix/gtk/widget/list-view.cpp +++ b/bsnes/phoenix/gtk/widget/list-view.cpp @@ -99,7 +99,8 @@ void pListView::setChecked(unsigned row, bool checked) { } void pListView::setHeaderText(const lstring &text) { - create(); + destructor(); + constructor(); } void pListView::setHeaderVisible(bool visible) { @@ -140,12 +141,6 @@ void pListView::setSelection(unsigned row) { void pListView::constructor() { gtkWidget = 0; subWidget = 0; - create(); -} - -void pListView::create() { - if(subWidget) gtk_widget_destroy(subWidget); - if(gtkWidget) gtk_widget_destroy(gtkWidget); gtkWidget = gtk_scrolled_window_new(0, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); @@ -189,23 +184,33 @@ void pListView::create() { g_signal_connect_swapped(G_OBJECT(subWidget), "cursor-changed", G_CALLBACK(ListView_change), (gpointer)&listView); g_signal_connect_swapped(G_OBJECT(subWidget), "row-activated", G_CALLBACK(ListView_activate), (gpointer)&listView); + gtk_widget_show(subWidget); + setHeaderVisible(listView.state.headerVisible); setCheckable(listView.state.checkable); foreach(text, listView.state.text) append(text); foreach(checked, listView.state.checked, n) setChecked(n, checked); if(listView.state.selected) setSelection(listView.state.selection); autoSizeColumns(); +} - gtk_widget_show(subWidget); +void pListView::destructor() { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +void pListView::orphan() { + destructor(); + constructor(); } void pListView::setFocused() { gtk_widget_grab_focus(subWidget); } -void pListView::setFont(Font &font) { - pWidget::setFont(font); +void pListView::setFont(const string &font) { + pFont::setFont(gtkWidget, font); for(unsigned n = 0; n < 1 + listView.state.headerText.size(); n++) { - gtk_widget_modify_font(column[n].label, font.p.gtkFont); + pFont::setFont(column[n].label, font); } } diff --git a/bsnes/phoenix/gtk/widget/progress-bar.cpp b/bsnes/phoenix/gtk/widget/progress-bar.cpp index 4e7d752c..972170b8 100755 --- a/bsnes/phoenix/gtk/widget/progress-bar.cpp +++ b/bsnes/phoenix/gtk/widget/progress-bar.cpp @@ -9,4 +9,15 @@ void pProgressBar::setPosition(unsigned position) { void pProgressBar::constructor() { gtkWidget = gtk_progress_bar_new(); + + setPosition(progressBar.state.position); +} + +void pProgressBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pProgressBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/radio-box.cpp b/bsnes/phoenix/gtk/widget/radio-box.cpp index 67e709ae..76e51a1e 100755 --- a/bsnes/phoenix/gtk/widget/radio-box.cpp +++ b/bsnes/phoenix/gtk/widget/radio-box.cpp @@ -7,8 +7,9 @@ bool pRadioBox::checked() { } Geometry pRadioBox::minimumGeometry() { - Font &font = pWidget::font(); - Geometry geometry = font.geometry(radioBox.state.text); + Geometry geometry = pFont::geometry(widget.state.font, radioBox.state.text); +//Font &font = pWidget::font(); +//Geometry geometry = font.geometry(radioBox.state.text); return { 0, 0, geometry.width + 28, geometry.height + 4 }; } @@ -35,4 +36,15 @@ void pRadioBox::setText(const string &text) { void pRadioBox::constructor() { gtkWidget = gtk_radio_button_new_with_label(0, ""); g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)&radioBox); + + setText(radioBox.state.text); +} + +void pRadioBox::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pRadioBox::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/text-edit.cpp b/bsnes/phoenix/gtk/widget/text-edit.cpp index cf6494f8..a1803bbf 100755 --- a/bsnes/phoenix/gtk/widget/text-edit.cpp +++ b/bsnes/phoenix/gtk/widget/text-edit.cpp @@ -1,4 +1,5 @@ static void TextEdit_change(TextEdit *self) { + self->state.text = self->text(); if(self->p.locked == false && self->onChange) self->onChange(); } @@ -45,4 +46,18 @@ void pTextEdit::constructor() { textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); g_signal_connect_swapped(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)&textEdit); gtk_widget_show(subWidget); + + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + setWordWrap(textEdit.state.wordWrap); +} + +void pTextEdit::destructor() { + gtk_widget_destroy(subWidget); + gtk_widget_destroy(gtkWidget); +} + +void pTextEdit::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp index bde3b73f..5eedbc5b 100755 --- a/bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp +++ b/bsnes/phoenix/gtk/widget/vertical-scroll-bar.cpp @@ -24,6 +24,17 @@ void pVerticalScrollBar::setPosition(unsigned position) { void pVerticalScrollBar::constructor() { gtkWidget = gtk_vscrollbar_new(0); - setLength(101); g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalScrollBar_change), (gpointer)&verticalScrollBar); + + setLength(verticalScrollBar.state.length); + setPosition(verticalScrollBar.state.position); +} + +void pVerticalScrollBar::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/vertical-slider.cpp b/bsnes/phoenix/gtk/widget/vertical-slider.cpp index ebe59ee7..b1148410 100755 --- a/bsnes/phoenix/gtk/widget/vertical-slider.cpp +++ b/bsnes/phoenix/gtk/widget/vertical-slider.cpp @@ -25,6 +25,17 @@ void pVerticalSlider::setPosition(unsigned position) { void pVerticalSlider::constructor() { gtkWidget = gtk_vscale_new_with_range(0, 100, 1); gtk_scale_set_draw_value(GTK_SCALE(gtkWidget), false); - setLength(101); g_signal_connect_swapped(G_OBJECT(gtkWidget), "value-changed", G_CALLBACK(VerticalSlider_change), (gpointer)&verticalSlider); + + setLength(verticalSlider.state.length); + setPosition(verticalSlider.state.position); +} + +void pVerticalSlider::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/gtk/widget/viewport.cpp b/bsnes/phoenix/gtk/widget/viewport.cpp index 7683c7f9..18c61f5b 100755 --- a/bsnes/phoenix/gtk/widget/viewport.cpp +++ b/bsnes/phoenix/gtk/widget/viewport.cpp @@ -13,3 +13,12 @@ void pViewport::constructor() { color.blue = 0; gtk_widget_modify_bg(gtkWidget, GTK_STATE_NORMAL, &color); } + +void pViewport::destructor() { + gtk_widget_destroy(gtkWidget); +} + +void pViewport::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/widget/widget.cpp b/bsnes/phoenix/gtk/widget/widget.cpp index fe885ce2..bc5b2b30 100755 --- a/bsnes/phoenix/gtk/widget/widget.cpp +++ b/bsnes/phoenix/gtk/widget/widget.cpp @@ -1,16 +1,3 @@ -static void Widget_setFont(GtkWidget *widget, gpointer font) { - if(font == 0) return; - gtk_widget_modify_font(widget, (PangoFontDescription*)font); - if(GTK_IS_CONTAINER(widget)) { - gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)Widget_setFont, font); - } -} - -Font& pWidget::font() { - if(widget.state.font) return *widget.state.font; - return pOS::defaultFont; -} - Geometry pWidget::minimumGeometry() { return { 0, 0, 0, 0 }; } @@ -20,6 +7,8 @@ bool pWidget::enabled() { } void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; gtk_widget_set_sensitive(gtkWidget, enabled); } @@ -27,35 +16,32 @@ void pWidget::setFocused() { gtk_widget_grab_focus(gtkWidget); } -void pWidget::setFont(Font &font) { - Widget_setFont(gtkWidget, font.p.gtkFont); +void pWidget::setFont(const string &font) { + pFont::setFont(gtkWidget, font); } void pWidget::setGeometry(const Geometry &geometry) { - if(parentWindow) gtk_fixed_move(GTK_FIXED(parentWindow->formContainer), gtkWidget, geometry.x, geometry.y); + if(sizable.state.window) gtk_fixed_move(GTK_FIXED(sizable.state.window->p.formContainer), gtkWidget, geometry.x, geometry.y); unsigned width = (signed)geometry.width <= 0 ? 1U : geometry.width; unsigned height = (signed)geometry.height <= 0 ? 1U : geometry.height; gtk_widget_set_size_request(gtkWidget, width, height); } -void pWidget::setParent(Window &parent) { - parentWindow = &parent.p; - - if(!widget.state.font && parent.state.widgetFont) { - setFont(*parent.state.widgetFont); - } - - gtk_fixed_put(GTK_FIXED(parent.p.formContainer), gtkWidget, 0, 0); - widget.setVisible(widget.visible()); -} - void pWidget::setVisible(bool visible) { if(widget.state.abstract) visible = false; - if(widget.state.layout && widget.state.layout->visible() == false) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; gtk_widget_set_visible(gtkWidget, visible); } void pWidget::constructor() { - parentWindow = 0; if(widget.state.abstract) gtkWidget = gtk_label_new(""); } + +void pWidget::destructor() { + if(widget.state.abstract) gtk_widget_destroy(gtkWidget); +} + +void pWidget::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/gtk/window.cpp b/bsnes/phoenix/gtk/window.cpp index 85beae54..175bfd34 100755 --- a/bsnes/phoenix/gtk/window.cpp +++ b/bsnes/phoenix/gtk/window.cpp @@ -1,9 +1,7 @@ -static void Action_setFont(GtkWidget *widget, gpointer font); -static void Widget_setFont(GtkWidget *widget, gpointer font); - static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) { + window->state.ignore = false; if(window->onClose) window->onClose(); - window->setVisible(false); + if(window->state.ignore == false) window->setVisible(false); return true; } @@ -78,25 +76,24 @@ static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *win } void pWindow::append(Layout &layout) { - layout.setParent(window); Geometry geometry = this->geometry(); geometry.x = geometry.y = 0; layout.setGeometry(geometry); } -void pWindow::append(Menu &subMenu) { - if(window.state.menuFont) subMenu.p.setFont(*window.state.menuFont); - gtk_menu_shell_append(GTK_MENU_SHELL(menu), subMenu.p.widget); - gtk_widget_show(subMenu.p.widget); +void pWindow::append(Menu &menu) { + if(window.state.menuFont != "") menu.p.setFont(window.state.menuFont); + else menu.p.setFont("Sans, 8"); + gtk_menu_shell_append(GTK_MENU_SHELL(this->menu), menu.p.widget); + gtk_widget_show(menu.p.widget); } void pWindow::append(Widget &widget) { - widget.p.parentWindow = this; - if(!widget.state.font && window.state.widgetFont) { - widget.setFont(*window.state.widgetFont); - } gtk_fixed_put(GTK_FIXED(formContainer), widget.p.gtkWidget, 0, 0); - widget.setVisible(); + if(widget.state.font != "") widget.p.setFont(widget.state.font); + else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Sans, 8"); + widget.setVisible(widget.visible()); } Color pWindow::backgroundColor() { @@ -126,6 +123,17 @@ Geometry pWindow::geometry() { return window.state.geometry; } +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + menu.p.orphan(); +} + +void pWindow::remove(Widget &widget) { + widget.p.orphan(); +} + void pWindow::setBackgroundColor(const Color &color) { GdkColor gdkColor; gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0); @@ -170,7 +178,7 @@ void pWindow::setGeometry(const Geometry &geometry) { } } -void pWindow::setMenuFont(Font &font) { +void pWindow::setMenuFont(const string &font) { foreach(item, window.state.menu) item.p.setFont(font); } @@ -183,8 +191,8 @@ void pWindow::setResizable(bool resizable) { gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(status), resizable); } -void pWindow::setStatusFont(Font &font) { - Widget_setFont(status, (gpointer)font.p.gtkFont); +void pWindow::setStatusFont(const string &font) { + pFont::setFont(status, font); } void pWindow::setStatusText(const string &text) { @@ -204,9 +212,9 @@ void pWindow::setVisible(bool visible) { gtk_widget_set_visible(widget, visible); } -void pWindow::setWidgetFont(Font &font) { +void pWindow::setWidgetFont(const string &font) { foreach(item, window.state.widget) { - if(!item.state.font) item.setFont(font); + if(item.state.font == "") item.setFont(font); } } @@ -244,6 +252,8 @@ void pWindow::constructor() { setTitle(""); setGeometry(window.state.geometry); + setMenuFont("Sans, 8"); + setStatusFont("Sans, 8"); g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window); g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window); diff --git a/bsnes/phoenix/qt/action/action.cpp b/bsnes/phoenix/qt/action/action.cpp index 57036439..62efaa2a 100755 --- a/bsnes/phoenix/qt/action/action.cpp +++ b/bsnes/phoenix/qt/action/action.cpp @@ -12,17 +12,19 @@ void pAction::setEnabled(bool enabled) { } } -void pAction::setFont(Font &font) { +void pAction::setFont(const string &font) { + QFont qtFont = pFont::create(font); + if(dynamic_cast(&action)) { ((Menu&)action).p.setFont(font); } else if(dynamic_cast(&action)) { - ((Separator&)action).p.qtAction->setFont(*font.p.qtFont); + ((Separator&)action).p.qtAction->setFont(qtFont); } else if(dynamic_cast(&action)) { - ((Item&)action).p.qtAction->setFont(*font.p.qtFont); + ((Item&)action).p.qtAction->setFont(qtFont); } else if(dynamic_cast(&action)) { - ((CheckItem&)action).p.qtAction->setFont(*font.p.qtFont); + ((CheckItem&)action).p.qtAction->setFont(qtFont); } else if(dynamic_cast(&action)) { - ((RadioItem&)action).p.qtAction->setFont(*font.p.qtFont); + ((RadioItem&)action).p.qtAction->setFont(qtFont); } } @@ -42,3 +44,6 @@ void pAction::setVisible(bool visible) { void pAction::constructor() { } + +void pAction::destructor() { +} diff --git a/bsnes/phoenix/qt/action/check-item.cpp b/bsnes/phoenix/qt/action/check-item.cpp index 19c91f2e..7c18d836 100755 --- a/bsnes/phoenix/qt/action/check-item.cpp +++ b/bsnes/phoenix/qt/action/check-item.cpp @@ -16,6 +16,11 @@ void pCheckItem::constructor() { connect(qtAction, SIGNAL(triggered()), SLOT(onTick())); } +void pCheckItem::destructor() { + if(action.state.menu) action.state.menu->remove(checkItem); + delete qtAction; +} + void pCheckItem::onTick() { checkItem.state.checked = checked(); if(checkItem.onTick) checkItem.onTick(); diff --git a/bsnes/phoenix/qt/action/item.cpp b/bsnes/phoenix/qt/action/item.cpp index 3b284d7c..9a9daec7 100755 --- a/bsnes/phoenix/qt/action/item.cpp +++ b/bsnes/phoenix/qt/action/item.cpp @@ -7,6 +7,11 @@ void pItem::constructor() { connect(qtAction, SIGNAL(triggered()), SLOT(onTick())); } +void pItem::destructor() { + if(action.state.menu) action.state.menu->remove(item); + delete qtAction; +} + void pItem::onTick() { if(item.onTick) item.onTick(); } diff --git a/bsnes/phoenix/qt/action/menu.cpp b/bsnes/phoenix/qt/action/menu.cpp index 913fe509..8892cee3 100755 --- a/bsnes/phoenix/qt/action/menu.cpp +++ b/bsnes/phoenix/qt/action/menu.cpp @@ -12,8 +12,24 @@ void pMenu::append(Action &action) { } } -void pMenu::setFont(Font &font) { - qtMenu->setFont(*font.p.qtFont); +void pMenu::remove(Action &action) { + if(dynamic_cast(&action)) { + //QMenu::removeMenu() does not exist + qtMenu->clear(); + foreach(action, menu.state.action) append(action); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Separator&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((Item&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } else if(dynamic_cast(&action)) { + qtMenu->removeAction(((CheckItem&)action).p.qtAction); + } +} + +void pMenu::setFont(const string &font) { + qtMenu->setFont(pFont::create(font)); foreach(item, menu.state.action) item.p.setFont(font); } @@ -24,3 +40,8 @@ void pMenu::setText(const string &text) { void pMenu::constructor() { qtMenu = new QMenu; } + +void pMenu::destructor() { + if(action.state.menu) action.state.menu->remove(menu); + delete qtMenu; +} diff --git a/bsnes/phoenix/qt/action/radio-item.cpp b/bsnes/phoenix/qt/action/radio-item.cpp index cdea2d02..420ea6b6 100755 --- a/bsnes/phoenix/qt/action/radio-item.cpp +++ b/bsnes/phoenix/qt/action/radio-item.cpp @@ -28,6 +28,11 @@ void pRadioItem::constructor() { connect(qtAction, SIGNAL(triggered()), SLOT(onTick())); } +void pRadioItem::destructor() { + if(action.state.menu) action.state.menu->remove(radioItem); + delete qtAction; +} + void pRadioItem::onTick() { if(radioItem.state.checked == false) { setChecked(); diff --git a/bsnes/phoenix/qt/action/separator.cpp b/bsnes/phoenix/qt/action/separator.cpp index 50253c12..95e66b6c 100755 --- a/bsnes/phoenix/qt/action/separator.cpp +++ b/bsnes/phoenix/qt/action/separator.cpp @@ -2,3 +2,8 @@ void pSeparator::constructor() { qtAction = new QAction(0); qtAction->setSeparator(true); } + +void pSeparator::destructor() { + if(action.state.menu) action.state.menu->remove(separator); + delete qtAction; +} diff --git a/bsnes/phoenix/qt/font.cpp b/bsnes/phoenix/qt/font.cpp index 4dc21c4b..3d9addfd 100755 --- a/bsnes/phoenix/qt/font.cpp +++ b/bsnes/phoenix/qt/font.cpp @@ -1,5 +1,27 @@ -Geometry pFont::geometry(const string &text) { - QFontMetrics metrics(*qtFont); +Geometry pFont::geometry(const string &description, const string &text) { + return pFont::geometry(pFont::create(description), text); +} + +QFont pFont::create(const string &description) { + lstring part; + part.split(",", description); + foreach(item, part) item.trim(" "); + + string name = part[0] != "" ? part[0] : "Sans"; + unsigned size = part.size() >= 2 ? decimal(part[1]) : 8u; + bool bold = part[2].position("Bold"); + bool italic = part[2].position("Italic"); + + QFont qtFont; + qtFont.setFamily(part[0]); + qtFont.setPointSize(decimal(part[1])); + if(bold) qtFont.setBold(true); + if(italic) qtFont.setItalic(true); + return qtFont; +} + +Geometry pFont::geometry(const QFont &qtFont, const string &text) { + QFontMetrics metrics(qtFont); lstring lines; lines.split("\n", text); @@ -11,23 +33,3 @@ Geometry pFont::geometry(const string &text) { return { 0, 0, maxWidth, metrics.height() * lines.size() }; } - -void pFont::setBold(bool bold) { update(); } -void pFont::setFamily(const string &family) { update(); } -void pFont::setItalic(bool italic) { update(); } -void pFont::setSize(unsigned size) { update(); } -void pFont::setUnderline(bool underline) { update(); } - -void pFont::constructor() { - qtFont = new QFont; - font.setFamily("Sans"); - font.setSize(8); -} - -void pFont::update() { - qtFont->setFamily(QString::fromUtf8(font.state.family)); - qtFont->setPointSize(font.state.size); - qtFont->setBold(font.state.bold); - qtFont->setItalic(font.state.italic); - qtFont->setUnderline(font.state.underline); -} diff --git a/bsnes/phoenix/qt/qt.cpp b/bsnes/phoenix/qt/platform.cpp similarity index 94% rename from bsnes/phoenix/qt/qt.cpp rename to bsnes/phoenix/qt/platform.cpp index 2eb69bdb..bbfc70a4 100755 --- a/bsnes/phoenix/qt/qt.cpp +++ b/bsnes/phoenix/qt/platform.cpp @@ -1,5 +1,5 @@ -#include "qt.moc.hpp" -#include "qt.moc" +#include "platform.moc.hpp" +#include "platform.moc" #include "settings.cpp" #include "font.cpp" @@ -32,9 +32,6 @@ #include "widget/vertical-slider.cpp" #include "widget/viewport.cpp" -QApplication *pOS::application = 0; -Font pOS::defaultFont; - Geometry pOS::availableGeometry() { QRect rect = QApplication::desktop()->availableGeometry(); return { rect.x(), rect.y(), rect.width(), rect.height() }; @@ -118,6 +115,8 @@ void pOS::processEvents() { void pOS::quit() { settings.save(); QApplication::quit(); + //note: QApplication cannot be deleted; or libQtGui will crash + qtApplication = 0; } void pOS::initialize() { @@ -129,5 +128,6 @@ void pOS::initialize() { argv[1] = 0; strcpy(argv[0], "phoenix"); char **argvp = argv; - application = new QApplication(argc, argvp); + + qtApplication = new QApplication(argc, argvp); } diff --git a/bsnes/phoenix/qt/qt.moc b/bsnes/phoenix/qt/platform.moc similarity index 99% rename from bsnes/phoenix/qt/qt.moc rename to bsnes/phoenix/qt/platform.moc index f2d15997..c2c84d43 100755 --- a/bsnes/phoenix/qt/qt.moc +++ b/bsnes/phoenix/qt/platform.moc @@ -1,14 +1,14 @@ /**************************************************************************** -** Meta object code from reading C++ file 'qt.moc.hpp' +** Meta object code from reading C++ file 'platform.moc.hpp' ** -** Created: Mon Aug 22 04:02:58 2011 +** Created: Tue Aug 30 09:38:15 2011 ** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0) ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ #if !defined(Q_MOC_OUTPUT_REVISION) -#error "The header file 'qt.moc.hpp' doesn't include ." +#error "The header file 'platform.moc.hpp' doesn't include ." #elif Q_MOC_OUTPUT_REVISION != 62 #error "This file was generated using the moc from 4.7.0. It" #error "cannot be used with the include files from this version of Qt." diff --git a/bsnes/phoenix/qt/qt.moc.hpp b/bsnes/phoenix/qt/platform.moc.hpp similarity index 83% rename from bsnes/phoenix/qt/qt.moc.hpp rename to bsnes/phoenix/qt/platform.moc.hpp index c9c5c6da..d1ecee36 100755 --- a/bsnes/phoenix/qt/qt.moc.hpp +++ b/bsnes/phoenix/qt/platform.moc.hpp @@ -1,3 +1,5 @@ +static QApplication *qtApplication = 0; + struct Settings : public configuration { unsigned frameGeometryX; unsigned frameGeometryY; @@ -9,24 +11,29 @@ struct Settings : public configuration { Settings(); }; -struct pFont; struct pWindow; struct pMenu; struct pLayout; struct pWidget; +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static QFont create(const string &description); + static Geometry geometry(const QFont &qtFont, const string &text); +}; + struct pObject { + Object &object; bool locked; - pObject() { - locked = false; - } + pObject(Object &object) : object(object), locked(false) {} + virtual ~pObject() {} + void constructor() {} + void destructor() {} }; struct pOS : public pObject { - static QApplication *application; - static Font defaultFont; - static Geometry availableGeometry(); static Geometry desktopGeometry(); static string fileLoad(Window &parent, const string &path, const lstring &filter); @@ -40,22 +47,6 @@ struct pOS : public pObject { static void initialize(); }; -struct pFont : public pObject { - Font &font; - QFont *qtFont; - - Geometry geometry(const string &text); - void setBold(bool bold); - void setFamily(const string &family); - void setItalic(bool italic); - void setSize(unsigned size); - void setUnderline(bool underline); - - pFont(Font &font) : font(font) {} - void constructor(); - void update(); -}; - struct pTimer : public QObject, public pObject { Q_OBJECT @@ -66,8 +57,9 @@ public: void setEnabled(bool enabled); void setInterval(unsigned milliseconds); - pTimer(Timer &timer) : timer(timer) {} + pTimer(Timer &timer) : pObject(timer), timer(timer) {} void constructor(); + void destructor(); public slots: void onTimeout(); @@ -105,22 +97,26 @@ public: Geometry frameMargin(); bool focused(); Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); void setBackgroundColor(const Color &color); void setFocused(); void setFullScreen(bool fullScreen); void setGeometry(const Geometry &geometry); - void setMenuFont(Font &font); + void setMenuFont(const string &font); void setMenuVisible(bool visible); void setResizable(bool resizable); - void setStatusFont(Font &font); + void setStatusFont(const string &font); void setStatusText(const string &text); void setStatusVisible(bool visible); void setTitle(const string &text); void setVisible(bool visible); - void setWidgetFont(Font &font); + void setWidgetFont(const string &font); - pWindow(Window &window) : window(window) {} + pWindow(Window &window) : pObject(window), window(window) {} void constructor(); + void destructor(); void updateFrameGeometry(); }; @@ -128,11 +124,12 @@ struct pAction : public pObject { Action &action; void setEnabled(bool enabled); - void setFont(Font &font); + void setFont(const string &font); void setVisible(bool visible); - pAction(Action &action) : action(action) {} + pAction(Action &action) : pObject(action), action(action) {} void constructor(); + void destructor(); }; struct pMenu : public pAction { @@ -140,11 +137,13 @@ struct pMenu : public pAction { QMenu *qtMenu; void append(Action &action); - void setFont(Font &font); + void remove(Action &action); + void setFont(const string &font); void setText(const string &text); pMenu(Menu &menu) : pAction(menu), menu(menu) {} void constructor(); + void destructor(); }; struct pSeparator : public pAction { @@ -153,6 +152,7 @@ struct pSeparator : public pAction { pSeparator(Separator &separator) : pAction(separator), separator(separator) {} void constructor(); + void destructor(); }; struct pItem : public QObject, public pAction { @@ -166,6 +166,7 @@ public: pItem(Item &item) : pAction(item), item(item) {} void constructor(); + void destructor(); public slots: void onTick(); @@ -184,6 +185,7 @@ public: pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} void constructor(); + void destructor(); public slots: void onTick(); @@ -204,26 +206,45 @@ public: pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} void constructor(); + void destructor(); public slots: void onTick(); }; -struct pWidget : public pObject { +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} + + void constructor() {} + void destructor() {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} + + void constructor() {} + void destructor() {} +}; + +struct pWidget : public pSizable { Widget &widget; QWidget *qtWidget; - Font& font(); virtual Geometry minimumGeometry(); void setEnabled(bool enabled); void setFocused(); - void setFont(Font &font); + void setFont(const string &font); virtual void setGeometry(const Geometry &geometry); - void setParent(Window &parent); void setVisible(bool visible); - pWidget(Widget &widget) : widget(widget) {} + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} void constructor(); + void destructor(); + virtual void orphan(); }; struct pButton : public QObject, public pWidget { @@ -238,6 +259,8 @@ public: pButton(Button &button) : pWidget(button), button(button) {} void constructor(); + void destructor(); + void orphan(); public slots: void onTick(); @@ -261,6 +284,8 @@ public: pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} void constructor(); + void destructor(); + void orphan(); public slots: }; @@ -279,6 +304,8 @@ public: pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} void constructor(); + void destructor(); + void orphan(); public slots: void onTick(); @@ -299,6 +326,8 @@ public: pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} void constructor(); + void destructor(); + void orphan(); public slots: void onChange(); @@ -326,6 +355,8 @@ public: pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} void constructor(); + void destructor(); + void orphan(); void keyPressEvent(QKeyEvent*); public slots: @@ -346,6 +377,8 @@ public: pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} void constructor(); + void destructor(); + void orphan(); public slots: void onChange(); @@ -365,6 +398,8 @@ public: pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} void constructor(); + void destructor(); + void orphan(); public slots: void onChange(); @@ -379,6 +414,8 @@ struct pLabel : public pWidget { pLabel(Label &label) : pWidget(label), label(label) {} void constructor(); + void destructor(); + void orphan(); }; struct pLineEdit : public QObject, public pWidget { @@ -395,6 +432,8 @@ public: pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} void constructor(); + void destructor(); + void orphan(); public slots: void onActivate(); @@ -424,6 +463,8 @@ public: pListView(ListView &listView) : pWidget(listView), listView(listView) {} void constructor(); + void destructor(); + void orphan(); public slots: void onActivate(); @@ -440,6 +481,8 @@ struct pProgressBar : public pWidget { pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} void constructor(); + void destructor(); + void orphan(); }; struct pRadioBox : public QObject, public pWidget { @@ -458,6 +501,8 @@ public: pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} void constructor(); + void destructor(); + void orphan(); public slots: void onTick(); @@ -478,6 +523,8 @@ public: pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} void constructor(); + void destructor(); + void orphan(); public slots: void onChange(); @@ -497,6 +544,8 @@ public: pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} void constructor(); + void destructor(); + void orphan(); public slots: void onChange(); @@ -516,6 +565,8 @@ public: pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} void constructor(); + void destructor(); + void orphan(); public slots: void onChange(); @@ -528,4 +579,6 @@ struct pViewport : public pWidget { pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} void constructor(); + void destructor(); + void orphan(); }; diff --git a/bsnes/phoenix/qt/timer.cpp b/bsnes/phoenix/qt/timer.cpp index eba78b5a..61f00ba8 100755 --- a/bsnes/phoenix/qt/timer.cpp +++ b/bsnes/phoenix/qt/timer.cpp @@ -16,6 +16,10 @@ void pTimer::constructor() { connect(qtTimer, SIGNAL(timeout()), SLOT(onTimeout())); } +void pTimer::destructor() { + delete qtTimer; +} + void pTimer::onTimeout() { if(timer.onTimeout) timer.onTimeout(); } diff --git a/bsnes/phoenix/qt/widget/button.cpp b/bsnes/phoenix/qt/widget/button.cpp index e6645dce..2be213d5 100755 --- a/bsnes/phoenix/qt/widget/button.cpp +++ b/bsnes/phoenix/qt/widget/button.cpp @@ -1,6 +1,5 @@ Geometry pButton::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(button.state.text); + Geometry geometry = pFont::geometry(qtWidget->font(), button.state.text); return { 0, 0, geometry.width + 20, geometry.height + 12 }; } @@ -11,6 +10,17 @@ void pButton::setText(const string &text) { void pButton::constructor() { qtWidget = qtButton = new QPushButton; connect(qtButton, SIGNAL(released()), SLOT(onTick())); + setText(button.state.text); +} + +void pButton::destructor() { + delete qtButton; + qtWidget = qtButton = 0; +} + +void pButton::orphan() { + destructor(); + constructor(); } void pButton::onTick() { diff --git a/bsnes/phoenix/qt/widget/canvas.cpp b/bsnes/phoenix/qt/widget/canvas.cpp index 05c661bc..cc79fd04 100755 --- a/bsnes/phoenix/qt/widget/canvas.cpp +++ b/bsnes/phoenix/qt/widget/canvas.cpp @@ -16,6 +16,20 @@ void pCanvas::update() { void pCanvas::constructor() { qtWidget = qtCanvas = new QtCanvas(*this); qtImage = new QImage(256, 256, QImage::Format_RGB32); + + update(); +} + +void pCanvas::destructor() { + delete qtCanvas; + delete qtImage; + qtWidget = qtCanvas = 0; + qtImage = 0; +} + +void pCanvas::orphan() { + destructor(); + constructor(); } void pCanvas::QtCanvas::paintEvent(QPaintEvent *event) { diff --git a/bsnes/phoenix/qt/widget/check-box.cpp b/bsnes/phoenix/qt/widget/check-box.cpp index 1cd89157..f23e9d3b 100755 --- a/bsnes/phoenix/qt/widget/check-box.cpp +++ b/bsnes/phoenix/qt/widget/check-box.cpp @@ -3,8 +3,7 @@ bool pCheckBox::checked() { } Geometry pCheckBox::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(checkBox.state.text); + Geometry geometry = pFont::geometry(qtWidget->font(), checkBox.state.text); return { 0, 0, geometry.width + 26, geometry.height + 6 }; } @@ -21,8 +20,22 @@ void pCheckBox::setText(const string &text) { void pCheckBox::constructor() { qtWidget = qtCheckBox = new QCheckBox; connect(qtCheckBox, SIGNAL(stateChanged(int)), SLOT(onTick())); + + setChecked(checkBox.state.checked); + setText(checkBox.state.text); +} + +void pCheckBox::destructor() { + delete qtCheckBox; + qtWidget = qtCheckBox = 0; +} + +void pCheckBox::orphan() { + destructor(); + constructor(); } void pCheckBox::onTick() { + checkBox.state.checked = checked(); if(locked == false && checkBox.onTick) checkBox.onTick(); } diff --git a/bsnes/phoenix/qt/widget/combo-box.cpp b/bsnes/phoenix/qt/widget/combo-box.cpp index 83090415..a26033f0 100755 --- a/bsnes/phoenix/qt/widget/combo-box.cpp +++ b/bsnes/phoenix/qt/widget/combo-box.cpp @@ -3,10 +3,9 @@ void pComboBox::append(const string &text) { } Geometry pComboBox::minimumGeometry() { - Font &font = this->font(); unsigned maximumWidth = 0; - foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(text).width); - Geometry geometry = font.geometry(" "); + foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(qtWidget->font(), text).width); + Geometry geometry = pFont::geometry(qtWidget->font(), " "); return { 0, 0, maximumWidth + 32, geometry.height + 12 }; } @@ -28,9 +27,25 @@ void pComboBox::setSelection(unsigned row) { void pComboBox::constructor() { qtWidget = qtComboBox = new QComboBox; connect(qtComboBox, SIGNAL(currentIndexChanged(int)), SLOT(onChange())); + + locked = true; + foreach(text, comboBox.state.text) append(text); + locked = false; + setSelection(comboBox.state.selection); +} + +void pComboBox::destructor() { + delete qtComboBox; + qtWidget = qtComboBox = 0; +} + +void pComboBox::orphan() { + destructor(); + constructor(); } void pComboBox::onChange() { + if(locked == true) return; comboBox.state.selection = selection(); - if(locked == false && comboBox.onChange) comboBox.onChange(); + if(comboBox.onChange) comboBox.onChange(); } diff --git a/bsnes/phoenix/qt/widget/hex-edit.cpp b/bsnes/phoenix/qt/widget/hex-edit.cpp index de26403b..a2f61203 100755 --- a/bsnes/phoenix/qt/widget/hex-edit.cpp +++ b/bsnes/phoenix/qt/widget/hex-edit.cpp @@ -80,6 +80,26 @@ void pHexEdit::constructor() { qtLayout->addWidget(qtScroll); connect(qtScroll, SIGNAL(actionTriggered(int)), SLOT(onScroll())); + + setColumns(hexEdit.state.columns); + setRows(hexEdit.state.rows); + setLength(hexEdit.state.length); + setOffset(hexEdit.state.offset); + update(); +} + +void pHexEdit::destructor() { + delete qtScroll; + delete qtLayout; + delete qtHexEdit; + qtWidget = qtHexEdit = 0; + qtLayout = 0; + qtScroll = 0; +} + +void pHexEdit::orphan() { + destructor(); + constructor(); } void pHexEdit::keyPressEvent(QKeyEvent *event) { diff --git a/bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp index 43f5c42f..5d770c68 100755 --- a/bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp +++ b/bsnes/phoenix/qt/widget/horizontal-scroll-bar.cpp @@ -21,6 +21,19 @@ void pHorizontalScrollBar::constructor() { qtScrollBar->setRange(0, 100); qtScrollBar->setPageStep(101 >> 3); connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + setLength(horizontalScrollBar.state.length); + setPosition(horizontalScrollBar.state.position); +} + +void pHorizontalScrollBar::destructor() { + delete qtScrollBar; + qtWidget = qtScrollBar = 0; +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); } void pHorizontalScrollBar::onChange() { diff --git a/bsnes/phoenix/qt/widget/horizontal-slider.cpp b/bsnes/phoenix/qt/widget/horizontal-slider.cpp index b29eab7b..4cfa7144 100755 --- a/bsnes/phoenix/qt/widget/horizontal-slider.cpp +++ b/bsnes/phoenix/qt/widget/horizontal-slider.cpp @@ -21,6 +21,19 @@ void pHorizontalSlider::constructor() { qtSlider->setRange(0, 100); qtSlider->setPageStep(101 >> 3); connect(qtSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + setLength(horizontalSlider.state.length); + setPosition(horizontalSlider.state.position); +} + +void pHorizontalSlider::destructor() { + delete qtSlider; + qtWidget = qtSlider = 0; +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); } void pHorizontalSlider::onChange() { diff --git a/bsnes/phoenix/qt/widget/label.cpp b/bsnes/phoenix/qt/widget/label.cpp index fb233fa0..98adf71f 100755 --- a/bsnes/phoenix/qt/widget/label.cpp +++ b/bsnes/phoenix/qt/widget/label.cpp @@ -1,6 +1,5 @@ Geometry pLabel::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(label.state.text); + Geometry geometry = pFont::geometry(qtWidget->font(), label.state.text); return { 0, 0, geometry.width, geometry.height }; } @@ -10,4 +9,15 @@ void pLabel::setText(const string &text) { void pLabel::constructor() { qtWidget = qtLabel = new QLabel; + setText(label.state.text); +} + +void pLabel::destructor() { + delete qtLabel; + qtWidget = qtLabel = 0; +} + +void pLabel::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/qt/widget/line-edit.cpp b/bsnes/phoenix/qt/widget/line-edit.cpp index 237e658c..6f992028 100755 --- a/bsnes/phoenix/qt/widget/line-edit.cpp +++ b/bsnes/phoenix/qt/widget/line-edit.cpp @@ -1,6 +1,5 @@ Geometry pLineEdit::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(lineEdit.state.text); + Geometry geometry = pFont::geometry(qtWidget->font(), lineEdit.state.text); return { 0, 0, geometry.width + 12, geometry.height + 12 }; } @@ -20,6 +19,18 @@ void pLineEdit::constructor() { qtWidget = qtLineEdit = new QLineEdit; connect(qtLineEdit, SIGNAL(returnPressed()), SLOT(onActivate())); connect(qtLineEdit, SIGNAL(textEdited(const QString&)), SLOT(onChange())); + setEditable(lineEdit.state.editable); + setText(lineEdit.state.text); +} + +void pLineEdit::destructor() { + delete qtLineEdit; + qtWidget = qtLineEdit = 0; +} + +void pLineEdit::orphan() { + destructor(); + constructor(); } void pLineEdit::onActivate() { diff --git a/bsnes/phoenix/qt/widget/list-view.cpp b/bsnes/phoenix/qt/widget/list-view.cpp index 6566a94f..ae169c7d 100755 --- a/bsnes/phoenix/qt/widget/list-view.cpp +++ b/bsnes/phoenix/qt/widget/list-view.cpp @@ -95,14 +95,34 @@ void pListView::setSelection(unsigned row) { void pListView::constructor() { qtWidget = qtListView = new QTreeWidget; - qtListView->setHeaderLabels(QStringList() << ""); - qtListView->setHeaderHidden(true); qtListView->setAllColumnsShowFocus(true); qtListView->setRootIsDecorated(false); connect(qtListView, SIGNAL(itemActivated(QTreeWidgetItem*, int)), SLOT(onActivate())); connect(qtListView, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(onChange(QTreeWidgetItem*))); connect(qtListView, SIGNAL(itemChanged(QTreeWidgetItem*, int)), SLOT(onTick(QTreeWidgetItem*))); + + setCheckable(listView.state.checkable); + setHeaderText(listView.state.headerText.size() ? listView.state.headerText : lstring{ " " }); + setHeaderVisible(listView.state.headerVisible); + foreach(row, listView.state.text) append(row); + if(listView.state.checkable) { + for(unsigned n = 0; n < listView.state.checked.size(); n++) { + setChecked(n, listView.state.checked[n]); + } + } + setSelected(listView.state.selected); + if(listView.state.selected) setSelection(listView.state.selection); +} + +void pListView::destructor() { + delete qtListView; + qtWidget = qtListView = 0; +} + +void pListView::orphan() { + destructor(); + constructor(); } void pListView::onActivate() { diff --git a/bsnes/phoenix/qt/widget/progress-bar.cpp b/bsnes/phoenix/qt/widget/progress-bar.cpp index 698c587e..a132f5bd 100755 --- a/bsnes/phoenix/qt/widget/progress-bar.cpp +++ b/bsnes/phoenix/qt/widget/progress-bar.cpp @@ -10,4 +10,16 @@ void pProgressBar::constructor() { qtWidget = qtProgressBar = new QProgressBar; qtProgressBar->setRange(0, 100); qtProgressBar->setTextVisible(false); + + setPosition(progressBar.state.position); +} + +void pProgressBar::destructor() { + delete qtProgressBar; + qtWidget = qtProgressBar = 0; +} + +void pProgressBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/qt/widget/radio-box.cpp b/bsnes/phoenix/qt/widget/radio-box.cpp index 22f0e911..f02ae64a 100755 --- a/bsnes/phoenix/qt/widget/radio-box.cpp +++ b/bsnes/phoenix/qt/widget/radio-box.cpp @@ -3,8 +3,7 @@ bool pRadioBox::checked() { } Geometry pRadioBox::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(radioBox.state.text); + Geometry geometry = pFont::geometry(qtWidget->font(), radioBox.state.text); return { 0, 0, geometry.width + 26, geometry.height + 6 }; } @@ -42,6 +41,20 @@ void pRadioBox::constructor() { qtGroup->addButton(qtRadioBox); qtRadioBox->setChecked(true); connect(qtRadioBox, SIGNAL(toggled(bool)), SLOT(onTick())); + + setText(radioBox.state.text); +} + +void pRadioBox::destructor() { + delete qtGroup; + delete qtRadioBox; + qtWidget = qtRadioBox = 0; + qtGroup = 0; +} + +void pRadioBox::orphan() { + destructor(); + constructor(); } void pRadioBox::onTick() { diff --git a/bsnes/phoenix/qt/widget/text-edit.cpp b/bsnes/phoenix/qt/widget/text-edit.cpp index 538bc103..67b8578f 100755 --- a/bsnes/phoenix/qt/widget/text-edit.cpp +++ b/bsnes/phoenix/qt/widget/text-edit.cpp @@ -24,6 +24,20 @@ string pTextEdit::text() { void pTextEdit::constructor() { qtWidget = qtTextEdit = new QTextEdit; connect(qtTextEdit, SIGNAL(textChanged()), SLOT(onChange())); + setEditable(textEdit.state.editable); + setText(textEdit.state.text); + setWordWrap(textEdit.state.wordWrap); +} + +void pTextEdit::destructor() { + if(sizable.state.layout) sizable.state.layout->remove(textEdit); + delete qtTextEdit; + qtWidget = qtTextEdit = 0; +} + +void pTextEdit::orphan() { + destructor(); + constructor(); } void pTextEdit::onChange() { diff --git a/bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp index a0638157..226a0274 100755 --- a/bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp +++ b/bsnes/phoenix/qt/widget/vertical-scroll-bar.cpp @@ -21,6 +21,19 @@ void pVerticalScrollBar::constructor() { qtScrollBar->setRange(0, 100); qtScrollBar->setPageStep(101 >> 3); connect(qtScrollBar, SIGNAL(valueChanged(int)), SLOT(onChange())); + + setLength(verticalScrollBar.state.length); + setPosition(verticalScrollBar.state.position); +} + +void pVerticalScrollBar::destructor() { + delete qtScrollBar; + qtWidget = qtScrollBar = 0; +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); } void pVerticalScrollBar::onChange() { diff --git a/bsnes/phoenix/qt/widget/vertical-slider.cpp b/bsnes/phoenix/qt/widget/vertical-slider.cpp index 10c05e50..a42c4cb8 100755 --- a/bsnes/phoenix/qt/widget/vertical-slider.cpp +++ b/bsnes/phoenix/qt/widget/vertical-slider.cpp @@ -21,6 +21,19 @@ void pVerticalSlider::constructor() { qtSlider->setRange(0, 100); qtSlider->setPageStep(101 >> 3); connect(qtSlider, SIGNAL(valueChanged(int)), SLOT(onChange())); + + setLength(verticalSlider.state.length); + setPosition(verticalSlider.state.position); +} + +void pVerticalSlider::destructor() { + delete qtSlider; + qtWidget = qtSlider = 0; +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); } void pVerticalSlider::onChange() { diff --git a/bsnes/phoenix/qt/widget/viewport.cpp b/bsnes/phoenix/qt/widget/viewport.cpp index fcc1c1a4..ed03c566 100755 --- a/bsnes/phoenix/qt/widget/viewport.cpp +++ b/bsnes/phoenix/qt/widget/viewport.cpp @@ -7,3 +7,13 @@ void pViewport::constructor() { qtWidget->setAttribute(Qt::WA_PaintOnScreen, true); qtWidget->setStyleSheet("background: #000000"); } + +void pViewport::destructor() { + delete qtWidget; + qtWidget = 0; +} + +void pViewport::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/qt/widget/widget.cpp b/bsnes/phoenix/qt/widget/widget.cpp index d79fc95f..e05f70a9 100755 --- a/bsnes/phoenix/qt/widget/widget.cpp +++ b/bsnes/phoenix/qt/widget/widget.cpp @@ -1,13 +1,10 @@ -Font& pWidget::font() { - if(widget.state.font) return *widget.state.font; - return pOS::defaultFont; -} - Geometry pWidget::minimumGeometry() { return { 0, 0, 0, 0 }; } void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; qtWidget->setEnabled(enabled); } @@ -15,28 +12,33 @@ void pWidget::setFocused() { qtWidget->setFocus(Qt::OtherFocusReason); } -void pWidget::setFont(Font &font) { - qtWidget->setFont(*font.p.qtFont); +void pWidget::setFont(const string &font) { + qtWidget->setFont(pFont::create(font)); } void pWidget::setGeometry(const Geometry &geometry) { qtWidget->setGeometry(geometry.x, geometry.y, geometry.width, geometry.height); } -void pWidget::setParent(Window &parent) { - if(!widget.state.font && parent.state.widgetFont) { - setFont(*parent.state.widgetFont); - } - qtWidget->setParent(parent.p.qtContainer); - widget.setVisible(widget.visible()); -} - void pWidget::setVisible(bool visible) { if(widget.state.abstract) visible = false; - if(widget.state.layout && widget.state.layout->visible() == false) visible = false; + if(sizable.state.layout == 0) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; qtWidget->setVisible(visible); } void pWidget::constructor() { if(widget.state.abstract) qtWidget = new QWidget; } + +void pWidget::destructor() { + if(widget.state.abstract) { + delete qtWidget; + qtWidget = 0; + } +} + +void pWidget::orphan() { + destructor(); + constructor(); +} diff --git a/bsnes/phoenix/qt/window.cpp b/bsnes/phoenix/qt/window.cpp index 7fa2bdff..b8b031b8 100755 --- a/bsnes/phoenix/qt/window.cpp +++ b/bsnes/phoenix/qt/window.cpp @@ -1,21 +1,22 @@ void pWindow::append(Layout &layout) { - layout.setParent(window); Geometry geometry = window.state.geometry; geometry.x = geometry.y = 0; layout.setGeometry(geometry); } void pWindow::append(Menu &menu) { - if(window.state.menuFont) menu.p.qtMenu->setFont(*window.state.menuFont->p.qtFont); + if(window.state.menuFont != "") menu.p.setFont(window.state.menuFont); + else menu.p.setFont("Sans, 8"); qtMenu->addMenu(menu.p.qtMenu); } void pWindow::append(Widget &widget) { - if(!widget.state.font && window.state.widgetFont) { - widget.setFont(*window.state.widgetFont); + if(widget.state.font == "") { + if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Sans, 8"); } widget.p.qtWidget->setParent(qtContainer); - widget.setVisible(widget.state.visible); + widget.setVisible(widget.visible()); } Color pWindow::backgroundColor() { @@ -49,6 +50,21 @@ Geometry pWindow::geometry() { return window.state.geometry; } +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + //QMenuBar::removeMenu() does not exist + qtMenu->clear(); + foreach(menu, window.state.menu) append(menu); +} + +void pWindow::remove(Widget &widget) { + //bugfix: orphan() destroys and recreates widgets (to disassociate them from their parent); + //attempting to create widget again after QApplication::quit() crashes libQtGui + if(qtApplication) widget.p.orphan(); +} + void pWindow::setBackgroundColor(const Color &color) { QPalette palette; palette.setColor(QPalette::Window, QColor(color.red, color.green, color.blue)); @@ -90,8 +106,8 @@ void pWindow::setGeometry(const Geometry &geometry_) { locked = false; } -void pWindow::setMenuFont(Font &font) { - qtMenu->setFont(*font.p.qtFont); +void pWindow::setMenuFont(const string &font) { + qtMenu->setFont(pFont::create(font)); foreach(item, window.state.menu) item.p.setFont(font); } @@ -111,8 +127,8 @@ void pWindow::setResizable(bool resizable) { qtStatus->setSizeGripEnabled(resizable); } -void pWindow::setStatusFont(Font &font) { - qtStatus->setFont(*font.p.qtFont); +void pWindow::setStatusFont(const string &font) { + qtStatus->setFont(pFont::create(font)); } void pWindow::setStatusText(const string &text) { @@ -138,7 +154,7 @@ void pWindow::setVisible(bool visible) { locked = false; } -void pWindow::setWidgetFont(Font &font) { +void pWindow::setWidgetFont(const string &font) { foreach(item, window.state.widget) { if(!item.state.font) item.setFont(font); } @@ -168,6 +184,16 @@ void pWindow::constructor() { qtLayout->addWidget(qtStatus); setGeometry(window.state.geometry); + setMenuFont("Sans, 8"); + setStatusFont("Sans, 8"); +} + +void pWindow::destructor() { + delete qtStatus; + delete qtContainer; + delete qtMenu; + delete qtLayout; + delete qtWindow; } void pWindow::updateFrameGeometry() { @@ -186,9 +212,10 @@ void pWindow::updateFrameGeometry() { } void pWindow::QtWindow::closeEvent(QCloseEvent *event) { + self.window.state.ignore = false; event->ignore(); - hide(); if(self.window.onClose) self.window.onClose(); + if(self.window.state.ignore == false) hide(); } void pWindow::QtWindow::moveEvent(QMoveEvent *event) { diff --git a/bsnes/phoenix/reference/action/check-item.cpp b/bsnes/phoenix/reference/action/check-item.cpp index 0d15c065..26970fc8 100755 --- a/bsnes/phoenix/reference/action/check-item.cpp +++ b/bsnes/phoenix/reference/action/check-item.cpp @@ -10,3 +10,6 @@ void pCheckItem::setText(const string &text) { void pCheckItem::constructor() { } + +void pCheckItem::destructor() { +} diff --git a/bsnes/phoenix/reference/action/item.cpp b/bsnes/phoenix/reference/action/item.cpp index 7e0062e8..d064389b 100755 --- a/bsnes/phoenix/reference/action/item.cpp +++ b/bsnes/phoenix/reference/action/item.cpp @@ -3,3 +3,6 @@ void pItem::setText(const string &text) { void pItem::constructor() { } + +void pItem::destructor() { +} diff --git a/bsnes/phoenix/reference/action/menu.cpp b/bsnes/phoenix/reference/action/menu.cpp index a90d6d74..c2c239f2 100755 --- a/bsnes/phoenix/reference/action/menu.cpp +++ b/bsnes/phoenix/reference/action/menu.cpp @@ -1,8 +1,14 @@ void pMenu::append(Action &action) { } +void pMenu::remove(Action &action) { +} + void pMenu::setText(const string &text) { } void pMenu::constructor() { } + +void pMenu::destructor() { +} diff --git a/bsnes/phoenix/reference/action/radio-item.cpp b/bsnes/phoenix/reference/action/radio-item.cpp index cb5b457b..fc732e04 100755 --- a/bsnes/phoenix/reference/action/radio-item.cpp +++ b/bsnes/phoenix/reference/action/radio-item.cpp @@ -13,3 +13,6 @@ void pRadioItem::setText(const string &text) { void pRadioItem::constructor() { } + +void pRadioItem::destructor() { +} diff --git a/bsnes/phoenix/reference/action/separator.cpp b/bsnes/phoenix/reference/action/separator.cpp index 782c2ea8..24a45c04 100755 --- a/bsnes/phoenix/reference/action/separator.cpp +++ b/bsnes/phoenix/reference/action/separator.cpp @@ -1,2 +1,5 @@ void pSeparator::constructor() { } + +void pSeparator::destructor() { +} diff --git a/bsnes/phoenix/reference/font.cpp b/bsnes/phoenix/reference/font.cpp index 77d98f70..bfda5c06 100755 --- a/bsnes/phoenix/reference/font.cpp +++ b/bsnes/phoenix/reference/font.cpp @@ -1,21 +1,3 @@ -Geometry pFont::geometry(const string &text) { +Geometry pFont::geometry(const string &description, const string &text) { return { 0, 0, 0, 0 }; } - -void pFont::setBold(bool bold) { -} - -void pFont::setFamily(const string &family) { -} - -void pFont::setItalic(bool italic) { -} - -void pFont::setSize(unsigned size) { -} - -void pFont::setUnderline(bool underline) { -} - -void pFont::constructor() { -} diff --git a/bsnes/phoenix/reference/reference.cpp b/bsnes/phoenix/reference/platform.cpp similarity index 98% rename from bsnes/phoenix/reference/reference.cpp rename to bsnes/phoenix/reference/platform.cpp index 7d2262bc..b35adcef 100755 --- a/bsnes/phoenix/reference/reference.cpp +++ b/bsnes/phoenix/reference/platform.cpp @@ -1,4 +1,4 @@ -#include "reference.hpp" +#include "platform.hpp" #include "font.cpp" #include "timer.cpp" diff --git a/bsnes/phoenix/reference/reference.hpp b/bsnes/phoenix/reference/platform.hpp similarity index 87% rename from bsnes/phoenix/reference/reference.hpp rename to bsnes/phoenix/reference/platform.hpp index d5872518..99523bfb 100755 --- a/bsnes/phoenix/reference/reference.hpp +++ b/bsnes/phoenix/reference/platform.hpp @@ -4,12 +4,19 @@ struct pMenu; struct pLayout; struct pWidget; +struct pFont { + static Geometry geometry(const string &description, const string &text); +}; + struct pObject { + Object &object; bool locked; - pObject() { - locked = false; - } + pObject(Object &object) : object(object), locked(locked) {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} }; struct pOS : public pObject { @@ -26,27 +33,13 @@ struct pOS : public pObject { static void initialize(); }; -struct pFont : public pObject { - Font &font; - - Geometry geometry(const string &text); - void setBold(bool bold); - void setFamily(const string &family); - void setItalic(bool italic); - void setSize(unsigned size); - void setUnderline(bool underline); - - pFont(Font &font) : font(font) {} - void constructor(); -}; - struct pTimer : public pObject { Timer &timer; void setEnabled(bool enabled); void setInterval(unsigned milliseconds); - pTimer(Timer &timer) : timer(timer) {} + pTimer(Timer &timer) : pObject(timer), timer(timer) {} void constructor(); }; @@ -67,21 +60,24 @@ struct pWindow : public pObject { bool focused(); Geometry frameMargin(); Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); void setBackgroundColor(const Color &color); void setFocused(); void setFullScreen(bool fullScreen); void setGeometry(const Geometry &geometry); - void setMenuFont(Font &font); + void setMenuFont(const string &font); void setMenuVisible(bool visible); void setResizable(bool resizable); - void setStatusFont(Font &font); + void setStatusFont(const string &font); void setStatusText(const string &text); void setStatusVisible(bool visible); void setTitle(const string &text); void setVisible(bool visible); - void setWidgetFont(Font &font); + void setWidgetFont(const string &font); - pWindow(Window &window) : window(window) {} + pWindow(Window &window) : pObject(window), window(window) {} void constructor(); }; @@ -91,7 +87,7 @@ struct pAction : public pObject { void setEnabled(bool enabled); void setVisible(bool visible); - pAction(Action &action) : action(action) {} + pAction(Action &action) : pObject(action), action(action) {} void constructor(); }; @@ -99,10 +95,12 @@ struct pMenu : public pAction { Menu &menu; void append(Action &action); + void remove(Action &action); void setText(const string &text); pMenu(Menu &menu) : pAction(menu), menu(menu) {} void constructor(); + void destructor(); }; struct pSeparator : public pAction { @@ -110,6 +108,7 @@ struct pSeparator : public pAction { pSeparator(Separator &separator) : pAction(separator), separator(separator) {} void constructor(); + void destructor(); }; struct pItem : public pAction { @@ -119,6 +118,7 @@ struct pItem : public pAction { pItem(Item &item) : pAction(item), item(item) {} void constructor(); + void destructor(); }; struct pCheckItem : public pAction { @@ -130,6 +130,7 @@ struct pCheckItem : public pAction { pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} void constructor(); + void destructor(); }; struct pRadioItem : public pAction { @@ -142,21 +143,33 @@ struct pRadioItem : public pAction { pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} void constructor(); + void destructor(); }; -struct pWidget : public pObject { +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { Widget &widget; bool enabled(); - Font& font(); Geometry minimumGeometry(); void setEnabled(bool enabled); void setFocused(); - void setFont(Font &font); + void setFont(const string &font); void setGeometry(const Geometry &geometry); void setVisible(bool visible); - pWidget(Widget &widget) : widget(widget) {} + pWidget(Widget &widget) : pSizable(widget), widget(widget) {} void constructor(); }; diff --git a/bsnes/phoenix/reference/widget/widget.cpp b/bsnes/phoenix/reference/widget/widget.cpp index a7787587..49a6c79e 100755 --- a/bsnes/phoenix/reference/widget/widget.cpp +++ b/bsnes/phoenix/reference/widget/widget.cpp @@ -2,10 +2,6 @@ bool pWidget::enabled() { return false; } -Font& pWidget::font() { - throw; -} - Geometry pWidget::minimumGeometry() { return { 0, 0, 0, 0 }; } @@ -16,7 +12,7 @@ void pWidget::setEnabled(bool enabled) { void pWidget::setFocused() { } -void pWidget::setFont(Font &font) { +void pWidget::setFont(const string &font) { } void pWidget::setGeometry(const Geometry &geometry) { diff --git a/bsnes/phoenix/reference/window.cpp b/bsnes/phoenix/reference/window.cpp index e9ceebb7..a865b619 100755 --- a/bsnes/phoenix/reference/window.cpp +++ b/bsnes/phoenix/reference/window.cpp @@ -23,6 +23,15 @@ Geometry pWindow::geometry() { return { 0, 0, 0, 0 }; } +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { +} + +void pWindow::remove(Widget &widget) { +} + void pWindow::setBackgroundColor(const Color &color) { } @@ -35,7 +44,7 @@ void pWindow::setFullScreen(bool fullScreen) { void pWindow::setGeometry(const Geometry &geometry) { } -void pWindow::setMenuFont(Font &font) { +void pWindow::setMenuFont(const string &font) { } void pWindow::setMenuVisible(bool visible) { @@ -44,7 +53,7 @@ void pWindow::setMenuVisible(bool visible) { void pWindow::setResizable(bool resizable) { } -void pWindow::setStatusFont(Font &font) { +void pWindow::setStatusFont(const string &font) { } void pWindow::setStatusText(const string &text) { @@ -59,7 +68,7 @@ void pWindow::setTitle(const string &text) { void pWindow::setVisible(bool visible) { } -void pWindow::setWidgetFont(Font &font) { +void pWindow::setWidgetFont(const string &font) { } void pWindow::constructor() { diff --git a/bsnes/phoenix/windows/action/check-item.cpp b/bsnes/phoenix/windows/action/check-item.cpp index 6f30339f..195deabd 100755 --- a/bsnes/phoenix/windows/action/check-item.cpp +++ b/bsnes/phoenix/windows/action/check-item.cpp @@ -3,7 +3,7 @@ bool pCheckItem::checked() { } void pCheckItem::setChecked(bool checked) { - if(parentMenu) CheckMenuItem(parentMenu, id, checked ? MF_CHECKED : MF_UNCHECKED); + if(parentMenu) CheckMenuItem(parentMenu->p.hmenu, id, checked ? MF_CHECKED : MF_UNCHECKED); } void pCheckItem::setText(const string &text) { @@ -12,3 +12,7 @@ void pCheckItem::setText(const string &text) { void pCheckItem::constructor() { } + +void pCheckItem::destructor() { + if(parentMenu) parentMenu->remove(checkItem); +} diff --git a/bsnes/phoenix/windows/action/item.cpp b/bsnes/phoenix/windows/action/item.cpp index 2755c425..2e24e6e9 100755 --- a/bsnes/phoenix/windows/action/item.cpp +++ b/bsnes/phoenix/windows/action/item.cpp @@ -4,3 +4,7 @@ void pItem::setText(const string &text) { void pItem::constructor() { } + +void pItem::destructor() { + if(parentMenu) parentMenu->remove(item); +} diff --git a/bsnes/phoenix/windows/action/menu.cpp b/bsnes/phoenix/windows/action/menu.cpp index 8e3763dc..ad1da691 100755 --- a/bsnes/phoenix/windows/action/menu.cpp +++ b/bsnes/phoenix/windows/action/menu.cpp @@ -1,7 +1,13 @@ void pMenu::append(Action &action) { + action.p.parentMenu = &menu; if(parentWindow) parentWindow->p.updateMenu(); } +void pMenu::remove(Action &action) { + if(parentWindow) parentWindow->p.updateMenu(); + action.p.parentMenu = 0; +} + void pMenu::setText(const string &text) { if(parentWindow) parentWindow->p.updateMenu(); } @@ -12,20 +18,21 @@ void pMenu::constructor() { //Windows actions lack the ability to toggle visibility. //To support this, menus must be destroyed and recreated when toggling any action's visibility. -void pMenu::update(Window &parentWindow, HMENU parentMenu) { - this->parentWindow = &parentWindow; +void pMenu::update(Window &parentWindow, Menu *parentMenu) { this->parentMenu = parentMenu; + this->parentWindow = &parentWindow; + if(hmenu) DestroyMenu(hmenu); hmenu = CreatePopupMenu(); foreach(action, menu.state.action) { + action.p.parentMenu = &menu; action.p.parentWindow = &parentWindow; - action.p.parentMenu = hmenu; unsigned enabled = action.state.enabled ? 0 : MF_GRAYED; if(dynamic_cast(&action)) { Menu &item = (Menu&)action; - item.p.update(parentWindow, hmenu); + item.p.update(parentWindow, &menu); AppendMenu(hmenu, MF_STRING | MF_POPUP | enabled, (UINT_PTR)item.p.hmenu, utf16_t(item.state.text)); } else if(dynamic_cast(&action)) { Separator &item = (Separator&)action; @@ -44,3 +51,12 @@ void pMenu::update(Window &parentWindow, HMENU parentMenu) { } } } + +void pMenu::destructor() { + if(parentMenu) { + parentMenu->remove(menu); + } else if(parentWindow) { + //belongs to window's main menubar + parentWindow->remove(menu); + } +} diff --git a/bsnes/phoenix/windows/action/radio-item.cpp b/bsnes/phoenix/windows/action/radio-item.cpp index b887623f..37b86631 100755 --- a/bsnes/phoenix/windows/action/radio-item.cpp +++ b/bsnes/phoenix/windows/action/radio-item.cpp @@ -7,7 +7,7 @@ void pRadioItem::setChecked() { //CheckMenuRadioItem takes: lo, hi, id; checking only id when lo <= id <= hi //phoenix does not force IDs to be linear, so to uncheck id, we use: lo == hi == id + 1 (out of range) //to check id, we use: lo == hi == id (only ID, but in range) - if(item.p.parentMenu) CheckMenuRadioItem(item.p.parentMenu, item.p.id, item.p.id, item.p.id + (id != item.p.id), MF_BYCOMMAND); + if(item.p.parentMenu) CheckMenuRadioItem(item.p.parentMenu->p.hmenu, item.p.id, item.p.id, item.p.id + (id != item.p.id), MF_BYCOMMAND); } } @@ -20,3 +20,7 @@ void pRadioItem::setText(const string &text) { void pRadioItem::constructor() { } + +void pRadioItem::destructor() { + if(parentMenu) parentMenu->remove(radioItem); +} diff --git a/bsnes/phoenix/windows/action/separator.cpp b/bsnes/phoenix/windows/action/separator.cpp index 782c2ea8..fac38eca 100755 --- a/bsnes/phoenix/windows/action/separator.cpp +++ b/bsnes/phoenix/windows/action/separator.cpp @@ -1,2 +1,6 @@ void pSeparator::constructor() { } + +void pSeparator::destructor() { + if(parentMenu) parentMenu->remove(separator); +} diff --git a/bsnes/phoenix/windows/font.cpp b/bsnes/phoenix/windows/font.cpp index 4153cc65..211b8c62 100755 --- a/bsnes/phoenix/windows/font.cpp +++ b/bsnes/phoenix/windows/font.cpp @@ -1,12 +1,37 @@ -static HFONT Font_createFont(const string &family, unsigned size, bool bold, bool italic, bool underline) { +Geometry pFont::geometry(const string &description, const string &text) { + HFONT hfont = pFont::create(description); + Geometry geometry = pFont::geometry(hfont, text); + pFont::free(hfont); + return geometry; +} + +HFONT pFont::create(const string &description) { + lstring part; + part.split(",", description); + foreach(item, part) item.trim(" "); + + string family = part[0]; + unsigned size = decimal(part[1]); + bool bold = part[2].position("Bold"); + bool italic = part[2].position("Italic"); + if(family == "") family = "Tahoma"; + if(size == 0) size = 8; + return CreateFont( -(size * 96.0 / 72.0 + 0.5), - 0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, underline, 0, 0, 0, 0, 0, 0, + 0, 0, 0, bold == false ? FW_NORMAL : FW_BOLD, italic, 0, 0, 0, 0, 0, 0, 0, utf16_t(family) ); } -Geometry pFont::geometry(const string &text) { +void pFont::free(HFONT hfont) { + DeleteObject(hfont); +} + +Geometry pFont::geometry(HFONT hfont, const string &text_) { + //temporary fix: empty text string returns height of zero; bad for eg Button height + string text = (text_ == "" ? " " : text_); + HDC hdc = GetDC(0); SelectObject(hdc, hfont); RECT rc = { 0, 0, 0, 0 }; @@ -14,38 +39,3 @@ Geometry pFont::geometry(const string &text) { ReleaseDC(0, hdc); return { 0, 0, rc.right, rc.bottom }; } - -unsigned pFont::height() { - return geometry(" ").height; -} - -void pFont::setBold(bool bold) { - if(hfont) { DeleteObject(hfont); hfont = 0; } - hfont = Font_createFont(font.state.family, font.state.size, font.state.bold, font.state.italic, font.state.underline); -} - -void pFont::setFamily(const string &family) { - if(hfont) { DeleteObject(hfont); hfont = 0; } - hfont = Font_createFont(font.state.family, font.state.size, font.state.bold, font.state.italic, font.state.underline); -} - -void pFont::setItalic(bool italic) { - if(hfont) { DeleteObject(hfont); hfont = 0; } - hfont = Font_createFont(font.state.family, font.state.size, font.state.bold, font.state.italic, font.state.underline); -} - -void pFont::setSize(unsigned size) { - if(hfont) { DeleteObject(hfont); hfont = 0; } - hfont = Font_createFont(font.state.family, font.state.size, font.state.bold, font.state.italic, font.state.underline); -} - -void pFont::setUnderline(bool underline) { - if(hfont) { DeleteObject(hfont); hfont = 0; } - hfont = Font_createFont(font.state.family, font.state.size, font.state.bold, font.state.italic, font.state.underline); -} - -void pFont::constructor() { - hfont = Font_createFont("Tahoma", 8, false, false, false); - font.setFamily("Tahoma"); - font.setSize(8); -} diff --git a/bsnes/phoenix/windows/object.cpp b/bsnes/phoenix/windows/object.cpp index 975fa377..39d68d08 100755 --- a/bsnes/phoenix/windows/object.cpp +++ b/bsnes/phoenix/windows/object.cpp @@ -1,6 +1,6 @@ array pObject::objects; -pObject::pObject() { +pObject::pObject(Object &object) : object(object) { static unsigned uniqueId = 100; objects.append(this); id = uniqueId++; diff --git a/bsnes/phoenix/windows/windows.cpp b/bsnes/phoenix/windows/platform.cpp similarity index 98% rename from bsnes/phoenix/windows/windows.cpp rename to bsnes/phoenix/windows/platform.cpp index 565099e4..a9ac5c50 100755 --- a/bsnes/phoenix/windows/windows.cpp +++ b/bsnes/phoenix/windows/platform.cpp @@ -1,4 +1,4 @@ -#include "windows.hpp" +#include "platform.hpp" #include "object.cpp" #include "font.cpp" @@ -34,8 +34,6 @@ static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM); -pOS::State *pOS::state = 0; - Geometry pOS::availableGeometry() { RECT rc; SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); @@ -169,11 +167,6 @@ void pOS::initialize() { CoInitialize(0); InitCommonControls(); - state = new State; - - state->defaultFont.setFamily("Tahoma"); - state->defaultFont.setSize(8); - WNDCLASS wc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -253,8 +246,9 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM switch(msg) { case WM_CLOSE: { + window.state.ignore = false; if(window.onClose) window.onClose(); - window.setVisible(false); + if(window.state.ignore == false) window.setVisible(false); return TRUE; } @@ -449,13 +443,13 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM HorizontalScrollBar &horizontalScrollBar = (HorizontalScrollBar&)*object; if(horizontalScrollBar.state.position != info.nPos) { horizontalScrollBar.state.position = info.nPos; - horizontalScrollBar.onChange(); + if(horizontalScrollBar.onChange) horizontalScrollBar.onChange(); } } else { VerticalScrollBar &verticalScrollBar = (VerticalScrollBar&)*object; if(verticalScrollBar.state.position != info.nPos) { verticalScrollBar.state.position = info.nPos; - verticalScrollBar.onChange(); + if(verticalScrollBar.onChange) verticalScrollBar.onChange(); } } diff --git a/bsnes/phoenix/windows/windows.hpp b/bsnes/phoenix/windows/platform.hpp similarity index 80% rename from bsnes/phoenix/windows/windows.hpp rename to bsnes/phoenix/windows/platform.hpp index 1cc92696..14f741ce 100755 --- a/bsnes/phoenix/windows/windows.hpp +++ b/bsnes/phoenix/windows/platform.hpp @@ -4,22 +4,29 @@ struct pMenu; struct pLayout; struct pWidget; +struct pFont { + static Geometry geometry(const string &description, const string &text); + + static HFONT create(const string &description); + static void free(HFONT hfont); + static Geometry geometry(HFONT hfont, const string &text); +}; + struct pObject { - unsigned id; + Object &object; + uintptr_t id; bool locked; static array objects; - pObject(); + pObject(Object &object); static pObject* find(unsigned id); - virtual void unused() {} + virtual ~pObject() {} + + void constructor() {} + void destructor() {} }; struct pOS : public pObject { - struct State { - Font defaultFont; - }; - static State *state; - static Geometry availableGeometry(); static Geometry desktopGeometry(); static string fileLoad(Window &parent, const string &path, const lstring &filter); @@ -33,22 +40,6 @@ struct pOS : public pObject { static void initialize(); }; -struct pFont : public pObject { - Font &font; - HFONT hfont; - - Geometry geometry(const string &text); - unsigned height(); - void setBold(bool bold); - void setFamily(const string &family); - void setItalic(bool italic); - void setSize(unsigned size); - void setUnderline(bool underline); - - pFont(Font &font) : font(font) {} - void constructor(); -}; - struct pTimer : public pObject { Timer &timer; UINT_PTR htimer; @@ -56,7 +47,7 @@ struct pTimer : public pObject { void setEnabled(bool enabled); void setInterval(unsigned milliseconds); - pTimer(Timer &timer) : timer(timer) {} + pTimer(Timer &timer) : pObject(timer), timer(timer) {} void constructor(); }; @@ -72,6 +63,7 @@ struct pWindow : public pObject { HWND hwnd; HMENU hmenu; HWND hstatus; + HFONT hstatusfont; HBRUSH brush; COLORREF brushColor; @@ -82,34 +74,38 @@ struct pWindow : public pObject { bool focused(); Geometry frameMargin(); Geometry geometry(); + void remove(Layout &layout); + void remove(Menu &menu); + void remove(Widget &widget); void setBackgroundColor(const Color &color); void setFocused(); void setFullScreen(bool fullScreen); void setGeometry(const Geometry &geometry); - void setMenuFont(Font &font); + void setMenuFont(const string &font); void setMenuVisible(bool visible); void setResizable(bool resizable); - void setStatusFont(Font &font); + void setStatusFont(const string &font); void setStatusText(const string &text); void setStatusVisible(bool visible); void setTitle(const string &text); void setVisible(bool visible); - void setWidgetFont(Font &font); + void setWidgetFont(const string &font); - pWindow(Window &window) : window(window) {} + pWindow(Window &window) : pObject(window), window(window) {} void constructor(); + void destructor(); void updateMenu(); }; struct pAction : public pObject { Action &action; - HMENU parentMenu; + Menu *parentMenu; Window *parentWindow; void setEnabled(bool enabled); void setVisible(bool visible); - pAction(Action &action) : action(action) {} + pAction(Action &action) : pObject(action), action(action) {} void constructor(); }; @@ -118,11 +114,13 @@ struct pMenu : public pAction { HMENU hmenu; void append(Action &action); + void remove(Action &action); void setText(const string &text); pMenu(Menu &menu) : pAction(menu), menu(menu) {} void constructor(); - void update(Window &parentWindow, HMENU parentMenu); + void destructor(); + void update(Window &parentWindow, Menu *parentMenu = 0); }; struct pSeparator : public pAction { @@ -130,6 +128,7 @@ struct pSeparator : public pAction { pSeparator(Separator &separator) : pAction(separator), separator(separator) {} void constructor(); + void destructor(); }; struct pItem : public pAction { @@ -139,6 +138,7 @@ struct pItem : public pAction { pItem(Item &item) : pAction(item), item(item) {} void constructor(); + void destructor(); }; struct pCheckItem : public pAction { @@ -150,6 +150,7 @@ struct pCheckItem : public pAction { pCheckItem(CheckItem &checkItem) : pAction(checkItem), checkItem(checkItem) {} void constructor(); + void destructor(); }; struct pRadioItem : public pAction { @@ -162,25 +163,41 @@ struct pRadioItem : public pAction { pRadioItem(RadioItem &radioItem) : pAction(radioItem), radioItem(radioItem) {} void constructor(); + void destructor(); }; -struct pWidget : public pObject { +struct pSizable : public pObject { + Sizable &sizable; + + pSizable(Sizable &sizable) : pObject(sizable), sizable(sizable) {} +}; + +struct pLayout : public pSizable { + Layout &layout; + + pLayout(Layout &layout) : pSizable(layout), layout(layout) {} +}; + +struct pWidget : public pSizable { Widget &widget; + Window *parentWindow; HWND hwnd; + HFONT hfont; bool enabled(); - Font& font(); virtual Geometry minimumGeometry(); void setEnabled(bool enabled); void setFocused(); - void setFont(Font &font); + void setFont(const string &font); virtual void setGeometry(const Geometry &geometry); void setVisible(bool visible); - pWidget(Widget &widget) : widget(widget) {} + pWidget(Widget &widget) : pSizable(widget), widget(widget) { parentWindow = &Window::None; } void constructor(); + void destructor(); + virtual void orphan(); void setDefaultFont(); - virtual void setParent(Window &parent); + void synchronize(); }; struct pButton : public pWidget { @@ -191,7 +208,8 @@ struct pButton : public pWidget { pButton(Button &button) : pWidget(button), button(button) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pCanvas : public pWidget { @@ -204,7 +222,8 @@ struct pCanvas : public pWidget { pCanvas(Canvas &canvas) : pWidget(canvas), canvas(canvas) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pCheckBox : public pWidget { @@ -217,7 +236,8 @@ struct pCheckBox : public pWidget { pCheckBox(CheckBox &checkBox) : pWidget(checkBox), checkBox(checkBox) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pComboBox : public pWidget { @@ -231,8 +251,9 @@ struct pComboBox : public pWidget { pComboBox(ComboBox &comboBox) : pWidget(comboBox), comboBox(comboBox) {} void constructor(); + void destructor(); + void orphan(); void setGeometry(const Geometry &geometry); - void setParent(Window &parent); }; struct pHexEdit : public pWidget { @@ -247,8 +268,9 @@ struct pHexEdit : public pWidget { pHexEdit(HexEdit &hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {} void constructor(); + void destructor(); + void orphan(); bool keyPress(unsigned key); - void setParent(Window &parent); }; struct pHorizontalScrollBar : public pWidget { @@ -261,7 +283,8 @@ struct pHorizontalScrollBar : public pWidget { pHorizontalScrollBar(HorizontalScrollBar &horizontalScrollBar) : pWidget(horizontalScrollBar), horizontalScrollBar(horizontalScrollBar) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pHorizontalSlider : public pWidget { @@ -274,7 +297,8 @@ struct pHorizontalSlider : public pWidget { pHorizontalSlider(HorizontalSlider &horizontalSlider) : pWidget(horizontalSlider), horizontalSlider(horizontalSlider) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pLabel : public pWidget { @@ -285,7 +309,8 @@ struct pLabel : public pWidget { pLabel(Label &label) : pWidget(label), label(label) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pLineEdit : public pWidget { @@ -298,7 +323,8 @@ struct pLineEdit : public pWidget { pLineEdit(LineEdit &lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pListView : public pWidget { @@ -321,8 +347,9 @@ struct pListView : public pWidget { pListView(ListView &listView) : pWidget(listView), listView(listView) {} void constructor(); + void destructor(); + void orphan(); void setGeometry(const Geometry &geometry); - void setParent(Window &parent); }; struct pProgressBar : public pWidget { @@ -333,7 +360,8 @@ struct pProgressBar : public pWidget { pProgressBar(ProgressBar &progressBar) : pWidget(progressBar), progressBar(progressBar) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pRadioBox : public pWidget { @@ -347,7 +375,8 @@ struct pRadioBox : public pWidget { pRadioBox(RadioBox &radioBox) : pWidget(radioBox), radioBox(radioBox) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pTextEdit : public pWidget { @@ -361,7 +390,8 @@ struct pTextEdit : public pWidget { pTextEdit(TextEdit &textEdit) : pWidget(textEdit), textEdit(textEdit) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pVerticalScrollBar : public pWidget { @@ -374,7 +404,8 @@ struct pVerticalScrollBar : public pWidget { pVerticalScrollBar(VerticalScrollBar &verticalScrollBar) : pWidget(verticalScrollBar), verticalScrollBar(verticalScrollBar) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pVerticalSlider : public pWidget { @@ -387,7 +418,8 @@ struct pVerticalSlider : public pWidget { pVerticalSlider(VerticalSlider &verticalSlider) : pWidget(verticalSlider), verticalSlider(verticalSlider) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; struct pViewport : public pWidget { @@ -397,5 +429,6 @@ struct pViewport : public pWidget { pViewport(Viewport &viewport) : pWidget(viewport), viewport(viewport) {} void constructor(); - void setParent(Window &parent); + void destructor(); + void orphan(); }; diff --git a/bsnes/phoenix/windows/widget/button.cpp b/bsnes/phoenix/windows/widget/button.cpp index 06b46d74..9286f6e5 100755 --- a/bsnes/phoenix/windows/widget/button.cpp +++ b/bsnes/phoenix/windows/widget/button.cpp @@ -1,7 +1,6 @@ Geometry pButton::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(button.state.text); - return { 0, 0, geometry.width + 20, font.p.height() + 10 }; + Geometry geometry = pFont::geometry(hfont, button.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 10 }; } void pButton::setText(const string &text) { @@ -9,14 +8,18 @@ void pButton::setText(const string &text) { } void pButton::constructor() { - setParent(Window::None); -} - -void pButton::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP | WS_VISIBLE, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + hwnd = CreateWindow(L"BUTTON", L"", WS_CHILD | WS_TABSTOP, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&button); setDefaultFont(); setText(button.state.text); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pButton::destructor() { + DestroyWindow(hwnd); +} + +void pButton::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/canvas.cpp b/bsnes/phoenix/windows/widget/canvas.cpp index 9964b401..78f7152c 100755 --- a/bsnes/phoenix/windows/widget/canvas.cpp +++ b/bsnes/phoenix/windows/widget/canvas.cpp @@ -44,12 +44,16 @@ void pCanvas::update() { void pCanvas::constructor() { bufferRGB = new uint32_t[256 * 256](); - setParent(Window::None); + hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas); + synchronize(); } -void pCanvas::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindow(L"phoenix_canvas", L"", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&canvas); - widget.setVisible(widget.visible()); +void pCanvas::destructor() { + DestroyWindow(hwnd); +} + +void pCanvas::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/check-box.cpp b/bsnes/phoenix/windows/widget/check-box.cpp index 769f1870..8f0d2eb8 100755 --- a/bsnes/phoenix/windows/widget/check-box.cpp +++ b/bsnes/phoenix/windows/widget/check-box.cpp @@ -3,9 +3,8 @@ bool pCheckBox::checked() { } Geometry pCheckBox::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(checkBox.state.text); - return { 0, 0, geometry.width + 20, font.p.height() + 4 }; + Geometry geometry = pFont::geometry(hfont, checkBox.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 4 }; } void pCheckBox::setChecked(bool checked) { @@ -17,18 +16,24 @@ void pCheckBox::setText(const string &text) { } void pCheckBox::constructor() { - setParent(Window::None); -} - -void pCheckBox::setParent(Window &parent) { hwnd = CreateWindow( L"BUTTON", L"", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + WS_CHILD | WS_TABSTOP | BS_CHECKBOX, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&checkBox); setDefaultFont(); if(checkBox.state.checked) setChecked(true); setText(checkBox.state.text); - widget.setVisible(widget.visible()); + synchronize(); + +} + +void pCheckBox::destructor() { + DestroyWindow(hwnd); +} + +void pCheckBox::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/combo-box.cpp b/bsnes/phoenix/windows/widget/combo-box.cpp index b2cf049a..62da6482 100755 --- a/bsnes/phoenix/windows/widget/combo-box.cpp +++ b/bsnes/phoenix/windows/widget/combo-box.cpp @@ -4,10 +4,9 @@ void pComboBox::append(const string &text) { } Geometry pComboBox::minimumGeometry() { - Font &font = this->font(); unsigned maximumWidth = 0; - foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, font.geometry(text).width); - return { 0, 0, maximumWidth + 24, font.p.height() + 10 }; + foreach(text, comboBox.state.text) maximumWidth = max(maximumWidth, pFont::geometry(hfont, text).width); + return { 0, 0, maximumWidth + 24, pFont::geometry(hfont, " ").height + 10 }; } void pComboBox::reset() { @@ -23,7 +22,26 @@ void pComboBox::setSelection(unsigned row) { } void pComboBox::constructor() { - setParent(Window::None); + hwnd = CreateWindow( + L"COMBOBOX", L"", + WS_CHILD | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS, + 0, 0, 0, 0, + parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&comboBox); + setDefaultFont(); + foreach(text, comboBox.state.text) append(text); + setSelection(comboBox.state.selection); + synchronize(); +} + +void pComboBox::destructor() { + DestroyWindow(hwnd); +} + +void pComboBox::orphan() { + destructor(); + constructor(); } void pComboBox::setGeometry(const Geometry &geometry) { @@ -33,18 +51,3 @@ void pComboBox::setGeometry(const Geometry &geometry) { unsigned adjustedHeight = geometry.height - ((rc.bottom - rc.top) - SendMessage(hwnd, CB_GETITEMHEIGHT, (WPARAM)-1, 0)); SendMessage(hwnd, CB_SETITEMHEIGHT, (WPARAM)-1, adjustedHeight); } - -void pComboBox::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindow( - L"COMBOBOX", L"", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS, - 0, 0, 0, 0, - parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 - ); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&comboBox); - setDefaultFont(); - foreach(text, comboBox.state.text) append(text); - setSelection(comboBox.state.selection); - widget.setVisible(widget.visible()); -} diff --git a/bsnes/phoenix/windows/widget/hex-edit.cpp b/bsnes/phoenix/windows/widget/hex-edit.cpp index 5c5d2117..789f4faf 100755 --- a/bsnes/phoenix/windows/widget/hex-edit.cpp +++ b/bsnes/phoenix/windows/widget/hex-edit.cpp @@ -62,7 +62,27 @@ void pHexEdit::update() { } void pHexEdit::constructor() { - setParent(Window::None); + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, L"EDIT", L"", + WS_CHILD | WS_TABSTOP | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + ); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&hexEdit); + setDefaultFont(); + update(); + + windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc); + synchronize(); +} + +void pHexEdit::destructor() { + DestroyWindow(hwnd); +} + +void pHexEdit::orphan() { + destructor(); + constructor(); } bool pHexEdit::keyPress(unsigned scancode) { @@ -114,19 +134,3 @@ bool pHexEdit::keyPress(unsigned scancode) { return true; } - -void pHexEdit::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindowEx( - WS_EX_CLIENTEDGE, L"EDIT", L"", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 - ); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&hexEdit); - setDefaultFont(); - update(); - - windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC); - SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc); - widget.setVisible(widget.visible()); -} diff --git a/bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp b/bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp index e55490fd..250ac247 100755 --- a/bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp +++ b/bsnes/phoenix/windows/widget/horizontal-scroll-bar.cpp @@ -12,23 +12,27 @@ void pHorizontalScrollBar::setLength(unsigned length) { horizontalScrollBar.setPosition(0); } -void pHorizontalScrollBar::setPosition(unsigned position) { return; +void pHorizontalScrollBar::setPosition(unsigned position) { SetScrollPos(hwnd, SB_CTL, position, TRUE); } void pHorizontalScrollBar::constructor() { - setParent(Window::None); -} - -void pHorizontalScrollBar::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindow( - L"SCROLLBAR", L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP | SBS_HORZ, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + L"SCROLLBAR", L"", WS_CHILD | WS_TABSTOP | SBS_HORZ, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalScrollBar); unsigned position = horizontalScrollBar.state.position; setLength(horizontalScrollBar.state.length); - setPosition(position); - widget.setVisible(widget.visible()); + horizontalScrollBar.setPosition(position); + synchronize(); +} + +void pHorizontalScrollBar::destructor() { + DestroyWindow(hwnd); +} + +void pHorizontalScrollBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/horizontal-slider.cpp b/bsnes/phoenix/windows/widget/horizontal-slider.cpp index a242a9c1..807086ae 100755 --- a/bsnes/phoenix/windows/widget/horizontal-slider.cpp +++ b/bsnes/phoenix/windows/widget/horizontal-slider.cpp @@ -18,18 +18,22 @@ void pHorizontalSlider::setPosition(unsigned position) { } void pHorizontalSlider::constructor() { - setParent(Window::None); -} - -void pHorizontalSlider::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindow( - TRACKBAR_CLASS, L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&horizontalSlider); unsigned position = horizontalSlider.state.position; setLength(horizontalSlider.state.length); - setPosition(position); - widget.setVisible(widget.visible()); + horizontalSlider.setPosition(position); + synchronize(); +} + +void pHorizontalSlider::destructor() { + DestroyWindow(hwnd); +} + +void pHorizontalSlider::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/label.cpp b/bsnes/phoenix/windows/widget/label.cpp index 1e30636d..53b894f5 100755 --- a/bsnes/phoenix/windows/widget/label.cpp +++ b/bsnes/phoenix/windows/widget/label.cpp @@ -1,6 +1,5 @@ Geometry pLabel::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(label.state.text); + Geometry geometry = pFont::geometry(hfont, label.state.text); return { 0, 0, geometry.width, geometry.height }; } @@ -10,16 +9,20 @@ void pLabel::setText(const string &text) { } void pLabel::constructor() { - setParent(Window::None); -} - -void pLabel::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&label); setDefaultFont(); setText(label.state.text); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pLabel::destructor() { + DestroyWindow(hwnd); +} + +void pLabel::orphan() { + destructor(); + constructor(); } static LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -39,7 +42,7 @@ static LRESULT CALLBACK Label_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPA GetClientRect(hwnd, &rc); FillRect(ps.hdc, &rc, window->p.brush ? window->p.brush : GetSysColorBrush(COLOR_3DFACE)); SetBkColor(ps.hdc, window->p.brush ? window->p.brushColor : GetSysColor(COLOR_3DFACE)); - SelectObject(ps.hdc, ((Widget*)label)->state.font ? ((Widget*)label)->state.font->p.hfont : pOS::state->defaultFont.p.hfont); + SelectObject(ps.hdc, ((Widget*)label)->p.hfont); unsigned length = GetWindowTextLength(hwnd); wchar_t text[length + 1]; GetWindowText(hwnd, text, length + 1); diff --git a/bsnes/phoenix/windows/widget/line-edit.cpp b/bsnes/phoenix/windows/widget/line-edit.cpp index 35802104..eb6a8fb7 100755 --- a/bsnes/phoenix/windows/widget/line-edit.cpp +++ b/bsnes/phoenix/windows/widget/line-edit.cpp @@ -1,7 +1,6 @@ Geometry pLineEdit::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(lineEdit.state.text); - return { 0, 0, geometry.width + 12, font.p.height() + 10 }; + Geometry geometry = pFont::geometry(hfont, lineEdit.state.text); + return { 0, 0, geometry.width + 12, geometry.height + 10 }; } void pLineEdit::setEditable(bool editable) { @@ -23,19 +22,24 @@ string pLineEdit::text() { } void pLineEdit::constructor() { - setParent(Window::None); -} - -void pLineEdit::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL | ES_AUTOVSCROLL, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&lineEdit); setDefaultFont(); setEditable(lineEdit.state.editable); setText(lineEdit.state.text); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pLineEdit::destructor() { + lineEdit.state.text = text(); + DestroyWindow(hwnd); +} + +void pLineEdit::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/list-view.cpp b/bsnes/phoenix/windows/widget/list-view.cpp index 925bbeda..bc985a85 100755 --- a/bsnes/phoenix/windows/widget/list-view.cpp +++ b/bsnes/phoenix/windows/widget/list-view.cpp @@ -16,7 +16,7 @@ void pListView::append(const lstring &list) { } void pListView::autoSizeColumns() { - for(unsigned n = 0; n < listView.state.headerText.size(); n++) { + for(unsigned n = 0; n < max(1, listView.state.headerText.size()); n++) { ListView_SetColumnWidth(hwnd, n, LVSCW_AUTOSIZE_USEHEADER); } } @@ -106,21 +106,10 @@ void pListView::setSelection(unsigned row) { void pListView::constructor() { lostFocus = false; - setParent(Window::None); - listView.setHeaderText(""); -} - -void pListView::setGeometry(const Geometry &geometry) { - pWidget::setGeometry(geometry); - autoSizeColumns(); -} - -void pListView::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | LVS_NOCOLUMNHEADER, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&listView); setDefaultFont(); @@ -131,5 +120,19 @@ void pListView::setParent(Window &parent) { foreach(checked, listView.state.checked, n) setChecked(n, checked); if(listView.state.selected) setSelection(listView.state.selection); autoSizeColumns(); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pListView::destructor() { + DestroyWindow(hwnd); +} + +void pListView::orphan() { + destructor(); + constructor(); +} + +void pListView::setGeometry(const Geometry &geometry) { + pWidget::setGeometry(geometry); + autoSizeColumns(); } diff --git a/bsnes/phoenix/windows/widget/progress-bar.cpp b/bsnes/phoenix/windows/widget/progress-bar.cpp index fdd3ef4e..f4703f1e 100755 --- a/bsnes/phoenix/windows/widget/progress-bar.cpp +++ b/bsnes/phoenix/windows/widget/progress-bar.cpp @@ -7,15 +7,19 @@ void pProgressBar::setPosition(unsigned position) { } void pProgressBar::constructor() { - setParent(Window::None); -} - -void pProgressBar::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | WS_VISIBLE | PBS_SMOOTH, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | PBS_SMOOTH, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&progressBar); SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessage(hwnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); setPosition(progressBar.state.position); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pProgressBar::destructor() { + DestroyWindow(hwnd); +} + +void pProgressBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/radio-box.cpp b/bsnes/phoenix/windows/widget/radio-box.cpp index e24afcbe..126db738 100755 --- a/bsnes/phoenix/windows/widget/radio-box.cpp +++ b/bsnes/phoenix/windows/widget/radio-box.cpp @@ -3,9 +3,8 @@ bool pRadioBox::checked() { } Geometry pRadioBox::minimumGeometry() { - Font &font = this->font(); - Geometry geometry = font.geometry(radioBox.state.text); - return { 0, 0, geometry.width + 20, font.p.height() + 4 }; + Geometry geometry = pFont::geometry(hfont, radioBox.state.text); + return { 0, 0, geometry.width + 20, geometry.height + 4 }; } void pRadioBox::setChecked() { @@ -22,18 +21,23 @@ void pRadioBox::setText(const string &text) { } void pRadioBox::constructor() { - setParent(Window::None); -} - -void pRadioBox::setParent(Window &parent) { hwnd = CreateWindow( L"BUTTON", L"", - WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + WS_CHILD | WS_TABSTOP | BS_RADIOBUTTON, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&radioBox); setDefaultFont(); if(radioBox.state.checked) setChecked(); setText(radioBox.state.text); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pRadioBox::destructor() { + DestroyWindow(hwnd); +} + +void pRadioBox::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/text-edit.cpp b/bsnes/phoenix/windows/widget/text-edit.cpp index f0552ca1..4c7dd404 100755 --- a/bsnes/phoenix/windows/widget/text-edit.cpp +++ b/bsnes/phoenix/windows/widget/text-edit.cpp @@ -18,10 +18,7 @@ void pTextEdit::setText(const string &text) { void pTextEdit::setWordWrap(bool wordWrap) { //ES_AUTOHSCROLL cannot be changed after widget creation. //As a result, we must destroy and re-create widget to change this setting. - HWND hwndParent = GetParent(hwnd); - Object *object = (Object*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); - if(object == 0) return; - if(dynamic_cast(object)) setParent(((Window&)*object)); + orphan(); } string pTextEdit::text() { @@ -35,20 +32,25 @@ string pTextEdit::text() { } void pTextEdit::constructor() { - setParent(Window::None); -} - -void pTextEdit::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"", - WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (textEdit.state.wordWrap == false ? ES_AUTOHSCROLL : 0), - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + WS_CHILD | ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN | (textEdit.state.wordWrap == false ? ES_AUTOHSCROLL : 0), + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&textEdit); setDefaultFont(); setCursorPosition(textEdit.state.cursorPosition); setEditable(textEdit.state.editable); setText(textEdit.state.text); - widget.setVisible(widget.visible()); + synchronize(); +} + +void pTextEdit::destructor() { + textEdit.state.text = text(); + DestroyWindow(hwnd); +} + +void pTextEdit::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp b/bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp index 025eb127..dcc281f2 100755 --- a/bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp +++ b/bsnes/phoenix/windows/widget/vertical-scroll-bar.cpp @@ -17,18 +17,22 @@ void pVerticalScrollBar::setPosition(unsigned position) { } void pVerticalScrollBar::constructor() { - setParent(Window::None); -} - -void pVerticalScrollBar::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindow( - L"SCROLLBAR", L"", WS_CHILD | WS_VISIBLE | SBS_VERT, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + L"SCROLLBAR", L"", WS_CHILD | SBS_VERT, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalScrollBar); unsigned position = verticalScrollBar.state.position; setLength(verticalScrollBar.state.length); - setPosition(position); - widget.setVisible(widget.visible()); + verticalScrollBar.setPosition(position); + synchronize(); +} + +void pVerticalScrollBar::destructor() { + DestroyWindow(hwnd); +} + +void pVerticalScrollBar::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/vertical-slider.cpp b/bsnes/phoenix/windows/widget/vertical-slider.cpp index 1e520b7c..ac5cb1ce 100755 --- a/bsnes/phoenix/windows/widget/vertical-slider.cpp +++ b/bsnes/phoenix/windows/widget/vertical-slider.cpp @@ -18,18 +18,22 @@ void pVerticalSlider::setPosition(unsigned position) { } void pVerticalSlider::constructor() { - setParent(Window::None); -} - -void pVerticalSlider::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); hwnd = CreateWindow( - TRACKBAR_CLASS, L"", WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_HORZ, - 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0 + TRACKBAR_CLASS, L"", WS_CHILD | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH | TBS_VERT, + 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0 ); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&verticalSlider); unsigned position = verticalSlider.state.position; setLength(verticalSlider.state.length); - setPosition(position); - widget.setVisible(widget.visible()); + verticalSlider.setPosition(position); + synchronize(); +} + +void pVerticalSlider::destructor() { + DestroyWindow(hwnd); +} + +void pVerticalSlider::orphan() { + destructor(); + constructor(); } diff --git a/bsnes/phoenix/windows/widget/viewport.cpp b/bsnes/phoenix/windows/widget/viewport.cpp index fea7f2a3..89942a2b 100755 --- a/bsnes/phoenix/windows/widget/viewport.cpp +++ b/bsnes/phoenix/windows/widget/viewport.cpp @@ -3,13 +3,18 @@ uintptr_t pViewport::handle() { } void pViewport::constructor() { - setParent(Window::None); + hwnd = CreateWindow(L"phoenix_viewport", L"", WS_CHILD | WS_DISABLED, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&viewport); + synchronize(); } -void pViewport::setParent(Window &parent) { - hwnd = CreateWindow(L"phoenix_viewport", L"", WS_CHILD | WS_VISIBLE | WS_DISABLED, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&viewport); - widget.setVisible(widget.visible()); +void pViewport::destructor() { + DestroyWindow(hwnd); +} + +void pViewport::orphan() { + destructor(); + constructor(); } static LRESULT CALLBACK Viewport_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { diff --git a/bsnes/phoenix/windows/widget/widget.cpp b/bsnes/phoenix/windows/widget/widget.cpp index 50423b74..b0e60c7d 100755 --- a/bsnes/phoenix/windows/widget/widget.cpp +++ b/bsnes/phoenix/windows/widget/widget.cpp @@ -2,16 +2,13 @@ bool pWidget::enabled() { return IsWindowEnabled(hwnd); } -Font& pWidget::font() { - if(widget.state.font) return *widget.state.font; - return pOS::state->defaultFont; -} - Geometry pWidget::minimumGeometry() { return { 0, 0, 0, 0 }; } void pWidget::setEnabled(bool enabled) { + if(widget.state.abstract) enabled = false; + if(sizable.state.layout && sizable.state.layout->enabled() == false) enabled = false; EnableWindow(hwnd, enabled); } @@ -19,8 +16,10 @@ void pWidget::setFocused() { SetFocus(hwnd); } -void pWidget::setFont(Font &font) { - SendMessage(hwnd, WM_SETFONT, (WPARAM)font.p.hfont, 0); +void pWidget::setFont(const string &font) { + if(hfont) DeleteObject(hfont); + hfont = pFont::create(font); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); } void pWidget::setGeometry(const Geometry &geometry) { @@ -29,26 +28,39 @@ void pWidget::setGeometry(const Geometry &geometry) { void pWidget::setVisible(bool visible) { if(widget.state.abstract) visible = false; - if(widget.state.layout && widget.state.layout->visible() == false) visible = false; + if(sizable.state.layout && sizable.state.layout->visible() == false) visible = false; ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); } void pWidget::constructor() { - hwnd = 0; - if(widget.state.abstract) setParent(Window::None); -} - -void pWidget::setDefaultFont() { - if(widget.state.font) { - SendMessage(hwnd, WM_SETFONT, (WPARAM)widget.state.font->p.hfont, 0); - } else { - SendMessage(hwnd, WM_SETFONT, (WPARAM)pOS::state->defaultFont.p.hfont, 0); + hfont = pFont::create("Tahoma, 8"); + if(widget.state.abstract) { + hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&widget); } } -void pWidget::setParent(Window &parent) { - if(hwnd) DestroyWindow(hwnd); - hwnd = CreateWindow(L"phoenix_label", L"", WS_CHILD, 0, 0, 0, 0, parent.p.hwnd, (HMENU)id, GetModuleHandle(0), 0); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&widget); - widget.setVisible(false); +void pWidget::destructor() { + if(widget.state.abstract) { + DestroyWindow(hwnd); + } +} + +void pWidget::orphan() { + destructor(); + constructor(); +} + +void pWidget::setDefaultFont() { + string description = widget.state.font; + if(description == "") description = "Tahoma, 8"; + hfont = pFont::create(description); + SendMessage(hwnd, WM_SETFONT, (WPARAM)hfont, 0); +} + +//calling Widget::setParent destroys widget and re-creates it: +//need to re-apply visiblity and enabled status; called by each subclassed setParent() function +void pWidget::synchronize() { + widget.setEnabled(widget.enabled()); + widget.setVisible(widget.visible()); } diff --git a/bsnes/phoenix/windows/window.cpp b/bsnes/phoenix/windows/window.cpp index 3955168d..5461c628 100755 --- a/bsnes/phoenix/windows/window.cpp +++ b/bsnes/phoenix/windows/window.cpp @@ -2,7 +2,6 @@ static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME; void pWindow::append(Layout &layout) { - layout.setParent(window); Geometry geom = window.state.geometry; geom.x = geom.y = 0; layout.setGeometry(geom); @@ -13,7 +12,11 @@ void pWindow::append(Menu &menu) { } void pWindow::append(Widget &widget) { - widget.p.setParent(window); + widget.p.parentWindow = &window; + widget.p.orphan(); + if(widget.state.font != "") widget.p.setFont(widget.state.font); + else if(window.state.widgetFont != "") widget.p.setFont(window.state.widgetFont); + else widget.p.setFont("Tahoma, 8"); } Color pWindow::backgroundColor() { @@ -61,6 +64,17 @@ Geometry pWindow::geometry() { return { x, y, width, height }; } +void pWindow::remove(Layout &layout) { +} + +void pWindow::remove(Menu &menu) { + updateMenu(); +} + +void pWindow::remove(Widget &widget) { + widget.p.orphan(); +} + void pWindow::setBackgroundColor(const Color &color) { if(brush) DeleteObject(brush); brushColor = RGB(color.red, color.green, color.blue); @@ -103,7 +117,7 @@ void pWindow::setGeometry(const Geometry &geometry) { locked = false; } -void pWindow::setMenuFont(Font &font) { +void pWindow::setMenuFont(const string &font) { } void pWindow::setMenuVisible(bool visible) { @@ -118,8 +132,10 @@ void pWindow::setResizable(bool resizable) { setGeometry(window.state.geometry); } -void pWindow::setStatusFont(Font &font) { - SendMessage(hstatus, WM_SETFONT, (WPARAM)font.p.hfont, 0); +void pWindow::setStatusFont(const string &font) { + if(hstatusfont) DeleteObject(hstatusfont); + hstatusfont = pFont::create(font); + SendMessage(hstatus, WM_SETFONT, (WPARAM)hstatusfont, 0); } void pWindow::setStatusText(const string &text) { @@ -141,9 +157,9 @@ void pWindow::setVisible(bool visible) { ShowWindow(hwnd, visible ? SW_SHOWNORMAL : SW_HIDE); } -void pWindow::setWidgetFont(Font &font) { +void pWindow::setWidgetFont(const string &font) { foreach(widget, window.state.widget) { - if(!widget.state.font) widget.setFont(font); + if(widget.state.font == "") widget.setFont(font); } } @@ -153,6 +169,8 @@ void pWindow::constructor() { hwnd = CreateWindow(L"phoenix_window", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0); hmenu = CreateMenu(); hstatus = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0); + hstatusfont = 0; + setStatusFont("Tahoma, 8"); //status bar will be capable of receiving tab focus if it is not disabled SetWindowLongPtr(hstatus, GWL_STYLE, GetWindowLong(hstatus, GWL_STYLE) | WS_DISABLED); @@ -161,12 +179,19 @@ void pWindow::constructor() { setGeometry({ 128, 128, 256, 256 }); } +void pWindow::destructor() { + DeleteObject(hstatusfont); + DestroyWindow(hstatus); + DestroyMenu(hmenu); + DestroyWindow(hwnd); +} + void pWindow::updateMenu() { if(hmenu) DestroyMenu(hmenu); hmenu = CreateMenu(); foreach(menu, window.state.menu) { - menu.p.update(window, hmenu); + menu.p.update(window); AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text)); } diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index a401dd69..307271ac 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "082.01"; + static const char Version[] = "082.02"; static const unsigned SerializerVersion = 21; } } diff --git a/bsnes/ui-gameboy/base.hpp b/bsnes/ui-gameboy/base.hpp index f1afddfe..840925ff 100755 --- a/bsnes/ui-gameboy/base.hpp +++ b/bsnes/ui-gameboy/base.hpp @@ -23,9 +23,9 @@ using namespace phoenix; struct Application { bool quit; - Font proportionalFont; - Font proportionalFontBold; - Font monospaceFont; + string proportionalFont; + string proportionalFontBold; + string monospaceFont; void main(int argc, char **argv); }; diff --git a/bsnes/ui-gameboy/main.cpp b/bsnes/ui-gameboy/main.cpp index 3bd04b82..9a1f27b9 100755 --- a/bsnes/ui-gameboy/main.cpp +++ b/bsnes/ui-gameboy/main.cpp @@ -10,25 +10,13 @@ void Application::main(int argc, char **argv) { quit = false; #if defined(PLATFORM_WIN) - proportionalFont.setFamily("Tahoma"); - proportionalFont.setSize(8); - - proportionalFontBold.setFamily("Tahoma"); - proportionalFontBold.setSize(8); - proportionalFontBold.setBold(); - - monospaceFont.setFamily("Lucida Console"); - monospaceFont.setSize(8); + proportionalFont = "Tahoma, 8"; + proportionalFontBold = "Tahoma, 8, Bold"; + monospaceFont = "Lucida Console, 8"; #else - proportionalFont.setFamily("Sans"); - proportionalFont.setSize(8); - - proportionalFontBold.setFamily("Sans"); - proportionalFontBold.setSize(8); - proportionalFontBold.setBold(); - - monospaceFont.setFamily("Liberation Mono"); - monospaceFont.setSize(8); + proportionalFont = "Sans, 8"; + proportionalFontBold = "Sans, 8, Bold"; + monospaceFont = "Liberation Mono, 8"; #endif mainWindow.create(); diff --git a/bsnes/ui/base.hpp b/bsnes/ui/base.hpp index acf9dcbb..34dcabdb 100755 --- a/bsnes/ui/base.hpp +++ b/bsnes/ui/base.hpp @@ -41,10 +41,10 @@ struct TopLevelWindow : Window { #endif struct Application { - Font proportionalFont; - Font proportionalFontBold; - Font monospaceFont; - Font titleFont; + string proportionalFont; + string proportionalFontBold; + string monospaceFont; + string titleFont; bool compositorActive; bool pause; diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 8391d119..69f8b024 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -25,34 +25,15 @@ void Application::main(int argc, char **argv) { inputMapper.bind(); #if defined(PLATFORM_WIN) - proportionalFont.setFamily("Tahoma"); - proportionalFont.setSize(8); - - proportionalFontBold.setFamily("Tahoma"); - proportionalFontBold.setSize(8); - proportionalFontBold.setBold(); - - monospaceFont.setFamily("Lucida Console"); - monospaceFont.setSize(8); - - titleFont.setFamily("Segoe Print"); - titleFont.setSize(16); - titleFont.setBold(); + proportionalFont = "Tahoma, 8"; + proportionalFontBold = "Tahoma, 8, Bold"; + monospaceFont = "Lucida Console, 8"; + titleFont = "Segoe Print, 16, Bold"; #else - proportionalFont.setFamily("Sans"); - proportionalFont.setSize(8); - - proportionalFontBold.setFamily("Sans"); - proportionalFontBold.setSize(8); - proportionalFontBold.setBold(); - - monospaceFont.setFamily("Liberation Mono"); - monospaceFont.setSize(8); - - titleFont.setFamily("Sans"); - titleFont.setSize(16); - titleFont.setBold(); - titleFont.setItalic(); + proportionalFont = "Sans, 8"; + proportionalFontBold = "Sans, 8, Bold"; + monospaceFont = "Liberation Mono, 8"; + titleFont = "Sans, 16, Bold Italic"; #endif SNES::system.init(&interface);