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]
This commit is contained in:
Tim Allen 2012-01-15 19:29:57 +11:00
parent ba081d309e
commit cc518dcc3c
82 changed files with 2552 additions and 669 deletions

View File

@ -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<item_t> list;
template<typename T>
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<typename T>
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++) {

View File

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

View File

@ -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) {

View File

@ -1,55 +0,0 @@
#ifndef NALL_HID_HPP
#define NALL_HID_HPP
#include <nall/xorg/xorg.hpp>
#include <nall/input.hpp>
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

View File

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

View File

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

View File

@ -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) {

87
bsnes/nall/map.hpp Executable file
View File

@ -0,0 +1,87 @@
#ifndef NALL_MAP_HPP
#define NALL_MAP_HPP
#include <nall/vector.hpp>
namespace nall {
template<typename LHS, typename RHS>
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<pair> list;
};
template<typename LHS, typename RHS>
struct bidirectional_map {
map<LHS, RHS> lhs;
map<RHS, LHS> 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

View File

@ -1,6 +1,7 @@
#ifndef NALL_SORT_HPP
#define NALL_SORT_HPP
#include <algorithm>
#include <nall/utility.hpp>
//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;
}

26
bsnes/nall/stream.hpp Executable file
View File

@ -0,0 +1,26 @@
#ifndef NALL_STREAM_HPP
#define NALL_STREAM_HPP
#include <algorithm>
#include <memory>
#include <nall/file.hpp>
#include <nall/filemap.hpp>
#include <nall/gzip.hpp>
#include <nall/http.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/zip.hpp>
#define NALL_STREAM_INTERNAL_HPP
#include <nall/stream/stream.hpp>
#include <nall/stream/memory.hpp>
#include <nall/stream/mmap.hpp>
#include <nall/stream/file.hpp>
#include <nall/stream/http.hpp>
#include <nall/stream/gzip.hpp>
#include <nall/stream/zip.hpp>
#include <nall/stream/auto.hpp>
#undef NALL_STREAM_INTERNAL_HPP
#endif

24
bsnes/nall/stream/auto.hpp Executable file
View File

@ -0,0 +1,24 @@
#ifdef NALL_STREAM_INTERNAL_HPP
namespace nall {
#define autostream(...) (*makestream(__VA_ARGS__))
inline std::unique_ptr<stream> makestream(const string &path) {
if(path.ibeginswith("http://")) return std::unique_ptr<stream>(new httpstream(path, 80));
if(path.iendswith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
if(path.iendswith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
return std::unique_ptr<stream>(new mmapstream(path));
}
inline std::unique_ptr<stream> makestream(uint8_t *data, unsigned size) {
return std::unique_ptr<stream>(new memorystream(data, size));
}
inline std::unique_ptr<stream> makestream(const uint8_t *data, unsigned size) {
return std::unique_ptr<stream>(new memorystream(data, size));
}
}
#endif

31
bsnes/nall/stream/file.hpp Executable file
View File

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

28
bsnes/nall/stream/gzip.hpp Executable file
View File

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

43
bsnes/nall/stream/http.hpp Executable file
View File

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

40
bsnes/nall/stream/memory.hpp Executable file
View File

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

36
bsnes/nall/stream/mmap.hpp Executable file
View File

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

90
bsnes/nall/stream/stream.hpp Executable file
View File

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

30
bsnes/nall/stream/zip.hpp Executable file
View File

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

View File

@ -35,7 +35,7 @@
#include <nall/string/math-fixed-point.hpp>
#include <nall/string/math-floating-point.hpp>
#include <nall/string/platform.hpp>
#include <nall/string/strl.hpp>
#include <nall/string/strm.hpp>
#include <nall/string/strpos.hpp>
#include <nall/string/trim.hpp>
#include <nall/string/replace.hpp>

View File

@ -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<unsigned> strpos(const char *str, const char *key);
@ -171,8 +174,6 @@ namespace nall {
template<bool Insensitive> alwaysinline bool chrequal(char x, char y);
template<bool Quoted, typename T> alwaysinline bool quoteskip(T *&p);
template<bool Quoted, typename T> 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);

View File

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

45
bsnes/nall/string/strm.hpp Executable file
View File

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

View File

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

View File

@ -9,12 +9,6 @@ namespace nall {
template<typename T> struct enable_if<false, T> {};
template<typename C, typename T = bool> struct mp_enable_if : enable_if<C::value, T> {};
template<typename T> inline void swap(T &x, T &y) {
T temp(std::move(x));
x = std::move(y);
y = std::move(temp);
}
template<typename T> struct base_from_member {
T value;
base_from_member(T value_) : value(value_) {}

View File

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

View File

@ -151,7 +151,7 @@ static string iNES(const uint8_t *data, unsigned size) {
"</cartridge>\n"
);
print(output, "\n");
//print(output, "\n");
return output;
}

View File

@ -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<bool> 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<Action&> &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<Action&> &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() {

View File

@ -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<typename... Args> 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<bool> 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<typename... Args> static nall::string fileOpen(Window &parent, const nall::string &path, const Args&... args) { return fileOpen_(parent, path, { args... }); }
template<typename... Args> 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<pTimer&>, Object {
nall::function<void ()> 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<pTimer&>, Object {
nall::function<void ()> 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<pWindow&>, Object {
static Window None;
nall::function<void ()> onClose;
nall::function<void (Keyboard::Keycode)> onKeyPress;
nall::function<void (Keyboard::Keycode)> onKeyRelease;
nall::function<void ()> onMove;
nall::function<void ()> onSize;
void append(Layout &layout);
void append(Menu &menu);
void append(Widget &widget);
inline void append() {}
inline void remove() {}
template<typename T, typename... Args> void append(T &arg, Args&... args) { append_(arg); append(args...); }
template<typename T, typename... Args> 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<pWindow&>, 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<pMenu&>, Action {
void append(Action &action);
void remove(Action &action);
template<typename... Args> void append(Args&... args) { append({ args... }); }
template<typename... Args> void remove(Args&... args) { remove({ args... }); }
void append(const nall::reference_array<Action&> &list);
void remove(const nall::reference_array<Action&> &list);
void setText(const nall::string &text);
Menu();
@ -214,6 +251,7 @@ struct Separator : private nall::base_from_member<pSeparator&>, Action {
struct Item : private nall::base_from_member<pItem&>, Action {
nall::function<void ()> 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<pWidget&>, Sizable {
struct Button : private nall::base_from_member<pButton&>, Widget {
nall::function<void ()> 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<pCheckBox&>, Widget {
struct ComboBox : private nall::base_from_member<pComboBox&>, Widget {
nall::function<void ()> onChange;
void append(const nall::string &text);
template<typename... Args> 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<pListView&>, Widget {
nall::function<void (unsigned)> onToggle;
template<typename... Args> void append(const Args&... args) { append_({ args... }); }
template<typename... Args> void modify(unsigned row, const Args&... args) { modify_(row, { args... }); }
template<typename... Args> void setHeaderText(const Args&... args) { setHeaderText_({ args... }); }
void append_(const nall::lstring &list);
void autoSizeColumns();
bool checked(unsigned row);
template<typename... Args> 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<typename... Args> 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<pListView&>, 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<pProgressBar&>, Widget {

45
bsnes/phoenix/core/keyboard.hpp Executable file
View File

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

View File

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

View File

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

36
bsnes/phoenix/gtk/desktop.cpp Executable file
View File

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

View File

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

144
bsnes/phoenix/gtk/keyboard.cpp Executable file
View File

@ -0,0 +1,144 @@
bidirectional_map<Keyboard::Scancode, unsigned> 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<bool> pKeyboard::state() {
array<bool> 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;
}

20
bsnes/phoenix/gtk/mouse.cpp Executable file
View File

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

View File

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

View File

@ -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<Keyboard::Scancode, unsigned> keymap;
static bool pressed(Keyboard::Scancode scancode);
static array<bool> 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) {}

View File

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

195
bsnes/phoenix/gtk/utility.cpp Executable file
View File

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

View File

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

View File

@ -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() {

View File

@ -17,13 +17,21 @@
#elif defined(PHOENIX_QT)
#include <QApplication>
#include <QtGui>
#include <nall/xorg/guard.hpp>
#define XK_MISCELLANY
#define XK_LATIN1
#include <X11/Xlib.h>
#include <X11/keysymdef.h>
#undef XK_MISCELLANY
#undef XK_LATIN1
#include <nall/xorg/guard.hpp>
#elif defined(PHOENIX_GTK)
#include <nall/xorg/guard.hpp>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <cairo.h>
#include <gdk/gdkkeysyms.h>
#include <cairo.h>
#include <X11/Xatom.h>
#include <nall/xorg/guard.hpp>
#elif defined(PHOENIX_REFERENCE)

View File

@ -6,6 +6,7 @@
#include <nall/config.hpp>
#include <nall/function.hpp>
#include <nall/image.hpp>
#include <nall/map.hpp>
#include <nall/reference_array.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>

View File

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

9
bsnes/phoenix/qt/desktop.cpp Executable file
View File

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

View File

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

144
bsnes/phoenix/qt/keyboard.cpp Executable file
View File

@ -0,0 +1,144 @@
bidirectional_map<Keyboard::Scancode, unsigned> 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<bool> pKeyboard::state() {
array<bool> 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;
}

14
bsnes/phoenix/qt/mouse.cpp Executable file
View File

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

View File

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

View File

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

View File

@ -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<Keyboard::Scancode, unsigned> keymap;
static bool pressed(Keyboard::Scancode scancode);
static array<bool> 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) {}

View File

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

182
bsnes/phoenix/qt/utility.cpp Executable file
View File

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

View File

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

View File

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

View File

@ -1,3 +1,6 @@
void pItem::setImage(const image &image) {
}
void pItem::setText(const string &text) {
}

View File

@ -0,0 +1,8 @@
Size pDesktop::size() {
return { 0, 0 };
}
Geometry pDesktop::workspace() {
return { 0, 0, 0, 0 };
}

View File

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

View File

@ -0,0 +1,10 @@
bool pKeyboard::pressed(Keyboard::Scancode scancode) {
return false;
}
array<bool> pKeyboard::state() {
array<bool> output;
output.resize((unsigned)Keyboard::Scancode::Limit);
for(auto &n : output) n = false;
return output;
}

View File

@ -0,0 +1,7 @@
Position pMouse::position() {
return { 0, 0 };
}
bool pMouse::pressed(Mouse::Button button) {
return false;
}

View File

@ -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() {
}

View File

@ -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<bool> 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) {}

View File

@ -1,3 +1,6 @@
void pButton::setImage(const image &image, Orientation orientation) {
}
void pButton::setText(const string &text) {
}

View File

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

View File

@ -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<Item*>(&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<CheckItem*>(&action)) {
CheckItem &item = (CheckItem&)action;
if(action.state.visible) AppendMenu(hmenu, MF_STRING | enabled, item.p.id, utf16_t(item.state.text));

View File

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

View File

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

View File

@ -0,0 +1,139 @@
bidirectional_map<Keyboard::Scancode, unsigned> 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<bool> pKeyboard::state() {
array<bool> 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;
}

14
bsnes/phoenix/windows/mouse.cpp Executable file
View File

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

View File

@ -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<Window*>(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<ListView*>(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<Window*>(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();

View File

@ -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<Keyboard::Scancode, unsigned> keymap;
static bool pressed(Keyboard::Scancode scancode);
static array<bool> 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();

150
bsnes/phoenix/windows/utility.cpp Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,7 +27,7 @@ void Application::run() {
}
Application::Application(int argc, char **argv) {
title = "bsnes v085";
title = "bsnes v085.01";
application = this;
quit = false;

View File

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

View File

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