From cc518dcc3c96538906dc400ab60c540a72243d66 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 15 Jan 2012 19:29:57 +1100 Subject: [PATCH] Update to v085r01 release. byuu says: Changelog: - updated bsnes to use the newest versions of nall and phoenix - fixed ui-libsnes compilation (testing would be a good idea, especially the cheat codes. I just copy-pasted that from the regular UI.) - fixed multitap controllers 2-4 [quequotion] --- bsnes/nall/config.hpp | 16 +- bsnes/nall/file.hpp | 6 +- bsnes/nall/gzip.hpp | 8 +- bsnes/nall/hid.hpp | 55 ------ bsnes/nall/http.hpp | 2 +- bsnes/nall/image.hpp | 34 ++-- bsnes/nall/interpolation.hpp | 8 +- bsnes/nall/map.hpp | 87 ++++++++++ bsnes/nall/sort.hpp | 3 +- bsnes/nall/stream.hpp | 26 +++ bsnes/nall/stream/auto.hpp | 24 +++ bsnes/nall/stream/file.hpp | 31 ++++ bsnes/nall/stream/gzip.hpp | 28 ++++ bsnes/nall/stream/http.hpp | 43 +++++ bsnes/nall/stream/memory.hpp | 40 +++++ bsnes/nall/stream/mmap.hpp | 36 ++++ bsnes/nall/stream/stream.hpp | 90 ++++++++++ bsnes/nall/stream/zip.hpp | 30 ++++ bsnes/nall/string.hpp | 2 +- bsnes/nall/string/base.hpp | 11 +- bsnes/nall/string/strl.hpp | 51 ------ bsnes/nall/string/strm.hpp | 45 +++++ bsnes/nall/string/utility.hpp | 15 +- bsnes/nall/utility.hpp | 6 - bsnes/nall/vector.hpp | 13 +- bsnes/nes/cartridge/ines.cpp | 2 +- bsnes/phoenix/core/core.cpp | 173 ++++++++++++------- bsnes/phoenix/core/core.hpp | 136 +++++++++------ bsnes/phoenix/core/keyboard.hpp | 45 +++++ bsnes/phoenix/core/state.hpp | 8 +- bsnes/phoenix/gtk/action/item.cpp | 7 +- bsnes/phoenix/gtk/desktop.cpp | 36 ++++ bsnes/phoenix/gtk/dialog-window.cpp | 69 ++++++++ bsnes/phoenix/gtk/keyboard.cpp | 144 ++++++++++++++++ bsnes/phoenix/gtk/mouse.cpp | 20 +++ bsnes/phoenix/gtk/platform.cpp | 117 ++----------- bsnes/phoenix/gtk/platform.hpp | 47 ++++-- bsnes/phoenix/gtk/settings.cpp | 12 +- bsnes/phoenix/gtk/utility.cpp | 195 ++++++++++++++++++++++ bsnes/phoenix/gtk/widget/button.cpp | 20 +++ bsnes/phoenix/gtk/window.cpp | 18 +- bsnes/phoenix/phoenix.cpp | 10 +- bsnes/phoenix/phoenix.hpp | 1 + bsnes/phoenix/qt/action/item.cpp | 9 + bsnes/phoenix/qt/desktop.cpp | 9 + bsnes/phoenix/qt/dialog-window.cpp | 57 +++++++ bsnes/phoenix/qt/keyboard.cpp | 144 ++++++++++++++++ bsnes/phoenix/qt/mouse.cpp | 14 ++ bsnes/phoenix/qt/platform.cpp | 80 ++------- bsnes/phoenix/qt/platform.moc | 2 +- bsnes/phoenix/qt/platform.moc.hpp | 54 ++++-- bsnes/phoenix/qt/settings.cpp | 12 +- bsnes/phoenix/qt/utility.cpp | 182 ++++++++++++++++++++ bsnes/phoenix/qt/widget/button.cpp | 28 +++- bsnes/phoenix/qt/window.cpp | 15 +- bsnes/phoenix/reference/action/item.cpp | 3 + bsnes/phoenix/reference/desktop.cpp | 8 + bsnes/phoenix/reference/dialog-window.cpp | 11 ++ bsnes/phoenix/reference/keyboard.cpp | 10 ++ bsnes/phoenix/reference/mouse.cpp | 7 + bsnes/phoenix/reference/platform.cpp | 27 +-- bsnes/phoenix/reference/platform.hpp | 42 +++-- bsnes/phoenix/reference/widget/button.cpp | 3 + bsnes/phoenix/windows/action/item.cpp | 19 +++ bsnes/phoenix/windows/action/menu.cpp | 13 +- bsnes/phoenix/windows/desktop.cpp | 9 + bsnes/phoenix/windows/dialog-window.cpp | 81 +++++++++ bsnes/phoenix/windows/keyboard.cpp | 139 +++++++++++++++ bsnes/phoenix/windows/mouse.cpp | 14 ++ bsnes/phoenix/windows/platform.cpp | 133 ++++----------- bsnes/phoenix/windows/platform.hpp | 56 +++++-- bsnes/phoenix/windows/utility.cpp | 150 +++++++++++++++++ bsnes/phoenix/windows/widget/button.cpp | 46 +++++ bsnes/snes/ppu/screen/screen.cpp | 6 +- bsnes/snes/system/serialization.cpp | 2 +- bsnes/ui-libsnes/libsnes.cpp | 42 ++++- bsnes/ui/general/file-browser.cpp | 2 +- bsnes/ui/input/input.cpp | 3 + bsnes/ui/interface/snes/snes.cpp | 12 +- bsnes/ui/main.cpp | 2 +- bsnes/ui/settings/input.cpp | 1 + bsnes/ui/tools/state-manager.cpp | 4 +- 82 files changed, 2552 insertions(+), 669 deletions(-) delete mode 100755 bsnes/nall/hid.hpp create mode 100755 bsnes/nall/map.hpp create mode 100755 bsnes/nall/stream.hpp create mode 100755 bsnes/nall/stream/auto.hpp create mode 100755 bsnes/nall/stream/file.hpp create mode 100755 bsnes/nall/stream/gzip.hpp create mode 100755 bsnes/nall/stream/http.hpp create mode 100755 bsnes/nall/stream/memory.hpp create mode 100755 bsnes/nall/stream/mmap.hpp create mode 100755 bsnes/nall/stream/stream.hpp create mode 100755 bsnes/nall/stream/zip.hpp delete mode 100755 bsnes/nall/string/strl.hpp create mode 100755 bsnes/nall/string/strm.hpp create mode 100755 bsnes/phoenix/core/keyboard.hpp create mode 100755 bsnes/phoenix/gtk/desktop.cpp create mode 100755 bsnes/phoenix/gtk/dialog-window.cpp create mode 100755 bsnes/phoenix/gtk/keyboard.cpp create mode 100755 bsnes/phoenix/gtk/mouse.cpp create mode 100755 bsnes/phoenix/gtk/utility.cpp create mode 100755 bsnes/phoenix/qt/desktop.cpp create mode 100755 bsnes/phoenix/qt/dialog-window.cpp create mode 100755 bsnes/phoenix/qt/keyboard.cpp create mode 100755 bsnes/phoenix/qt/mouse.cpp create mode 100755 bsnes/phoenix/qt/utility.cpp create mode 100755 bsnes/phoenix/reference/desktop.cpp create mode 100755 bsnes/phoenix/reference/dialog-window.cpp create mode 100755 bsnes/phoenix/reference/keyboard.cpp create mode 100755 bsnes/phoenix/reference/mouse.cpp create mode 100755 bsnes/phoenix/windows/desktop.cpp create mode 100755 bsnes/phoenix/windows/dialog-window.cpp create mode 100755 bsnes/phoenix/windows/keyboard.cpp create mode 100755 bsnes/phoenix/windows/mouse.cpp create mode 100755 bsnes/phoenix/windows/utility.cpp diff --git a/bsnes/nall/config.hpp b/bsnes/nall/config.hpp index 0c6602df..0ce259d6 100755 --- a/bsnes/nall/config.hpp +++ b/bsnes/nall/config.hpp @@ -32,7 +32,7 @@ namespace nall { string desc; type_t type; - string get() const { + inline string get() const { switch(type) { case boolean_t: return { *(bool*)data }; case signed_t: return { *(signed*)data }; @@ -43,7 +43,7 @@ namespace nall { return "???"; } - void set(string s) { + inline void set(string s) { switch(type) { case boolean_t: *(bool*)data = (s == "true"); break; case signed_t: *(signed*)data = integer(s); break; @@ -56,7 +56,7 @@ namespace nall { linear_vector list; template - void attach(T &data, const char *name, const char *desc = "") { + inline void append(T &data, const char *name, const char *desc = "") { unsigned n = list.size(); list[n].data = (uintptr_t)&data; list[n].name = name; @@ -70,7 +70,13 @@ namespace nall { else list[n].type = unknown_t; } - virtual bool load(const string &filename) { + //deprecated + template + inline void attach(T &data, const char *name, const char *desc = "") { + append(data, name, desc); + } + + inline virtual bool load(const string &filename) { string data; if(data.readfile(filename) == true) { data.replace("\r", ""); @@ -100,7 +106,7 @@ namespace nall { } } - virtual bool save(const string &filename) const { + inline virtual bool save(const string &filename) const { file fp; if(fp.open(filename, file::mode::write)) { for(unsigned i = 0; i < list.size(); i++) { diff --git a/bsnes/nall/file.hpp b/bsnes/nall/file.hpp index 8447f3ab..2c26ce56 100755 --- a/bsnes/nall/file.hpp +++ b/bsnes/nall/file.hpp @@ -134,12 +134,12 @@ namespace nall { file_offset = req_offset; } - int offset() { + int offset() const { if(!fp) return -1; //file not open return file_offset; } - int size() { + int size() const { if(!fp) return -1; //file not open return file_size; } @@ -194,7 +194,7 @@ namespace nall { } } - bool open() { + bool open() const { return fp; } diff --git a/bsnes/nall/gzip.hpp b/bsnes/nall/gzip.hpp index 8f5d206b..fa0aaad1 100755 --- a/bsnes/nall/gzip.hpp +++ b/bsnes/nall/gzip.hpp @@ -11,11 +11,11 @@ struct gzip { uint8_t *data; unsigned size; - bool decompress(const string &filename); - bool decompress(const uint8_t *data, unsigned size); + inline bool decompress(const string &filename); + inline bool decompress(const uint8_t *data, unsigned size); - gzip(); - ~gzip(); + inline gzip(); + inline ~gzip(); }; bool gzip::decompress(const string &filename) { diff --git a/bsnes/nall/hid.hpp b/bsnes/nall/hid.hpp deleted file mode 100755 index fd48249c..00000000 --- a/bsnes/nall/hid.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef NALL_HID_HPP -#define NALL_HID_HPP - -#include -#include - -namespace nall { -namespace HID { - -struct Keyboard { - XlibDisplay *display; - - inline void poll() { - XQueryKeymap(display, state); - } - - inline bool operator[](unsigned id) { - return state[scancode[id] >> 3] & (1 << (scancode[id] & 7)); - } - - inline Keyboard() { - display = XOpenDisplay(0); - memset(&scancode, 0, sizeof scancode); - - #define map(key, sym) scancode[key] = XKeysymToKeycode(display, sym) - - using nall::Keyboard; - map(Keyboard::Insert, XK_Insert); - map(Keyboard::Delete, XK_Delete); - map(Keyboard::Home, XK_Home); - map(Keyboard::End, XK_End); - map(Keyboard::PageUp, XK_Prior); - map(Keyboard::PageDown, XK_Next); - - map(Keyboard::Up, XK_Up); - map(Keyboard::Down, XK_Down); - map(Keyboard::Left, XK_Left); - map(Keyboard::Right, XK_Right); - - #undef map - } - - inline ~Keyboard() { - XCloseDisplay(display); - } - -private: - char state[32]; - uint8_t scancode[256]; -}; - -} -} - -#endif diff --git a/bsnes/nall/http.hpp b/bsnes/nall/http.hpp index 1b2eab4f..55190e82 100755 --- a/bsnes/nall/http.hpp +++ b/bsnes/nall/http.hpp @@ -117,7 +117,7 @@ struct http { } } } else if(auto position = header.iposition("\r\nContent-Length: ")) { - unsigned length = decimal((const char*)header + position() + 16); + unsigned length = decimal((const char*)header + position() + 18); while(length) { char buffer[256]; int packetlength = recv(serversocket, buffer, min(256, length), 0); diff --git a/bsnes/nall/image.hpp b/bsnes/nall/image.hpp index fd762d4b..683b59e4 100755 --- a/bsnes/nall/image.hpp +++ b/bsnes/nall/image.hpp @@ -193,8 +193,8 @@ bool image::load(const string &filename) { } void image::scale(unsigned outputWidth, unsigned outputHeight, interpolation op) { - scaleX(outputWidth, op); - scaleY(outputHeight, op); + if(width != outputWidth) scaleX(outputWidth, op); + if(height != outputHeight) scaleY(outputHeight, op); } void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) { @@ -284,6 +284,7 @@ void image::scaleX(unsigned outputWidth, interpolation op) { uint8_t *outputData = new uint8_t[outputWidth * height * stride]; unsigned outputPitch = outputWidth * stride; double step = (double)width / (double)outputWidth; + const uint8_t *terminal = data + pitch * height; #pragma omp parallel for for(unsigned y = 0; y < height; y++) { @@ -291,15 +292,12 @@ void image::scaleX(unsigned outputWidth, interpolation op) { uint8_t *sp = data + pitch * y; double fraction = 0.0; - uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + uint64_t s[4] = { sp < terminal ? read(sp) : 0 }; //B,C (0,1) = center of kernel { 0, 0, 1, 2 } + s[1] = s[0]; + s[2] = sp + stride < terminal ? read(sp += stride) : s[1]; + s[3] = sp + stride < terminal ? read(sp += stride) : s[2]; for(unsigned x = 0; x < width; x++) { - if(sp >= data + pitch * height) break; - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - s[3] = read(sp); - while(fraction <= 1.0) { if(dp >= outputData + outputPitch * height) break; write(dp, interpolate(fraction, (const uint64_t*)&s, op)); @@ -307,7 +305,8 @@ void image::scaleX(unsigned outputWidth, interpolation op) { fraction += step; } - sp += stride; + s[0] = s[1]; s[1] = s[2]; s[2] = s[3]; + if(sp + stride < terminal) s[3] = read(sp += stride); fraction -= 1.0; } } @@ -321,6 +320,7 @@ void image::scaleX(unsigned outputWidth, interpolation op) { void image::scaleY(unsigned outputHeight, interpolation op) { uint8_t *outputData = new uint8_t[width * outputHeight * stride]; double step = (double)height / (double)outputHeight; + const uint8_t *terminal = data + pitch * height; #pragma omp parallel for for(unsigned x = 0; x < width; x++) { @@ -328,15 +328,12 @@ void image::scaleY(unsigned outputHeight, interpolation op) { uint8_t *sp = data + stride * x; double fraction = 0.0; - uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) }; + uint64_t s[4] = { sp < terminal ? read(sp) : 0 }; + s[1] = s[0]; + s[2] = sp + pitch < terminal ? read(sp += pitch) : s[1]; + s[3] = sp + pitch < terminal ? read(sp += pitch) : s[2]; for(unsigned y = 0; y < height; y++) { - if(sp >= data + pitch * height) break; - s[0] = s[1]; - s[1] = s[2]; - s[2] = s[3]; - s[3] = read(sp); - while(fraction <= 1.0) { if(dp >= outputData + pitch * outputHeight) break; write(dp, interpolate(fraction, (const uint64_t*)&s, op)); @@ -344,7 +341,8 @@ void image::scaleY(unsigned outputHeight, interpolation op) { fraction += step; } - sp += pitch; + s[0] = s[1]; s[1] = s[2]; s[2] = s[3]; + if(sp + pitch < terminal) s[3] = read(sp += pitch); fraction -= 1.0; } } diff --git a/bsnes/nall/interpolation.hpp b/bsnes/nall/interpolation.hpp index 46a09a49..afc7108b 100755 --- a/bsnes/nall/interpolation.hpp +++ b/bsnes/nall/interpolation.hpp @@ -5,23 +5,23 @@ namespace nall { struct Interpolation { static inline double Nearest(double mu, double a, double b, double c, double d) { - return (mu < 0.5 ? c : d); + return (mu <= 0.5 ? b : c); } static inline double Sublinear(double mu, double a, double b, double c, double d) { mu = ((mu - 0.5) * 2.0) + 0.5; if(mu < 0) mu = 0; if(mu > 1) mu = 1; - return c * (1.0 - mu) + d * mu; + return b * (1.0 - mu) + c * mu; } static inline double Linear(double mu, double a, double b, double c, double d) { - return c * (1.0 - mu) + d * mu; + return b * (1.0 - mu) + c * mu; } static inline double Cosine(double mu, double a, double b, double c, double d) { mu = (1.0 - cos(mu * 3.14159265)) / 2.0; - return c * (1.0 - mu) + d * mu; + return b * (1.0 - mu) + c * mu; } static inline double Cubic(double mu, double a, double b, double c, double d) { diff --git a/bsnes/nall/map.hpp b/bsnes/nall/map.hpp new file mode 100755 index 00000000..4e6bc204 --- /dev/null +++ b/bsnes/nall/map.hpp @@ -0,0 +1,87 @@ +#ifndef NALL_MAP_HPP +#define NALL_MAP_HPP + +#include + +namespace nall { + +template +struct map { + struct pair { + LHS name; + RHS data; + }; + + void reset() { + list.reset(); + } + + unsigned size() const { + return list.size(); + } + + //O(n) + void append(const LHS &name, const RHS &data) { + signed offset = size(); + for(unsigned n = 0; n < size(); n++) { + if(name < list[n].name) { offset = n; break; } + } + list.insert(offset, { name, data }); + } + + //O(log n) + RHS& operator[](const LHS &name) { + signed first = 0, last = size() - 1; + while(first <= last) { + signed middle = (first + last) / 2; + if(name < list[middle].name) last = middle - 1; //search lower half + else if(name > list[middle].name) first = middle + 1; //search upper half + else return list[middle].data; //match found + } + throw; + } + + //O(log n) nothrow + const RHS& operator()(const LHS &name, const RHS &data) { + signed first = 0, last = size() - 1; + while(first <= last) { + signed middle = (first + last) / 2; + if(name < list[middle].name) last = middle - 1; //search lower half + else if(name > list[middle].name) first = middle + 1; //search upper half + else return list[middle].data; //match found + } + return data; + } + + pair* begin() { return list.begin(); } + pair* end() { return list.end(); } + const pair* begin() const { return list.begin(); } + const pair* end() const { return list.end(); } + +protected: + vector list; +}; + +template +struct bidirectional_map { + map lhs; + map rhs; + + void reset() { + lhs.reset(); + rhs.reset(); + } + + unsigned size() const { + return lhs.size(); + } + + void append(const LHS &ldata, const RHS &rdata) { + lhs.append(ldata, rdata); + rhs.append(rdata, ldata); + } +}; + +} + +#endif diff --git a/bsnes/nall/sort.hpp b/bsnes/nall/sort.hpp index 23c317a5..3bd6dc59 100755 --- a/bsnes/nall/sort.hpp +++ b/bsnes/nall/sort.hpp @@ -1,6 +1,7 @@ #ifndef NALL_SORT_HPP #define NALL_SORT_HPP +#include #include //class: merge sort @@ -29,7 +30,7 @@ namespace nall { for(unsigned j = i + 1; j < length; j++) { if(list[j] < list[min]) min = j; } - if(min != i) swap(list[i], list[min]); + if(min != i) std::swap(list[i], list[min]); } return; } diff --git a/bsnes/nall/stream.hpp b/bsnes/nall/stream.hpp new file mode 100755 index 00000000..586ccda7 --- /dev/null +++ b/bsnes/nall/stream.hpp @@ -0,0 +1,26 @@ +#ifndef NALL_STREAM_HPP +#define NALL_STREAM_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NALL_STREAM_INTERNAL_HPP +#include +#include +#include +#include +#include +#include +#include +#include +#undef NALL_STREAM_INTERNAL_HPP + +#endif diff --git a/bsnes/nall/stream/auto.hpp b/bsnes/nall/stream/auto.hpp new file mode 100755 index 00000000..148c7fd4 --- /dev/null +++ b/bsnes/nall/stream/auto.hpp @@ -0,0 +1,24 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +#define autostream(...) (*makestream(__VA_ARGS__)) + +inline std::unique_ptr makestream(const string &path) { + if(path.ibeginswith("http://")) return std::unique_ptr(new httpstream(path, 80)); + if(path.iendswith(".gz")) return std::unique_ptr(new gzipstream(filestream{path})); + if(path.iendswith(".zip")) return std::unique_ptr(new zipstream(filestream{path})); + return std::unique_ptr(new mmapstream(path)); +} + +inline std::unique_ptr makestream(uint8_t *data, unsigned size) { + return std::unique_ptr(new memorystream(data, size)); +} + +inline std::unique_ptr makestream(const uint8_t *data, unsigned size) { + return std::unique_ptr(new memorystream(data, size)); +} + +} + +#endif diff --git a/bsnes/nall/stream/file.hpp b/bsnes/nall/stream/file.hpp new file mode 100755 index 00000000..55521f07 --- /dev/null +++ b/bsnes/nall/stream/file.hpp @@ -0,0 +1,31 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +struct filestream : stream { + inline bool seekable() const { return true; } + inline bool readable() const { return true; } + inline bool writable() const { return pwritable; } + inline bool randomaccess() const { return false; } + + inline unsigned size() const { return pfile.size(); } + inline unsigned offset() const { return pfile.offset(); } + inline void seek(unsigned offset) const { pfile.seek(offset); } + + inline uint8_t read() const { return pfile.read(); } + inline void write(uint8_t data) const { pfile.write(data); } + + inline filestream(const string &filename) { + pfile.open(filename, file::mode::readwrite); + pwritable = pfile.open(); + if(!pwritable) pfile.open(filename, file::mode::read); + } + +private: + mutable file pfile; + bool pwritable; +}; + +} + +#endif diff --git a/bsnes/nall/stream/gzip.hpp b/bsnes/nall/stream/gzip.hpp new file mode 100755 index 00000000..37bd9778 --- /dev/null +++ b/bsnes/nall/stream/gzip.hpp @@ -0,0 +1,28 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +struct gzipstream : memorystream { + inline gzipstream(const stream &stream) { + unsigned size = stream.size(); + uint8_t *data = new uint8_t[size]; + stream.read(data, size); + + gzip archive; + bool result = archive.decompress(data, size); + delete[] data; + if(result == false) return; + + psize = archive.size; + pdata = new uint8_t[psize]; + memcpy(pdata, archive.data, psize); + } + + inline ~gzipstream() { + if(pdata) delete[] pdata; + } +}; + +} + +#endif diff --git a/bsnes/nall/stream/http.hpp b/bsnes/nall/stream/http.hpp new file mode 100755 index 00000000..b853d51c --- /dev/null +++ b/bsnes/nall/stream/http.hpp @@ -0,0 +1,43 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +struct httpstream : stream { + inline bool seekable() const { return true; } + inline bool readable() const { return true; } + inline bool writable() const { return true; } + inline bool randomaccess() const { return true; } + + inline unsigned size() const { return psize; } + inline unsigned offset() const { return poffset; } + inline void seek(unsigned offset) const { poffset = offset; } + + inline uint8_t read() const { return pdata[poffset++]; } + inline void write(uint8_t data) const { pdata[poffset++] = data; } + + inline uint8_t read(unsigned offset) const { return pdata[offset]; } + inline void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + + inline httpstream(const string &url, unsigned port) : pdata(nullptr), psize(0), poffset(0) { + string uri = url; + uri.ltrim<1>("http://"); + lstring part = uri.split<1>("/"); + part[1] = { "/", part[1] }; + + http connection; + if(connection.connect(part[0], port) == false) return; + connection.download(part[1], pdata, psize); + } + + inline ~httpstream() { + if(pdata) delete[] pdata; + } + +private: + mutable uint8_t *pdata; + mutable unsigned psize, poffset; +}; + +} + +#endif diff --git a/bsnes/nall/stream/memory.hpp b/bsnes/nall/stream/memory.hpp new file mode 100755 index 00000000..80bbb240 --- /dev/null +++ b/bsnes/nall/stream/memory.hpp @@ -0,0 +1,40 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +struct memorystream : stream { + inline bool seekable() const { return true; } + inline bool readable() const { return true; } + inline bool writable() const { return pwritable; } + inline bool randomaccess() const { return true; } + + inline unsigned size() const { return psize; } + inline unsigned offset() const { return poffset; } + inline void seek(unsigned offset) const { poffset = offset; } + + inline uint8_t read() const { return pdata[poffset++]; } + inline void write(uint8_t data) const { pdata[poffset++] = data; } + + inline uint8_t read(unsigned offset) const { return pdata[offset]; } + inline void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + + inline memorystream() : pdata(nullptr), psize(0), poffset(0), pwritable(true) {} + + inline memorystream(uint8_t *data, unsigned size) { + pdata = data, psize = size, poffset = 0; + pwritable = true; + } + + inline memorystream(const uint8_t *data, unsigned size) { + pdata = (uint8_t*)data, psize = size, poffset = 0; + pwritable = false; + } + +protected: + mutable uint8_t *pdata; + mutable unsigned psize, poffset, pwritable; +}; + +} + +#endif diff --git a/bsnes/nall/stream/mmap.hpp b/bsnes/nall/stream/mmap.hpp new file mode 100755 index 00000000..a172ccf1 --- /dev/null +++ b/bsnes/nall/stream/mmap.hpp @@ -0,0 +1,36 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +struct mmapstream : stream { + inline bool seekable() const { return true; } + inline bool readable() const { return true; } + inline bool writable() const { return pwritable; } + inline bool randomaccess() const { return false; } + + inline unsigned size() const { return pmmap.size(); } + inline unsigned offset() const { return poffset; } + inline void seek(unsigned offset) const { poffset = offset; } + + inline uint8_t read() const { return pdata[poffset++]; } + inline void write(uint8_t data) const { pdata[poffset++] = data; } + + inline uint8_t read(unsigned offset) const { return pdata[offset]; } + inline void write(unsigned offset, uint8_t data) const { pdata[offset] = data; } + + inline mmapstream(const string &filename) { + pmmap.open(filename, filemap::mode::readwrite); + pwritable = pmmap.open(); + if(!pwritable) pmmap.open(filename, filemap::mode::read); + pdata = pmmap.data(), poffset = 0; + } + +private: + mutable filemap pmmap; + mutable uint8_t *pdata; + mutable unsigned pwritable, poffset; +}; + +} + +#endif diff --git a/bsnes/nall/stream/stream.hpp b/bsnes/nall/stream/stream.hpp new file mode 100755 index 00000000..3fdee984 --- /dev/null +++ b/bsnes/nall/stream/stream.hpp @@ -0,0 +1,90 @@ +#ifndef NALL_STREAM_STREAM_HPP +#define NALL_STREAM_STREAM_HPP + +namespace nall { + +struct stream { + virtual bool seekable() const = 0; + virtual bool readable() const = 0; + virtual bool writable() const = 0; + virtual bool randomaccess() const = 0; + + virtual unsigned size() const = 0; + virtual unsigned offset() const = 0; + virtual void seek(unsigned offset) const = 0; + + virtual uint8_t read() const = 0; + virtual void write(uint8_t data) const = 0; + + inline virtual uint8_t read(unsigned) const { return 0; } + inline virtual void write(unsigned, uint8_t) const {} + + inline bool end() const { + return offset() >= size(); + } + + inline void copy(uint8_t *&data, unsigned &length) const { + seek(0); + length = size(); + data = new uint8_t[length]; + for(unsigned n = 0; n < length; n++) data[n] = read(); + } + + inline uintmax_t readl(unsigned length = 1) const { + uintmax_t data = 0, shift = 0; + while(length--) { data |= read() << shift; shift += 8; } + return data; + } + + inline uintmax_t readm(unsigned length = 1) const { + uintmax_t data = 0; + while(length--) data = (data << 8) | read(); + return data; + } + + inline void read(uint8_t *data, unsigned length) const { + while(length--) *data++ = read(); + } + + inline void writel(uintmax_t data, unsigned length = 1) const { + while(length--) { + write(data); + data >>= 8; + } + } + + inline void writem(uintmax_t data, unsigned length = 1) const { + uintmax_t shift = 8 * length; + while(length--) { + shift -= 8; + write(data >> shift); + } + } + + inline void write(const uint8_t *data, unsigned length) const { + while(length--) write(*data++); + } + + struct byte { + inline operator uint8_t() const { return s.read(offset); } + inline byte& operator=(uint8_t data) { s.write(offset, data); } + inline byte(const stream &s, unsigned offset) : s(s), offset(offset) {} + + private: + const stream &s; + const unsigned offset; + }; + + inline byte operator[](unsigned offset) const { + return byte(*this, offset); + } + + inline stream() {} + inline virtual ~stream() {} + stream(const stream&) = delete; + stream& operator=(const stream&) = delete; +}; + +} + +#endif diff --git a/bsnes/nall/stream/zip.hpp b/bsnes/nall/stream/zip.hpp new file mode 100755 index 00000000..dc1d82bc --- /dev/null +++ b/bsnes/nall/stream/zip.hpp @@ -0,0 +1,30 @@ +#ifdef NALL_STREAM_INTERNAL_HPP + +namespace nall { + +struct zipstream : memorystream { + inline zipstream(const stream &stream, const string &filter = "*") { + unsigned size = stream.size(); + uint8_t *data = new uint8_t[size]; + stream.read(data, size); + + zip archive; + if(archive.open(data, size) == false) return; + delete[] data; + + for(auto &file : archive.file) { + if(file.name.wildcard(filter)) { + archive.extract(file, pdata, psize); + return; + } + } + } + + inline ~zipstream() { + if(pdata) delete[] pdata; + } +}; + +} + +#endif diff --git a/bsnes/nall/string.hpp b/bsnes/nall/string.hpp index 1b255ce2..fbc25384 100755 --- a/bsnes/nall/string.hpp +++ b/bsnes/nall/string.hpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/bsnes/nall/string/base.hpp b/bsnes/nall/string/base.hpp index 8f4e9bb4..2e0d4296 100755 --- a/bsnes/nall/string/base.hpp +++ b/bsnes/nall/string/base.hpp @@ -151,9 +151,12 @@ namespace nall { inline string userpath(); inline string currentpath(); - //strl.hpp - inline unsigned strlcpy(char *dest, const char *src, unsigned length); - inline unsigned strlcat(char *dest, const char *src, unsigned length); + //strm.hpp + inline unsigned strmcpy(char *target, const char *source, unsigned length); + inline unsigned strmcat(char *target, const char *source, unsigned length); + inline bool strccpy(char *target, const char *source, unsigned length); + inline bool strccat(char *target, const char *source, unsigned length); + inline void strpcpy(char *&target, const char *source, unsigned &length); //strpos.hpp inline optional strpos(const char *str, const char *key); @@ -171,8 +174,6 @@ namespace nall { template alwaysinline bool chrequal(char x, char y); template alwaysinline bool quoteskip(T *&p); template alwaysinline bool quotecopy(char *&t, T *&p); - inline unsigned strlcpy(string &dest, const char *src, unsigned length); - inline unsigned strlcat(string &dest, const char *src, unsigned length); inline string substr(const char *src, unsigned start = 0, unsigned length = ~0u); inline string sha256(const uint8_t *data, unsigned size); diff --git a/bsnes/nall/string/strl.hpp b/bsnes/nall/string/strl.hpp deleted file mode 100755 index 44f6d6f7..00000000 --- a/bsnes/nall/string/strl.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifdef NALL_STRING_INTERNAL_HPP - -namespace nall { - -//strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller - -//return = strlen(src) -unsigned strlcpy(char *dest, const char *src, unsigned length) { - char *d = dest; - const char *s = src; - unsigned n = length; - - if(n) { - while(--n && (*d++ = *s++)); //copy as many bytes as possible, or until null terminator reached - } - - if(!n) { - if(length) *d = 0; - while(*s++); //traverse rest of s, so that s - src == strlen(src) - } - - return (s - src - 1); //return length of copied string, sans null terminator -} - -//return = strlen(src) + min(length, strlen(dest)) -unsigned strlcat(char *dest, const char *src, unsigned length) { - char *d = dest; - const char *s = src; - unsigned n = length; - - while(n-- && *d) d++; //find end of dest - unsigned dlength = d - dest; - n = length - dlength; //subtract length of dest from maximum string length - - if(!n) return dlength + strlen(s); - - while(*s) { - if(n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = 0; - - return dlength + (s - src); //return length of resulting string, sans null terminator -} - -} - -#endif diff --git a/bsnes/nall/string/strm.hpp b/bsnes/nall/string/strm.hpp new file mode 100755 index 00000000..21d05652 --- /dev/null +++ b/bsnes/nall/string/strm.hpp @@ -0,0 +1,45 @@ +#ifdef NALL_STRING_INTERNAL_HPP + +namespace nall { + +// +//strmcpy, strmcat created by byuu +// + +//return = strlen(target) +unsigned strmcpy(char *target, const char *source, unsigned length) { + const char *origin = target; + if(length) { + while(*source && --length) *target++ = *source++; + *target = 0; + } + return target - origin; +} + +//return = strlen(target) +unsigned strmcat(char *target, const char *source, unsigned length) { + const char *origin = target; + while(*target && length) target++, length--; + return (target - origin) + strmcpy(target, source, length); +} + +//return = true when all of source was copied +bool strccpy(char *target, const char *source, unsigned length) { + return !source[strmcpy(target, source, length)]; +} + +//return = true when all of source was copied +bool strccat(char *target, const char *source, unsigned length) { + while(*target && length) target++, length--; + return !source[strmcpy(target, source, length)]; +} + +//return = reserved for future use +void strpcpy(char *&target, const char *source, unsigned &length) { + unsigned offset = strmcpy(target, source, length); + target += offset, length -= offset; +} + +} + +#endif diff --git a/bsnes/nall/string/utility.hpp b/bsnes/nall/string/utility.hpp index 2212688b..355451c9 100755 --- a/bsnes/nall/string/utility.hpp +++ b/bsnes/nall/string/utility.hpp @@ -34,24 +34,15 @@ bool quotecopy(char *&t, T *&p) { return true; } -unsigned strlcpy(string &dest, const char *src, unsigned length) { - dest.reserve(length); - return strlcpy(dest(), src, length); -} - -unsigned strlcat(string &dest, const char *src, unsigned length) { - dest.reserve(length); - return strlcat(dest(), src, length); -} - string substr(const char *src, unsigned start, unsigned length) { string dest; + dest.reserve(length + 1); if(length == ~0u) { //copy entire string - dest = src + start; + strcpy(dest(), src + start); } else { //copy partial string - strlcpy(dest, src + start, length + 1); + strmcpy(dest(), src + start, length + 1); } return dest; } diff --git a/bsnes/nall/utility.hpp b/bsnes/nall/utility.hpp index ff8d8bee..8da56ff3 100755 --- a/bsnes/nall/utility.hpp +++ b/bsnes/nall/utility.hpp @@ -9,12 +9,6 @@ namespace nall { template struct enable_if {}; template struct mp_enable_if : enable_if {}; - template inline void swap(T &x, T &y) { - T temp(std::move(x)); - x = std::move(y); - y = std::move(temp); - } - template struct base_from_member { T value; base_from_member(T value_) : value(value_) {} diff --git a/bsnes/nall/vector.hpp b/bsnes/nall/vector.hpp index 1af16d29..e03214d0 100755 --- a/bsnes/nall/vector.hpp +++ b/bsnes/nall/vector.hpp @@ -55,15 +55,18 @@ namespace nall { new(pool + objectsize++) T(data); } - void prepend(const T& data) { + void insert(unsigned position, const T& data) { append(data); - for(unsigned n = objectsize - 1; n; n--) swap(pool[n], pool[n - 1]); + for(signed n = size() - 1; n > position; n--) pool[n] = pool[n - 1]; + pool[position] = data; + } + + void prepend(const T& data) { + insert(0, data); } void remove(unsigned index, unsigned count = 1) { - for(unsigned n = index; count + n < objectsize; n++) { - pool[n] = pool[count + n]; - } + for(unsigned n = index; count + n < objectsize; n++) pool[n] = pool[count + n]; objectsize = (count + index >= objectsize) ? index : objectsize - count; } diff --git a/bsnes/nes/cartridge/ines.cpp b/bsnes/nes/cartridge/ines.cpp index b6a91775..902ef440 100755 --- a/bsnes/nes/cartridge/ines.cpp +++ b/bsnes/nes/cartridge/ines.cpp @@ -151,7 +151,7 @@ static string iNES(const uint8_t *data, unsigned size) { "\n" ); - print(output, "\n"); +//print(output, "\n"); return output; } diff --git a/bsnes/phoenix/core/core.cpp b/bsnes/phoenix/core/core.cpp index f4396c3f..7e4c559e 100755 --- a/bsnes/phoenix/core/core.cpp +++ b/bsnes/phoenix/core/core.cpp @@ -50,6 +50,85 @@ Font::Font(const string &description): description(description) { } +//Desktop +//======= + +Size Desktop::size() { + return pDesktop::size(); +} + +Geometry Desktop::workspace() { + return pDesktop::workspace(); +} + +//Keyboard +//======== + +bool Keyboard::pressed(Keyboard::Scancode scancode) { + return pKeyboard::pressed(scancode); +} + +bool Keyboard::released(Keyboard::Scancode scancode) { + return !pressed(scancode); +} + +array Keyboard::state() { + return pKeyboard::state(); +} + +//Mouse +//===== + +Position Mouse::position() { + return pMouse::position(); +} + +bool Mouse::pressed(Mouse::Button button) { + return pMouse::pressed(button); +} + +bool Mouse::released(Mouse::Button button) { + return !pressed(button); +} + +//DialogWindow +//============ + +string DialogWindow::fileOpen_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pDialogWindow::fileOpen(parent, path, filter); +} + +string DialogWindow::fileSave_(Window &parent, const string &path, const lstring &filter_) { + auto filter = filter_; + if(filter.size() == 0) filter.append("All files (*)"); + return pDialogWindow::fileSave(parent, path, filter); +} + +string DialogWindow::folderSelect(Window &parent, const string &path) { + return pDialogWindow::folderSelect(parent, path); +} + +//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); +} + //Object //====== @@ -67,30 +146,6 @@ Object::~Object() { //OS //== -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(); } @@ -142,29 +197,10 @@ Timer::~Timer() { delete &state; } -//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) { +void Window::append_(Layout &layout) { if(state.layout.append(layout)) { ((Sizable&)layout).state.window = this; ((Sizable&)layout).state.layout = 0; @@ -173,14 +209,14 @@ void Window::append(Layout &layout) { } } -void Window::append(Menu &menu) { +void Window::append_(Menu &menu) { if(state.menu.append(menu)) { ((Action&)menu).state.window = this; p.append(menu); } } -void Window::append(Widget &widget) { +void Window::append_(Widget &widget) { if(state.widget.append(widget)) { ((Sizable&)widget).state.window = this; p.append(widget); @@ -220,21 +256,21 @@ void Window::ignore() { state.ignore = true; } -void Window::remove(Layout &layout) { +void Window::remove_(Layout &layout) { if(state.layout.remove(layout)) { p.remove(layout); ((Sizable&)layout).state.window = 0; } } -void Window::remove(Menu &menu) { +void Window::remove_(Menu &menu) { if(state.menu.remove(menu)) { p.remove(menu); ((Action&)menu).state.window = 0; } } -void Window::remove(Widget &widget) { +void Window::remove_(Widget &widget) { if(state.widget.remove(widget)) { p.remove(widget); ((Sizable&)widget).state.window = 0; @@ -376,17 +412,21 @@ Action::~Action() { //Menu //==== -void Menu::append(Action &action) { - if(state.action.append(action)) { - action.state.menu = this; - return p.append(action); +void Menu::append(const reference_array &list) { + for(auto &action : list) { + if(state.action.append(action)) { + action.state.menu = this; + p.append(action); + } } } -void Menu::remove(Action &action) { - if(state.action.remove(action)) { - action.state.menu = 0; - return p.remove(action); +void Menu::remove(const reference_array &list) { + for(auto &action : list) { + if(state.action.remove(action)) { + action.state.menu = 0; + return p.remove(action); + } } } @@ -425,6 +465,11 @@ Separator::~Separator() { //Item //==== +void Item::setImage(const image &image) { + state.image = image; + return p.setImage(image); +} + void Item::setText(const string &text) { state.text = text; return p.setText(text); @@ -658,6 +703,12 @@ Widget::~Widget() { //Button //====== +void Button::setImage(const image &image, Orientation orientation) { + state.image = image; + state.orientation = orientation; + return p.setImage(image, orientation); +} + void Button::setText(const string &text) { state.text = text; return p.setText(text); @@ -756,9 +807,11 @@ CheckBox::~CheckBox() { //ComboBox //======== -void ComboBox::append(const string &text) { - state.text.append(text); - return p.append(text); +void ComboBox::append_(const lstring &list) { + for(auto &text : list) { + state.text.append(text); + p.append(text); + } } void ComboBox::reset() { diff --git a/bsnes/phoenix/core/core.hpp b/bsnes/phoenix/core/core.hpp index 1e3d53ff..bb18b1f2 100755 --- a/bsnes/phoenix/core/core.hpp +++ b/bsnes/phoenix/core/core.hpp @@ -70,53 +70,48 @@ struct Geometry { Geometry(const nall::string &text); }; +enum class Orientation : unsigned { Horizontal, Vertical }; + struct Font { nall::string description; Geometry geometry(const nall::string &text); Font(const nall::string &description = ""); }; -struct Object { - Object(pObject &p); - Object& operator=(const Object&) = delete; - Object(const Object&) = delete; - virtual ~Object(); - pObject &p; +struct Desktop { + static Size size(); + static Geometry workspace(); + Desktop() = delete; }; -struct OS : Object { - static Geometry availableGeometry(); - static Geometry desktopGeometry(); - template static nall::string fileLoad(Window &parent, const nall::string &path, const Args&... args) { return fileLoad_(parent, path, { args... }); } +struct Keyboard { + #include "keyboard.hpp" + static bool pressed(Scancode scancode); + static bool released(Scancode scancode); + static nall::array state(); + Keyboard() = delete; +}; + +struct Mouse { + enum class Button : unsigned { Left, Middle, Right }; + static Position position(); + static bool pressed(Button); + static bool released(Button); + Mouse() = delete; +}; + +struct DialogWindow { + template static nall::string fileOpen(Window &parent, const nall::string &path, const Args&... args) { return fileOpen_(parent, path, { args... }); } template static nall::string fileSave(Window &parent, const nall::string &path, const Args&... args) { return fileSave_(parent, path, { args... }); } static nall::string folderSelect(Window &parent, const nall::string &path); - static void main(); - static bool pendingEvents(); - static void processEvents(); - static void quit(); - - OS(); - static void initialize(); + DialogWindow() = delete; private: - static nall::string fileLoad_(Window &parent, const nall::string &path, const nall::lstring& filter); + static nall::string fileOpen_(Window &parent, const nall::string &path, const nall::lstring& filter); static nall::string fileSave_(Window &parent, const nall::string &path, const nall::lstring& filter); }; -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; -}; - -struct MessageWindow : Object { +struct MessageWindow { enum class Buttons : unsigned { Ok, OkCancel, @@ -134,17 +129,56 @@ struct MessageWindow : Object { static Response question(Window &parent, const nall::string &text, Buttons = Buttons::YesNo); static Response warning(Window &parent, const nall::string &text, Buttons = Buttons::Ok); static Response critical(Window &parent, const nall::string &text, Buttons = Buttons::Ok); + MessageWindow() = delete; +}; + +struct Object { + Object(pObject &p); + Object& operator=(const Object&) = delete; + Object(const Object&) = delete; + virtual ~Object(); + pObject &p; +}; + +struct OS : Object { + static void main(); + static bool pendingEvents(); + static void processEvents(); + static void quit(); + + OS(); + static void initialize(); +}; + +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; }; struct Window : private nall::base_from_member, Object { static Window None; nall::function onClose; + nall::function onKeyPress; + nall::function onKeyRelease; nall::function onMove; nall::function onSize; - void append(Layout &layout); - void append(Menu &menu); - void append(Widget &widget); + inline void append() {} + inline void remove() {} + template void append(T &arg, Args&... args) { append_(arg); append(args...); } + template void remove(T &arg, Args&... args) { remove_(arg); remove(args...); } + + void append_(Layout &layout); + void append_(Menu &menu); + void append_(Widget &widget); Color backgroundColor(); Geometry frameGeometry(); Geometry frameMargin(); @@ -152,9 +186,9 @@ struct Window : private nall::base_from_member, Object { bool fullScreen(); Geometry geometry(); void ignore(); - void remove(Layout &layout); - void remove(Menu &menu); - void remove(Widget &widget); + void remove_(Layout &layout); + void remove_(Menu &menu); + void remove_(Widget &widget); void setBackgroundColor(const Color &color); void setFrameGeometry(const Geometry &geometry); void setFocused(); @@ -194,8 +228,11 @@ struct Action : Object { }; struct Menu : private nall::base_from_member, Action { - void append(Action &action); - void remove(Action &action); + template void append(Args&... args) { append({ args... }); } + template void remove(Args&... args) { remove({ args... }); } + + void append(const nall::reference_array &list); + void remove(const nall::reference_array &list); void setText(const nall::string &text); Menu(); @@ -214,6 +251,7 @@ struct Separator : private nall::base_from_member, Action { struct Item : private nall::base_from_member, Action { nall::function onActivate; + void setImage(const nall::image &image); void setText(const nall::string &text); Item(); @@ -308,6 +346,7 @@ struct Widget : private nall::base_from_member, Sizable { struct Button : private nall::base_from_member, Widget { nall::function onActivate; + void setImage(const nall::image &image, Orientation = Orientation::Horizontal); void setText(const nall::string &text); Button(); @@ -348,7 +387,9 @@ struct CheckBox : private nall::base_from_member, Widget { struct ComboBox : private nall::base_from_member, Widget { nall::function onChange; - void append(const nall::string &text); + template void append(const Args&... args) { append_({ args... }); } + + void append_(const nall::lstring &list); void reset(); unsigned selection(); void setSelection(unsigned row); @@ -438,15 +479,19 @@ struct ListView : private nall::base_from_member, Widget { nall::function onToggle; template void append(const Args&... args) { append_({ args... }); } + template void modify(unsigned row, const Args&... args) { modify_(row, { args... }); } + template void setHeaderText(const Args&... args) { setHeaderText_({ args... }); } + + void append_(const nall::lstring &list); void autoSizeColumns(); bool checked(unsigned row); - template void modify(unsigned row, const Args&... args) { modify_(row, { args... }); } + void modify_(unsigned row, const nall::lstring &list); void reset(); bool selected(); unsigned selection(); void setCheckable(bool checkable = true); void setChecked(unsigned row, bool checked = true); - template void setHeaderText(const Args&... args) { setHeaderText_({ args... }); } + void setHeaderText_(const nall::lstring &list); void setHeaderVisible(bool visible = true); void setSelected(bool selected = true); void setSelection(unsigned row); @@ -456,11 +501,6 @@ struct ListView : private nall::base_from_member, Widget { struct State; State &state; pListView &p; - -private: - void append_(const nall::lstring &list); - void modify_(unsigned row, const nall::lstring &list); - void setHeaderText_(const nall::lstring &list); }; struct ProgressBar : private nall::base_from_member, Widget { diff --git a/bsnes/phoenix/core/keyboard.hpp b/bsnes/phoenix/core/keyboard.hpp new file mode 100755 index 00000000..ed04ec05 --- /dev/null +++ b/bsnes/phoenix/core/keyboard.hpp @@ -0,0 +1,45 @@ +//each code refers to a physical key +//names are taken assuming: NumLock on, CapsLock off, Shift off +//layout uses US-104 keyboard +enum class Scancode : unsigned { + None, + + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + PrintScreen, ScrollLock, Pause, + Insert, Delete, Home, End, PageUp, PageDown, + Up, Down, Left, Right, + + Grave, Number1, Number2, Number3, Number4, Number5, Number6, Number7, Number8, Number9, Number0, Minus, Equal, Backspace, + BracketLeft, BracketRight, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, + Tab, CapsLock, Return, ShiftLeft, ShiftRight, ControlLeft, ControlRight, SuperLeft, SuperRight, AltLeft, AltRight, Space, Menu, + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + + NumLock, Divide, Multiply, Subtract, Add, Enter, Point, + Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, + + Limit, +}; + +//each enum refers to a translated scancode (eg Shift+1 = !) +enum class Keycode : unsigned { + None, + + Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + PrintScreen, SysRq, ScrollLock, Pause, Break, + Insert, Delete, Home, End, PageUp, PageDown, + Up, Down, Left, Right, + + Grave, Number1, Number2, Number3, Number4, Number5, Number6, Number7, Number8, Number9, Number0, Minus, Equal, Backspace, + Tilde, Exclamation, At, Pound, Dollar, Percent, Power, Ampersand, Asterisk, ParenthesisLeft, ParenthesisRight, Underscore, Plus, + BracketLeft, BracketRight, Backslash, Semicolon, Apostrophe, Comma, Period, Slash, + BraceLeft, BraceRight, Pipe, Colon, Quote, CaretLeft, CaretRight, Question, + Tab, CapsLock, Return, ShiftLeft, ShiftRight, ControlLeft, ControlRight, SuperLeft, SuperRight, AltLeft, AltRight, Space, Menu, + A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, + + NumLock, Divide, Multiply, Subtract, Add, Enter, Point, + Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0, + KeypadInsert, KeypadDelete, KeypadHome, KeypadEnd, KeypadPageUp, KeypadPageDown, KeypadUp, KeypadDown, KeypadLeft, KeypadRight, KeypadCenter, + + Limit, +}; diff --git a/bsnes/phoenix/core/state.hpp b/bsnes/phoenix/core/state.hpp index 136d89e7..e0c3b2df 100755 --- a/bsnes/phoenix/core/state.hpp +++ b/bsnes/phoenix/core/state.hpp @@ -60,7 +60,11 @@ struct Menu::State { }; struct Item::State { + nall::image image; string text; + + State() : image(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) { + } }; struct CheckItem::State { @@ -113,9 +117,11 @@ struct Widget::State { }; struct Button::State { + nall::image image; + Orientation orientation; string text; - State() { + State() : image(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) { } }; diff --git a/bsnes/phoenix/gtk/action/item.cpp b/bsnes/phoenix/gtk/action/item.cpp index 907c0b49..d3a505eb 100755 --- a/bsnes/phoenix/gtk/action/item.cpp +++ b/bsnes/phoenix/gtk/action/item.cpp @@ -2,12 +2,17 @@ static void Item_activate(Item *self) { if(self->onActivate) self->onActivate(); } +void pItem::setImage(const image &image) { + GtkImage *gtkImage = CreateImage(image, /* menuIcon = */ true); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), (GtkWidget*)gtkImage); +} + void pItem::setText(const string &text) { gtk_menu_item_set_label(GTK_MENU_ITEM(widget), text); } void pItem::constructor() { - widget = gtk_menu_item_new_with_label(item.state.text); + widget = gtk_image_menu_item_new_with_label(item.state.text); g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_activate), (gpointer)&item); } diff --git a/bsnes/phoenix/gtk/desktop.cpp b/bsnes/phoenix/gtk/desktop.cpp new file mode 100755 index 00000000..2b1801ad --- /dev/null +++ b/bsnes/phoenix/gtk/desktop.cpp @@ -0,0 +1,36 @@ +Size pDesktop::size() { + return { + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; +} + +Geometry pDesktop::workspace() { + XlibDisplay *display = XOpenDisplay(0); + int screen = DefaultScreen(display); + + static Atom atom = XlibNone; + if(atom == XlibNone) atom = XInternAtom(display, "_NET_WORKAREA", True); + + int format; + unsigned char *data = 0; + unsigned long items, after; + Atom returnAtom; + + int result = XGetWindowProperty( + display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data + ); + + XCloseDisplay(display); + + if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) { + unsigned long *workarea = (unsigned long*)data; + return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] }; + } + + return { + 0, 0, + gdk_screen_get_width(gdk_screen_get_default()), + gdk_screen_get_height(gdk_screen_get_default()) + }; +} diff --git a/bsnes/phoenix/gtk/dialog-window.cpp b/bsnes/phoenix/gtk/dialog-window.cpp new file mode 100755 index 00000000..b9d64886 --- /dev/null +++ b/bsnes/phoenix/gtk/dialog-window.cpp @@ -0,0 +1,69 @@ +static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) { + string name; + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + save == 0 ? "Load File" : "Save File", + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + save == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)0 + ); + + if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + for(auto &filterItem : filter) { + GtkFileFilter *gtkFilter = gtk_file_filter_new(); + gtk_file_filter_set_name(gtkFilter, filterItem); + lstring part; + part.split("(", filterItem); + part[1].rtrim<1>(")"); + lstring list; + list.split(",", part[1]); + for(auto &pattern : list) gtk_file_filter_add_pattern(gtkFilter, pattern); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); + } + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + return name; +} + +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + return FileDialog(0, parent, path, filter); +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + return FileDialog(1, parent, path, filter); +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + string name; + + GtkWidget *dialog = gtk_file_chooser_dialog_new( + "Select Folder", + &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + (const gchar*)0 + ); + + if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); + + if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + name = temp; + g_free(temp); + } + + gtk_widget_destroy(dialog); + if(name == "") return ""; + if(name.endswith("/") == false) name.append("/"); + return name; +} diff --git a/bsnes/phoenix/gtk/keyboard.cpp b/bsnes/phoenix/gtk/keyboard.cpp new file mode 100755 index 00000000..6082d376 --- /dev/null +++ b/bsnes/phoenix/gtk/keyboard.cpp @@ -0,0 +1,144 @@ +bidirectional_map pKeyboard::keymap; + +void pKeyboard::initialize() { + auto append = [](Keyboard::Scancode scancode, unsigned keysym) { + keymap.append(scancode, XKeysymToKeycode(pOS::display, keysym)); + }; + + append(Keyboard::Scancode::Escape, XK_Escape); + append(Keyboard::Scancode::F1, XK_F1); + append(Keyboard::Scancode::F2, XK_F2); + append(Keyboard::Scancode::F3, XK_F3); + append(Keyboard::Scancode::F4, XK_F4); + append(Keyboard::Scancode::F5, XK_F5); + append(Keyboard::Scancode::F6, XK_F6); + append(Keyboard::Scancode::F7, XK_F7); + append(Keyboard::Scancode::F8, XK_F8); + append(Keyboard::Scancode::F9, XK_F9); + append(Keyboard::Scancode::F10, XK_F10); + append(Keyboard::Scancode::F11, XK_F11); + append(Keyboard::Scancode::F12, XK_F12); + + append(Keyboard::Scancode::PrintScreen, XK_Print); + append(Keyboard::Scancode::ScrollLock, XK_Scroll_Lock); + append(Keyboard::Scancode::Pause, XK_Pause); + + append(Keyboard::Scancode::Insert, XK_Insert); + append(Keyboard::Scancode::Delete, XK_Delete); + append(Keyboard::Scancode::Home, XK_Home); + append(Keyboard::Scancode::End, XK_End); + append(Keyboard::Scancode::PageUp, XK_Prior); + append(Keyboard::Scancode::PageDown, XK_Next); + + append(Keyboard::Scancode::Up, XK_Up); + append(Keyboard::Scancode::Down, XK_Down); + append(Keyboard::Scancode::Left, XK_Left); + append(Keyboard::Scancode::Right, XK_Right); + + append(Keyboard::Scancode::Grave, XK_asciitilde); + append(Keyboard::Scancode::Number1, XK_1); + append(Keyboard::Scancode::Number2, XK_2); + append(Keyboard::Scancode::Number3, XK_3); + append(Keyboard::Scancode::Number4, XK_4); + append(Keyboard::Scancode::Number5, XK_5); + append(Keyboard::Scancode::Number6, XK_6); + append(Keyboard::Scancode::Number7, XK_7); + append(Keyboard::Scancode::Number8, XK_8); + append(Keyboard::Scancode::Number9, XK_9); + append(Keyboard::Scancode::Number0, XK_0); + append(Keyboard::Scancode::Minus, XK_minus); + append(Keyboard::Scancode::Equal, XK_equal); + append(Keyboard::Scancode::Backspace, XK_BackSpace); + + append(Keyboard::Scancode::BracketLeft, XK_bracketleft); + append(Keyboard::Scancode::BracketRight, XK_bracketright); + append(Keyboard::Scancode::Backslash, XK_backslash); + append(Keyboard::Scancode::Semicolon, XK_semicolon); + append(Keyboard::Scancode::Apostrophe, XK_apostrophe); + append(Keyboard::Scancode::Comma, XK_comma); + append(Keyboard::Scancode::Period, XK_period); + append(Keyboard::Scancode::Slash, XK_slash); + + append(Keyboard::Scancode::Tab, XK_Tab); + append(Keyboard::Scancode::CapsLock, XK_Caps_Lock); + append(Keyboard::Scancode::Return, XK_Return); + append(Keyboard::Scancode::ShiftLeft, XK_Shift_L); + append(Keyboard::Scancode::ShiftRight, XK_Shift_R); + append(Keyboard::Scancode::ControlLeft, XK_Control_L); + append(Keyboard::Scancode::ControlRight, XK_Control_R); + append(Keyboard::Scancode::SuperLeft, XK_Super_L); + append(Keyboard::Scancode::SuperRight, XK_Super_R); + append(Keyboard::Scancode::AltLeft, XK_Alt_L); + append(Keyboard::Scancode::AltRight, XK_Alt_R); + append(Keyboard::Scancode::Space, XK_space); + append(Keyboard::Scancode::Menu, XK_Menu); + + append(Keyboard::Scancode::A, XK_A); + append(Keyboard::Scancode::B, XK_B); + append(Keyboard::Scancode::C, XK_C); + append(Keyboard::Scancode::D, XK_D); + append(Keyboard::Scancode::E, XK_E); + append(Keyboard::Scancode::F, XK_F); + append(Keyboard::Scancode::G, XK_G); + append(Keyboard::Scancode::H, XK_H); + append(Keyboard::Scancode::I, XK_I); + append(Keyboard::Scancode::J, XK_J); + append(Keyboard::Scancode::K, XK_K); + append(Keyboard::Scancode::L, XK_L); + append(Keyboard::Scancode::M, XK_M); + append(Keyboard::Scancode::N, XK_N); + append(Keyboard::Scancode::O, XK_O); + append(Keyboard::Scancode::P, XK_P); + append(Keyboard::Scancode::Q, XK_Q); + append(Keyboard::Scancode::R, XK_R); + append(Keyboard::Scancode::S, XK_S); + append(Keyboard::Scancode::T, XK_T); + append(Keyboard::Scancode::U, XK_U); + append(Keyboard::Scancode::V, XK_V); + append(Keyboard::Scancode::W, XK_W); + append(Keyboard::Scancode::X, XK_X); + append(Keyboard::Scancode::Y, XK_Y); + append(Keyboard::Scancode::Z, XK_Z); + + append(Keyboard::Scancode::NumLock, XK_Num_Lock); + append(Keyboard::Scancode::Divide, XK_KP_Divide); + append(Keyboard::Scancode::Multiply, XK_KP_Multiply); + append(Keyboard::Scancode::Subtract, XK_KP_Subtract); + append(Keyboard::Scancode::Add, XK_KP_Add); + append(Keyboard::Scancode::Enter, XK_KP_Enter); + append(Keyboard::Scancode::Point, XK_KP_Decimal); + + append(Keyboard::Scancode::Keypad1, XK_KP_1); + append(Keyboard::Scancode::Keypad2, XK_KP_2); + append(Keyboard::Scancode::Keypad3, XK_KP_3); + append(Keyboard::Scancode::Keypad4, XK_KP_4); + append(Keyboard::Scancode::Keypad5, XK_KP_5); + append(Keyboard::Scancode::Keypad6, XK_KP_6); + append(Keyboard::Scancode::Keypad7, XK_KP_7); + append(Keyboard::Scancode::Keypad8, XK_KP_8); + append(Keyboard::Scancode::Keypad9, XK_KP_9); + append(Keyboard::Scancode::Keypad0, XK_KP_0); +} + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + char state[256]; + XQueryKeymap(pOS::display, state); + unsigned id = keymap.lhs[scancode]; + return state[id >> 3] & (1 << (id & 7)); +} + +array pKeyboard::state() { + array output; + output.reserve((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + + char state[256]; + XQueryKeymap(pOS::display, state); + for(auto &n : keymap.rhs) { + if(state[n.name >> 3] & (1 << (n.name & 7))) { + output[(unsigned)n.data] = true; + } + } + + return output; +} diff --git a/bsnes/phoenix/gtk/mouse.cpp b/bsnes/phoenix/gtk/mouse.cpp new file mode 100755 index 00000000..e00f7ff7 --- /dev/null +++ b/bsnes/phoenix/gtk/mouse.cpp @@ -0,0 +1,20 @@ +Position pMouse::position() { + XlibWindow root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + XQueryPointer(pOS::display, DefaultRootWindow(pOS::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); + return { rootx, rooty }; +} + +bool pMouse::pressed(Mouse::Button button) { + XlibWindow root, child; + int rootx, rooty, winx, winy; + unsigned int mask; + XQueryPointer(pOS::display, DefaultRootWindow(pOS::display), &root, &child, &rootx, &rooty, &winx, &winy, &mask); + switch(button) { + case Mouse::Button::Left: return mask & Button1Mask; + case Mouse::Button::Middle: return mask & Button2Mask; + case Mouse::Button::Right: return mask & Button3Mask; + } + return false; +} diff --git a/bsnes/phoenix/gtk/platform.cpp b/bsnes/phoenix/gtk/platform.cpp index 6801aef3..0866412a 100755 --- a/bsnes/phoenix/gtk/platform.cpp +++ b/bsnes/phoenix/gtk/platform.cpp @@ -1,9 +1,15 @@ #include "platform.hpp" +#include "utility.cpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" #include "settings.cpp" #include "font.cpp" #include "timer.cpp" -#include "message-window.cpp" #include "window.cpp" #include "action/action.cpp" @@ -31,112 +37,9 @@ #include "widget/vertical-slider.cpp" #include "widget/viewport.cpp" +XlibDisplay* pOS::display = 0; Font pOS::defaultFont; -Geometry pOS::availableGeometry() { - XlibDisplay *display = XOpenDisplay(0); - int screen = DefaultScreen(display); - - static Atom atom = XlibNone; - if(atom == XlibNone) atom = XInternAtom(display, "_NET_WORKAREA", True); - - int format; - unsigned char *data = 0; - unsigned long items, after; - Atom returnAtom; - - int result = XGetWindowProperty( - display, RootWindow(display, screen), atom, 0, 4, False, XA_CARDINAL, &returnAtom, &format, &items, &after, &data - ); - - XCloseDisplay(display); - - if(result == Success && returnAtom == XA_CARDINAL && format == 32 && items == 4) { - unsigned long *workarea = (unsigned long*)data; - return { (signed)workarea[0], (signed)workarea[1], (unsigned)workarea[2], (unsigned)workarea[3] }; - } - - return desktopGeometry(); -} - -Geometry pOS::desktopGeometry() { - return { - 0, 0, - gdk_screen_get_width(gdk_screen_get_default()), - gdk_screen_get_height(gdk_screen_get_default()) - }; -} - -static string pOS_fileDialog(bool save, Window &parent, const string &path, const lstring &filter) { - string name; - - GtkWidget *dialog = gtk_file_chooser_dialog_new( - save == 0 ? "Load File" : "Save File", - &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, - save == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - (const gchar*)0 - ); - - if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); - - for(auto &filterItem : filter) { - GtkFileFilter *gtkFilter = gtk_file_filter_new(); - gtk_file_filter_set_name(gtkFilter, filterItem); - lstring part; - part.split("(", filterItem); - part[1].rtrim<1>(")"); - lstring list; - list.split(",", part[1]); - for(auto &pattern : list) gtk_file_filter_add_pattern(gtkFilter, pattern); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); - } - - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - name = temp; - g_free(temp); - } - - gtk_widget_destroy(dialog); - return name; -} - -string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { - return pOS_fileDialog(0, parent, path, filter); -} - -string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { - return pOS_fileDialog(1, parent, path, filter); -} - -string pOS::folderSelect(Window &parent, const string &path) { - string name; - - GtkWidget *dialog = gtk_file_chooser_dialog_new( - "Select Folder", - &parent != &Window::None ? GTK_WINDOW(parent.p.widget) : (GtkWindow*)0, - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - (const gchar*)0 - ); - - if(path) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), path); - - if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *temp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - name = temp; - g_free(temp); - } - - gtk_widget_destroy(dialog); - if(name == "") return ""; - if(name.endswith("/") == false) name.append("/"); - return name; -} - void pOS::main() { gtk_main(); } @@ -154,6 +57,8 @@ void pOS::quit() { } void pOS::initialize() { + display = XOpenDisplay(0); + settings = new Settings; settings->load(); @@ -177,4 +82,6 @@ void pOS::initialize() { class "GtkTreeView" style "phoenix-gtk" # class "GtkComboBox" style "phoenix-gtk" )"); + + pKeyboard::initialize(); } diff --git a/bsnes/phoenix/gtk/platform.hpp b/bsnes/phoenix/gtk/platform.hpp index 8ce3ed92..c46b051d 100755 --- a/bsnes/phoenix/gtk/platform.hpp +++ b/bsnes/phoenix/gtk/platform.hpp @@ -26,6 +26,38 @@ struct pFont { static void setFont(GtkWidget *widget, gpointer font); }; +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bidirectional_map keymap; + + static bool pressed(Keyboard::Scancode scancode); + static array state(); + + static void initialize(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + struct pObject { Object &object; bool locked; @@ -38,13 +70,9 @@ struct pObject { }; struct pOS : public pObject { + static XlibDisplay *display; static Font defaultFont; - static Geometry availableGeometry(); - static Geometry desktopGeometry(); - static string fileLoad(Window &parent, const string &path, const lstring &filter); - static string fileSave(Window &parent, const string &path, const lstring &filter); - static string folderSelect(Window &parent, const string &path); static void main(); static bool pendingEvents(); static void processEvents(); @@ -63,13 +91,6 @@ struct pTimer : public pObject { void constructor(); }; -struct pMessageWindow : public pObject { - static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); -}; - struct pWindow : public pObject { Window &window; GtkWidget *widget; @@ -150,6 +171,7 @@ struct pSeparator : public pAction { struct pItem : public pAction { Item &item; + void setImage(const image &image); void setText(const string &text); pItem(Item &item) : pAction(item), item(item) {} @@ -219,6 +241,7 @@ struct pButton : public pWidget { Button &button; Geometry minimumGeometry(); + void setImage(const image &image, Orientation orientation); void setText(const string &text); pButton(Button &button) : pWidget(button), button(button) {} diff --git a/bsnes/phoenix/gtk/settings.cpp b/bsnes/phoenix/gtk/settings.cpp index 0905288f..aedc20be 100755 --- a/bsnes/phoenix/gtk/settings.cpp +++ b/bsnes/phoenix/gtk/settings.cpp @@ -15,10 +15,10 @@ void Settings::save() { } Settings::Settings() { - attach(frameGeometryX = 4, "frameGeometryX"); - attach(frameGeometryY = 24, "frameGeometryY"); - attach(frameGeometryWidth = 8, "frameGeometryWidth"); - attach(frameGeometryHeight = 28, "frameGeometryHeight"); - attach(menuGeometryHeight = 20, "menuGeometryHeight"); - attach(statusGeometryHeight = 20, "statusGeometryHeight"); + append(frameGeometryX = 4, "frameGeometryX"); + append(frameGeometryY = 24, "frameGeometryY"); + append(frameGeometryWidth = 8, "frameGeometryWidth"); + append(frameGeometryHeight = 28, "frameGeometryHeight"); + append(menuGeometryHeight = 20, "menuGeometryHeight"); + append(statusGeometryHeight = 20, "statusGeometryHeight"); } diff --git a/bsnes/phoenix/gtk/utility.cpp b/bsnes/phoenix/gtk/utility.cpp new file mode 100755 index 00000000..360e51e3 --- /dev/null +++ b/bsnes/phoenix/gtk/utility.cpp @@ -0,0 +1,195 @@ +static GtkImage* CreateImage(const nall::image &image, bool menuIcon = false) { + nall::image gdkImage = image; + gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); //GTK+ uses ABGR format + if(menuIcon) gdkImage.scale(16, 16, Interpolation::Linear); + + GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, gdkImage.width, gdkImage.height); + memcpy(gdk_pixbuf_get_pixels(pixbuf), gdkImage.data, gdkImage.width * gdkImage.height * 4); + GtkImage *gtkImage = (GtkImage*)gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + + return gtkImage; +} + +static Keyboard::Keycode Keysym(unsigned keysym) { + switch(keysym) { + case GDK_Escape: return Keyboard::Keycode::Escape; + case GDK_F1: return Keyboard::Keycode::F1; + case GDK_F2: return Keyboard::Keycode::F2; + case GDK_F3: return Keyboard::Keycode::F3; + case GDK_F4: return Keyboard::Keycode::F4; + case GDK_F5: return Keyboard::Keycode::F5; + case GDK_F6: return Keyboard::Keycode::F6; + case GDK_F7: return Keyboard::Keycode::F7; + case GDK_F8: return Keyboard::Keycode::F8; + case GDK_F9: return Keyboard::Keycode::F9; + case GDK_F10: return Keyboard::Keycode::F10; + case GDK_F11: return Keyboard::Keycode::F11; + case GDK_F12: return Keyboard::Keycode::F12; + + case GDK_Print: return Keyboard::Keycode::PrintScreen; + //Keyboard::Keycode::SysRq + case GDK_Scroll_Lock: return Keyboard::Keycode::ScrollLock; + case GDK_Pause: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case GDK_Insert: return Keyboard::Keycode::Insert; + case GDK_Delete: return Keyboard::Keycode::Delete; + case GDK_Home: return Keyboard::Keycode::Home; + case GDK_End: return Keyboard::Keycode::End; + case GDK_Prior: return Keyboard::Keycode::PageUp; + case GDK_Next: return Keyboard::Keycode::PageDown; + + case GDK_Up: return Keyboard::Keycode::Up; + case GDK_Down: return Keyboard::Keycode::Down; + case GDK_Left: return Keyboard::Keycode::Left; + case GDK_Right: return Keyboard::Keycode::Right; + + case GDK_grave: return Keyboard::Keycode::Grave; + case GDK_1: return Keyboard::Keycode::Number1; + case GDK_2: return Keyboard::Keycode::Number2; + case GDK_3: return Keyboard::Keycode::Number3; + case GDK_4: return Keyboard::Keycode::Number4; + case GDK_5: return Keyboard::Keycode::Number5; + case GDK_6: return Keyboard::Keycode::Number6; + case GDK_7: return Keyboard::Keycode::Number7; + case GDK_8: return Keyboard::Keycode::Number8; + case GDK_9: return Keyboard::Keycode::Number9; + case GDK_0: return Keyboard::Keycode::Number0; + case GDK_minus: return Keyboard::Keycode::Minus; + case GDK_equal: return Keyboard::Keycode::Equal; + case GDK_BackSpace: return Keyboard::Keycode::Backspace; + + case GDK_asciitilde: return Keyboard::Keycode::Tilde; + case GDK_exclam: return Keyboard::Keycode::Exclamation; + case GDK_at: return Keyboard::Keycode::At; + case GDK_numbersign: return Keyboard::Keycode::Pound; + case GDK_dollar: return Keyboard::Keycode::Dollar; + case GDK_percent: return Keyboard::Keycode::Percent; + case GDK_asciicircum: return Keyboard::Keycode::Power; + case GDK_ampersand: return Keyboard::Keycode::Ampersand; + case GDK_asterisk: return Keyboard::Keycode::Asterisk; + case GDK_parenleft: return Keyboard::Keycode::ParenthesisLeft; + case GDK_parenright: return Keyboard::Keycode::ParenthesisRight; + case GDK_underscore: return Keyboard::Keycode::Underscore; + case GDK_plus: return Keyboard::Keycode::Plus; + + case GDK_bracketleft: return Keyboard::Keycode::BracketLeft; + case GDK_bracketright: return Keyboard::Keycode::BracketRight; + case GDK_backslash: return Keyboard::Keycode::Backslash; + case GDK_semicolon: return Keyboard::Keycode::Semicolon; + case GDK_apostrophe: return Keyboard::Keycode::Apostrophe; + case GDK_comma: return Keyboard::Keycode::Comma; + case GDK_period: return Keyboard::Keycode::Period; + case GDK_slash: return Keyboard::Keycode::Slash; + + case GDK_braceleft: return Keyboard::Keycode::BraceLeft; + case GDK_braceright: return Keyboard::Keycode::BraceRight; + case GDK_bar: return Keyboard::Keycode::Pipe; + case GDK_colon: return Keyboard::Keycode::Colon; + case GDK_quotedbl: return Keyboard::Keycode::Quote; + case GDK_less: return Keyboard::Keycode::CaretLeft; + case GDK_greater: return Keyboard::Keycode::CaretRight; + case GDK_question: return Keyboard::Keycode::Question; + + case GDK_Tab: return Keyboard::Keycode::Tab; + case GDK_Caps_Lock: return Keyboard::Keycode::CapsLock; + case GDK_Return: return Keyboard::Keycode::Return; + case GDK_Shift_L: return Keyboard::Keycode::ShiftLeft; + case GDK_Shift_R: return Keyboard::Keycode::ShiftRight; + case GDK_Control_L: return Keyboard::Keycode::ControlLeft; + case GDK_Control_R: return Keyboard::Keycode::ControlRight; + case GDK_Super_L: return Keyboard::Keycode::SuperLeft; + case GDK_Super_R: return Keyboard::Keycode::SuperRight; + case GDK_Alt_L: return Keyboard::Keycode::AltLeft; + case GDK_Alt_R: return Keyboard::Keycode::AltRight; + case GDK_space: return Keyboard::Keycode::Space; + case GDK_Menu: return Keyboard::Keycode::Menu; + + case GDK_A: return Keyboard::Keycode::A; + case GDK_B: return Keyboard::Keycode::B; + case GDK_C: return Keyboard::Keycode::C; + case GDK_D: return Keyboard::Keycode::D; + case GDK_E: return Keyboard::Keycode::E; + case GDK_F: return Keyboard::Keycode::F; + case GDK_G: return Keyboard::Keycode::G; + case GDK_H: return Keyboard::Keycode::H; + case GDK_I: return Keyboard::Keycode::I; + case GDK_J: return Keyboard::Keycode::J; + case GDK_K: return Keyboard::Keycode::K; + case GDK_L: return Keyboard::Keycode::L; + case GDK_M: return Keyboard::Keycode::M; + case GDK_N: return Keyboard::Keycode::N; + case GDK_O: return Keyboard::Keycode::O; + case GDK_P: return Keyboard::Keycode::P; + case GDK_Q: return Keyboard::Keycode::Q; + case GDK_R: return Keyboard::Keycode::R; + case GDK_S: return Keyboard::Keycode::S; + case GDK_T: return Keyboard::Keycode::T; + case GDK_U: return Keyboard::Keycode::U; + case GDK_V: return Keyboard::Keycode::V; + case GDK_W: return Keyboard::Keycode::W; + case GDK_X: return Keyboard::Keycode::X; + case GDK_Y: return Keyboard::Keycode::Y; + case GDK_Z: return Keyboard::Keycode::Z; + + case GDK_a: return Keyboard::Keycode::a; + case GDK_b: return Keyboard::Keycode::b; + case GDK_c: return Keyboard::Keycode::c; + case GDK_d: return Keyboard::Keycode::d; + case GDK_e: return Keyboard::Keycode::e; + case GDK_f: return Keyboard::Keycode::f; + case GDK_g: return Keyboard::Keycode::g; + case GDK_h: return Keyboard::Keycode::h; + case GDK_i: return Keyboard::Keycode::i; + case GDK_j: return Keyboard::Keycode::j; + case GDK_k: return Keyboard::Keycode::k; + case GDK_l: return Keyboard::Keycode::l; + case GDK_m: return Keyboard::Keycode::m; + case GDK_n: return Keyboard::Keycode::n; + case GDK_o: return Keyboard::Keycode::o; + case GDK_p: return Keyboard::Keycode::p; + case GDK_q: return Keyboard::Keycode::q; + case GDK_r: return Keyboard::Keycode::r; + case GDK_s: return Keyboard::Keycode::s; + case GDK_t: return Keyboard::Keycode::t; + case GDK_u: return Keyboard::Keycode::u; + case GDK_v: return Keyboard::Keycode::v; + case GDK_w: return Keyboard::Keycode::w; + case GDK_x: return Keyboard::Keycode::x; + case GDK_y: return Keyboard::Keycode::y; + case GDK_z: return Keyboard::Keycode::z; + + case GDK_Num_Lock: return Keyboard::Keycode::NumLock; + case GDK_KP_Divide: return Keyboard::Keycode::Divide; + case GDK_KP_Multiply: return Keyboard::Keycode::Multiply; + case GDK_KP_Subtract: return Keyboard::Keycode::Subtract; + case GDK_KP_Add: return Keyboard::Keycode::Add; + case GDK_KP_Enter: return Keyboard::Keycode::Enter; + case GDK_KP_Decimal: return Keyboard::Keycode::Point; + + case GDK_KP_1: return Keyboard::Keycode::Keypad1; + case GDK_KP_2: return Keyboard::Keycode::Keypad2; + case GDK_KP_3: return Keyboard::Keycode::Keypad3; + case GDK_KP_4: return Keyboard::Keycode::Keypad4; + case GDK_KP_5: return Keyboard::Keycode::Keypad5; + case GDK_KP_6: return Keyboard::Keycode::Keypad6; + case GDK_KP_7: return Keyboard::Keycode::Keypad7; + case GDK_KP_8: return Keyboard::Keycode::Keypad8; + case GDK_KP_9: return Keyboard::Keycode::Keypad9; + case GDK_KP_0: return Keyboard::Keycode::Keypad0; + + case GDK_KP_Home: return Keyboard::Keycode::KeypadHome; + case GDK_KP_End: return Keyboard::Keycode::KeypadEnd; + case GDK_KP_Page_Up: return Keyboard::Keycode::KeypadPageUp; + case GDK_KP_Page_Down: return Keyboard::Keycode::KeypadPageDown; + case GDK_KP_Up: return Keyboard::Keycode::KeypadUp; + case GDK_KP_Down: return Keyboard::Keycode::KeypadDown; + case GDK_KP_Left: return Keyboard::Keycode::KeypadLeft; + case GDK_KP_Right: return Keyboard::Keycode::KeypadRight; + case GDK_KP_Begin: return Keyboard::Keycode::KeypadCenter; + case GDK_KP_Insert: return Keyboard::Keycode::KeypadInsert; + case GDK_KP_Delete: return Keyboard::Keycode::KeypadDelete; + } + return Keyboard::Keycode::None; +} diff --git a/bsnes/phoenix/gtk/widget/button.cpp b/bsnes/phoenix/gtk/widget/button.cpp index 9d590a4c..485fdacb 100755 --- a/bsnes/phoenix/gtk/widget/button.cpp +++ b/bsnes/phoenix/gtk/widget/button.cpp @@ -4,9 +4,29 @@ static void Button_activate(Button *self) { Geometry pButton::minimumGeometry() { Geometry geometry = pFont::geometry(widget.state.font, button.state.text); + + if(button.state.orientation == Orientation::Horizontal) { + geometry.width += button.state.image.width; + geometry.height = max(button.state.image.height, geometry.height); + } + + if(button.state.orientation == Orientation::Vertical) { + geometry.width = max(button.state.image.width, geometry.width); + geometry.height += button.state.image.height; + } + return { 0, 0, geometry.width + 24, geometry.height + 12 }; } +void pButton::setImage(const image &image, Orientation orientation) { + GtkImage *gtkImage = CreateImage(image); + gtk_button_set_image(GTK_BUTTON(gtkWidget), (GtkWidget*)gtkImage); + switch(orientation) { + case Orientation::Horizontal: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_LEFT); break; + case Orientation::Vertical: gtk_button_set_image_position(GTK_BUTTON(gtkWidget), GTK_POS_TOP); break; + } +} + void pButton::setText(const string &text) { gtk_button_set_label(GTK_BUTTON(gtkWidget), text); setFont(widget.state.font); diff --git a/bsnes/phoenix/gtk/window.cpp b/bsnes/phoenix/gtk/window.cpp index 3b7f54fe..e6d08bc6 100755 --- a/bsnes/phoenix/gtk/window.cpp +++ b/bsnes/phoenix/gtk/window.cpp @@ -79,6 +79,18 @@ static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *win return false; } +static gboolean Window_keyPressEvent(GtkWidget *widget, GdkEventKey *event, Window *window) { + Keyboard::Keycode key = Keysym(event->keyval); + if(key != Keyboard::Keycode::None && window->onKeyPress) window->onKeyPress(key); + return false; +} + +static gboolean Window_keyReleaseEvent(GtkWidget *widget, GdkEventKey *event, Window *window) { + Keyboard::Keycode key = Keysym(event->keyval); + if(key != Keyboard::Keycode::None && window->onKeyRelease) window->onKeyRelease(key); + return false; +} + void pWindow::append(Layout &layout) { Geometry geometry = this->geometry(); geometry.x = geometry.y = 0; @@ -123,7 +135,7 @@ bool pWindow::focused() { Geometry pWindow::geometry() { if(window.state.fullScreen == true) { - return { 0, menuHeight(), OS::desktopGeometry().width, OS::desktopGeometry().height - menuHeight() - statusHeight() }; + return { 0, menuHeight(), Desktop::size().width, Desktop::size().height - menuHeight() - statusHeight() }; }; return window.state.geometry; } @@ -163,7 +175,7 @@ void pWindow::setFullScreen(bool fullScreen) { } else { gtk_window_fullscreen(GTK_WINDOW(widget)); gtk_window_set_decorated(GTK_WINDOW(widget), false); - gtk_widget_set_size_request(widget, OS::desktopGeometry().width, OS::desktopGeometry().height); + gtk_widget_set_size_request(widget, Desktop::size().width, Desktop::size().height); gtk_window_set_resizable(GTK_WINDOW(widget), false); } gdk_display_sync(gtk_widget_get_display(widget)); @@ -275,6 +287,8 @@ void pWindow::constructor() { 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); g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window); + g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window); } unsigned pWindow::menuHeight() { diff --git a/bsnes/phoenix/phoenix.cpp b/bsnes/phoenix/phoenix.cpp index 9db54560..422ab29e 100755 --- a/bsnes/phoenix/phoenix.cpp +++ b/bsnes/phoenix/phoenix.cpp @@ -17,13 +17,21 @@ #elif defined(PHOENIX_QT) #include #include + #include + #define XK_MISCELLANY + #define XK_LATIN1 + #include + #include + #undef XK_MISCELLANY + #undef XK_LATIN1 + #include #elif defined(PHOENIX_GTK) #include #include #include #include - #include #include + #include #include #include #elif defined(PHOENIX_REFERENCE) diff --git a/bsnes/phoenix/phoenix.hpp b/bsnes/phoenix/phoenix.hpp index 33903fea..4767d0ed 100755 --- a/bsnes/phoenix/phoenix.hpp +++ b/bsnes/phoenix/phoenix.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include diff --git a/bsnes/phoenix/qt/action/item.cpp b/bsnes/phoenix/qt/action/item.cpp index f53aa5b6..a516909d 100755 --- a/bsnes/phoenix/qt/action/item.cpp +++ b/bsnes/phoenix/qt/action/item.cpp @@ -1,3 +1,12 @@ +void pItem::setImage(const image &image) { + nall::image qtBuffer = image; + qtBuffer.transform(0, 32u, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + + QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); + QIcon qtIcon(QPixmap::fromImage(qtImage)); + qtAction->setIcon(qtIcon); +} + void pItem::setText(const string &text) { qtAction->setText(QString::fromUtf8(text)); } diff --git a/bsnes/phoenix/qt/desktop.cpp b/bsnes/phoenix/qt/desktop.cpp new file mode 100755 index 00000000..554106b5 --- /dev/null +++ b/bsnes/phoenix/qt/desktop.cpp @@ -0,0 +1,9 @@ +Size pDesktop::size() { + QRect rect = QApplication::desktop()->screenGeometry(); + return { rect.width(), rect.height() }; +} + +Geometry pDesktop::workspace() { + QRect rect = QApplication::desktop()->availableGeometry(); + return { rect.x(), rect.y(), rect.width(), rect.height() }; +} diff --git a/bsnes/phoenix/qt/dialog-window.cpp b/bsnes/phoenix/qt/dialog-window.cpp new file mode 100755 index 00000000..82c6af5c --- /dev/null +++ b/bsnes/phoenix/qt/dialog-window.cpp @@ -0,0 +1,57 @@ +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + string filterList; + for(auto &item : filter) { + filterList.append(item); + filterList.append(";;"); + } + filterList.rtrim<1>(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parenthesis = 0; + for(auto &n : filterList) { + if(n == '(') parenthesis++; + if(n == ')') parenthesis--; + if(n == ',' && parenthesis) n = ' '; + } + + QString filename = QFileDialog::getOpenFileName( + &parent != &Window::None ? parent.p.qtWindow : 0, "Load File", + QString::fromUtf8(path), QString::fromUtf8(filterList) + ); + return filename.toUtf8().constData(); +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + string filterList; + for(auto &item : filter) { + filterList.append(item); + filterList.append(";;"); + } + filterList.rtrim<1>(";;"); + + //convert filter list from phoenix to Qt format, example: + //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" + signed parenthesis = 0; + for(auto &n : filterList) { + if(n == '(') parenthesis++; + if(n == ')') parenthesis--; + if(n == ',' && parenthesis) n = ' '; + } + + QString filename = QFileDialog::getSaveFileName( + &parent != &Window::None ? parent.p.qtWindow : 0, "Save File", + QString::fromUtf8(path), QString::fromUtf8(filterList) + ); + return filename.toUtf8().constData(); +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + QString directory = QFileDialog::getExistingDirectory( + &parent != &Window::None ? parent.p.qtWindow : 0, "Select Directory", + QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks + ); + string name = directory.toUtf8().constData(); + if(name != "" && name.endswith("/") == false) name.append("/"); + return name; +} diff --git a/bsnes/phoenix/qt/keyboard.cpp b/bsnes/phoenix/qt/keyboard.cpp new file mode 100755 index 00000000..aa7be5f0 --- /dev/null +++ b/bsnes/phoenix/qt/keyboard.cpp @@ -0,0 +1,144 @@ +bidirectional_map pKeyboard::keymap; + +void pKeyboard::initialize() { + auto append = [](Keyboard::Scancode scancode, unsigned keysym) { + keymap.append(scancode, XKeysymToKeycode(pOS::display, keysym)); + }; + + append(Keyboard::Scancode::Escape, XK_Escape); + append(Keyboard::Scancode::F1, XK_F1); + append(Keyboard::Scancode::F2, XK_F2); + append(Keyboard::Scancode::F3, XK_F3); + append(Keyboard::Scancode::F4, XK_F4); + append(Keyboard::Scancode::F5, XK_F5); + append(Keyboard::Scancode::F6, XK_F6); + append(Keyboard::Scancode::F7, XK_F7); + append(Keyboard::Scancode::F8, XK_F8); + append(Keyboard::Scancode::F9, XK_F9); + append(Keyboard::Scancode::F10, XK_F10); + append(Keyboard::Scancode::F11, XK_F11); + append(Keyboard::Scancode::F12, XK_F12); + + append(Keyboard::Scancode::PrintScreen, XK_Print); + append(Keyboard::Scancode::ScrollLock, XK_Scroll_Lock); + append(Keyboard::Scancode::Pause, XK_Pause); + + append(Keyboard::Scancode::Insert, XK_Insert); + append(Keyboard::Scancode::Delete, XK_Delete); + append(Keyboard::Scancode::Home, XK_Home); + append(Keyboard::Scancode::End, XK_End); + append(Keyboard::Scancode::PageUp, XK_Prior); + append(Keyboard::Scancode::PageDown, XK_Next); + + append(Keyboard::Scancode::Up, XK_Up); + append(Keyboard::Scancode::Down, XK_Down); + append(Keyboard::Scancode::Left, XK_Left); + append(Keyboard::Scancode::Right, XK_Right); + + append(Keyboard::Scancode::Grave, XK_asciitilde); + append(Keyboard::Scancode::Number1, XK_1); + append(Keyboard::Scancode::Number2, XK_2); + append(Keyboard::Scancode::Number3, XK_3); + append(Keyboard::Scancode::Number4, XK_4); + append(Keyboard::Scancode::Number5, XK_5); + append(Keyboard::Scancode::Number6, XK_6); + append(Keyboard::Scancode::Number7, XK_7); + append(Keyboard::Scancode::Number8, XK_8); + append(Keyboard::Scancode::Number9, XK_9); + append(Keyboard::Scancode::Number0, XK_0); + append(Keyboard::Scancode::Minus, XK_minus); + append(Keyboard::Scancode::Equal, XK_equal); + append(Keyboard::Scancode::Backspace, XK_BackSpace); + + append(Keyboard::Scancode::BracketLeft, XK_bracketleft); + append(Keyboard::Scancode::BracketRight, XK_bracketright); + append(Keyboard::Scancode::Backslash, XK_backslash); + append(Keyboard::Scancode::Semicolon, XK_semicolon); + append(Keyboard::Scancode::Apostrophe, XK_apostrophe); + append(Keyboard::Scancode::Comma, XK_comma); + append(Keyboard::Scancode::Period, XK_period); + append(Keyboard::Scancode::Slash, XK_slash); + + append(Keyboard::Scancode::Tab, XK_Tab); + append(Keyboard::Scancode::CapsLock, XK_Caps_Lock); + append(Keyboard::Scancode::Return, XK_Return); + append(Keyboard::Scancode::ShiftLeft, XK_Shift_L); + append(Keyboard::Scancode::ShiftRight, XK_Shift_R); + append(Keyboard::Scancode::ControlLeft, XK_Control_L); + append(Keyboard::Scancode::ControlRight, XK_Control_R); + append(Keyboard::Scancode::SuperLeft, XK_Super_L); + append(Keyboard::Scancode::SuperRight, XK_Super_R); + append(Keyboard::Scancode::AltLeft, XK_Alt_L); + append(Keyboard::Scancode::AltRight, XK_Alt_R); + append(Keyboard::Scancode::Space, XK_space); + append(Keyboard::Scancode::Menu, XK_Menu); + + append(Keyboard::Scancode::A, XK_A); + append(Keyboard::Scancode::B, XK_B); + append(Keyboard::Scancode::C, XK_C); + append(Keyboard::Scancode::D, XK_D); + append(Keyboard::Scancode::E, XK_E); + append(Keyboard::Scancode::F, XK_F); + append(Keyboard::Scancode::G, XK_G); + append(Keyboard::Scancode::H, XK_H); + append(Keyboard::Scancode::I, XK_I); + append(Keyboard::Scancode::J, XK_J); + append(Keyboard::Scancode::K, XK_K); + append(Keyboard::Scancode::L, XK_L); + append(Keyboard::Scancode::M, XK_M); + append(Keyboard::Scancode::N, XK_N); + append(Keyboard::Scancode::O, XK_O); + append(Keyboard::Scancode::P, XK_P); + append(Keyboard::Scancode::Q, XK_Q); + append(Keyboard::Scancode::R, XK_R); + append(Keyboard::Scancode::S, XK_S); + append(Keyboard::Scancode::T, XK_T); + append(Keyboard::Scancode::U, XK_U); + append(Keyboard::Scancode::V, XK_V); + append(Keyboard::Scancode::W, XK_W); + append(Keyboard::Scancode::X, XK_X); + append(Keyboard::Scancode::Y, XK_Y); + append(Keyboard::Scancode::Z, XK_Z); + + append(Keyboard::Scancode::NumLock, XK_Num_Lock); + append(Keyboard::Scancode::Divide, XK_KP_Divide); + append(Keyboard::Scancode::Multiply, XK_KP_Multiply); + append(Keyboard::Scancode::Subtract, XK_KP_Subtract); + append(Keyboard::Scancode::Add, XK_KP_Add); + append(Keyboard::Scancode::Enter, XK_KP_Enter); + append(Keyboard::Scancode::Point, XK_KP_Decimal); + + append(Keyboard::Scancode::Keypad1, XK_KP_1); + append(Keyboard::Scancode::Keypad2, XK_KP_2); + append(Keyboard::Scancode::Keypad3, XK_KP_3); + append(Keyboard::Scancode::Keypad4, XK_KP_4); + append(Keyboard::Scancode::Keypad5, XK_KP_5); + append(Keyboard::Scancode::Keypad6, XK_KP_6); + append(Keyboard::Scancode::Keypad7, XK_KP_7); + append(Keyboard::Scancode::Keypad8, XK_KP_8); + append(Keyboard::Scancode::Keypad9, XK_KP_9); + append(Keyboard::Scancode::Keypad0, XK_KP_0); +} + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + char state[256]; + XQueryKeymap(pOS::display, state); + unsigned id = keymap.lhs[scancode]; + return state[id >> 3] & (1 << (id & 7)); +} + +array pKeyboard::state() { + array output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + + char state[256]; + XQueryKeymap(pOS::display, state); + for(auto &n : keymap.rhs) { + if(state[n.name >> 3] & (1 << (n.name & 7))) { + output[(unsigned)n.data] = true; + } + } + + return output; +} diff --git a/bsnes/phoenix/qt/mouse.cpp b/bsnes/phoenix/qt/mouse.cpp new file mode 100755 index 00000000..4ea06cc9 --- /dev/null +++ b/bsnes/phoenix/qt/mouse.cpp @@ -0,0 +1,14 @@ +Position pMouse::position() { + QPoint point = QCursor::pos(); + return { point.x(), point.y() }; +} + +bool pMouse::pressed(Mouse::Button button) { + Qt::MouseButtons buttons = QApplication::mouseButtons(); + switch(button) { + case Mouse::Button::Left: return buttons & Qt::LeftButton; + case Mouse::Button::Middle: return buttons & Qt::MidButton; + case Mouse::Button::Right: return buttons & Qt::RightButton; + } + return false; +} diff --git a/bsnes/phoenix/qt/platform.cpp b/bsnes/phoenix/qt/platform.cpp index a8c11c9a..01068595 100755 --- a/bsnes/phoenix/qt/platform.cpp +++ b/bsnes/phoenix/qt/platform.cpp @@ -1,10 +1,16 @@ #include "platform.moc.hpp" #include "platform.moc" +#include "utility.cpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" #include "settings.cpp" #include "font.cpp" #include "timer.cpp" -#include "message-window.cpp" #include "window.cpp" #include "action/action.cpp" @@ -32,73 +38,7 @@ #include "widget/vertical-slider.cpp" #include "widget/viewport.cpp" -Geometry pOS::availableGeometry() { - QRect rect = QApplication::desktop()->availableGeometry(); - return { rect.x(), rect.y(), rect.width(), rect.height() }; -} - -Geometry pOS::desktopGeometry() { - QRect rect = QApplication::desktop()->screenGeometry(); - return { 0, 0, rect.width(), rect.height() }; -} - -string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { - string filterList; - for(auto &item : filter) { - filterList.append(item); - filterList.append(";;"); - } - filterList.rtrim<1>(";;"); - - //convert filter list from phoenix to Qt format, example: - //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" - signed parenthesis = 0; - for(auto &n : filterList) { - if(n == '(') parenthesis++; - if(n == ')') parenthesis--; - if(n == ',' && parenthesis) n = ' '; - } - - QString filename = QFileDialog::getOpenFileName( - &parent != &Window::None ? parent.p.qtWindow : 0, "Load File", - QString::fromUtf8(path), QString::fromUtf8(filterList) - ); - return filename.toUtf8().constData(); -} - -string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { - string filterList; - for(auto &item : filter) { - filterList.append(item); - filterList.append(";;"); - } - filterList.rtrim<1>(";;"); - - //convert filter list from phoenix to Qt format, example: - //"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)" - signed parenthesis = 0; - for(auto &n : filterList) { - if(n == '(') parenthesis++; - if(n == ')') parenthesis--; - if(n == ',' && parenthesis) n = ' '; - } - - QString filename = QFileDialog::getSaveFileName( - &parent != &Window::None ? parent.p.qtWindow : 0, "Save File", - QString::fromUtf8(path), QString::fromUtf8(filterList) - ); - return filename.toUtf8().constData(); -} - -string pOS::folderSelect(Window &parent, const string &path) { - QString directory = QFileDialog::getExistingDirectory( - &parent != &Window::None ? parent.p.qtWindow : 0, "Select Directory", - QString::fromUtf8(path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks - ); - string name = directory.toUtf8().constData(); - if(name != "" && name.endswith("/") == false) name.append("/"); - return name; -} +XlibDisplay* pOS::display = 0; void pOS::main() { QApplication::exec(); @@ -127,6 +67,8 @@ void pOS::syncX() { } void pOS::initialize() { + display = XOpenDisplay(0); + settings = new Settings; settings->load(); @@ -138,4 +80,6 @@ void pOS::initialize() { char **argvp = argv; qtApplication = new QApplication(argc, argvp); + + pKeyboard::initialize(); } diff --git a/bsnes/phoenix/qt/platform.moc b/bsnes/phoenix/qt/platform.moc index 059a846c..dffcba03 100755 --- a/bsnes/phoenix/qt/platform.moc +++ b/bsnes/phoenix/qt/platform.moc @@ -1,7 +1,7 @@ /**************************************************************************** ** Meta object code from reading C++ file 'platform.moc.hpp' ** -** Created: Tue Dec 13 07:23:09 2011 +** Created: Sat Jan 14 09:18:07 2012 ** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3) ** ** WARNING! All changes made in this file will be lost! diff --git a/bsnes/phoenix/qt/platform.moc.hpp b/bsnes/phoenix/qt/platform.moc.hpp index 70892cb8..f931b8b3 100755 --- a/bsnes/phoenix/qt/platform.moc.hpp +++ b/bsnes/phoenix/qt/platform.moc.hpp @@ -25,6 +25,38 @@ struct pFont { static Geometry geometry(const QFont &qtFont, const string &text); }; +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bidirectional_map keymap; + + static bool pressed(Keyboard::Scancode scancode); + static array state(); + + static void initialize(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + struct pObject { Object &object; bool locked; @@ -36,18 +68,15 @@ struct pObject { }; struct pOS : public pObject { - static Geometry availableGeometry(); - static Geometry desktopGeometry(); - static string fileLoad(Window &parent, const string &path, const lstring &filter); - static string fileSave(Window &parent, const string &path, const lstring &filter); - static string folderSelect(Window &parent, const string &path); + static XlibDisplay *display; + static void main(); static bool pendingEvents(); static void processEvents(); static void quit(); - static void syncX(); static void initialize(); + static void syncX(); }; struct pTimer : public QObject, public pObject { @@ -68,13 +97,6 @@ public slots: void onTimeout(); }; -struct pMessageWindow : public pObject { - static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); -}; - struct pWindow : public QObject, public pObject { Q_OBJECT @@ -83,6 +105,8 @@ public: struct QtWindow : public QWidget { pWindow &self; void closeEvent(QCloseEvent*); + void keyPressEvent(QKeyEvent*); + void keyReleaseEvent(QKeyEvent*); void moveEvent(QMoveEvent*); void resizeEvent(QResizeEvent*); QSize sizeHint() const; @@ -165,6 +189,7 @@ public: Item &item; QAction *qtAction; + void setImage(const image &image); void setText(const string &text); pItem(Item &item) : pAction(item), item(item) {} @@ -256,9 +281,10 @@ struct pButton : public QObject, public pWidget { public: Button &button; - QPushButton *qtButton; + QToolButton *qtButton; Geometry minimumGeometry(); + void setImage(const image &image, Orientation orientation); void setText(const string &text); pButton(Button &button) : pWidget(button), button(button) {} diff --git a/bsnes/phoenix/qt/settings.cpp b/bsnes/phoenix/qt/settings.cpp index 4a849014..90d3a76e 100755 --- a/bsnes/phoenix/qt/settings.cpp +++ b/bsnes/phoenix/qt/settings.cpp @@ -15,10 +15,10 @@ void Settings::save() { } Settings::Settings() { - attach(frameGeometryX = 4, "frameGeometryX"); - attach(frameGeometryY = 24, "frameGeometryY"); - attach(frameGeometryWidth = 8, "frameGeometryWidth"); - attach(frameGeometryHeight = 28, "frameGeometryHeight"); - attach(menuGeometryHeight = 20, "menuGeometryHeight"); - attach(statusGeometryHeight = 20, "statusGeometryHeight"); + append(frameGeometryX = 4, "frameGeometryX"); + append(frameGeometryY = 24, "frameGeometryY"); + append(frameGeometryWidth = 8, "frameGeometryWidth"); + append(frameGeometryHeight = 28, "frameGeometryHeight"); + append(menuGeometryHeight = 20, "menuGeometryHeight"); + append(statusGeometryHeight = 20, "statusGeometryHeight"); } diff --git a/bsnes/phoenix/qt/utility.cpp b/bsnes/phoenix/qt/utility.cpp new file mode 100755 index 00000000..4f06c202 --- /dev/null +++ b/bsnes/phoenix/qt/utility.cpp @@ -0,0 +1,182 @@ +static Keyboard::Keycode Keysym(int keysym) { + switch(keysym) { + case XK_Escape: return Keyboard::Keycode::Escape; + case XK_F1: return Keyboard::Keycode::F1; + case XK_F2: return Keyboard::Keycode::F2; + case XK_F3: return Keyboard::Keycode::F3; + case XK_F4: return Keyboard::Keycode::F4; + case XK_F5: return Keyboard::Keycode::F5; + case XK_F6: return Keyboard::Keycode::F6; + case XK_F7: return Keyboard::Keycode::F7; + case XK_F8: return Keyboard::Keycode::F8; + case XK_F9: return Keyboard::Keycode::F9; + case XK_F10: return Keyboard::Keycode::F10; + case XK_F11: return Keyboard::Keycode::F11; + case XK_F12: return Keyboard::Keycode::F12; + + case XK_Print: return Keyboard::Keycode::PrintScreen; + //Keyboard::Keycode::SysRq + case XK_Scroll_Lock: return Keyboard::Keycode::ScrollLock; + case XK_Pause: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case XK_Insert: return Keyboard::Keycode::Insert; + case XK_Delete: return Keyboard::Keycode::Delete; + case XK_Home: return Keyboard::Keycode::Home; + case XK_End: return Keyboard::Keycode::End; + case XK_Prior: return Keyboard::Keycode::PageUp; + case XK_Next: return Keyboard::Keycode::PageDown; + + case XK_Up: return Keyboard::Keycode::Up; + case XK_Down: return Keyboard::Keycode::Down; + case XK_Left: return Keyboard::Keycode::Left; + case XK_Right: return Keyboard::Keycode::Right; + + case XK_grave: return Keyboard::Keycode::Grave; + case XK_1: return Keyboard::Keycode::Number1; + case XK_2: return Keyboard::Keycode::Number2; + case XK_3: return Keyboard::Keycode::Number3; + case XK_4: return Keyboard::Keycode::Number4; + case XK_5: return Keyboard::Keycode::Number5; + case XK_6: return Keyboard::Keycode::Number6; + case XK_7: return Keyboard::Keycode::Number7; + case XK_8: return Keyboard::Keycode::Number8; + case XK_9: return Keyboard::Keycode::Number9; + case XK_0: return Keyboard::Keycode::Number0; + case XK_minus: return Keyboard::Keycode::Minus; + case XK_equal: return Keyboard::Keycode::Equal; + case XK_BackSpace: return Keyboard::Keycode::Backspace; + + case XK_asciitilde: return Keyboard::Keycode::Tilde; + case XK_exclam: return Keyboard::Keycode::Exclamation; + case XK_at: return Keyboard::Keycode::At; + case XK_numbersign: return Keyboard::Keycode::Pound; + case XK_dollar: return Keyboard::Keycode::Dollar; + case XK_percent: return Keyboard::Keycode::Percent; + case XK_asciicircum: return Keyboard::Keycode::Power; + case XK_ampersand: return Keyboard::Keycode::Ampersand; + case XK_asterisk: return Keyboard::Keycode::Asterisk; + case XK_parenleft: return Keyboard::Keycode::ParenthesisLeft; + case XK_parenright: return Keyboard::Keycode::ParenthesisRight; + case XK_underscore: return Keyboard::Keycode::Underscore; + case XK_plus: return Keyboard::Keycode::Plus; + + case XK_bracketleft: return Keyboard::Keycode::BracketLeft; + case XK_bracketright: return Keyboard::Keycode::BracketRight; + case XK_backslash: return Keyboard::Keycode::Backslash; + case XK_semicolon: return Keyboard::Keycode::Semicolon; + case XK_apostrophe: return Keyboard::Keycode::Apostrophe; + case XK_comma: return Keyboard::Keycode::Comma; + case XK_period: return Keyboard::Keycode::Period; + case XK_slash: return Keyboard::Keycode::Slash; + + case XK_braceleft: return Keyboard::Keycode::BraceLeft; + case XK_braceright: return Keyboard::Keycode::BraceRight; + case XK_bar: return Keyboard::Keycode::Pipe; + case XK_colon: return Keyboard::Keycode::Colon; + case XK_quotedbl: return Keyboard::Keycode::Quote; + case XK_less: return Keyboard::Keycode::CaretLeft; + case XK_greater: return Keyboard::Keycode::CaretRight; + case XK_question: return Keyboard::Keycode::Question; + + case XK_Tab: return Keyboard::Keycode::Tab; + case XK_Caps_Lock: return Keyboard::Keycode::CapsLock; + case XK_Return: return Keyboard::Keycode::Return; + case XK_Shift_L: return Keyboard::Keycode::ShiftLeft; + case XK_Shift_R: return Keyboard::Keycode::ShiftRight; + case XK_Control_L: return Keyboard::Keycode::ControlLeft; + case XK_Control_R: return Keyboard::Keycode::ControlRight; + case XK_Super_L: return Keyboard::Keycode::SuperLeft; + case XK_Super_R: return Keyboard::Keycode::SuperRight; + case XK_Alt_L: return Keyboard::Keycode::AltLeft; + case XK_Alt_R: return Keyboard::Keycode::AltRight; + case XK_space: return Keyboard::Keycode::Space; + case XK_Menu: return Keyboard::Keycode::Menu; + + case XK_A: return Keyboard::Keycode::A; + case XK_B: return Keyboard::Keycode::B; + case XK_C: return Keyboard::Keycode::C; + case XK_D: return Keyboard::Keycode::D; + case XK_E: return Keyboard::Keycode::E; + case XK_F: return Keyboard::Keycode::F; + case XK_G: return Keyboard::Keycode::G; + case XK_H: return Keyboard::Keycode::H; + case XK_I: return Keyboard::Keycode::I; + case XK_J: return Keyboard::Keycode::J; + case XK_K: return Keyboard::Keycode::K; + case XK_L: return Keyboard::Keycode::L; + case XK_M: return Keyboard::Keycode::M; + case XK_N: return Keyboard::Keycode::N; + case XK_O: return Keyboard::Keycode::O; + case XK_P: return Keyboard::Keycode::P; + case XK_Q: return Keyboard::Keycode::Q; + case XK_R: return Keyboard::Keycode::R; + case XK_S: return Keyboard::Keycode::S; + case XK_T: return Keyboard::Keycode::T; + case XK_U: return Keyboard::Keycode::U; + case XK_V: return Keyboard::Keycode::V; + case XK_W: return Keyboard::Keycode::W; + case XK_X: return Keyboard::Keycode::X; + case XK_Y: return Keyboard::Keycode::Y; + case XK_Z: return Keyboard::Keycode::Z; + + case XK_a: return Keyboard::Keycode::a; + case XK_b: return Keyboard::Keycode::b; + case XK_c: return Keyboard::Keycode::c; + case XK_d: return Keyboard::Keycode::d; + case XK_e: return Keyboard::Keycode::e; + case XK_f: return Keyboard::Keycode::f; + case XK_g: return Keyboard::Keycode::g; + case XK_h: return Keyboard::Keycode::h; + case XK_i: return Keyboard::Keycode::i; + case XK_j: return Keyboard::Keycode::j; + case XK_k: return Keyboard::Keycode::k; + case XK_l: return Keyboard::Keycode::l; + case XK_m: return Keyboard::Keycode::m; + case XK_n: return Keyboard::Keycode::n; + case XK_o: return Keyboard::Keycode::o; + case XK_p: return Keyboard::Keycode::p; + case XK_q: return Keyboard::Keycode::q; + case XK_r: return Keyboard::Keycode::r; + case XK_s: return Keyboard::Keycode::s; + case XK_t: return Keyboard::Keycode::t; + case XK_u: return Keyboard::Keycode::u; + case XK_v: return Keyboard::Keycode::v; + case XK_w: return Keyboard::Keycode::w; + case XK_x: return Keyboard::Keycode::x; + case XK_y: return Keyboard::Keycode::y; + case XK_z: return Keyboard::Keycode::z; + + case XK_Num_Lock: return Keyboard::Keycode::NumLock; + case XK_KP_Divide: return Keyboard::Keycode::Divide; + case XK_KP_Multiply: return Keyboard::Keycode::Multiply; + case XK_KP_Subtract: return Keyboard::Keycode::Subtract; + case XK_KP_Add: return Keyboard::Keycode::Add; + case XK_KP_Enter: return Keyboard::Keycode::Enter; + case XK_KP_Decimal: return Keyboard::Keycode::Point; + + case XK_KP_1: return Keyboard::Keycode::Keypad1; + case XK_KP_2: return Keyboard::Keycode::Keypad2; + case XK_KP_3: return Keyboard::Keycode::Keypad3; + case XK_KP_4: return Keyboard::Keycode::Keypad4; + case XK_KP_5: return Keyboard::Keycode::Keypad5; + case XK_KP_6: return Keyboard::Keycode::Keypad6; + case XK_KP_7: return Keyboard::Keycode::Keypad7; + case XK_KP_8: return Keyboard::Keycode::Keypad8; + case XK_KP_9: return Keyboard::Keycode::Keypad9; + case XK_KP_0: return Keyboard::Keycode::Keypad0; + + case XK_KP_Home: return Keyboard::Keycode::KeypadHome; + case XK_KP_End: return Keyboard::Keycode::KeypadEnd; + case XK_KP_Page_Up: return Keyboard::Keycode::KeypadPageUp; + case XK_KP_Page_Down: return Keyboard::Keycode::KeypadPageDown; + case XK_KP_Up: return Keyboard::Keycode::KeypadUp; + case XK_KP_Down: return Keyboard::Keycode::KeypadDown; + case XK_KP_Left: return Keyboard::Keycode::KeypadLeft; + case XK_KP_Right: return Keyboard::Keycode::KeypadRight; + case XK_KP_Begin: return Keyboard::Keycode::KeypadCenter; + case XK_KP_Insert: return Keyboard::Keycode::KeypadInsert; + case XK_KP_Delete: return Keyboard::Keycode::KeypadDelete; + } + return Keyboard::Keycode::None; +} diff --git a/bsnes/phoenix/qt/widget/button.cpp b/bsnes/phoenix/qt/widget/button.cpp index 4f18bcc1..98c04373 100755 --- a/bsnes/phoenix/qt/widget/button.cpp +++ b/bsnes/phoenix/qt/widget/button.cpp @@ -1,14 +1,40 @@ Geometry pButton::minimumGeometry() { Geometry geometry = pFont::geometry(qtWidget->font(), button.state.text); + + if(button.state.orientation == Orientation::Horizontal) { + geometry.width += button.state.image.width; + geometry.height = max(button.state.image.height, geometry.height); + } + + if(button.state.orientation == Orientation::Vertical) { + geometry.width = max(button.state.image.width, geometry.width); + geometry.height += button.state.image.height; + } + return { 0, 0, geometry.width + 20, geometry.height + 12 }; } +void pButton::setImage(const image &image, Orientation orientation) { + nall::image qtBuffer = image; + qtBuffer.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + + QImage qtImage(qtBuffer.data, qtBuffer.width, qtBuffer.height, QImage::Format_ARGB32); + QIcon qtIcon(QPixmap::fromImage(qtImage)); + qtButton->setIconSize(QSize(qtBuffer.width, qtBuffer.height)); + qtButton->setIcon(qtIcon); + switch(orientation) { + case Orientation::Horizontal: qtButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); break; + case Orientation::Vertical: qtButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); break; + } +} + void pButton::setText(const string &text) { qtButton->setText(QString::fromUtf8(text)); } void pButton::constructor() { - qtWidget = qtButton = new QPushButton; + qtWidget = qtButton = new QToolButton; + qtButton->setToolButtonStyle(Qt::ToolButtonTextOnly); connect(qtButton, SIGNAL(released()), SLOT(onActivate())); pWidget::synchronizeState(); diff --git a/bsnes/phoenix/qt/window.cpp b/bsnes/phoenix/qt/window.cpp index 05d62962..4bec7b14 100755 --- a/bsnes/phoenix/qt/window.cpp +++ b/bsnes/phoenix/qt/window.cpp @@ -45,7 +45,7 @@ Geometry pWindow::geometry() { if(window.state.fullScreen) { unsigned menuHeight = window.state.menuVisible ? qtMenu->height() : 0; unsigned statusHeight = window.state.statusVisible ? qtStatus->height() : 0; - return { 0, menuHeight, OS::desktopGeometry().width, OS::desktopGeometry().height - menuHeight - statusHeight }; + return { 0, menuHeight, Desktop::size().width, Desktop::size().height - menuHeight - statusHeight }; } return window.state.geometry; } @@ -84,9 +84,8 @@ void pWindow::setFullScreen(bool fullScreen) { qtWindow->showNormal(); qtWindow->adjustSize(); } else { - Geometry geometry = OS::desktopGeometry(), margin = frameMargin(); qtLayout->setSizeConstraint(QLayout::SetDefaultConstraint); - qtContainer->setFixedSize(geometry.width - margin.width, geometry.height - margin.height); + qtContainer->setFixedSize(Desktop::size().width - frameMargin().width, Desktop::size().height - frameMargin().height); qtWindow->showFullScreen(); } } @@ -243,6 +242,16 @@ void pWindow::QtWindow::moveEvent(QMoveEvent *event) { } } +void pWindow::QtWindow::keyPressEvent(QKeyEvent *event) { + Keyboard::Keycode sym = Keysym(event->nativeVirtualKey()); + if(sym != Keyboard::Keycode::None && self.window.onKeyPress) self.window.onKeyPress(sym); +} + +void pWindow::QtWindow::keyReleaseEvent(QKeyEvent *event) { + Keyboard::Keycode sym = Keysym(event->nativeVirtualKey()); + if(sym != Keyboard::Keycode::None && self.window.onKeyRelease) self.window.onKeyRelease(sym); +} + void pWindow::QtWindow::resizeEvent(QResizeEvent*) { if(self.locked == false && self.window.state.fullScreen == false && self.qtWindow->isVisible() == true) { self.window.state.geometry.width = self.qtContainer->geometry().width(); diff --git a/bsnes/phoenix/reference/action/item.cpp b/bsnes/phoenix/reference/action/item.cpp index d064389b..438ed32f 100755 --- a/bsnes/phoenix/reference/action/item.cpp +++ b/bsnes/phoenix/reference/action/item.cpp @@ -1,3 +1,6 @@ +void pItem::setImage(const image &image) { +} + void pItem::setText(const string &text) { } diff --git a/bsnes/phoenix/reference/desktop.cpp b/bsnes/phoenix/reference/desktop.cpp new file mode 100755 index 00000000..a96eb1f0 --- /dev/null +++ b/bsnes/phoenix/reference/desktop.cpp @@ -0,0 +1,8 @@ +Size pDesktop::size() { + return { 0, 0 }; +} + +Geometry pDesktop::workspace() { + return { 0, 0, 0, 0 }; +} + diff --git a/bsnes/phoenix/reference/dialog-window.cpp b/bsnes/phoenix/reference/dialog-window.cpp new file mode 100755 index 00000000..c7d089ae --- /dev/null +++ b/bsnes/phoenix/reference/dialog-window.cpp @@ -0,0 +1,11 @@ +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + return ""; +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + return ""; +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + return ""; +} diff --git a/bsnes/phoenix/reference/keyboard.cpp b/bsnes/phoenix/reference/keyboard.cpp new file mode 100755 index 00000000..22122aed --- /dev/null +++ b/bsnes/phoenix/reference/keyboard.cpp @@ -0,0 +1,10 @@ +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + return false; +} + +array pKeyboard::state() { + array output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + return output; +} diff --git a/bsnes/phoenix/reference/mouse.cpp b/bsnes/phoenix/reference/mouse.cpp new file mode 100755 index 00000000..f103a15a --- /dev/null +++ b/bsnes/phoenix/reference/mouse.cpp @@ -0,0 +1,7 @@ +Position pMouse::position() { + return { 0, 0 }; +} + +bool pMouse::pressed(Mouse::Button button) { + return false; +} diff --git a/bsnes/phoenix/reference/platform.cpp b/bsnes/phoenix/reference/platform.cpp index b35adcef..e64f7eab 100755 --- a/bsnes/phoenix/reference/platform.cpp +++ b/bsnes/phoenix/reference/platform.cpp @@ -1,8 +1,13 @@ #include "platform.hpp" +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" + #include "font.cpp" #include "timer.cpp" -#include "message-window.cpp" #include "window.cpp" #include "action/action.cpp" @@ -30,26 +35,6 @@ #include "widget/vertical-slider.cpp" #include "widget/viewport.cpp" -Geometry pOS::availableGeometry() { - return { 0, 0, 0, 0 }; -} - -Geometry pOS::desktopGeometry() { - return { 0, 0, 0, 0 }; -} - -string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { - return ""; -} - -string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { - return ""; -} - -string pOS::folderSelect(Window &parent, const string &path) { - return ""; -} - void pOS::main() { } diff --git a/bsnes/phoenix/reference/platform.hpp b/bsnes/phoenix/reference/platform.hpp index fccb99ed..666b0af3 100755 --- a/bsnes/phoenix/reference/platform.hpp +++ b/bsnes/phoenix/reference/platform.hpp @@ -8,6 +8,34 @@ struct pFont { static Geometry geometry(const string &description, const string &text); }; +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bool pressed(Keyboard::Scancode scancode); + static array state(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + struct pObject { Object &object; bool locked; @@ -20,11 +48,6 @@ struct pObject { }; struct pOS : public pObject { - static Geometry availableGeometry(); - static Geometry desktopGeometry(); - static string fileLoad(Window &parent, const string &path, const lstring &filter); - static string fileSave(Window &parent, const string &path, const lstring &filter); - static string folderSelect(Window &parent, const string &path); static void main(); static bool pendingEvents(); static void processEvents(); @@ -43,13 +66,6 @@ struct pTimer : public pObject { void constructor(); }; -struct pMessageWindow : public pObject { - static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); -}; - struct pWindow : public pObject { Window &window; @@ -114,6 +130,7 @@ struct pSeparator : public pAction { struct pItem : public pAction { Item &item; + void setImage(const image &image); void setText(const string &text); pItem(Item &item) : pAction(item), item(item) {} @@ -176,6 +193,7 @@ struct pWidget : public pSizable { struct pButton : public pWidget { Button &button; + void setImage(const image &image, Orientation orientation); void setText(const string &text); pButton(Button &button) : pWidget(button), button(button) {} diff --git a/bsnes/phoenix/reference/widget/button.cpp b/bsnes/phoenix/reference/widget/button.cpp index a56410c1..fc06c371 100755 --- a/bsnes/phoenix/reference/widget/button.cpp +++ b/bsnes/phoenix/reference/widget/button.cpp @@ -1,3 +1,6 @@ +void pButton::setImage(const image &image, Orientation orientation) { +} + void pButton::setText(const string &text) { } diff --git a/bsnes/phoenix/windows/action/item.cpp b/bsnes/phoenix/windows/action/item.cpp index 2e24e6e9..eb076c3a 100755 --- a/bsnes/phoenix/windows/action/item.cpp +++ b/bsnes/phoenix/windows/action/item.cpp @@ -1,10 +1,29 @@ +void pItem::setImage(const image &image) { + createBitmap(); + if(parentWindow) parentWindow->p.updateMenu(); +} + void pItem::setText(const string &text) { if(parentWindow) parentWindow->p.updateMenu(); } void pItem::constructor() { + createBitmap(); } void pItem::destructor() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } if(parentMenu) parentMenu->remove(item); } + +void pItem::createBitmap() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + + if(item.state.image.width && item.state.image.height) { + nall::image nallImage = item.state.image; + nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + nallImage.alphaBlend(GetSysColor(COLOR_MENU)); //Windows does not alpha blend menu icons properly (leaves black outline) + nallImage.scale(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK), Interpolation::Linear); + hbitmap = CreateBitmap(nallImage); + } +} \ No newline at end of file diff --git a/bsnes/phoenix/windows/action/menu.cpp b/bsnes/phoenix/windows/action/menu.cpp index 4e060955..633a831f 100755 --- a/bsnes/phoenix/windows/action/menu.cpp +++ b/bsnes/phoenix/windows/action/menu.cpp @@ -39,7 +39,18 @@ void pMenu::update(Window &parentWindow, Menu *parentMenu) { if(action.state.visible) AppendMenu(hmenu, MF_SEPARATOR | enabled, item.p.id, L""); } else if(dynamic_cast(&action)) { Item &item = (Item&)action; - if(action.state.visible) AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + if(action.state.visible) { + AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); + + if(item.state.image.width && item.state.image.height) { + MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; + //Windows XP and below displays MIIM_BITMAP + hbmpItem in its own column (separate from check/radio marks) + //this causes too much spacing, so use a custom checkmark image instead + mii.fMask = MIIM_CHECKMARKS; + mii.hbmpUnchecked = item.p.hbitmap; + SetMenuItemInfo(hmenu, item.p.id, FALSE, &mii); + } + } } else if(dynamic_cast(&action)) { CheckItem &item = (CheckItem&)action; if(action.state.visible) AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text)); diff --git a/bsnes/phoenix/windows/desktop.cpp b/bsnes/phoenix/windows/desktop.cpp new file mode 100755 index 00000000..956ba521 --- /dev/null +++ b/bsnes/phoenix/windows/desktop.cpp @@ -0,0 +1,9 @@ +Size pDesktop::size() { + return { GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) }; +} + +Geometry pDesktop::workspace() { + RECT rc; + SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); + return { rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top }; +} diff --git a/bsnes/phoenix/windows/dialog-window.cpp b/bsnes/phoenix/windows/dialog-window.cpp new file mode 100755 index 00000000..4488487d --- /dev/null +++ b/bsnes/phoenix/windows/dialog-window.cpp @@ -0,0 +1,81 @@ +static string FileDialog(bool save, Window &parent, const string &path, const lstring &filter) { + string dir = path; + dir.replace("/", "\\"); + + string filterList; + for(auto &filterItem : filter) { + lstring part; + part.split("(", filterItem); + if(part.size() != 2) continue; + part[1].rtrim<1>(")"); + part[1].replace(" ", ""); + part[1].transform(",", ";"); + filterList.append(string(filterItem, "\t", part[1], "\t")); + } + + utf16_t wfilter(filterList); + utf16_t wdir(dir); + wchar_t wfilename[PATH_MAX + 1] = L""; + + wchar_t *p = wfilter; + while(*p != L'\0') { + if(*p == L'\t') *p = L'\0'; + p++; + } + + OPENFILENAME ofn; + memset(&ofn, 0, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; + ofn.lpstrFilter = wfilter; + ofn.lpstrInitialDir = wdir; + ofn.lpstrFile = wfilename; + ofn.nMaxFile = PATH_MAX; + ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = L""; + + bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); + if(result == false) return ""; + string name = (const char*)utf8_t(wfilename); + name.transform("\\", "/"); + return name; +} + +string pDialogWindow::fileOpen(Window &parent, const string &path, const lstring &filter) { + return FileDialog(false, parent, path, filter); +} + +string pDialogWindow::fileSave(Window &parent, const string &path, const lstring &filter) { + return FileDialog(true, parent, path, filter); +} + +string pDialogWindow::folderSelect(Window &parent, const string &path) { + wchar_t wfilename[PATH_MAX + 1] = L""; + BROWSEINFO bi; + bi.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; + bi.pidlRoot = NULL; + bi.pszDisplayName = wfilename; + bi.lpszTitle = L""; + bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; + bi.lpfn = NULL; + bi.lParam = 0; + bi.iImage = 0; + bool result = false; + LPITEMIDLIST pidl = SHBrowseForFolder(&bi); + if(pidl) { + if(SHGetPathFromIDList(pidl, wfilename)) { + result = true; + IMalloc *imalloc = 0; + if(SUCCEEDED(SHGetMalloc(&imalloc))) { + imalloc->Free(pidl); + imalloc->Release(); + } + } + } + if(result == false) return ""; + string name = (const char*)utf8_t(wfilename); + if(name == "") return ""; + name.transform("\\", "/"); + if(name.endswith("/") == false) name.append("/"); + return name; +} \ No newline at end of file diff --git a/bsnes/phoenix/windows/keyboard.cpp b/bsnes/phoenix/windows/keyboard.cpp new file mode 100755 index 00000000..eb288979 --- /dev/null +++ b/bsnes/phoenix/windows/keyboard.cpp @@ -0,0 +1,139 @@ +bidirectional_map pKeyboard::keymap; + +void pKeyboard::initialize() { + auto append = [](Keyboard::Scancode scancode, unsigned keysym) { + keymap.append(scancode, keysym); + }; + + append(Keyboard::Scancode::Escape, VK_ESCAPE); + append(Keyboard::Scancode::F1, VK_F1); + append(Keyboard::Scancode::F2, VK_F2); + append(Keyboard::Scancode::F3, VK_F3); + append(Keyboard::Scancode::F4, VK_F4); + append(Keyboard::Scancode::F5, VK_F5); + append(Keyboard::Scancode::F6, VK_F6); + append(Keyboard::Scancode::F7, VK_F7); + append(Keyboard::Scancode::F8, VK_F8); + append(Keyboard::Scancode::F9, VK_F9); + append(Keyboard::Scancode::F10, VK_F10); + append(Keyboard::Scancode::F11, VK_F11); + append(Keyboard::Scancode::F12, VK_F12); + + append(Keyboard::Scancode::PrintScreen, VK_SNAPSHOT); + append(Keyboard::Scancode::ScrollLock, VK_SCROLL); + append(Keyboard::Scancode::Pause, VK_PAUSE); + + append(Keyboard::Scancode::Insert, VK_INSERT); + append(Keyboard::Scancode::Delete, VK_DELETE); + append(Keyboard::Scancode::Home, VK_HOME); + append(Keyboard::Scancode::End, VK_END); + append(Keyboard::Scancode::PageUp, VK_PRIOR); + append(Keyboard::Scancode::PageDown, VK_NEXT); + + append(Keyboard::Scancode::Up, VK_UP); + append(Keyboard::Scancode::Down, VK_DOWN); + append(Keyboard::Scancode::Left, VK_LEFT); + append(Keyboard::Scancode::Right, VK_RIGHT); + + append(Keyboard::Scancode::Grave, VK_OEM_3); + append(Keyboard::Scancode::Number1, '1'); + append(Keyboard::Scancode::Number2, '2'); + append(Keyboard::Scancode::Number3, '3'); + append(Keyboard::Scancode::Number4, '4'); + append(Keyboard::Scancode::Number5, '5'); + append(Keyboard::Scancode::Number6, '6'); + append(Keyboard::Scancode::Number7, '7'); + append(Keyboard::Scancode::Number8, '8'); + append(Keyboard::Scancode::Number9, '9'); + append(Keyboard::Scancode::Number0, '0'); + append(Keyboard::Scancode::Minus, VK_OEM_MINUS); + append(Keyboard::Scancode::Equal, VK_OEM_PLUS); + append(Keyboard::Scancode::Backspace, VK_BACK); + + append(Keyboard::Scancode::BracketLeft, VK_OEM_4); + append(Keyboard::Scancode::BracketRight, VK_OEM_6); + append(Keyboard::Scancode::Backslash, VK_OEM_5); + append(Keyboard::Scancode::Semicolon, VK_OEM_1); + append(Keyboard::Scancode::Apostrophe, VK_OEM_7); + append(Keyboard::Scancode::Comma, VK_OEM_COMMA); + append(Keyboard::Scancode::Period, VK_OEM_PERIOD); + append(Keyboard::Scancode::Slash, VK_OEM_2); + + append(Keyboard::Scancode::Tab, VK_TAB); + append(Keyboard::Scancode::CapsLock, VK_CAPITAL); + append(Keyboard::Scancode::Return, VK_RETURN); + append(Keyboard::Scancode::ShiftLeft, VK_LSHIFT); + append(Keyboard::Scancode::ShiftRight, VK_RSHIFT); + append(Keyboard::Scancode::ControlLeft, VK_LCONTROL); + append(Keyboard::Scancode::ControlRight, VK_RCONTROL); + append(Keyboard::Scancode::SuperLeft, VK_LWIN); + append(Keyboard::Scancode::SuperRight, VK_RWIN); + append(Keyboard::Scancode::AltLeft, VK_LMENU); + append(Keyboard::Scancode::AltRight, VK_RMENU); + append(Keyboard::Scancode::Space, VK_SPACE); + append(Keyboard::Scancode::Menu, VK_APPS); + + append(Keyboard::Scancode::A, 'A'); + append(Keyboard::Scancode::B, 'B'); + append(Keyboard::Scancode::C, 'C'); + append(Keyboard::Scancode::D, 'D'); + append(Keyboard::Scancode::E, 'E'); + append(Keyboard::Scancode::F, 'F'); + append(Keyboard::Scancode::G, 'G'); + append(Keyboard::Scancode::H, 'H'); + append(Keyboard::Scancode::I, 'I'); + append(Keyboard::Scancode::J, 'J'); + append(Keyboard::Scancode::K, 'K'); + append(Keyboard::Scancode::L, 'L'); + append(Keyboard::Scancode::M, 'M'); + append(Keyboard::Scancode::N, 'N'); + append(Keyboard::Scancode::O, 'O'); + append(Keyboard::Scancode::P, 'P'); + append(Keyboard::Scancode::Q, 'Q'); + append(Keyboard::Scancode::R, 'R'); + append(Keyboard::Scancode::S, 'S'); + append(Keyboard::Scancode::T, 'T'); + append(Keyboard::Scancode::U, 'U'); + append(Keyboard::Scancode::V, 'V'); + append(Keyboard::Scancode::W, 'W'); + append(Keyboard::Scancode::X, 'X'); + append(Keyboard::Scancode::Y, 'Y'); + append(Keyboard::Scancode::Z, 'Z'); + + append(Keyboard::Scancode::NumLock, VK_NUMLOCK); + append(Keyboard::Scancode::Divide, VK_DIVIDE); + append(Keyboard::Scancode::Multiply, VK_MULTIPLY); + append(Keyboard::Scancode::Subtract, VK_SUBTRACT); + append(Keyboard::Scancode::Add, VK_ADD); +//append(Keyboard::Scancode::Enter, ...); + append(Keyboard::Scancode::Point, VK_DECIMAL); + + append(Keyboard::Scancode::Keypad1, VK_NUMPAD1); + append(Keyboard::Scancode::Keypad2, VK_NUMPAD2); + append(Keyboard::Scancode::Keypad3, VK_NUMPAD3); + append(Keyboard::Scancode::Keypad4, VK_NUMPAD4); + append(Keyboard::Scancode::Keypad5, VK_NUMPAD5); + append(Keyboard::Scancode::Keypad6, VK_NUMPAD6); + append(Keyboard::Scancode::Keypad7, VK_NUMPAD7); + append(Keyboard::Scancode::Keypad8, VK_NUMPAD8); + append(Keyboard::Scancode::Keypad9, VK_NUMPAD9); + append(Keyboard::Scancode::Keypad0, VK_NUMPAD0); +} + +bool pKeyboard::pressed(Keyboard::Scancode scancode) { + return GetAsyncKeyState(keymap.lhs[scancode]) & 0x8000; +} + +array pKeyboard::state() { + array output; + output.resize((unsigned)Keyboard::Scancode::Limit); + for(auto &n : output) n = false; + + for(auto &n : keymap.rhs) { + if(GetAsyncKeyState(n.name) & 0x8000) { + output[(unsigned)n.data] = true; + } + } + + return output; +} diff --git a/bsnes/phoenix/windows/mouse.cpp b/bsnes/phoenix/windows/mouse.cpp new file mode 100755 index 00000000..e5004645 --- /dev/null +++ b/bsnes/phoenix/windows/mouse.cpp @@ -0,0 +1,14 @@ +Position pMouse::position() { + POINT point = { 0 }; + GetCursorPos(&point); + return { point.x, point.y }; +} + +bool pMouse::pressed(Mouse::Button button) { + switch(button) { + case Mouse::Button::Left: return GetAsyncKeyState(VK_LBUTTON) & 0x8000; + case Mouse::Button::Middle: return GetAsyncKeyState(VK_MBUTTON) & 0x8000; + case Mouse::Button::Right: return GetAsyncKeyState(VK_RBUTTON) & 0x8000; + } + return false; +} \ No newline at end of file diff --git a/bsnes/phoenix/windows/platform.cpp b/bsnes/phoenix/windows/platform.cpp index ce97ed3f..27cfef8b 100755 --- a/bsnes/phoenix/windows/platform.cpp +++ b/bsnes/phoenix/windows/platform.cpp @@ -1,9 +1,15 @@ #include "platform.hpp" +#include "utility.cpp" + +#include "desktop.cpp" +#include "keyboard.cpp" +#include "mouse.cpp" +#include "dialog-window.cpp" +#include "message-window.cpp" #include "object.cpp" #include "font.cpp" #include "timer.cpp" -#include "message-window.cpp" #include "window.cpp" #include "action/action.cpp" @@ -35,98 +41,6 @@ static bool OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); static void OS_processDialogMessage(MSG&); static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM); -Geometry pOS::availableGeometry() { - RECT rc; - SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); - return { rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top }; -} - -Geometry pOS::desktopGeometry() { - return { 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN) }; -} - -static string pOS_fileDialog(bool save, Window &parent, const string &path, const lstring &filter) { - string dir = path; - dir.replace("/", "\\"); - - string filterList; - for(auto &filterItem : filter) { - lstring part; - part.split("(", filterItem); - if(part.size() != 2) continue; - part[1].rtrim<1>(")"); - part[1].replace(" ", ""); - part[1].transform(",", ";"); - filterList.append(string(filterItem, "\t", part[1], "\t")); - } - - utf16_t wfilter(filterList); - utf16_t wdir(dir); - wchar_t wfilename[PATH_MAX + 1] = L""; - - wchar_t *p = wfilter; - while(*p != L'\0') { - if(*p == L'\t') *p = L'\0'; - p++; - } - - OPENFILENAME ofn; - memset(&ofn, 0, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; - ofn.lpstrFilter = wfilter; - ofn.lpstrInitialDir = wdir; - ofn.lpstrFile = wfilename; - ofn.nMaxFile = PATH_MAX; - ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; - ofn.lpstrDefExt = L""; - - bool result = (save == false ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)); - if(result == false) return ""; - string name = (const char*)utf8_t(wfilename); - name.transform("\\", "/"); - return name; -} - -string pOS::fileLoad(Window &parent, const string &path, const lstring &filter) { - return pOS_fileDialog(false, parent, path, filter); -} - -string pOS::fileSave(Window &parent, const string &path, const lstring &filter) { - return pOS_fileDialog(true, parent, path, filter); -} - -string pOS::folderSelect(Window &parent, const string &path) { - wchar_t wfilename[PATH_MAX + 1] = L""; - BROWSEINFO bi; - bi.hwndOwner = &parent != &Window::None ? parent.p.hwnd : 0; - bi.pidlRoot = NULL; - bi.pszDisplayName = wfilename; - bi.lpszTitle = L""; - bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS; - bi.lpfn = NULL; - bi.lParam = 0; - bi.iImage = 0; - bool result = false; - LPITEMIDLIST pidl = SHBrowseForFolder(&bi); - if(pidl) { - if(SHGetPathFromIDList(pidl, wfilename)) { - result = true; - IMalloc *imalloc = 0; - if(SUCCEEDED(SHGetMalloc(&imalloc))) { - imalloc->Free(pidl); - imalloc->Release(); - } - } - } - if(result == false) return ""; - string name = (const char*)utf8_t(wfilename); - if(name == "") return ""; - name.transform("\\", "/"); - if(name.endswith("/") == false) name.append("/"); - return name; -} - void pOS::main() { MSG msg; while(GetMessage(&msg, 0, 0, 0)) { @@ -149,7 +63,8 @@ void pOS::processEvents() { } void OS_processDialogMessage(MSG &msg) { - if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) { + if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP + || msg.message == WM_SYSKEYDOWN || msg.message == WM_SYSKEYUP) { if(OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam)) { DispatchMessage(&msg); return; @@ -163,6 +78,7 @@ void OS_processDialogMessage(MSG &msg) { } void pOS::quit() { + osQuit = true; PostQuitMessage(0); } @@ -218,16 +134,31 @@ void pOS::initialize() { wc.lpszMenuName = 0; wc.style = CS_HREDRAW | CS_VREDRAW; RegisterClass(&wc); + + pKeyboard::initialize(); } static bool OS_keyboardProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { + if(msg != WM_KEYDOWN && msg != WM_SYSKEYDOWN && msg != WM_KEYUP && msg != WM_SYSKEYUP) return false; + + GUITHREADINFO info; + memset(&info, 0, sizeof(GUITHREADINFO)); + info.cbSize = sizeof(GUITHREADINFO); + GetGUIThreadInfo(GetCurrentThreadId(), &info); + Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); + if(object == nullptr) return false; + + if(dynamic_cast(object)) { + Window &window = (Window&)*object; + Keyboard::Keycode keysym = Keysym(wparam, lparam); + if(keysym != Keyboard::Keycode::None) { + if((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) && window.onKeyPress) window.onKeyPress(keysym); + if((msg == WM_KEYUP || msg == WM_SYSKEYUP) && window.onKeyRelease) window.onKeyRelease(keysym); + } + return false; + } + if(msg == WM_KEYDOWN) { - GUITHREADINFO info; - memset(&info, 0, sizeof(GUITHREADINFO)); - info.cbSize = sizeof(GUITHREADINFO); - GetGUIThreadInfo(GetCurrentThreadId(), &info); - Object *object = (Object*)GetWindowLongPtr(info.hwndFocus, GWLP_USERDATA); - if(object == nullptr) return false; if(dynamic_cast(object)) { ListView &listView = (ListView&)*object; if(wparam == VK_RETURN) { @@ -287,7 +218,7 @@ static LRESULT CALLBACK OS_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM if(!object || !dynamic_cast(object)) return DefWindowProc(hwnd, msg, wparam, lparam); Window &window = (Window&)*object; - switch(msg) { + if(!osQuit) switch(msg) { case WM_CLOSE: { window.state.ignore = false; if(window.onClose) window.onClose(); diff --git a/bsnes/phoenix/windows/platform.hpp b/bsnes/phoenix/windows/platform.hpp index e6ff5973..bc4d4808 100755 --- a/bsnes/phoenix/windows/platform.hpp +++ b/bsnes/phoenix/windows/platform.hpp @@ -4,6 +4,8 @@ struct pMenu; struct pLayout; struct pWidget; +static bool osQuit = false; + struct pFont { static Geometry geometry(const string &description, const string &text); @@ -12,6 +14,38 @@ struct pFont { static Geometry geometry(HFONT hfont, const string &text); }; +struct pDesktop { + static Size size(); + static Geometry workspace(); +}; + +struct pKeyboard { + static bidirectional_map keymap; + + static bool pressed(Keyboard::Scancode scancode); + static array state(); + + static void initialize(); +}; + +struct pMouse { + static Position position(); + static bool pressed(Mouse::Button button); +}; + +struct pDialogWindow { + static string fileOpen(Window &parent, const string &path, const lstring &filter); + static string fileSave(Window &parent, const string &path, const lstring &filter); + static string folderSelect(Window &parent, const string &path); +}; + +struct pMessageWindow { + static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); + static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); +}; + struct pObject { Object &object; uintptr_t id; @@ -27,11 +61,6 @@ struct pObject { }; struct pOS : public pObject { - static Geometry availableGeometry(); - static Geometry desktopGeometry(); - static string fileLoad(Window &parent, const string &path, const lstring &filter); - static string fileSave(Window &parent, const string &path, const lstring &filter); - static string folderSelect(Window &parent, const string &path); static void main(); static bool pendingEvents(); static void processEvents(); @@ -51,13 +80,6 @@ struct pTimer : public pObject { void constructor(); }; -struct pMessageWindow : public pObject { - static MessageWindow::Response information(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response question(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response warning(Window &parent, const string &text, MessageWindow::Buttons buttons); - static MessageWindow::Response critical(Window &parent, const string &text, MessageWindow::Buttons buttons); -}; - struct pWindow : public pObject { Window &window; HWND hwnd; @@ -133,12 +155,15 @@ struct pSeparator : public pAction { struct pItem : public pAction { Item &item; + HBITMAP hbitmap; + void setImage(const image &image); void setText(const string &text); - pItem(Item &item) : pAction(item), item(item) {} + pItem(Item &item) : pAction(item), item(item), hbitmap(0) {} void constructor(); void destructor(); + void createBitmap(); }; struct pCheckItem : public pAction { @@ -202,11 +227,14 @@ struct pWidget : public pSizable { struct pButton : public pWidget { Button &button; + HBITMAP hbitmap; + HIMAGELIST himagelist; Geometry minimumGeometry(); + void setImage(const image &image, Orientation orientation); void setText(const string &text); - pButton(Button &button) : pWidget(button), button(button) {} + pButton(Button &button) : pWidget(button), button(button), hbitmap(0), himagelist(0) {} void constructor(); void destructor(); void orphan(); diff --git a/bsnes/phoenix/windows/utility.cpp b/bsnes/phoenix/windows/utility.cpp new file mode 100755 index 00000000..c247d5cc --- /dev/null +++ b/bsnes/phoenix/windows/utility.cpp @@ -0,0 +1,150 @@ +static const unsigned Windows2000 = 0x0500; +static const unsigned WindowsXP = 0x0501; +static const unsigned WindowsVista = 0x0600; +static const unsigned Windows7 = 0x0601; + +static unsigned OsVersion() { + OSVERSIONINFO versionInfo = { 0 }; + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versionInfo); + return (versionInfo.dwMajorVersion << 8) + (versionInfo.dwMajorVersion << 0); +} + +static HBITMAP CreateBitmap(const image &image) { + HDC hdc = GetDC(0); + BITMAPINFO bitmapInfo; + memset(&bitmapInfo, 0, sizeof(BITMAPINFO)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = image.width; + bitmapInfo.bmiHeader.biHeight = -image.height; //bitmaps are stored upside down unless we negate height + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = image.width * image.height * 4; + void *bits = nullptr; + HBITMAP hbitmap = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, &bits, NULL, 0); + if(bits) memcpy(bits, image.data, image.width * image.height * 4); + ReleaseDC(0, hdc); + return hbitmap; +} + +static Keyboard::Keycode Keysym(unsigned keysym, unsigned keyflags) { + #define pressed(keysym) (GetAsyncKeyState(keysym) & 0x8000) + #define enabled(keysym) (GetKeyState(keysym)) + #define shifted() (pressed(VK_LSHIFT) || pressed(VK_RSHIFT)) + #define extended() (keyflags & (1 << 24)) + + switch(keysym) { + case VK_ESCAPE: return Keyboard::Keycode::Escape; + case VK_F1: return Keyboard::Keycode::F1; + case VK_F2: return Keyboard::Keycode::F2; + case VK_F3: return Keyboard::Keycode::F3; + case VK_F4: return Keyboard::Keycode::F4; + case VK_F5: return Keyboard::Keycode::F5; + case VK_F6: return Keyboard::Keycode::F6; + case VK_F7: return Keyboard::Keycode::F7; + case VK_F8: return Keyboard::Keycode::F8; + case VK_F9: return Keyboard::Keycode::F9; + //Keyboard::Keycode::F10 (should be captured under VK_MENU from WM_SYSKEY(UP,DOWN); but this is not working...) + case VK_F11: return Keyboard::Keycode::F11; + case VK_F12: return Keyboard::Keycode::F12; + + //Keyboard::Keycode::PrintScreen + //Keyboard::Keycode::SysRq + case VK_SCROLL: return Keyboard::Keycode::ScrollLock; + case VK_PAUSE: return Keyboard::Keycode::Pause; + //Keyboard::Keycode::Break + + case VK_INSERT: return extended() ? Keyboard::Keycode::Insert : Keyboard::Keycode::KeypadInsert; + case VK_DELETE: return extended() ? Keyboard::Keycode::Delete : Keyboard::Keycode::KeypadDelete; + case VK_HOME: return extended() ? Keyboard::Keycode::Home : Keyboard::Keycode::KeypadHome; + case VK_END: return extended() ? Keyboard::Keycode::End : Keyboard::Keycode::KeypadEnd; + case VK_PRIOR: return extended() ? Keyboard::Keycode::PageUp : Keyboard::Keycode::KeypadPageUp; + case VK_NEXT: return extended() ? Keyboard::Keycode::PageDown : Keyboard::Keycode::KeypadPageDown; + + case VK_UP: return extended() ? Keyboard::Keycode::Up : Keyboard::Keycode::KeypadUp; + case VK_DOWN: return extended() ? Keyboard::Keycode::Down : Keyboard::Keycode::KeypadDown; + case VK_LEFT: return extended() ? Keyboard::Keycode::Left : Keyboard::Keycode::KeypadLeft; + case VK_RIGHT: return extended() ? Keyboard::Keycode::Right : Keyboard::Keycode::KeypadRight; + + case VK_OEM_3: return !shifted() ? Keyboard::Keycode::Grave : Keyboard::Keycode::Tilde; + case '1': return !shifted() ? Keyboard::Keycode::Number1 : Keyboard::Keycode::Exclamation; + case '2': return !shifted() ? Keyboard::Keycode::Number2 : Keyboard::Keycode::At; + case '3': return !shifted() ? Keyboard::Keycode::Number3 : Keyboard::Keycode::Pound; + case '4': return !shifted() ? Keyboard::Keycode::Number4 : Keyboard::Keycode::Dollar; + case '5': return !shifted() ? Keyboard::Keycode::Number5 : Keyboard::Keycode::Percent; + case '6': return !shifted() ? Keyboard::Keycode::Number6 : Keyboard::Keycode::Power; + case '7': return !shifted() ? Keyboard::Keycode::Number7 : Keyboard::Keycode::Ampersand; + case '8': return !shifted() ? Keyboard::Keycode::Number8 : Keyboard::Keycode::Asterisk; + case '9': return !shifted() ? Keyboard::Keycode::Number9 : Keyboard::Keycode::ParenthesisLeft; + case '0': return !shifted() ? Keyboard::Keycode::Number0 : Keyboard::Keycode::ParenthesisRight; + case VK_OEM_MINUS: return !shifted() ? Keyboard::Keycode::Minus : Keyboard::Keycode::Underscore; + case VK_OEM_PLUS: return !shifted() ? Keyboard::Keycode::Equal : Keyboard::Keycode::Plus; + case VK_BACK: return Keyboard::Keycode::Backspace; + + case VK_OEM_4: return !shifted() ? Keyboard::Keycode::BracketLeft : Keyboard::Keycode::BraceLeft; + case VK_OEM_6: return !shifted() ? Keyboard::Keycode::BracketRight : Keyboard::Keycode::BraceRight; + case VK_OEM_5: return !shifted() ? Keyboard::Keycode::Backslash : Keyboard::Keycode::Pipe; + case VK_OEM_1: return !shifted() ? Keyboard::Keycode::Semicolon : Keyboard::Keycode::Colon; + case VK_OEM_7: return !shifted() ? Keyboard::Keycode::Apostrophe : Keyboard::Keycode::Quote; + case VK_OEM_COMMA: return !shifted() ? Keyboard::Keycode::Comma : Keyboard::Keycode::CaretLeft; + case VK_OEM_PERIOD: return !shifted() ? Keyboard::Keycode::Period : Keyboard::Keycode::CaretRight; + case VK_OEM_2: return !shifted() ? Keyboard::Keycode::Slash : Keyboard::Keycode::Question; + + case VK_TAB: return Keyboard::Keycode::Tab; + case VK_CAPITAL: return Keyboard::Keycode::CapsLock; + case VK_RETURN: return !extended() ? Keyboard::Keycode::Return : Keyboard::Keycode::Enter; + case VK_SHIFT: return !pressed(VK_RSHIFT) ? Keyboard::Keycode::ShiftLeft : Keyboard::Keycode::ShiftRight; + case VK_CONTROL: return !pressed(VK_RCONTROL) ? Keyboard::Keycode::ControlLeft : Keyboard::Keycode::ControlRight; + case VK_LWIN: return Keyboard::Keycode::SuperLeft; + case VK_RWIN: return Keyboard::Keycode::SuperRight; + case VK_MENU: + if(keyflags & (1 << 24)) return Keyboard::Keycode::AltRight; + return Keyboard::Keycode::AltLeft; + case VK_SPACE: return Keyboard::Keycode::Space; + case VK_APPS: return Keyboard::Keycode::Menu; + + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': + case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': + if(enabled(VK_CAPITAL)) { + if(shifted()) { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::a + keysym - 'A'); + } else { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::A + keysym - 'A'); + } + } else { + if(shifted()) { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::A + keysym - 'A'); + } else { + return (Keyboard::Keycode)((unsigned)Keyboard::Keycode::a + keysym - 'A'); + } + } + break; + + case VK_NUMLOCK: return Keyboard::Keycode::NumLock; + case VK_DIVIDE: return Keyboard::Keycode::Divide; + case VK_MULTIPLY: return Keyboard::Keycode::Multiply; + case VK_SUBTRACT: return Keyboard::Keycode::Subtract; + case VK_ADD: return Keyboard::Keycode::Add; + case VK_DECIMAL: return Keyboard::Keycode::Point; + case VK_NUMPAD1: return Keyboard::Keycode::Keypad1; + case VK_NUMPAD2: return Keyboard::Keycode::Keypad2; + case VK_NUMPAD3: return Keyboard::Keycode::Keypad3; + case VK_NUMPAD4: return Keyboard::Keycode::Keypad4; + case VK_NUMPAD5: return Keyboard::Keycode::Keypad5; + case VK_NUMPAD6: return Keyboard::Keycode::Keypad6; + case VK_NUMPAD7: return Keyboard::Keycode::Keypad7; + case VK_NUMPAD8: return Keyboard::Keycode::Keypad8; + case VK_NUMPAD9: return Keyboard::Keycode::Keypad9; + case VK_NUMPAD0: return Keyboard::Keycode::Keypad0; + + case VK_CLEAR: return Keyboard::Keycode::KeypadCenter; + } + + return Keyboard::Keycode::None; + + #undef pressed + #undef enabled + #undef shifted + #undef extended +} diff --git a/bsnes/phoenix/windows/widget/button.cpp b/bsnes/phoenix/windows/widget/button.cpp index 9286f6e5..ae53f503 100755 --- a/bsnes/phoenix/windows/widget/button.cpp +++ b/bsnes/phoenix/windows/widget/button.cpp @@ -1,8 +1,51 @@ Geometry pButton::minimumGeometry() { Geometry geometry = pFont::geometry(hfont, button.state.text); + + if(button.state.orientation == Orientation::Horizontal) { + geometry.width += button.state.image.width; + geometry.height = max(button.state.image.height, geometry.height); + } + + if(button.state.orientation == Orientation::Vertical) { + geometry.width = max(button.state.image.width, geometry.width); + geometry.height += button.state.image.height; + } + return { 0, 0, geometry.width + 20, geometry.height + 10 }; } +void pButton::setImage(const image &image, Orientation orientation) { + nall::image nallImage = image; + nallImage.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0); + + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } + + if(OsVersion() >= WindowsVista) { + hbitmap = CreateBitmap(nallImage); + SendMessage(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbitmap); + switch(orientation) { + case Orientation::Horizontal: SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~BS_TOP); break; + case Orientation::Vertical: SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | BS_TOP); break; + } + } else { + //Windows XP and earlier cannot display bitmaps and text at the same time with BM_SETIMAGE + //Use BCM_SETIMAGELIST instead. It does not support alpha blending, so blend with button color + //The XP theme and above use a gradient fade background, so it won't be a perfect match there + nallImage.alphaBlend(GetSysColor(COLOR_BTNFACE)); + hbitmap = CreateBitmap(nallImage); + himagelist = ImageList_Create(nallImage.width, nallImage.height, ILC_COLOR32, 1, 0); + ImageList_Add(himagelist, hbitmap, NULL); + BUTTON_IMAGELIST list; + list.himl = himagelist; + switch(orientation) { + case Orientation::Horizontal: SetRect(&list.margin, 5, 0, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; break; + case Orientation::Vertical: SetRect(&list.margin, 0, 5, 0, 0); list.uAlign = BUTTON_IMAGELIST_ALIGN_TOP; break; + } + Button_SetImageList(hwnd, &list); + } +} + void pButton::setText(const string &text) { SetWindowText(hwnd, utf16_t(text)); } @@ -11,11 +54,14 @@ void pButton::constructor() { 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(); + setImage(button.state.image, button.state.orientation); setText(button.state.text); synchronize(); } void pButton::destructor() { + if(hbitmap) { DeleteObject(hbitmap); hbitmap = 0; } + if(himagelist) { ImageList_Destroy(himagelist); himagelist = 0; } DestroyWindow(hwnd); } diff --git a/bsnes/snes/ppu/screen/screen.cpp b/bsnes/snes/ppu/screen/screen.cpp index 64d2464d..aaf0427f 100755 --- a/bsnes/snes/ppu/screen/screen.cpp +++ b/bsnes/snes/ppu/screen/screen.cpp @@ -116,9 +116,9 @@ uint32 PPU::Screen::get_pixel(bool swap) { } if(swap == true) { - nall::swap(priority_main, priority_sub); - nall::swap(color_main, color_sub); - nall::swap(source_main, source_sub); + std::swap(priority_main, priority_sub); + std::swap(color_main, color_sub); + std::swap(source_main, source_sub); } uint16 output; diff --git a/bsnes/snes/system/serialization.cpp b/bsnes/snes/system/serialization.cpp index f7d6f3b1..5b5d41e8 100755 --- a/bsnes/snes/system/serialization.cpp +++ b/bsnes/snes/system/serialization.cpp @@ -7,7 +7,7 @@ serializer System::serialize() { char description[512], profile[16]; memset(&description, 0, sizeof description); memset(&profile, 0, sizeof profile); - strlcpy(profile, Info::Profile, sizeof profile); + strmcpy(profile, Info::Profile, sizeof profile); s.integer(signature); s.integer(version); diff --git a/bsnes/ui-libsnes/libsnes.cpp b/bsnes/ui-libsnes/libsnes.cpp index fbb4482c..b190800f 100755 --- a/bsnes/ui-libsnes/libsnes.cpp +++ b/bsnes/ui-libsnes/libsnes.cpp @@ -79,7 +79,7 @@ struct Interface : public SNES::Interface { static Interface interface; const char* snes_library_id(void) { - return "bsnes v083"; + return "bsnes v085"; } unsigned snes_library_revision_major(void) { @@ -115,7 +115,8 @@ void snes_set_cartridge_basename(const char *basename) { } void snes_init(void) { - interface.initialize(&interface); + SNES::interface = &interface; + SNES::system.init(); SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad); SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); } @@ -163,7 +164,10 @@ static linear_vector cheatList; void snes_cheat_reset(void) { cheatList.reset(); - interface.setCheats(); + GameBoy::cheat.reset(); + GameBoy::cheat.synchronize(); + SNES::cheat.reset(); + SNES::cheat.synchronize(); } void snes_cheat_set(unsigned index, bool enable, const char *code) { @@ -173,7 +177,35 @@ void snes_cheat_set(unsigned index, bool enable, const char *code) { for(unsigned n = 0; n < cheatList.size(); n++) { if(cheatList[n].enable) list.append(cheatList[n].code); } - interface.setCheats(list); + + if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) { + GameBoy::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data, comp; + if(GameBoy::Cheat::decode(part, addr, data, comp)) { + GameBoy::cheat.append({ addr, data, comp }); + } + } + } + GameBoy::cheat.synchronize(); + return; + } + + SNES::cheat.reset(); + for(auto &code : list) { + lstring codelist; + codelist.split("+", code); + for(auto &part : codelist) { + unsigned addr, data; + if(SNES::Cheat::decode(part, addr, data)) { + SNES::cheat.append({ addr, data }); + } + } + } + SNES::cheat.synchronize(); } bool snes_load_cartridge_normal( @@ -244,7 +276,7 @@ bool snes_load_cartridge_super_game_boy( uint8_t *data = new uint8_t[dmg_size]; memcpy(data, dmg_data, dmg_size); string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup; - GameBoy::cartridge.load(xmldmg, data, dmg_size); + GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, xmldmg, data, dmg_size); delete[] data; } SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom); diff --git a/bsnes/ui/general/file-browser.cpp b/bsnes/ui/general/file-browser.cpp index 255086be..4a9d6fee 100755 --- a/bsnes/ui/general/file-browser.cpp +++ b/bsnes/ui/general/file-browser.cpp @@ -27,7 +27,7 @@ FileBrowser::FileBrowser() { }; pathBrowse.onActivate = [&] { - string path = OS::folderSelect(*this, mode->path); + string path = DialogWindow::folderSelect(*this, mode->path); if(path != "") setPath(path); }; diff --git a/bsnes/ui/input/input.cpp b/bsnes/ui/input/input.cpp index b64bddba..35f5afcf 100755 --- a/bsnes/ui/input/input.cpp +++ b/bsnes/ui/input/input.cpp @@ -38,6 +38,7 @@ int16_t AbstractInput::poll() { // bool AnalogInput::bind(int16_t scancode, int16_t value) { + using nall::Mouse; string encode = Scancode::encode(scancode); Type type = Type::Button; @@ -66,6 +67,8 @@ int16_t AnalogInput::poll() { // bool DigitalInput::bind(int16_t scancode, int16_t value) { + using nall::Keyboard; + using nall::Mouse; string encode = Scancode::encode(scancode); Type type = Type::Button; diff --git a/bsnes/ui/interface/snes/snes.cpp b/bsnes/ui/interface/snes/snes.cpp index afe7ac92..5469d6a1 100755 --- a/bsnes/ui/interface/snes/snes.cpp +++ b/bsnes/ui/interface/snes/snes.cpp @@ -317,9 +317,9 @@ int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned if(device == SNES::Input::Device::Joypad) return inputManager->snes.port1.gamepad.poll(id); if(device == SNES::Input::Device::Multitap) { if(index == 0) return inputManager->snes.port1.multitap1.poll(id); - if(index == 1) return inputManager->snes.port1.multitap1.poll(id); - if(index == 2) return inputManager->snes.port1.multitap1.poll(id); - if(index == 3) return inputManager->snes.port1.multitap1.poll(id); + if(index == 1) return inputManager->snes.port1.multitap2.poll(id); + if(index == 2) return inputManager->snes.port1.multitap3.poll(id); + if(index == 3) return inputManager->snes.port1.multitap4.poll(id); } if(device == SNES::Input::Device::Mouse) return inputManager->snes.port1.mouse.poll(id); } @@ -328,9 +328,9 @@ int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned if(device == SNES::Input::Device::Joypad) return inputManager->snes.port2.gamepad.poll(id); if(device == SNES::Input::Device::Multitap) { if(index == 0) return inputManager->snes.port2.multitap1.poll(id); - if(index == 1) return inputManager->snes.port2.multitap1.poll(id); - if(index == 2) return inputManager->snes.port2.multitap1.poll(id); - if(index == 3) return inputManager->snes.port2.multitap1.poll(id); + if(index == 1) return inputManager->snes.port2.multitap2.poll(id); + if(index == 2) return inputManager->snes.port2.multitap3.poll(id); + if(index == 3) return inputManager->snes.port2.multitap4.poll(id); } if(device == SNES::Input::Device::Mouse) return inputManager->snes.port2.mouse.poll(id); if(device == SNES::Input::Device::SuperScope) return inputManager->snes.port2.superScope.poll(id); diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 2456fc7e..66d32045 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -27,7 +27,7 @@ void Application::run() { } Application::Application(int argc, char **argv) { - title = "bsnes v085"; + title = "bsnes v085.01"; application = this; quit = false; diff --git a/bsnes/ui/settings/input.cpp b/bsnes/ui/settings/input.cpp index e049187f..a5999b9b 100755 --- a/bsnes/ui/settings/input.cpp +++ b/bsnes/ui/settings/input.cpp @@ -133,6 +133,7 @@ void InputSettings::clearInput() { } void InputSettings::inputEvent(int16_t scancode, int16_t value, bool allowMouseInput) { + using nall::Mouse; if(activeInput == 0) return; if(allowMouseInput == false && (Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode))) return; if(activeInput->bind(scancode, value) == false) return; diff --git a/bsnes/ui/tools/state-manager.cpp b/bsnes/ui/tools/state-manager.cpp index a7e103ff..28f369fc 100755 --- a/bsnes/ui/tools/state-manager.cpp +++ b/bsnes/ui/tools/state-manager.cpp @@ -141,7 +141,7 @@ void StateManager::slotErase() { string StateManager::slotLoadDescription(unsigned n) { if(slot[n].capacity() == 0) return "(empty)"; char text[DescriptionLength]; - strlcpy(text, (const char*)slot[n].data() + HeaderLength, DescriptionLength); + strmcpy(text, (const char*)slot[n].data() + HeaderLength, DescriptionLength); return text; } @@ -149,7 +149,7 @@ void StateManager::slotSaveDescription() { if(stateList.selected() == false) return; string text = descEdit.text(); if(slot[stateList.selection()].capacity() > 0) { - strlcpy((char*)slot[stateList.selection()].data() + HeaderLength, (const char*)text, DescriptionLength); + strmcpy((char*)slot[stateList.selection()].data() + HeaderLength, (const char*)text, DescriptionLength); } refresh(); }