Update to v093r02 release.

byuu says:

Changelog:
- nall: fixed major memory leak in string class
- ruby: video shaders support #define-based settings now
- phoenix/GTK+: support > 256x256 icons for window / task bar / alt-tab
- sfc: remove random/ and config/, merge into system/
- ethos: delete higan.png (48x48), replace with higan512.png (512x512)
  as new higan.png
- ethos: default gamma to 100% (no color adjustment)
- ethos: use "Video Shaders/Display Emulation/" instead of "Video
  Shaders/Emulation/"
- use g++ instead of g++-4.7 (g++ -v must be >= 4.7)
- use -std=c++11 instead of -std=gnu++11
- applied a few patches from Debian upstream to make their packaging job
  easier

So because colors are normalized in GLSL, I won't be able to offer video
shaders absolute color literals. We will have to perform basic color
conversion inside the core.

As such, the current plan is to create some sort of Emulator::Settings
interface. With that, I'll connect an option for color correction, which
will be on by default. For FC/SFC, that will mean gamma correction
(darker / stronger colors), and for GB/GBC/GBA, it will mean simulating
the weird brightness levels of the displays. I am undecided on whether
to use pea soup green for the GB or not. By not doing so, it'll be
easier for the display emulation shader to do it.
This commit is contained in:
Tim Allen 2013-11-09 22:45:54 +11:00
parent 66f136718e
commit 8c0b0fa4ad
87 changed files with 1446 additions and 455 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "higan";
static const char Version[] = "093.01";
static const char Version[] = "093.02";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";

View File

@ -10,10 +10,7 @@
[space] :=
[space] +=
#####
# platform detection
#####
ifeq ($(platform),)
uname := $(shell uname -s)
ifeq ($(uname),)
@ -37,6 +34,7 @@ ifeq ($(platform),)
endif
endif
# compiler detection
ifeq ($(compiler),)
ifeq ($(platform),windows)
compiler := g++
@ -48,19 +46,20 @@ ifeq ($(compiler),)
link := -lc++ -lobjc
else ifeq ($(platform),bsd)
compiler := clang++
flags := -w
flags := -w -I/usr/local/include
else
compiler := g++-4.7
compiler := g++
flags :=
link :=
endif
cflags := -x c -std=gnu99
objcflags := -x objective-c -std=gnu99
cppflags := -x c++ -std=gnu++11
objcppflags := -x objective-c++ -std=gnu++11
cflags := -x c -std=c99
objcflags := -x objective-c -std=c99
cppflags := -x c++ -std=c++11
objcppflags := -x objective-c++ -std=c++11
endif
# cross-compilation support
ifeq ($(arch),x86)
flags := -m32 $(flags)
link := -m32 $(link)
@ -70,9 +69,7 @@ ifeq ($(prefix),)
prefix := /usr/local
endif
#####
# function rwildcard(directory, pattern)
#####
rwildcard = \
$(strip \
$(filter $(if $2,$2,%), \
@ -84,9 +81,7 @@ rwildcard = \
) \
)
#####
# function strtr(source, from, to)
#####
strtr = \
$(eval __temp := $1) \
$(strip \
@ -99,19 +94,13 @@ strtr = \
$(__temp) \
)
#####
# function strupper(source)
#####
strupper = $(call strtr,$1,$([a-z]),$([A-Z]))
#####
# function strlower(source)
#####
strlower = $(call strtr,$1,$([A-Z]),$([a-z]))
#####
# function strlen(source)
#####
strlen = \
$(eval __temp := $(subst $([space]),_,$1)) \
$(words \
@ -126,12 +115,8 @@ strlen = \
) \
)
#####
# function streq(source)
#####
streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1)
#####
# function strne(source)
#####
strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,)

View File

@ -8,6 +8,7 @@ namespace nall {
constexpr inline uintmax_t binary_(const char* s, uintmax_t sum = 0) {
return (
*s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') :
*s == '\'' ? binary_(s + 1, sum) :
sum
);
}
@ -15,6 +16,7 @@ constexpr inline uintmax_t binary_(const char* s, uintmax_t sum = 0) {
constexpr inline uintmax_t octal_(const char* s, uintmax_t sum = 0) {
return (
*s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') :
*s == '\'' ? octal_(s + 1, sum) :
sum
);
}
@ -22,6 +24,7 @@ constexpr inline uintmax_t octal_(const char* s, uintmax_t sum = 0) {
constexpr inline uintmax_t decimal_(const char* s, uintmax_t sum = 0) {
return (
*s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') :
*s == '\'' ? decimal_(s + 1, sum) :
sum
);
}
@ -31,6 +34,7 @@ constexpr inline uintmax_t hex_(const char* s, uintmax_t sum = 0) {
*s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) :
*s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) :
*s >= '0' && *s <= '9' ? hex_(s + 1, (sum << 4) | *s - '0') :
*s == '\'' ? hex_(s + 1, sum) :
sum
);
}

View File

@ -32,7 +32,7 @@ struct Node {
void set(const string& value) {
switch(type) {
case Type::Bool: *(bool*)data = (value == "true"); break;
case Type::Bool: *(bool*)data = (value != "false"); break;
case Type::Signed: *(signed*)data = integer(value); break;
case Type::Unsigned: *(unsigned*)data = decimal(value); break;
case Type::Double: *(double*)data = real(value); break;

View File

@ -1,6 +1,8 @@
#ifndef NALL_DSP_HPP
#define NALL_DSP_HPP
#include <nall/bit.hpp>
#include <algorithm>
#ifdef __SSE__
#include <xmmintrin.h>

View File

@ -535,7 +535,7 @@ void ResampleUtility::gen_sinc(double* out, int size, double cutoff, double kais
// Generate right half of sinc
for ( int i = 0; i < half_size; i++ )
{
double angle = (i * 2 + 1) * (M_PI / 2);
double angle = (i * 2 + 1) * (Math::Pi / 2);
mid [i] = sin( angle * cutoff ) / angle;
}
@ -553,9 +553,9 @@ void ResampleUtility::gen_sinc_os(double* out, int size, double cutoff, double k
for(int i = 0; i < size; i++)
{
if(i == (size / 2))
out[i] = 2 * M_PI * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
out[i] = 2 * Math::Pi * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
else
out[i] = sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
out[i] = sin(2 * Math::Pi * (cutoff / 2) * (i - size / 2)) / (i - (size / 2));
// out[i] *= 0.3635819 - 0.4891775 * cos(2 * M_PI * i / (size - 1)) + 0.1365995 * cos(4 * M_PI * i / (size - 1)) - 0.0106411 * cos(6 * M_PI * i / (size - 1));
//0.42 - 0.5 * cos(2 * M_PI * i / (size - 1)) + 0.08 * cos(4 * M_PI * i / (size - 1));

View File

@ -5,6 +5,7 @@
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/windows/utf8.hpp>
#include <nall/stream/memory.hpp>
@ -18,7 +19,7 @@ inline FILE* fopen_utf8(const string& filename, const string& mode) {
#endif
}
struct file {
struct file : varint {
enum class mode : unsigned { read, write, modify, append, readwrite = modify, writeread = append };
enum class index : unsigned { absolute, relative };
enum class time : unsigned { create, modify, access };
@ -32,11 +33,16 @@ struct file {
}
static bool move(const string& sourcename, const string& targetname) {
#if !defined(_WIN32)
return rename(sourcename, targetname) == 0;
#else
return _wrename(utf16_t(sourcename), utf16_t(targetname)) == 0;
#endif
auto result = rename(sourcename, targetname);
if(result == 0) return true;
if(errno == EXDEV) {
//cannot move files between file systems; copy file instead of failing
if(file::copy(sourcename, targetname)) {
file::remove(sourcename);
return true;
}
}
return false;
}
static bool remove(const string& filename) {

View File

@ -496,9 +496,9 @@ bool image::loadPNG(const uint8_t* pngData, unsigned pngSize) {
}
bool image::loadPNG(const string& filename) {
filemap map;
if(map.open(filename, filemap::mode::read) == false) return false;
return loadPNG(map.data(), map.size());
if(!file::exists(filename)) return false;
auto buffer = file::read(filename);
return loadPNG(buffer.data(), buffer.size());
}
}

View File

@ -4,12 +4,14 @@
namespace nall {
struct Intrinsics {
enum class Compiler : unsigned { Clang, GCC, VisualC, Unknown };
enum class Platform : unsigned { X, OSX, Windows, Unknown };
enum class Compiler : unsigned { Clang, GCC, VisualCPP, Unknown };
enum class Platform : unsigned { Windows, MacOSX, X, Unknown }; //X = Linux, BSD, etc
enum class Architecture : unsigned { x86, amd64, Unknown };
enum class Endian : unsigned { LSB, MSB, Unknown };
static inline Compiler compiler();
static inline Platform platform();
static inline Architecture architecture();
static inline Endian endian();
};
@ -22,8 +24,8 @@ struct Intrinsics {
#define COMPILER_GCC
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::GCC; }
#elif defined(_MSC_VER)
#define COMPILER_VISUALC
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualC; }
#define COMPILER_VISUALCPP
Intrinsics::Compiler Intrinsics::compiler() { return Intrinsics::Compiler::VisualCPP; }
#else
#warning "unable to detect compiler"
#define COMPILER_UNKNOWN
@ -32,36 +34,46 @@ struct Intrinsics {
/* Platform detection */
#if defined(linux) || defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if defined(_WIN32)
#define PLATFORM_WINDOWS
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; }
#elif defined(__APPLE__)
#define PLATFORM_MACOSX
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::MacOSX; }
#elif defined(linux) || defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__GNU__)
#define PLATFORM_X
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::X; }
#elif defined(__APPLE__)
#define PLATFORM_OSX
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::OSX; }
#elif defined(_WIN32)
#define PLATFORM_WINDOWS
#define PLATFORM_WIN
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Windows; }
#else
#warning "unable to detect platform"
#define PLATFORM_UNKNOWN
Intrinsics::Platform Intrinsics::platform() { return Intrinsics::Platform::Unknown; }
#endif
/* Architecture Detection */
#if defined(__i386__) || defined(_M_IX86)
#define ARCH_X86
Intrinsics::Architecture Intrinsics::architecture() { return Intrinsics::Architecture::x86; }
#elif defined(__amd64__) || defined(_M_AMD64)
#define ARCH_AMD64
Intrinsics::Architecture Intrinsics::architecture() { return Intrinsics::Architecture::amd64; }
#else
#warning "unable to detect architecture"
#define ARCH_UNKNOWN
Intrinsics::Architecture Intrinsics::architecture() { return Intrinsics::Architecture::Unknown; }
#endif
/* Endian detection */
#if defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64)
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) || defined(__i386__) || defined(__amd64__) || defined(_M_IX86) || defined(_M_AMD64)
#define ENDIAN_LSB
#define ARCH_LSB
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::LSB; }
#elif defined(__powerpc__) || defined(_M_PPC) || defined(__BIG_ENDIAN__)
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(__powerpc__) || defined(_M_PPC)
#define ENDIAN_MSB
#define ARCH_MSB
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::MSB; }
#else
#warning "unable to detect endian"
#define ENDIAN_UNKNOWN
#define ARCH_UNKNOWN
Intrinsics::Endian Intrinsics::endian() { return Intrinsics::Endian::Unknown; }
#endif

View File

@ -23,7 +23,7 @@ namespace nall {
template<typename... Args> inline void invoke(const string& name, Args&&... args) {
lstring argl(std::forward<Args>(args)...);
for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""};
string arguments = argl.concatenate(" ");
string arguments = argl.merge(" ");
ShellExecuteW(NULL, NULL, utf16_t(name), utf16_t(arguments), NULL, SW_SHOWNORMAL);
}

View File

@ -1,6 +1,11 @@
#ifndef NALL_PLATFORM_HPP
#define NALL_PLATFORM_HPP
namespace Math {
static const long double e = 2.71828182845904523536;
static const long double Pi = 3.14159265358979323846;
}
#if defined(_WIN32)
//minimum version needed for _wstat64, etc
#undef __MSVCRT_VERSION__
@ -40,29 +45,24 @@
#define dllexport
#endif
//==================
//warning supression
//==================
//==========
//Visual C++
#if defined(_MSC_VER)
//disable libc "deprecation" warnings
#pragma warning(disable:4996)
#endif
//================
//POSIX compliance
//================
//==========
#if defined(_MSC_VER)
#define PATH_MAX _MAX_PATH
#pragma warning(disable:4996) //disable libc "deprecation" warnings
#define va_copy(dest, src) ((dest) = (src))
#endif
#if defined(_WIN32)
#define getcwd _getcwd
#define putenv _putenv
#define vsnprintf _vsnprintf
extern "C" int _fileno(FILE*);
inline int access(const char* path, int amode) { return _waccess(nall::utf16_t(path), amode); }
inline int fileno(FILE* stream) { return _fileno(stream); }
inline char* getcwd(char* buf, size_t size) { wchar_t wpath[PATH_MAX] = L""; if(!_wgetcwd(wpath, size)) return nullptr; strcpy(buf, nall::utf8_t(wpath)); return buf; }
inline int putenv(char* string) { return _wputenv(nall::utf16_t(string)); }
inline char* realpath(const char* file_name, char* resolved_name) { wchar_t wfile_name[PATH_MAX] = L""; if(!_wfullpath(wfile_name, nall::utf16_t(file_name), PATH_MAX)) return nullptr; strcpy(resolved_name, nall::utf8_t(wfile_name)); return resolved_name; }
inline int rename(const char* oldname, const char* newname) { return _wrename(nall::utf16_t(oldname), nall::utf16_t(newname)); }
inline void usleep(unsigned milliseconds) { Sleep(milliseconds / 1000); }
#endif
@ -72,15 +72,12 @@
#if defined(__clang__) || defined(__GNUC__)
#define noinline __attribute__((noinline))
#define inline inline
#define alwaysinline inline __attribute__((always_inline))
#elif defined(_MSC_VER)
#define noinline __declspec(noinline)
#define inline inline
#define alwaysinline inline __forceinline
#else
#define noinline
#define inline inline
#define alwaysinline inline
#endif

View File

@ -137,7 +137,7 @@ bool png::decode(const uint8_t* sourceData, unsigned sourceSize) {
uint8_t *interlacedData = new uint8_t[interlacedSize];
bool result = inflate(interlacedData, interlacedSize, compressedData + 2, compressedSize - 6);
delete[] compressedData;
free(compressedData);
if(result == false) {
delete[] interlacedData;

View File

@ -63,6 +63,7 @@ void string::reset() {
string& string::operator=(const string& source) {
if(&source == this) return *this;
reset();
_data = source._data;
_capacity = source._capacity;
_size = source._size;
@ -71,6 +72,7 @@ string& string::operator=(const string& source) {
string& string::operator=(string&& source) {
if(&source == this) return *this;
reset();
_data = std::move(source._data);
_capacity = source._capacity;
_size = source._size;
@ -80,17 +82,21 @@ string& string::operator=(string&& source) {
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_capacity = 0;
_size = 0;
construct();
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_capacity = 0;
_size = 0;
construct();
}
string::~string() {
reset();
}
void string::construct() {
_capacity = 0;
_size = 0;
}
}

View File

@ -63,6 +63,7 @@ void string::reset() {
string& string::operator=(const string& source) {
if(&source == this) return *this;
reset();
if(source._capacity >= SSO) {
_data = (char*)malloc(source._capacity + 1);
_capacity = source._capacity;
@ -78,6 +79,7 @@ string& string::operator=(const string& source) {
string& string::operator=(string&& source) {
if(&source == this) return *this;
reset();
memcpy(this, &source, sizeof(string));
source._data = nullptr;
source._capacity = SSO - 1;
@ -86,20 +88,22 @@ string& string::operator=(string&& source) {
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_data = nullptr;
_capacity = SSO - 1;
_size = 0;
construct();
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_data = nullptr;
_capacity = SSO - 1;
_size = 0;
construct();
}
string::~string() {
if(_capacity >= SSO) free(_data);
reset();
}
void string::construct() {
_data = nullptr;
_capacity = SSO - 1;
_size = 0;
}
}

View File

@ -50,6 +50,7 @@ void string::reset() {
string& string::operator=(const string& source) {
if(&source == this) return *this;
reset();
_data = (char*)malloc(source._size + 1);
_capacity = source._size;
_size = source._size;
@ -59,6 +60,7 @@ string& string::operator=(const string& source) {
string& string::operator=(string&& source) {
if(&source == this) return *this;
reset();
_data = source._data;
_capacity = source._capacity;
_size = source._size;
@ -69,20 +71,22 @@ string& string::operator=(string&& source) {
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_data = nullptr;
_capacity = 0;
_size = 0;
construct();
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_data = nullptr;
_capacity = 0;
_size = 0;
construct();
}
string::~string() {
if(_data) free(_data);
reset();
}
void string::construct() {
_data = nullptr;
_capacity = 0;
_size = 0;
}
}

View File

@ -144,6 +144,9 @@ public:
template<unsigned Limit, bool Insensitive, bool Quoted> inline string& ureplace(rstring, rstring);
inline string& _append(const char*);
private:
inline void construct();
#if defined(QSTRING_H)
public:
inline operator QString() const;
@ -154,7 +157,6 @@ public:
struct lstring : vector<string> {
inline optional<unsigned> find(rstring) const;
inline string merge(const string&) const;
inline string concatenate(const string&) const; //deprecated
inline lstring& isort();
inline lstring& strip();
inline void append() {}
@ -188,6 +190,7 @@ inline string notdir(string name);
inline string parentdir(string name);
inline string basename(string name);
inline string extension(string name);
inline string tempname();
//format.hpp
template<signed precision = 0, char padchar = ' '> inline string format(const string& value);

View File

@ -62,6 +62,7 @@ inline void utf8_write(char* s, const UTF8& utf8);
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 char* strduplicate(const char* s);
}

View File

@ -11,29 +11,40 @@ bool chrequal(char x, char y) {
template<bool Quoted, typename T>
bool quoteskip(T*& p) {
if(Quoted == false) return false;
if(*p != '\'' && *p != '\"') return false;
if(*p != '\"') return false;
while(*p == '\'' || *p == '\"') {
while(*p == '\"') {
char x = *p++;
while(*p && *p++ != x);
}
return true;
}
template<bool Quoted, typename T>
bool quotecopy(char*& t, T*& p) {
if(Quoted == false) return false;
if(*p != '\'' && *p != '\"') return false;
if(*p != '\"') return false;
while(*p == '\'' || *p == '\"') {
while(*p == '\"') {
char x = *p++;
*t++ = x;
while(*p && *p != x) *t++ = *p++;
*t++ = *p++;
}
return true;
}
//strdup() is not a standard function, so recreate it
char* strduplicate(const char* s) {
if(s == nullptr) return nullptr;
unsigned length = strlen(s);
char* result = (char*)malloc(length + 1);
strcpy(result, s);
return result;
}
}
#endif

View File

@ -75,10 +75,12 @@ bool string::operator> (const char* str) const { return strcmp(data(), str) > 0
bool string::operator>=(const char* str) const { return strcmp(data(), str) >= 0; }
string::string(const string& source) {
construct();
operator=(source);
}
string::string(string&& source) {
construct();
operator=(std::move(source));
}

View File

@ -19,7 +19,7 @@ inline string literalNumber(const char*& s) {
if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) {
unsigned prefix = 1 + (p[0] == '0');
p += prefix;
while(p[0] == '0' || p[0] == '1') p++;
while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++;
if(p - s <= prefix) throw "invalid binary literal";
string result = substr(s, 0, p - s);
s = p;
@ -30,7 +30,7 @@ inline string literalNumber(const char*& s) {
if(p[0] == '0' && p[1] == 'o') {
unsigned prefix = 1 + (p[0] == '0');
p += prefix;
while(p[0] >= '0' && p[0] <= '7') p++;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++;
if(p - s <= prefix) throw "invalid octal literal";
string result = substr(s, 0, p - s);
s = p;
@ -41,7 +41,7 @@ inline string literalNumber(const char*& s) {
if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) {
unsigned prefix = 1 + (p[0] == '0');
p += prefix;
while((p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++;
if(p - s <= prefix) throw "invalid hex literal";
string result = substr(s, 0, p - s);
s = p;
@ -49,7 +49,7 @@ inline string literalNumber(const char*& s) {
}
//decimal
while(p[0] >= '0' && p[0] <= '9') p++;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++;
if(p[0] != '.') {
string result = substr(s, 0, p - s);
s = p;
@ -58,7 +58,7 @@ inline string literalNumber(const char*& s) {
//floating-point
p++;
while(p[0] >= '0' && p[0] <= '9') p++;
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9')) p++;
string result = substr(s, 0, p - s);
s = p;
return result;

View File

@ -69,6 +69,16 @@ string extension(string name) {
return name;
}
string tempname() {
string path = temppath();
srand(time(nullptr));
while(true) {
uint32_t seed = rand();
string filename = {path, ".temporary-", hex<8>(seed)};
if(access(filename, F_OK) != 0) return filename;
}
}
}
#endif

View File

@ -18,11 +18,6 @@ string lstring::merge(const string& separator) const {
return output;
}
//deprecated: alias to merge()
string lstring::concatenate(const string& separator) const {
return merge(separator);
}
lstring& lstring::isort() {
nall::sort(pool, objectsize, [](const string& x, const string& y) {
return istrcmp(x, y) < 0;

View File

@ -115,7 +115,7 @@ struct Node {
if(path.size() == 0) result.append(node);
else {
auto list = node.find(path.concatenate("/"));
auto list = node.find(path.merge("/"));
for(auto& item : list) result.append(item);
}
}

View File

@ -3,33 +3,22 @@
namespace nall {
string activepath() {
string result;
#if defined(PLATFORM_WINDOWS)
wchar_t path[PATH_MAX] = L"";
auto unused = _wgetcwd(path, PATH_MAX);
result = (const char*)utf8_t(path);
result.transform("\\", "/");
#else
char path[PATH_MAX] = "";
auto unused = getcwd(path, PATH_MAX);
result = path;
#endif
string result = path;
if(result.empty()) result = ".";
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}
string realpath(const string& name) {
string result;
#if defined(PLATFORM_WINDOWS)
wchar_t path[PATH_MAX] = L"";
if(_wfullpath(path, utf16_t(name), PATH_MAX)) result = (const char*)utf8_t(path);
result.transform("\\", "/");
#else
char path[PATH_MAX] = "";
if(::realpath(name, path)) result = path;
#endif
if(result.empty()) result = {activepath(), name};
result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result;
}

View File

@ -26,7 +26,7 @@ string& string::ureplace(rstring key, rstring token) {
signed displacementSize = displacement * counter;
if(token.size() > key.size()) {
t = base = strdup(data());
t = base = strduplicate(data());
reserve((unsigned)(p - data()) + displacementSize);
}
char* o = data();

View File

@ -3,10 +3,53 @@
#include <nall/bit.hpp>
#include <nall/serializer.hpp>
#include <nall/stdint.hpp>
#include <nall/traits.hpp>
namespace nall {
struct varint {
virtual uint8_t read() = 0;
virtual void write(uint8_t) = 0;
uintmax_t readvu() {
uintmax_t data = 0, shift = 1;
while(true) {
uint8_t x = read();
data += (x & 0x7f) * shift;
if(x & 0x80) break;
shift <<= 7;
data += shift;
}
return data;
}
intmax_t readvs() {
uintmax_t data = readvu();
bool sign = data & 1;
data >>= 1;
if(sign) data = -data;
return data;
}
void writevu(uintmax_t data) {
while(true) {
uint8_t x = data & 0x7f;
data >>= 7;
if(data == 0) return write(0x80 | x);
write(x);
data--;
}
}
void writevs(intmax_t data) {
bool sign = data < 0;
if(sign) data = -data;
data = (data << 1) | sign;
writevu(data);
}
};
template<unsigned bits> struct uint_t {
private:
typedef typename type_if<bits <= 8 * sizeof(unsigned), unsigned, uintmax_t>::type type_t;

View File

@ -28,7 +28,7 @@ struct registry {
lstring part = name.split("/");
HKEY handle, rootKey = root(part.take(0));
string node = part.take();
string path = part.concatenate("\\");
string path = part.merge("\\");
if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) {
wchar_t data[NWR_SIZE] = L"";
DWORD size = NWR_SIZE * sizeof(wchar_t);
@ -43,7 +43,7 @@ struct registry {
lstring part = name.split("/");
HKEY handle, rootKey = root(part.take(0));
string node = part.take();
string path = part.concatenate("\\");
string path = part.merge("\\");
if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) {
wchar_t data[NWR_SIZE] = L"";
DWORD size = NWR_SIZE * sizeof(wchar_t);
@ -75,7 +75,7 @@ struct registry {
lstring part = name.split("/");
HKEY rootKey = root(part.take(0));
string node = part.take();
string path = part.concatenate("\\");
string path = part.merge("\\");
if(node.empty()) return SHDeleteKeyW(rootKey, utf16_t(path)) == ERROR_SUCCESS;
return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS;
}
@ -84,7 +84,7 @@ struct registry {
lstring part = name.split("/"), result;
HKEY handle, rootKey = root(part.take(0));
part.remove();
string path = part.concatenate("\\");
string path = part.merge("\\");
if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) {
DWORD folders, nodes;
RegQueryInfoKey(handle, nullptr, nullptr, nullptr, &folders, nullptr, nullptr, &nodes, nullptr, nullptr, nullptr, nullptr);

View File

@ -16,6 +16,10 @@
#include <windows.h>
#undef interface
#if !defined(PATH_MAX)
#define PATH_MAX 260
#endif
namespace nall {
//UTF-8 to UTF-16
struct utf16_t {
@ -74,7 +78,7 @@ namespace nall {
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
argv = new char*[argc];
for(unsigned i = 0; i < argc; i++) {
argv[i] = new char[_MAX_PATH];
argv[i] = new char[PATH_MAX];
strcpy(argv[i], nall::utf8_t(wargv[i]));
}
}

View File

@ -23,6 +23,7 @@
#include "widget/canvas.cpp"
#include "widget/check-button.cpp"
#include "widget/combo-button.cpp"
#include "widget/console.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroller.cpp"
#include "widget/horizontal-slider.cpp"

View File

@ -30,6 +30,7 @@ namespace phoenix {
#include "widget/canvas.hpp"
#include "widget/check-button.hpp"
#include "widget/combo-button.hpp"
#include "widget/console.hpp"
#include "widget/hex-edit.hpp"
#include "widget/horizontal-scroller.hpp"
#include "widget/horizontal-slider.hpp"

View File

@ -0,0 +1,32 @@
@implementation CocoaConsole : NSScrollView
-(id) initWith:(phoenix::Console&)consoleReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
console = &consoleReference;
}
return self;
}
@end
namespace phoenix {
void pConsole::print(string text) {
}
void pConsole::reset() {
}
void pConsole::constructor() {
@autoreleasepool {
cocoaView = cocoaConsole = [[CocoaConsole alloc] initWith:console];
}
}
void pConsole::destructor() {
@autoreleasepool {
[cocoaView release];
}
}
}

View File

@ -0,0 +1,22 @@
@interface CocoaConsole : NSScrollView {
@public
phoenix::Console* console;
}
-(id) initWith:(phoenix::Console&)console;
@end
namespace phoenix {
struct pConsole : public pWidget {
Console& console;
CocoaConsole* cocoaConsole = nullptr;
void print(string text);
void reset();
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
};
}

View File

@ -999,6 +999,30 @@ ComboButton::~ComboButton() {
delete &state;
}
//Console
//=======
void Console::print_(string text) {
return p.print(text);
}
void Console::reset() {
return p.reset();
}
Console::Console():
state(*new State),
base_from_member<pConsole&>(*new pConsole(*this)),
Widget(base_from_member<pConsole&>::value),
p(base_from_member<pConsole&>::value) {
p.constructor();
}
Console::~Console() {
p.destructor();
delete &state;
}
//HexEdit
//=======

View File

@ -38,6 +38,7 @@ struct pButton;
struct pCanvas;
struct pCheckButton;
struct pComboButton;
struct pConsole;
struct pHexEdit;
struct pHorizontalScroller;
struct pHorizontalSlider;
@ -469,6 +470,21 @@ struct ComboButton : private nall::base_from_member<pComboButton&>, Widget {
pComboButton& p;
};
struct Console : private nall::base_from_member<pConsole&>, Widget {
nall::function<void (nall::string)> onActivate;
template<typename... Args> void print(Args&&... args) { print_({args...}); }
void print_(nall::string text);
void reset();
Console();
~Console();
struct State;
State& state;
pConsole& p;
};
struct HexEdit : private nall::base_from_member<pHexEdit&>, Widget {
nall::function<uint8_t (unsigned)> onRead;
nall::function<void (unsigned, uint8_t)> onWrite;

View File

@ -111,6 +111,9 @@ struct ComboButton::State {
vector<string> text;
};
struct Console::State {
};
struct HexEdit::State {
unsigned columns = 16;
unsigned length = 0;

View File

@ -39,7 +39,7 @@ void pApplication::initialize() {
gtk_init(&argc, &argvp);
GtkSettings* gtkSettings = gtk_settings_get_default();
g_object_set(gtkSettings, "gtk-button-images", true, nullptr);
//g_object_set(gtkSettings, "gtk-button-images", true, nullptr);
gtk_rc_parse_string(R"(
style "phoenix-gtk"

View File

@ -24,6 +24,7 @@
#include "widget/canvas.cpp"
#include "widget/check-button.cpp"
#include "widget/combo-button.cpp"
#include "widget/console.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroller.cpp"
#include "widget/horizontal-slider.cpp"

View File

@ -314,6 +314,23 @@ struct pComboButton : public pWidget {
void orphan();
};
struct pConsole : public pWidget {
Console& console;
GtkWidget* subWidget;
GtkTextBuffer* textBuffer;
string command;
void print(string text);
void reset();
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
void orphan();
bool keyPress(unsigned scancode, unsigned mask);
void seekCursorToEnd();
};
struct pHexEdit : public pWidget {
HexEdit& hexEdit;
GtkWidget* container;
@ -334,8 +351,10 @@ struct pHexEdit : public pWidget {
void destructor();
void orphan();
unsigned cursorPosition();
bool keyPress(unsigned scancode);
void scroll(unsigned position);
bool keyPress(unsigned scancode, unsigned mask);
signed rows();
signed rowsScrollable();
void scroll(signed position);
void setCursorPosition(unsigned position);
void setScroll();
void updateScroll();

View File

@ -1,5 +1,14 @@
namespace phoenix {
static GdkColor CreateColor(uint8_t r, uint8_t g, uint8_t b) {
GdkColor color;
color.pixel = (r << 16) | (g << 8) | (b << 0);
color.red = (r << 8) | (r << 0);
color.green = (g << 8) | (g << 0);
color.blue = (b << 8) | (b << 0);
return color;
}
static GdkPixbuf* CreatePixbuf(const nall::image& image, bool scale = false) {
nall::image gdkImage = image;
gdkImage.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16);

View File

@ -0,0 +1,88 @@
namespace phoenix {
static bool Console_keyPress(GtkWidget* widget, GdkEventKey* event, Console* self) {
return self->p.keyPress(event->keyval, event->state);
}
void pConsole::print(string text) {
seekCursorToEnd();
gtk_text_buffer_insert_at_cursor(textBuffer, text, -1);
GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert");
gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark);
}
void pConsole::reset() {
gtk_text_buffer_set_text(textBuffer, "", -1);
}
void pConsole::constructor() {
gtkWidget = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN);
subWidget = gtk_text_view_new();
gtk_text_view_set_editable(GTK_TEXT_VIEW(subWidget), false);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE);
gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget);
textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget));
GdkColor background = CreateColor(48, 24, 24);
gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, &background);
GdkColor foreground = CreateColor(255, 255, 255);
gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, &foreground);
g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(Console_keyPress), (gpointer)&console);
gtk_widget_show(subWidget);
}
void pConsole::destructor() {
gtk_widget_destroy(subWidget);
gtk_widget_destroy(gtkWidget);
}
void pConsole::orphan() {
destructor();
constructor();
}
bool pConsole::keyPress(unsigned scancode, unsigned mask) {
if(mask & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK)) return false; //allow actions such as Ctrl+C (copy)
if(scancode == GDK_KEY_Return || scancode == GDK_KEY_KP_Enter) {
print("\n");
if(console.onActivate) console.onActivate(command);
command.reset();
return true;
}
if(scancode == GDK_KEY_BackSpace) {
if(command.size()) {
command.resize(command.size() - 1);
GtkTextIter lhs, rhs;
gtk_text_buffer_get_end_iter(textBuffer, &lhs);
gtk_text_buffer_get_end_iter(textBuffer, &rhs);
gtk_text_iter_set_offset(&lhs, gtk_text_iter_get_offset(&lhs) - 1);
gtk_text_buffer_delete(textBuffer, &lhs, &rhs);
seekCursorToEnd();
}
return true;
}
if(scancode >= 0x20 && scancode <= 0x7e) {
print({(char)scancode});
command.append((char)scancode);
return true;
}
return false;
}
void pConsole::seekCursorToEnd() {
GtkTextIter iter;
gtk_text_buffer_get_end_iter(textBuffer, &iter);
gtk_text_buffer_place_cursor(textBuffer, &iter);
}
}

View File

@ -1,16 +1,30 @@
namespace phoenix {
static bool HexEdit_keyPress(GtkWidget* widget, GdkEventKey* event, HexEdit* self) {
return self->p.keyPress(event->keyval);
return self->p.keyPress(event->keyval, event->state);
}
static bool HexEdit_scroll(GtkRange* range, GtkScrollType scroll, gdouble value, HexEdit* self) {
self->p.scroll((unsigned)value);
return false;
static bool HexEdit_mouseScroll(GtkWidget* widget, GdkEventScroll* event, HexEdit* self) {
double position = gtk_range_get_value(GTK_RANGE(self->p.scrollBar));
if(event->direction == GDK_SCROLL_UP) {
self->p.scroll(position - 1);
}
if(event->direction == GDK_SCROLL_DOWN) {
self->p.scroll(position + 1);
}
return true; //do not propagate event further
}
static bool HexEdit_scroll(GtkRange* range, GtkScrollType scroll, double value, HexEdit* self) {
self->p.scroll((signed)value);
return true; //do not propagate event further
}
bool pHexEdit::focused() {
return GTK_WIDGET_HAS_FOCUS(subWidget);
return GTK_WIDGET_HAS_FOCUS(subWidget) || GTK_WIDGET_HAS_FOCUS(scrollBar);
}
void pHexEdit::setColumns(unsigned columns) {
@ -55,8 +69,7 @@ void pHexEdit::update() {
uint8_t data = hexEdit.onRead(offset++);
hexdata.append(hex<2>(data));
hexdata.append(" ");
char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 };
ansidata.append(buffer);
ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
} else {
hexdata.append(" ");
ansidata.append(" ");
@ -78,7 +91,7 @@ void pHexEdit::constructor() {
gtkWidget = gtk_hbox_new(false, 0);
container = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(container), GTK_SHADOW_ETCHED_IN);
subWidget = gtk_text_view_new();
@ -86,12 +99,14 @@ void pHexEdit::constructor() {
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_NONE);
gtk_container_add(GTK_CONTAINER(container), subWidget);
g_signal_connect(G_OBJECT(subWidget), "key-press-event", G_CALLBACK(HexEdit_keyPress), (gpointer)&hexEdit);
g_signal_connect(G_OBJECT(subWidget), "scroll-event", G_CALLBACK(HexEdit_mouseScroll), (gpointer)&hexEdit);
scrollBar = gtk_vscrollbar_new((GtkAdjustment*)0);
scrollBar = gtk_vscrollbar_new((GtkAdjustment*)nullptr);
gtk_range_set_range(GTK_RANGE(scrollBar), 0, 255);
gtk_range_set_increments(GTK_RANGE(scrollBar), 1, 16);
gtk_widget_set_sensitive(scrollBar, false);
g_signal_connect(G_OBJECT(scrollBar), "change-value", G_CALLBACK(HexEdit_scroll), (gpointer)&hexEdit);
g_signal_connect(G_OBJECT(scrollBar), "scroll-event", G_CALLBACK(HexEdit_mouseScroll), (gpointer)&hexEdit);
gtk_box_pack_start(GTK_BOX(gtkWidget), container, true, true, 0);
gtk_box_pack_start(GTK_BOX(gtkWidget), scrollBar, false, false, 1);
@ -128,13 +143,15 @@ unsigned pHexEdit::cursorPosition() {
return gtk_text_iter_get_offset(&iter);
}
bool pHexEdit::keyPress(unsigned scancode) {
bool pHexEdit::keyPress(unsigned scancode, unsigned mask) {
if(!hexEdit.onRead) return false;
unsigned position = cursorPosition();
unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1;
unsigned cursorY = position / lineWidth;
unsigned cursorX = position % lineWidth;
if(mask & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK)) return false; //allow actions such as Ctrl+C (copy)
signed position = cursorPosition();
signed lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1;
signed cursorY = position / lineWidth;
signed cursorX = position % lineWidth;
if(scancode == GDK_Home) {
setCursorPosition(cursorY * lineWidth + 10);
@ -158,6 +175,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
}
if(scancode == GDK_Down) {
if(cursorY >= rows() - 1) return true;
if(cursorY != hexEdit.state.rows - 1) return false;
signed newOffset = hexEdit.state.offset + hexEdit.state.columns;
@ -234,9 +252,19 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
void pHexEdit::scroll(unsigned position) {
unsigned rows = hexEdit.state.length / hexEdit.state.columns;
if(position >= rows) position = rows - 1;
//number of actual rows
signed pHexEdit::rows() {
return (max(1u, hexEdit.state.length) + hexEdit.state.columns - 1) / hexEdit.state.columns;
}
//number of scrollable row positions
signed pHexEdit::rowsScrollable() {
return max(0u, rows() - hexEdit.state.rows);
}
void pHexEdit::scroll(signed position) {
if(position > rowsScrollable()) position = rowsScrollable();
if(position < 0) position = 0;
hexEdit.setOffset(position * hexEdit.state.columns);
}
@ -254,10 +282,8 @@ void pHexEdit::setCursorPosition(unsigned position) {
}
void pHexEdit::setScroll() {
unsigned rows = hexEdit.state.length / hexEdit.state.columns;
if(rows) rows--;
if(rows) {
gtk_range_set_range(GTK_RANGE(scrollBar), 0, rows);
if(rowsScrollable() > 0) {
gtk_range_set_range(GTK_RANGE(scrollBar), 0, rowsScrollable());
gtk_widget_set_sensitive(scrollBar, true);
} else {
gtk_widget_set_sensitive(scrollBar, false);

View File

@ -49,11 +49,15 @@ void pTextEdit::constructor() {
gtkWidget = gtk_scrolled_window_new(0, 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkWidget), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkWidget), GTK_SHADOW_ETCHED_IN);
subWidget = gtk_text_view_new();
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(subWidget), GTK_WRAP_WORD_CHAR);
gtk_container_add(GTK_CONTAINER(gtkWidget), subWidget);
textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget));
g_signal_connect_swapped(G_OBJECT(textBuffer), "changed", G_CALLBACK(TextEdit_change), (gpointer)&textEdit);
gtk_widget_show(subWidget);
setEditable(textEdit.state.editable);

View File

@ -212,11 +212,7 @@ void pWindow::remove(Widget& widget) {
}
void pWindow::setBackgroundColor(Color color) {
GdkColor gdkColor;
gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0);
gdkColor.red = (color.red << 8) | (color.red << 0);
gdkColor.green = (color.green << 8) | (color.green << 0);
gdkColor.blue = (color.blue << 8) | (color.blue << 0);
GdkColor gdkColor = CreateColor(color.red, color.green, color.blue);
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor);
}
@ -327,10 +323,15 @@ void pWindow::constructor() {
//if program was given a name, try and set the window taskbar icon from one of the pixmaps folders
if(applicationState.name.empty() == false) {
if(file::exists({"/usr/share/pixmaps/", applicationState.name, ".png"})) {
gtk_window_set_icon_from_file(GTK_WINDOW(widget), string{"/usr/share/pixmaps/", applicationState.name, ".png"}, nullptr);
} else if(file::exists({"/usr/local/share/pixmaps/", applicationState.name, ".png"})) {
gtk_window_set_icon_from_file(GTK_WINDOW(widget), string{"/usr/local/share/pixmaps/", applicationState.name, ".png"}, nullptr);
string filename = {"/usr/share/pixmaps/", applicationState.name, ".png"};
if(!file::exists(filename)) filename = {"/usr/local/share/pixmaps/", applicationState.name, ".png"};
if(file::exists(filename)) {
//maximum image size supported by GTK+ is 256x256; so we must scale larger images ourselves
nall::image icon(filename);
icon.scale(min(256u, icon.width), min(256u, icon.height), Interpolation::Hermite);
GdkPixbuf* pixbuf = CreatePixbuf(icon);
gtk_window_set_icon(GTK_WINDOW(widget), pixbuf);
g_object_unref(G_OBJECT(pixbuf));
}
}

View File

@ -12,7 +12,7 @@ string pBrowserWindow::directory(BrowserWindow::State& state) {
}
string pBrowserWindow::open(BrowserWindow::State& state) {
string filters = state.filters.concatenate(";;");
string filters = state.filters.merge(";;");
//convert filter list from phoenix to Qt format, example:
//"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)"
@ -32,7 +32,7 @@ string pBrowserWindow::open(BrowserWindow::State& state) {
}
string pBrowserWindow::save(BrowserWindow::State& state) {
string filters = state.filters.concatenate(";;");
string filters = state.filters.merge(";;");
//convert filter list from phoenix to Qt format, example:
//"Text, XML files (*.txt,*.xml)" -> "Text, XML files (*.txt *.xml)"

View File

@ -25,6 +25,7 @@
#include "widget/canvas.cpp"
#include "widget/check-button.cpp"
#include "widget/combo-button.cpp"
#include "widget/console.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroller.cpp"
#include "widget/horizontal-slider.cpp"

View File

@ -1,16 +1,16 @@
/****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp'
**
** Created: Wed Jul 17 05:52:48 2013
** by: The Qt Meta Object Compiler version 62 (Qt 4.6.3)
** Created: Tue Nov 5 18:38:24 2013
** by: The Qt Meta Object Compiler version 63 (Qt 4.8.2)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'platform.moc.hpp' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 62
#error "This file was generated using the moc from 4.6.3. It"
#elif Q_MOC_OUTPUT_REVISION != 63
#error "This file was generated using the moc from 4.8.2. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
@ -19,7 +19,7 @@ QT_BEGIN_MOC_NAMESPACE
static const uint qt_meta_data_phoenix__pTimer[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -39,9 +39,26 @@ static const char qt_meta_stringdata_phoenix__pTimer[] = {
"phoenix::pTimer\0\0onActivate()\0"
};
void phoenix::pTimer::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pTimer *_t = static_cast<pTimer *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pTimer::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pTimer::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pTimer,
qt_meta_data_phoenix__pTimer, 0 }
qt_meta_data_phoenix__pTimer, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -69,10 +86,8 @@ int phoenix::pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -80,7 +95,7 @@ int phoenix::pTimer::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pWindow[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@ -97,9 +112,21 @@ static const char qt_meta_stringdata_phoenix__pWindow[] = {
"phoenix::pWindow\0"
};
void phoenix::pWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pWindow::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pWindow::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pWindow,
qt_meta_data_phoenix__pWindow, 0 }
qt_meta_data_phoenix__pWindow, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -131,7 +158,7 @@ int phoenix::pWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pItem[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -151,9 +178,26 @@ static const char qt_meta_stringdata_phoenix__pItem[] = {
"phoenix::pItem\0\0onActivate()\0"
};
void phoenix::pItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pItem *_t = static_cast<pItem *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pItem::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pItem::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pItem,
qt_meta_data_phoenix__pItem, 0 }
qt_meta_data_phoenix__pItem, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -181,10 +225,8 @@ int phoenix::pItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -192,7 +234,7 @@ int phoenix::pItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pCheckItem[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -212,9 +254,26 @@ static const char qt_meta_stringdata_phoenix__pCheckItem[] = {
"phoenix::pCheckItem\0\0onToggle()\0"
};
void phoenix::pCheckItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pCheckItem *_t = static_cast<pCheckItem *>(_o);
switch (_id) {
case 0: _t->onToggle(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pCheckItem::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pCheckItem::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pCheckItem,
qt_meta_data_phoenix__pCheckItem, 0 }
qt_meta_data_phoenix__pCheckItem, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -242,10 +301,8 @@ int phoenix::pCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onToggle(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -253,7 +310,7 @@ int phoenix::pCheckItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pRadioItem[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -273,9 +330,26 @@ static const char qt_meta_stringdata_phoenix__pRadioItem[] = {
"phoenix::pRadioItem\0\0onActivate()\0"
};
void phoenix::pRadioItem::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pRadioItem *_t = static_cast<pRadioItem *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pRadioItem::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pRadioItem::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pRadioItem,
qt_meta_data_phoenix__pRadioItem, 0 }
qt_meta_data_phoenix__pRadioItem, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -303,10 +377,8 @@ int phoenix::pRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -314,7 +386,7 @@ int phoenix::pRadioItem::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pButton[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -334,9 +406,26 @@ static const char qt_meta_stringdata_phoenix__pButton[] = {
"phoenix::pButton\0\0onActivate()\0"
};
void phoenix::pButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pButton *_t = static_cast<pButton *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pButton::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pButton::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pButton,
qt_meta_data_phoenix__pButton, 0 }
qt_meta_data_phoenix__pButton, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -364,10 +453,8 @@ int phoenix::pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -375,7 +462,7 @@ int phoenix::pButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pCanvas[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
@ -392,9 +479,21 @@ static const char qt_meta_stringdata_phoenix__pCanvas[] = {
"phoenix::pCanvas\0"
};
void phoenix::pCanvas::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pCanvas::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pCanvas::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pCanvas,
qt_meta_data_phoenix__pCanvas, 0 }
qt_meta_data_phoenix__pCanvas, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -426,7 +525,7 @@ int phoenix::pCanvas::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pCheckButton[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -446,9 +545,26 @@ static const char qt_meta_stringdata_phoenix__pCheckButton[] = {
"phoenix::pCheckButton\0\0onToggle()\0"
};
void phoenix::pCheckButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pCheckButton *_t = static_cast<pCheckButton *>(_o);
switch (_id) {
case 0: _t->onToggle(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pCheckButton::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pCheckButton::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pCheckButton,
qt_meta_data_phoenix__pCheckButton, 0 }
qt_meta_data_phoenix__pCheckButton, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -476,10 +592,8 @@ int phoenix::pCheckButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onToggle(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -487,7 +601,7 @@ int phoenix::pCheckButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pComboButton[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -507,9 +621,26 @@ static const char qt_meta_stringdata_phoenix__pComboButton[] = {
"phoenix::pComboButton\0\0onChange()\0"
};
void phoenix::pComboButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pComboButton *_t = static_cast<pComboButton *>(_o);
switch (_id) {
case 0: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pComboButton::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pComboButton::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pComboButton,
qt_meta_data_phoenix__pComboButton, 0 }
qt_meta_data_phoenix__pComboButton, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -537,18 +668,79 @@ int phoenix::pComboButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
}
static const uint qt_meta_data_phoenix__pConsole[] = {
// content:
6, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
static const char qt_meta_stringdata_phoenix__pConsole[] = {
"phoenix::pConsole\0"
};
void phoenix::pConsole::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pConsole::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pConsole::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pConsole,
qt_meta_data_phoenix__pConsole, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
const QMetaObject &phoenix::pConsole::getStaticMetaObject() { return staticMetaObject; }
#endif //Q_NO_DATA_RELOCATION
const QMetaObject *phoenix::pConsole::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
}
void *phoenix::pConsole::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_phoenix__pConsole))
return static_cast<void*>(const_cast< pConsole*>(this));
if (!strcmp(_clname, "pWidget"))
return static_cast< pWidget*>(const_cast< pConsole*>(this));
return QObject::qt_metacast(_clname);
}
int phoenix::pConsole::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
static const uint qt_meta_data_phoenix__pHexEdit[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -568,9 +760,26 @@ static const char qt_meta_stringdata_phoenix__pHexEdit[] = {
"phoenix::pHexEdit\0\0onScroll()\0"
};
void phoenix::pHexEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pHexEdit *_t = static_cast<pHexEdit *>(_o);
switch (_id) {
case 0: _t->onScroll(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pHexEdit::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pHexEdit::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pHexEdit,
qt_meta_data_phoenix__pHexEdit, 0 }
qt_meta_data_phoenix__pHexEdit, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -598,10 +807,8 @@ int phoenix::pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onScroll(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -609,7 +816,7 @@ int phoenix::pHexEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pHorizontalScroller[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -629,9 +836,26 @@ static const char qt_meta_stringdata_phoenix__pHorizontalScroller[] = {
"phoenix::pHorizontalScroller\0\0onChange()\0"
};
void phoenix::pHorizontalScroller::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pHorizontalScroller *_t = static_cast<pHorizontalScroller *>(_o);
switch (_id) {
case 0: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pHorizontalScroller::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pHorizontalScroller::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pHorizontalScroller,
qt_meta_data_phoenix__pHorizontalScroller, 0 }
qt_meta_data_phoenix__pHorizontalScroller, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -659,10 +883,8 @@ int phoenix::pHorizontalScroller::qt_metacall(QMetaObject::Call _c, int _id, voi
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -670,7 +892,7 @@ int phoenix::pHorizontalScroller::qt_metacall(QMetaObject::Call _c, int _id, voi
static const uint qt_meta_data_phoenix__pHorizontalSlider[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -690,9 +912,26 @@ static const char qt_meta_stringdata_phoenix__pHorizontalSlider[] = {
"phoenix::pHorizontalSlider\0\0onChange()\0"
};
void phoenix::pHorizontalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pHorizontalSlider *_t = static_cast<pHorizontalSlider *>(_o);
switch (_id) {
case 0: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pHorizontalSlider::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pHorizontalSlider::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pHorizontalSlider,
qt_meta_data_phoenix__pHorizontalSlider, 0 }
qt_meta_data_phoenix__pHorizontalSlider, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -720,10 +959,8 @@ int phoenix::pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -731,7 +968,7 @@ int phoenix::pHorizontalSlider::qt_metacall(QMetaObject::Call _c, int _id, void
static const uint qt_meta_data_phoenix__pLineEdit[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
2, 14, // methods
@ -753,9 +990,27 @@ static const char qt_meta_stringdata_phoenix__pLineEdit[] = {
"onChange()\0"
};
void phoenix::pLineEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pLineEdit *_t = static_cast<pLineEdit *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
case 1: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pLineEdit::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pLineEdit::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pLineEdit,
qt_meta_data_phoenix__pLineEdit, 0 }
qt_meta_data_phoenix__pLineEdit, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -783,11 +1038,8 @@ int phoenix::pLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
case 1: onChange(); break;
default: ;
}
if (_id < 2)
qt_static_metacall(this, _c, _id, _a);
_id -= 2;
}
return _id;
@ -795,7 +1047,7 @@ int phoenix::pLineEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pListView[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
3, 14, // methods
@ -819,9 +1071,27 @@ static const char qt_meta_stringdata_phoenix__pListView[] = {
"onToggle(QTreeWidgetItem*)\0"
};
void phoenix::pListView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pListView *_t = static_cast<pListView *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
case 1: _t->onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
case 2: _t->onToggle((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
default: ;
}
}
}
const QMetaObjectExtraData phoenix::pListView::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pListView::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pListView,
qt_meta_data_phoenix__pListView, 0 }
qt_meta_data_phoenix__pListView, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -849,12 +1119,8 @@ int phoenix::pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
case 1: onChange((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
case 2: onToggle((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1]))); break;
default: ;
}
if (_id < 3)
qt_static_metacall(this, _c, _id, _a);
_id -= 3;
}
return _id;
@ -862,7 +1128,7 @@ int phoenix::pListView::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pRadioButton[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -882,9 +1148,26 @@ static const char qt_meta_stringdata_phoenix__pRadioButton[] = {
"phoenix::pRadioButton\0\0onActivate()\0"
};
void phoenix::pRadioButton::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pRadioButton *_t = static_cast<pRadioButton *>(_o);
switch (_id) {
case 0: _t->onActivate(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pRadioButton::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pRadioButton::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pRadioButton,
qt_meta_data_phoenix__pRadioButton, 0 }
qt_meta_data_phoenix__pRadioButton, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -912,10 +1195,8 @@ int phoenix::pRadioButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onActivate(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -923,7 +1204,7 @@ int phoenix::pRadioButton::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pTextEdit[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -943,9 +1224,26 @@ static const char qt_meta_stringdata_phoenix__pTextEdit[] = {
"phoenix::pTextEdit\0\0onChange()\0"
};
void phoenix::pTextEdit::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pTextEdit *_t = static_cast<pTextEdit *>(_o);
switch (_id) {
case 0: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pTextEdit::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pTextEdit::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pTextEdit,
qt_meta_data_phoenix__pTextEdit, 0 }
qt_meta_data_phoenix__pTextEdit, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -973,10 +1271,8 @@ int phoenix::pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -984,7 +1280,7 @@ int phoenix::pTextEdit::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
static const uint qt_meta_data_phoenix__pVerticalScroller[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -1004,9 +1300,26 @@ static const char qt_meta_stringdata_phoenix__pVerticalScroller[] = {
"phoenix::pVerticalScroller\0\0onChange()\0"
};
void phoenix::pVerticalScroller::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pVerticalScroller *_t = static_cast<pVerticalScroller *>(_o);
switch (_id) {
case 0: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pVerticalScroller::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pVerticalScroller::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pVerticalScroller,
qt_meta_data_phoenix__pVerticalScroller, 0 }
qt_meta_data_phoenix__pVerticalScroller, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -1034,10 +1347,8 @@ int phoenix::pVerticalScroller::qt_metacall(QMetaObject::Call _c, int _id, void
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;
@ -1045,7 +1356,7 @@ int phoenix::pVerticalScroller::qt_metacall(QMetaObject::Call _c, int _id, void
static const uint qt_meta_data_phoenix__pVerticalSlider[] = {
// content:
4, // revision
6, // revision
0, // classname
0, 0, // classinfo
1, 14, // methods
@ -1065,9 +1376,26 @@ static const char qt_meta_stringdata_phoenix__pVerticalSlider[] = {
"phoenix::pVerticalSlider\0\0onChange()\0"
};
void phoenix::pVerticalSlider::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Q_ASSERT(staticMetaObject.cast(_o));
pVerticalSlider *_t = static_cast<pVerticalSlider *>(_o);
switch (_id) {
case 0: _t->onChange(); break;
default: ;
}
}
Q_UNUSED(_a);
}
const QMetaObjectExtraData phoenix::pVerticalSlider::staticMetaObjectExtraData = {
0, qt_static_metacall
};
const QMetaObject phoenix::pVerticalSlider::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_phoenix__pVerticalSlider,
qt_meta_data_phoenix__pVerticalSlider, 0 }
qt_meta_data_phoenix__pVerticalSlider, &staticMetaObjectExtraData }
};
#ifdef Q_NO_DATA_RELOCATION
@ -1095,10 +1423,8 @@ int phoenix::pVerticalSlider::qt_metacall(QMetaObject::Call _c, int _id, void **
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: onChange(); break;
default: ;
}
if (_id < 1)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
}
return _id;

View File

@ -388,6 +388,29 @@ public slots:
void onChange();
};
struct pConsole : public QObject, public pWidget {
Q_OBJECT
public:
Console& console;
struct QtConsole : public QTextEdit {
pConsole& self;
void keyPressEvent(QKeyEvent*);
void keyPressEventAcknowledge(QKeyEvent*);
QtConsole(pConsole& self) : self(self) {}
};
QtConsole* qtConsole;
void print(string text);
void reset();
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
void orphan();
void keyPressEvent(QKeyEvent*);
};
struct pHexEdit : public QObject, public pWidget {
Q_OBJECT
@ -397,11 +420,17 @@ public:
pHexEdit& self;
void keyPressEvent(QKeyEvent*);
void keyPressEventAcknowledge(QKeyEvent*);
void wheelEvent(QWheelEvent*);
QtHexEdit(pHexEdit& self) : self(self) {}
};
struct QtHexEditScrollBar : public QScrollBar {
pHexEdit& self;
bool event(QEvent*);
QtHexEditScrollBar(pHexEdit& self) : QScrollBar(Qt::Vertical), self(self) {}
};
QtHexEdit* qtHexEdit;
QHBoxLayout* qtLayout;
QScrollBar* qtScroll;
QtHexEditScrollBar* qtScroll;
void setColumns(unsigned columns);
void setLength(unsigned length);
@ -414,6 +443,9 @@ public:
void destructor();
void orphan();
void keyPressEvent(QKeyEvent*);
signed rows();
signed rowsScrollable();
void scrollTo(signed position);
public slots:
void onScroll();

View File

@ -0,0 +1,36 @@
namespace phoenix {
void pConsole::print(string text) {
}
void pConsole::reset() {
}
void pConsole::constructor() {
qtWidget = qtConsole = new QtConsole(*this);
pWidget::synchronizeState();
}
void pConsole::destructor() {
delete qtConsole;
qtWidget = qtConsole = nullptr;
}
void pConsole::orphan() {
destructor();
constructor();
}
void pConsole::keyPressEvent(QKeyEvent* event) {
}
void pConsole::QtConsole::keyPressEvent(QKeyEvent* event) {
self.keyPressEvent(event);
}
void pConsole::QtConsole::keyPressEventAcknowledge(QKeyEvent* event) {
QTextEdit::keyPressEvent(event);
}
}

View File

@ -45,8 +45,7 @@ void pHexEdit::update() {
uint8_t data = hexEdit.onRead(offset++);
hexdata.append(hex<2>(data));
hexdata.append(" ");
char buffer[2] = { data >= 0x20 && data <= 0x7e ? (char)data : '.', 0 };
ansidata.append(buffer);
ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
} else {
hexdata.append(" ");
ansidata.append(" ");
@ -70,6 +69,7 @@ void pHexEdit::constructor() {
qtHexEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
qtHexEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
qtHexEdit->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
qtLayout = new QHBoxLayout;
qtLayout->setAlignment(Qt::AlignRight);
@ -77,7 +77,7 @@ void pHexEdit::constructor() {
qtLayout->setSpacing(0);
qtHexEdit->setLayout(qtLayout);
qtScroll = new QScrollBar(Qt::Vertical);
qtScroll = new QtHexEditScrollBar(*this);
qtScroll->setSingleStep(1);
qtLayout->addWidget(qtScroll);
@ -108,38 +108,92 @@ void pHexEdit::orphan() {
void pHexEdit::keyPressEvent(QKeyEvent* event) {
if(!hexEdit.onRead) return;
QTextCursor cursor = qtHexEdit->textCursor();
unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1;
unsigned cursorY = cursor.position() / lineWidth;
unsigned cursorX = cursor.position() % lineWidth;
//allow Ctrl+C (copy)
if(event->key() == Qt::Key_C && event->modifiers() == Qt::ControlModifier) {
qtHexEdit->keyPressEventAcknowledge(event);
return;
}
unsigned nibble;
//disallow other text operations (cut, paste, etc)
if(event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)) return;
QTextCursor cursor = qtHexEdit->textCursor();
signed lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 1;
signed cursorY = cursor.position() / lineWidth;
signed cursorX = cursor.position() % lineWidth;
unsigned nibble = 0;
switch(event->key()) {
case Qt::Key_0: nibble = 0; break;
case Qt::Key_1: nibble = 1; break;
case Qt::Key_2: nibble = 2; break;
case Qt::Key_3: nibble = 3; break;
case Qt::Key_4: nibble = 4; break;
case Qt::Key_5: nibble = 5; break;
case Qt::Key_6: nibble = 6; break;
case Qt::Key_7: nibble = 7; break;
case Qt::Key_8: nibble = 8; break;
case Qt::Key_9: nibble = 9; break;
case Qt::Key_A: nibble = 10; break;
case Qt::Key_B: nibble = 11; break;
case Qt::Key_C: nibble = 12; break;
case Qt::Key_D: nibble = 13; break;
case Qt::Key_E: nibble = 14; break;
case Qt::Key_F: nibble = 15; break;
default: {
//allow navigation keys to move cursor, but block text input
qtHexEdit->setTextInteractionFlags(Qt::TextInteractionFlags(
Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse
));
qtHexEdit->keyPressEventAcknowledge(event);
qtHexEdit->setTextInteractionFlags(Qt::TextEditorInteraction);
return;
default: return;
case Qt::Key_Left:
if(cursorX > 0) {
cursor.setPosition(cursor.position() - 1);
qtHexEdit->setTextCursor(cursor);
}
return;
case Qt::Key_Right:
if(cursorX < lineWidth - 1) {
cursor.setPosition(cursor.position() + 1);
qtHexEdit->setTextCursor(cursor);
}
return;
case Qt::Key_Home:
cursor.setPosition(cursorY * lineWidth + 10);
qtHexEdit->setTextCursor(cursor);
return;
case Qt::Key_End:
cursor.setPosition(cursorY * lineWidth + 57);
qtHexEdit->setTextCursor(cursor);
return;
case Qt::Key_Up:
if(cursorY > 0) {
cursor.setPosition(cursor.position() - lineWidth);
qtHexEdit->setTextCursor(cursor);
} else {
scrollTo(qtScroll->sliderPosition() - 1);
}
return;
case Qt::Key_Down:
if(cursorY >= rows() - 1) {
//cannot scroll down further
} else if(cursorY < hexEdit.state.rows - 1) {
cursor.setPosition(cursor.position() + lineWidth);
qtHexEdit->setTextCursor(cursor);
} else {
scrollTo(qtScroll->sliderPosition() + 1);
}
return;
case Qt::Key_PageUp:
scrollTo(qtScroll->sliderPosition() - hexEdit.state.rows);
return;
case Qt::Key_PageDown:
scrollTo(qtScroll->sliderPosition() + hexEdit.state.rows);
return;
case Qt::Key_0: nibble = 0; break;
case Qt::Key_1: nibble = 1; break;
case Qt::Key_2: nibble = 2; break;
case Qt::Key_3: nibble = 3; break;
case Qt::Key_4: nibble = 4; break;
case Qt::Key_5: nibble = 5; break;
case Qt::Key_6: nibble = 6; break;
case Qt::Key_7: nibble = 7; break;
case Qt::Key_8: nibble = 8; break;
case Qt::Key_9: nibble = 9; break;
case Qt::Key_A: nibble = 10; break;
case Qt::Key_B: nibble = 11; break;
case Qt::Key_C: nibble = 12; break;
case Qt::Key_D: nibble = 13; break;
case Qt::Key_E: nibble = 14; break;
case Qt::Key_F: nibble = 15; break;
}
if(cursorX >= 10) {
@ -177,6 +231,22 @@ void pHexEdit::keyPressEvent(QKeyEvent* event) {
}
}
//number of actual rows
signed pHexEdit::rows() {
return (max(1u, hexEdit.state.length) + hexEdit.state.columns - 1) / hexEdit.state.columns;
}
//number of scrollable row positions
signed pHexEdit::rowsScrollable() {
return max(0u, rows() - hexEdit.state.rows);
}
void pHexEdit::scrollTo(signed position) {
if(position > rowsScrollable()) position = rowsScrollable();
if(position < 0) position = 0;
qtScroll->setSliderPosition(position);
}
void pHexEdit::onScroll() {
if(locked) return;
unsigned offset = qtScroll->sliderPosition();
@ -192,4 +262,24 @@ void pHexEdit::QtHexEdit::keyPressEventAcknowledge(QKeyEvent* event) {
QTextEdit::keyPressEvent(event);
}
void pHexEdit::QtHexEdit::wheelEvent(QWheelEvent* event) {
if(event->orientation() == Qt::Vertical) {
signed offset = event->delta() < 0 ? +1 : -1;
self.scrollTo(self.qtScroll->sliderPosition() + offset);
event->accept();
}
}
bool pHexEdit::QtHexEditScrollBar::event(QEvent* event) {
if(event->type() == QEvent::Wheel) {
QWheelEvent* wheelEvent = (QWheelEvent*)event;
if(wheelEvent->orientation() == Qt::Vertical) {
signed offset = wheelEvent->delta() < 0 ? +1 : -1;
self.scrollTo(sliderPosition() + offset);
return true;
}
}
return QScrollBar::event(event);
}
}

View File

@ -8,7 +8,7 @@ void pTextEdit::setCursorPosition(unsigned position) {
}
void pTextEdit::setEditable(bool editable) {
qtTextEdit->setReadOnly(!editable);
qtTextEdit->setTextInteractionFlags(editable ? Qt::TextEditorInteraction : Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
}
void pTextEdit::setText(string text) {
@ -36,7 +36,6 @@ void pTextEdit::constructor() {
}
void pTextEdit::destructor() {
if(sizable.state.layout) sizable.state.layout->remove(textEdit);
delete qtTextEdit;
qtWidget = qtTextEdit = nullptr;
}

View File

@ -22,6 +22,7 @@
#include "widget/canvas.cpp"
#include "widget/check-button.cpp"
#include "widget/combo-button.cpp"
#include "widget/console.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroller.cpp"
#include "widget/horizontal-slider.cpp"

View File

@ -30,6 +30,7 @@ namespace phoenix {
#include "widget/canvas.hpp"
#include "widget/check-button.hpp"
#include "widget/combo-button.hpp"
#include "widget/console.hpp"
#include "widget/hex-edit.hpp"
#include "widget/horizontal-scroller.hpp"
#include "widget/horizontal-slider.hpp"

View File

@ -0,0 +1,15 @@
namespace phoenix {
void pConsole::print(string text) {
}
void pConsole::reset() {
}
void pConsole::constructor() {
}
void pConsole::destructor() {
}
}

View File

@ -0,0 +1,14 @@
namespace phoenix {
struct pConsole : public pWidget {
Console& console;
void print(string text);
void reset();
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
};
}

View File

@ -267,7 +267,12 @@ static LRESULT CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wpara
case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC: {
Object* object = (Object*)GetWindowLongPtr((HWND)lparam, GWLP_USERDATA);
if(object && window.p.brush) {
if(object == nullptr) break;
if(dynamic_cast<HexEdit*>(object) || dynamic_cast<LineEdit*>(object) || dynamic_cast<TextEdit*>(object)) {
//text edit controls, when disabled, use CTLCOLORSTATIC instead of CTLCOLOREDIT
//override this behavior: we do not want read-only edit controls to use the parent window background color
return DefWindowProc(hwnd, WM_CTLCOLOREDIT, wparam, lparam);
} else if(window.p.brush) {
HDC hdc = (HDC)wparam;
SetBkColor((HDC)wparam, window.p.brushColor);
return (INT_PTR)window.p.brush;

View File

@ -25,6 +25,7 @@
#include "widget/canvas.cpp"
#include "widget/check-button.cpp"
#include "widget/combo-button.cpp"
#include "widget/console.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroller.cpp"
#include "widget/horizontal-slider.cpp"

View File

@ -305,8 +305,23 @@ struct pComboButton : public pWidget {
void setGeometry(Geometry geometry);
};
struct pConsole : public pWidget {
Console& console;
LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM);
void print(string text);
void reset();
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
void orphan();
bool keyPress(unsigned key);
};
struct pHexEdit : public pWidget {
HexEdit& hexEdit;
HWND scrollBar;
LRESULT CALLBACK (*windowProc)(HWND, UINT, LPARAM, WPARAM);
void setColumns(unsigned columns);
@ -320,6 +335,10 @@ struct pHexEdit : public pWidget {
void destructor();
void orphan();
bool keyPress(unsigned key);
signed rows();
signed rowsScrollable();
signed scrollPosition();
void scrollTo(signed position);
};
struct pHorizontalScroller : public pWidget {

View File

@ -0,0 +1,44 @@
namespace phoenix {
static LRESULT CALLBACK Console_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
Console& console = *(Console*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(msg == WM_CHAR) {
if(console.p.keyPress(wparam)) return 0;
}
return console.p.windowProc(hwnd, msg, wparam, lparam);
}
void pConsole::print(string text) {
}
void pConsole::reset() {
}
void pConsole::constructor() {
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | WS_TABSTOP | ES_READONLY | ES_MULTILINE | ES_WANTRETURN,
0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0
);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&console);
setDefaultFont();
windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)Console_windowProc);
synchronize();
}
void pConsole::destructor() {
DestroyWindow(hwnd);
}
void pConsole::orphan() {
destructor();
constructor();
}
bool pConsole::keyPress(unsigned scancode) {
return false;
}
}

View File

@ -2,9 +2,52 @@ namespace phoenix {
static LRESULT CALLBACK HexEdit_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
HexEdit& hexEdit = *(HexEdit*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(msg == WM_CHAR) {
switch(msg) {
case WM_KEYDOWN:
if(hexEdit.p.keyPress(wparam)) return 0;
break;
case WM_MOUSEWHEEL: {
signed offset = -((int16_t)HIWORD(wparam) / WHEEL_DELTA);
hexEdit.p.scrollTo(hexEdit.p.scrollPosition() + offset);
return true;
}
case WM_SIZE: {
RECT rc;
GetClientRect(hexEdit.p.hwnd, &rc);
SetWindowPos(hexEdit.p.scrollBar, HWND_TOP, rc.right - 18, 0, 18, rc.bottom, SWP_SHOWWINDOW);
break;
}
case WM_VSCROLL: {
SCROLLINFO info;
memset(&info, 0, sizeof(SCROLLINFO));
info.cbSize = sizeof(SCROLLINFO);
info.fMask = SIF_ALL;
GetScrollInfo((HWND)lparam, SB_CTL, &info);
switch(LOWORD(wparam)) {
case SB_LEFT: info.nPos = info.nMin; break;
case SB_RIGHT: info.nPos = info.nMax; break;
case SB_LINELEFT: info.nPos--; break;
case SB_LINERIGHT: info.nPos++; break;
case SB_PAGELEFT: info.nPos -= info.nMax >> 3; break;
case SB_PAGERIGHT: info.nPos += info.nMax >> 3; break;
case SB_THUMBTRACK: info.nPos = info.nTrackPos; break;
}
info.fMask = SIF_POS;
SetScrollInfo((HWND)lparam, SB_CTL, &info, TRUE);
GetScrollInfo((HWND)lparam, SB_CTL, &info); //get clamped position
hexEdit.p.scrollTo(info.nPos);
return TRUE;
}
}
return hexEdit.p.windowProc(hwnd, msg, wparam, lparam);
}
@ -13,10 +56,13 @@ void pHexEdit::setColumns(unsigned columns) {
}
void pHexEdit::setLength(unsigned length) {
SetScrollRange(scrollBar, SB_CTL, 0, rowsScrollable(), TRUE);
EnableWindow(scrollBar, rowsScrollable() > 0);
update();
}
void pHexEdit::setOffset(unsigned offset) {
SetScrollPos(scrollBar, SB_CTL, offset / hexEdit.state.columns, TRUE);
update();
}
@ -45,8 +91,7 @@ void pHexEdit::update() {
uint8_t data = hexEdit.onRead(offset++);
hexdata.append(hex<2>(data));
hexdata.append(" ");
char buffer[2] = {data >= 0x20 && data <= 0x7e ? (char)data : '.', 0};
ansidata.append(buffer);
ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.');
} else {
hexdata.append(" ");
ansidata.append(" ");
@ -66,15 +111,27 @@ void pHexEdit::update() {
void pHexEdit::constructor() {
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, L"EDIT", L"",
WS_CHILD | WS_TABSTOP | ES_READONLY | ES_MULTILINE | ES_WANTRETURN,
WS_CHILD | WS_TABSTOP | ES_AUTOHSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN,
0, 0, 0, 0, parentWindow->p.hwnd, (HMENU)id, GetModuleHandle(0), 0
);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&hexEdit);
setDefaultFont();
update();
scrollBar = CreateWindowEx(
0, L"SCROLLBAR", L"",
WS_VISIBLE | WS_CHILD | SBS_VERT,
0, 0, 0, 0, hwnd, (HMENU)id, GetModuleHandle(0), 0
);
SetWindowLongPtr(scrollBar, GWLP_USERDATA, (LONG_PTR)&hexEdit);
windowProc = (LRESULT CALLBACK (*)(HWND, UINT, LPARAM, WPARAM))GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HexEdit_windowProc);
setDefaultFont();
setLength(hexEdit.state.length);
setOffset(hexEdit.state.offset);
update();
PostMessage(hwnd, EM_SETSEL, 10, 10);
synchronize();
}
@ -90,10 +147,45 @@ void pHexEdit::orphan() {
bool pHexEdit::keyPress(unsigned scancode) {
if(!hexEdit.onRead) return false;
unsigned position = LOWORD(Edit_GetSel(hwnd));
unsigned lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 2;
unsigned cursorY = position / lineWidth;
unsigned cursorX = position % lineWidth;
signed position = LOWORD(Edit_GetSel(hwnd));
signed lineWidth = 10 + (hexEdit.state.columns * 3) + 1 + hexEdit.state.columns + 2;
signed cursorY = position / lineWidth;
signed cursorX = position % lineWidth;
if(scancode == VK_HOME) {
signed offset = cursorY * lineWidth + 10;
Edit_SetSel(hwnd, offset, offset);
return true;
}
if(scancode == VK_END) {
signed offset = cursorY * lineWidth + 57;
Edit_SetSel(hwnd, offset, offset);
return true;
}
if(scancode == VK_UP) {
if(cursorY > 0) return false;
scrollTo(scrollPosition() - 1);
return true;
}
if(scancode == VK_DOWN) {
if(cursorY >= rows() - 1) return true;
if(cursorY < hexEdit.state.rows - 1) return false;
scrollTo(scrollPosition() + 1);
return true;
}
if(scancode == VK_PRIOR) {
scrollTo(scrollPosition() - hexEdit.state.rows);
return true;
}
if(scancode == VK_NEXT) {
scrollTo(scrollPosition() + hexEdit.state.rows);
return true;
}
//convert scancode to hex nibble
if(scancode >= '0' && scancode <= '9') scancode = scancode - '0';
@ -137,4 +229,23 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
signed pHexEdit::rows() {
return (max(1u, hexEdit.state.length) + hexEdit.state.columns - 1) / hexEdit.state.columns;
}
signed pHexEdit::rowsScrollable() {
return max(0u, rows() - hexEdit.state.rows);
}
signed pHexEdit::scrollPosition() {
return hexEdit.state.offset / hexEdit.state.columns;
}
void pHexEdit::scrollTo(signed position) {
if(position > rowsScrollable()) position = rowsScrollable();
if(position < 0) position = 0;
if(position == scrollPosition()) return;
hexEdit.setOffset(position * hexEdit.state.columns);
}
}

View File

@ -5,6 +5,8 @@ void OpenGL::shader(const char* pathname) {
for(auto& frame : frames) glDeleteTextures(1, &frame.texture);
frames.reset();
settings.reset();
format = GL_RGBA8;
filter = GL_LINEAR;
wrap = GL_CLAMP_TO_BORDER;
@ -13,6 +15,11 @@ void OpenGL::shader(const char* pathname) {
if(pathname) {
auto document = Markup::Document(file::read({pathname, "manifest.bml"}));
for(auto& node : document["settings"]) {
settings.insert({node.name, node.text()});
}
for(auto& node : document.find("program")) {
unsigned n = programs.size();
programs(n).bind(this, node, pathname);

View File

@ -2,10 +2,10 @@
#include <GL/gl.h>
#include <GL/glx.h>
#define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(PLATFORM_OSX)
#elif defined(PLATFORM_MACOSX)
#include <OpenGL/gl.h>
#include <OpenGL/gl3.h>
#elif defined(PLATFORM_WIN)
#elif defined(PLATFORM_WINDOWS)
#include <GL/gl.h>
#include <GL/glext.h>
#define glGetProcAddress(name) wglGetProcAddress(name)
@ -57,6 +57,7 @@ struct OpenGLProgram : OpenGLSurface {
vector<OpenGLTexture> pixmaps;
void bind(OpenGL* instance, const Markup::Node& node, const string& pathname);
void parse(OpenGL* instance, string& source);
void release();
};
@ -74,6 +75,17 @@ struct OpenGL : OpenGLProgram {
unsigned outputWidth = 0;
unsigned outputHeight = 0;
struct Setting {
string name;
string value;
bool operator< (const Setting& source) { return name < source.name; }
bool operator==(const Setting& source) { return name == source.name; }
Setting() {}
Setting(const string& name) : name(name) {}
Setting(const string& name, const string& value) : name(name), value(value) {}
};
set<Setting> settings;
void shader(const char* pathname);
void bind(const Markup::Node& node, const string& pathname);
bool lock(uint32_t*& data, unsigned& pitch);

View File

@ -17,6 +17,7 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
if(file::exists({pathname, node["vertex"].text()})) {
string source = file::read({pathname, node["vertex"].text()});
parse(instance, source);
vertex = glrCreateShader(program, GL_VERTEX_SHADER, source);
} else {
vertex = glrCreateShader(program, GL_VERTEX_SHADER, OpenGLVertexShader);
@ -24,6 +25,7 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
if(file::exists({pathname, node["geometry"].text()})) {
string source = file::read({pathname, node["geometry"].text()});
parse(instance, source);
geometry = glrCreateShader(program, GL_GEOMETRY_SHADER, source);
} else {
//geometry shaders, when attached, must pass all vertex output through to the fragment shaders
@ -32,6 +34,7 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
if(file::exists({pathname, node["fragment"].text()})) {
string source = file::read({pathname, node["fragment"].text()});
parse(instance, source);
fragment = glrCreateShader(program, GL_FRAGMENT_SHADER, source);
} else {
fragment = glrCreateShader(program, GL_FRAGMENT_SHADER, OpenGLFragmentShader);
@ -68,6 +71,25 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
glrLinkProgram(program);
}
//apply manifest settings to shader source #in tags
void OpenGLProgram::parse(OpenGL* instance, string& source) {
lstring lines = source.split("\n");
for(auto& line : lines) {
string s = line;
if(auto position = s.find("//")) s.resize(position()); //strip comments
s.strip(); //remove extraneous whitespace
if(s.match("#in ?*")) {
s.ltrim<1>("#in ").strip();
if(auto setting = instance->settings.find({s})) {
line = {"#define ", setting().name, " ", setting().value};
} else {
line.reset(); //undefined variable (test in source with #ifdef)
}
}
}
source = lines.merge("\n");
}
void OpenGLProgram::release() {
OpenGLSurface::release();
for(auto& pixmap : pixmaps) glDeleteTextures(1, &pixmap.texture);

View File

@ -126,9 +126,6 @@ void PPU::enable() {
}
void PPU::power() {
ppu1_version = config.ppu1.version;
ppu2_version = config.ppu2.version;
for(auto& n : vram) n = 0x00;
for(auto& n : oam) n = 0x00;
for(auto& n : cgram) n = 0x00;

View File

@ -14,8 +14,8 @@ struct PPU : Thread, public PPUcounter {
uint32* surface;
uint32* output;
uint8 ppu1_version;
uint8 ppu2_version;
unsigned ppu1_version = 1;
unsigned ppu2_version = 3;
static void Enter();
void add_clocks(unsigned clocks);

View File

@ -53,7 +53,6 @@ void SuperFX::unload() {
void SuperFX::power() {
GSU::power();
clockmode = config.superfx.speed;
}
void SuperFX::reset() {

View File

@ -19,7 +19,7 @@ struct SuperFX : Processor::GSU, Coprocessor {
void serialize(serializer&);
privileged:
unsigned clockmode;
unsigned clockmode = 0; //0 = selectable, 1 = force 10.74mhz, 2 = force 21.48mhz
unsigned instruction_counter;
};

View File

@ -1,26 +0,0 @@
#ifdef SYSTEM_CPP
Configuration config;
Configuration::Configuration() {
controller_port1 = Input::Device::Joypad;
controller_port2 = Input::Device::Joypad;
expansion_port = System::ExpansionPortDevice::Satellaview;
region = System::Region::Autodetect;
random = true;
cpu.version = 2;
cpu.ntsc_frequency = 21477272; //315 / 88 * 6000000
cpu.pal_frequency = 21281370;
cpu.wram_init_value = 0x55;
smp.ntsc_frequency = 24607104; //32040.5 * 768
smp.pal_frequency = 24607104;
ppu1.version = 1;
ppu2.version = 3;
superfx.speed = 0; //0 = auto-select, 1 = force 10.74MHz, 2 = force 21.48MHz
}
#endif

View File

@ -1,35 +0,0 @@
struct Configuration {
Input::Device controller_port1;
Input::Device controller_port2;
System::ExpansionPortDevice expansion_port;
System::Region region;
bool random;
struct CPU {
unsigned version;
unsigned ntsc_frequency;
unsigned pal_frequency;
unsigned wram_init_value;
} cpu;
struct SMP {
unsigned ntsc_frequency;
unsigned pal_frequency;
} smp;
struct PPU1 {
unsigned version;
} ppu1;
struct PPU2 {
unsigned version;
} ppu2;
struct SuperFX {
unsigned speed;
} superfx;
Configuration();
};
extern Configuration config;

View File

@ -120,8 +120,7 @@ void CPU::enable() {
}
void CPU::power() {
cpu_version = config.cpu.version;
for(auto& byte : wram) byte = random(config.cpu.wram_init_value);
for(auto& byte : wram) byte = random(0x55);
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;

View File

@ -26,13 +26,13 @@ struct CPU : Processor::R65816, Thread, public PPUcounter {
~CPU();
privileged:
unsigned cpu_version = 2; //allowed: 1, 2
#include "dma/dma.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
uint8 cpu_version;
struct Status {
bool interrupt_pending;

View File

@ -87,9 +87,6 @@ void PPU::enable() {
}
void PPU::power() {
ppu1_version = config.ppu1.version;
ppu2_version = config.ppu2.version;
for(auto& n : vram) n = random(0x00);
for(auto& n : oam) n = random(0x00);
for(auto& n : cgram) n = random(0x00);

View File

@ -22,12 +22,12 @@ struct PPU : Thread, public PPUcounter {
~PPU();
privileged:
unsigned ppu1_version = 1; //allowed: 1
unsigned ppu2_version = 3; //allowed: 1, 2, 3
uint32* surface;
uint32* output;
uint8 ppu1_version;
uint8 ppu2_version;
struct {
bool interlace;
bool overscan;

View File

@ -1,18 +0,0 @@
Random random;
void Random::seed(unsigned seed_iter) {
iter = seed_iter;
}
unsigned Random::operator()(unsigned result) {
if(config.random == false) return result;
return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320);
}
void Random::serialize(serializer& s) {
s.integer(iter);
}
Random::Random() {
iter = 0;
}

View File

@ -1,11 +0,0 @@
struct Random {
void seed(unsigned seed);
unsigned operator()(unsigned result = 0);
void serialize(serializer&);
Random();
private:
unsigned iter;
};
extern Random random;

View File

@ -12,7 +12,7 @@
namespace SuperFamicom {
namespace Info {
static const char Name[] = "bsnes";
static const unsigned SerializerVersion = 26;
static const unsigned SerializerVersion = 27;
}
}

View File

@ -21,8 +21,8 @@ void Input::connect(bool port, Input::Device id) {
}
switch(port) {
case Controller::Port1: config.controller_port1 = id; break;
case Controller::Port2: config.controller_port2 = id; break;
case Controller::Port1: configuration.controller_port1 = id; break;
case Controller::Port2: configuration.controller_port2 = id; break;
}
}

View File

@ -4,16 +4,16 @@
namespace SuperFamicom {
System system;
#include <sfc/config/config.cpp>
#include <sfc/scheduler/scheduler.cpp>
#include <sfc/random/random.cpp>
Configuration configuration;
Random random;
#include "video.cpp"
#include "audio.cpp"
#include "input.cpp"
#include "serialization.cpp"
#include <sfc/scheduler/scheduler.cpp>
void System::run() {
scheduler.sync = Scheduler::SynchronizeMode::None;
@ -86,8 +86,8 @@ void System::init() {
video.init();
audio.init();
input.connect(0, config.controller_port1);
input.connect(1, config.controller_port2);
input.connect(0, configuration.controller_port1);
input.connect(1, configuration.controller_port2);
}
void System::term() {
@ -102,14 +102,14 @@ void System::load() {
interface->notify("Error: required Super Famicom firmware ipl.rom not found.\n");
}
region = config.region;
expansion = config.expansion_port;
region = configuration.region;
expansion = configuration.expansion_port;
if(region == Region::Autodetect) {
region = (cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL);
}
cpu_frequency = region() == Region::NTSC ? config.cpu.ntsc_frequency : config.cpu.pal_frequency;
apu_frequency = region() == Region::NTSC ? config.smp.ntsc_frequency : config.smp.pal_frequency;
cpu_frequency = region() == Region::NTSC ? 21477272 : 21281370;
apu_frequency = 24607104;
audio.coprocessor_enable(false);
@ -233,8 +233,8 @@ void System::reset() {
if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1);
scheduler.init();
input.connect(0, config.controller_port1);
input.connect(1, config.controller_port2);
input.connect(0, configuration.controller_port1);
input.connect(1, configuration.controller_port2);
}
void System::scanline() {

View File

@ -42,12 +42,40 @@ private:
friend class Input;
};
extern System system;
#include "video.hpp"
#include "audio.hpp"
#include "input.hpp"
#include <sfc/config/config.hpp>
#include <sfc/scheduler/scheduler.hpp>
#include <sfc/random/random.hpp>
extern System system;
struct Configuration {
Input::Device controller_port1 = Input::Device::Joypad;
Input::Device controller_port2 = Input::Device::Joypad;
System::ExpansionPortDevice expansion_port = System::ExpansionPortDevice::Satellaview;
System::Region region = System::Region::Autodetect;
bool random = true;
};
extern Configuration configuration;
struct Random {
void seed(unsigned seed) {
iter = seed;
}
unsigned operator()(unsigned result) {
if(configuration.random == false) return result;
return iter = (iter >> 1) ^ (((iter & 1) - 1) & 0xedb88320);
}
void serialize(serializer& s) {
s.integer(iter);
}
private:
unsigned iter = 0;
};
extern Random random;

View File

@ -74,7 +74,7 @@ void Video::draw_cursor(uint16_t color, int x, int y) {
}
void Video::update() {
switch(config.controller_port2) {
switch(configuration.controller_port2) {
case Input::Device::SuperScope:
if(dynamic_cast<SuperScope*>(input.port2)) {
SuperScope &device = (SuperScope&)*input.port2;

View File

@ -79,7 +79,7 @@ else ifeq ($(platform),macosx)
mkdir out/$(name).app/Contents/MacOS
mkdir out/$(name).app/Contents/Resources
cp data/Info.plist out/$(name).app/Contents/Info.plist
sips -s format icns data/higan512.png --out out/$(name).app/Contents/Resources/higan.icns
sips -s format icns data/higan.png --out out/$(name).app/Contents/Resources/higan.icns
$(strip $(compiler) -o out/$(name).app/Contents/MacOS/$(name) $(objects) $(link))
else
$(strip $(compiler) -o out/$(name) $(objects) $(link))

View File

@ -12,7 +12,7 @@ ConfigurationSettings::ConfigurationSettings() {
video.maskOverscan.append(video.maskOverscan.vertical = 8, "Vertical");
video.append(video.maskOverscan, "MaskOverscan");
video.append(video.saturation = 100, "Saturation");
video.append(video.gamma = 150, "Gamma");
video.append(video.gamma = 100, "Gamma");
video.append(video.luminance = 100, "Luminance");
video.append(video.startFullScreen = false, "StartFullScreen");
append(video, "Video");

View File

@ -53,7 +53,7 @@ Program::Program(int argc, char** argv) {
bootstrap();
active = nullptr;
if(Intrinsics::platform() == Intrinsics::Platform::OSX) {
if(Intrinsics::platform() == Intrinsics::Platform::MacOSX) {
normalFont = Font::sans(12);
boldFont = Font::sans(12, "Bold");
titleFont = Font::sans(20, "Bold");

View File

@ -105,7 +105,7 @@ Presentation::Presentation() {
}
settingsMenu.append(*new Separator);
settingsMenu.append(synchronizeVideo, synchronizeAudio, muteAudio);
if(Intrinsics::platform() != Intrinsics::Platform::OSX) {
if(Intrinsics::platform() != Intrinsics::Platform::MacOSX) {
settingsMenu.append(*new Separator);
settingsMenu.append(configurationSettings);
}
@ -133,7 +133,7 @@ Presentation::Presentation() {
onClose = [&] {
setVisible(false);
if(Intrinsics::platform() == Intrinsics::Platform::OSX) {
if(Intrinsics::platform() == Intrinsics::Platform::MacOSX) {
utility->unload();
} else {
Application::quit();
@ -151,7 +151,7 @@ Presentation::Presentation() {
shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); };
shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); };
shaderEmulation.onActivate = [&] { config->video.shader = "Emulation"; utility->updateShader(); };
shaderEmulation.onActivate = [&] { config->video.shader = "Display Emulation"; utility->updateShader(); };
centerVideo.onActivate = [&] { config->video.scaleMode = 0; utility->resize(); };
scaleVideo.onActivate = [&] { config->video.scaleMode = 1; utility->resize(); };
stretchVideo.onActivate = [&] { config->video.scaleMode = 2; utility->resize(); };

View File

@ -57,7 +57,7 @@ AdvancedSettings::AdvancedSettings() {
libraryLayout.append(libraryLabel, {0, 0}, 5);
libraryLayout.append(libraryPath, {~0, 0}, 5);
libraryLayout.append(libraryBrowse, {80, 0});
if(Intrinsics::platform() != Intrinsics::Platform::OSX) {
if(Intrinsics::platform() != Intrinsics::Platform::MacOSX) {
append(spacer, {~0, ~0});
append(infoLabel, {~0, 0});
}

View File

@ -203,10 +203,10 @@ void Utility::updateShader() {
video.set(Video::Shader, (const char*)"");
video.set(Video::Filter, Video::FilterLinear);
return;
} else if(config->video.shader == "Emulation") {
} else if(config->video.shader == "Display Emulation") {
if(program->active) {
string pathname = program->path("Video Shaders/");
pathname.append("Emulation/");
pathname.append("Display Emulation/");
pathname.append(presentation->systemName, ".shader/");
if(directory::exists(pathname)) {
video.set(Video::Shader, (const char*)pathname);