Update to v093r05 release.

byuu says:

Library concept has been refined as per the general forum discussion.
This commit is contained in:
Tim Allen 2013-12-03 21:01:59 +11:00
parent b4f18c3b47
commit ed4e87f65e
37 changed files with 303 additions and 212 deletions

View File

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

View File

@ -8,7 +8,7 @@ namespace nall {
struct beatArchive : beatBase { struct beatArchive : beatBase {
bool create(const string& beatname, string pathname, const string& metadata = "") { bool create(const string& beatname, string pathname, const string& metadata = "") {
if(fp.open(beatname, file::mode::write) == false) return false; if(fp.open(beatname, file::mode::write) == false) return false;
if(pathname.endswith("/") == false) pathname.append("/"); if(pathname.endsWith("/") == false) pathname.append("/");
checksum = ~0; checksum = ~0;
writeString("BPA1"); writeString("BPA1");
@ -18,7 +18,7 @@ struct beatArchive : beatBase {
lstring list; lstring list;
ls(list, pathname, pathname); ls(list, pathname, pathname);
for(auto &name : list) { for(auto &name : list) {
if(name.endswith("/")) { if(name.endsWith("/")) {
name.rtrim<1>("/"); name.rtrim<1>("/");
writeNumber(0 | ((name.length() - 1) << 1)); writeNumber(0 | ((name.length() - 1) << 1));
writeString(name); writeString(name);
@ -46,7 +46,7 @@ struct beatArchive : beatBase {
bool unpack(const string& beatname, string pathname) { bool unpack(const string& beatname, string pathname) {
if(fp.open(beatname, file::mode::read) == false) return false; if(fp.open(beatname, file::mode::read) == false) return false;
if(pathname.endswith("/") == false) pathname.append("/"); if(pathname.endsWith("/") == false) pathname.append("/");
checksum = ~0; checksum = ~0;
if(readString(4) != "BPA1") return false; if(readString(4) != "BPA1") return false;

View File

@ -34,7 +34,7 @@ struct bpsmulti {
ls(targetList, targetPath, targetPath); ls(targetList, targetPath, targetPath);
for(auto& targetName : targetList) { for(auto& targetName : targetList) {
if(targetName.endswith("/")) { if(targetName.endsWith("/")) {
targetName.rtrim<1>("/"); targetName.rtrim<1>("/");
writeNumber(CreatePath | ((targetName.length() - 1) << 2)); writeNumber(CreatePath | ((targetName.length() - 1) << 2));
writeString(targetName); writeString(targetName);

View File

@ -168,7 +168,7 @@ private:
inline bool directory::remove(const string& pathname) { inline bool directory::remove(const string& pathname) {
lstring list = directory::contents(pathname); lstring list = directory::contents(pathname);
for(auto& name : list) { for(auto& name : list) {
if(name.endswith("/")) directory::remove({pathname, name}); if(name.endsWith("/")) directory::remove({pathname, name});
else file::remove({pathname, name}); else file::remove({pathname, name});
} }
return rmdir(pathname) == 0; return rmdir(pathname) == 0;

View File

@ -38,7 +38,7 @@ private:
#if defined(PLATFORM_X) #if defined(PLATFORM_X)
inline bool library::open(const string& name, const string& path) { inline bool library::open(const string& name, const string& path) {
if(handle) close(); if(handle) close();
handle = (uintptr_t)dlopen(string(path, !path.empty() && !path.endswith("/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY); handle = (uintptr_t)dlopen(string(path, !path.empty() && !path.endsWith("/") ? "/" : "", "lib", name, ".so"), RTLD_LAZY);
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
return handle; return handle;
} }
@ -62,7 +62,7 @@ inline void library::close() {
#elif defined(PLATFORM_MACOSX) #elif defined(PLATFORM_MACOSX)
inline bool library::open(const string& name, const string& path) { inline bool library::open(const string& name, const string& path) {
if(handle) close(); if(handle) close();
handle = (uintptr_t)dlopen(string(path, !path.empty() && !path.endswith("/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY); handle = (uintptr_t)dlopen(string(path, !path.empty() && !path.endsWith("/") ? "/" : "", "lib", name, ".dylib"), RTLD_LAZY);
if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
return handle; return handle;
} }
@ -86,7 +86,7 @@ inline void library::close() {
#elif defined(PLATFORM_WINDOWS) #elif defined(PLATFORM_WINDOWS)
inline bool library::open(const string& name, const string& path) { inline bool library::open(const string& name, const string& path) {
if(handle) close(); if(handle) close();
string filepath(path, !path.empty() && !path.endswith("/") && !path.endswith("\\") ? "/" : "", name, ".dll"); string filepath(path, !path.empty() && !path.endswith("/") && !path.endsWith("\\") ? "/" : "", name, ".dll");
handle = (uintptr_t)LoadLibraryW(utf16_t(filepath)); handle = (uintptr_t)LoadLibraryW(utf16_t(filepath));
return handle; return handle;
} }

View File

@ -41,11 +41,11 @@ template<typename T> struct group : protected vector<T*> {
return false; return false;
} }
struct iterator : protected vector<T*>::const_iterator { struct iterator : protected vector<T*>::constIterator {
T& operator*() const { return *vector<T*>::const_iterator::operator*(); } T& operator*() const { return *vector<T*>::constIterator::operator*(); }
bool operator!=(const iterator& source) const { return vector<T*>::const_iterator::operator!=(source); } bool operator!=(const iterator& source) const { return vector<T*>::constIterator::operator!=(source); }
iterator& operator++() { vector<T*>::const_iterator::operator++(); return *this; } iterator& operator++() { vector<T*>::constIterator::operator++(); return *this; }
iterator(const group& source, unsigned position) : vector<T*>::const_iterator(source, position) {} iterator(const group& source, unsigned position) : vector<T*>::constIterator(source, position) {}
}; };
const iterator begin() const { return iterator(*this, 0); } const iterator begin() const { return iterator(*this, 0); }

View File

@ -81,7 +81,7 @@ struct http {
if(length <= 0) return output; if(length <= 0) return output;
buffer[1] = 0; buffer[1] = 0;
output.append(buffer); output.append(buffer);
} while(output.endswith("\r\n\r\n") == false); } while(output.endsWith("\r\n\r\n") == false);
return output; return output;
} }
@ -93,7 +93,7 @@ struct http {
if(length <= 0) return output; if(length <= 0) return output;
buffer[1] = 0; buffer[1] = 0;
output.append(buffer); output.append(buffer);
} while(output.endswith("\r\n") == false); } while(output.endsWith("\r\n") == false);
return output; return output;
} }

View File

@ -113,6 +113,7 @@ unsigned image::bitShift(uint64_t color) {
} }
uint64_t image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) { uint64_t image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) {
if(sourceDepth == 0 || targetDepth == 0) return 0;
while(sourceDepth < targetDepth) { while(sourceDepth < targetDepth) {
color = (color << sourceDepth) | color; color = (color << sourceDepth) | color;
sourceDepth += sourceDepth; sourceDepth += sourceDepth;

View File

@ -176,6 +176,10 @@ struct context {
if(mosaicWidth < 1) mosaicWidth = 1; if(mosaicWidth < 1) mosaicWidth = 1;
if(mosaicHeight < 1) mosaicHeight = 1; if(mosaicHeight < 1) mosaicHeight = 1;
//set alpha to full opacity
paddingColor |= 255u << 24;
for(auto& color : palette) color |= 255u << 24;
} }
void reset() { void reset() {
@ -208,7 +212,7 @@ struct context {
paddingWidth = 0; paddingWidth = 0;
paddingHeight = 0; paddingHeight = 0;
paddingColor = 0x000000; paddingColor = 0;
palette.reset(); palette.reset();
} }

View File

@ -9,7 +9,7 @@ struct parser {
//export from bitstream to canvas //export from bitstream to canvas
void load(bitstream& stream, uint64_t offset, context& ctx, unsigned width, unsigned height) { void load(bitstream& stream, uint64_t offset, context& ctx, unsigned width, unsigned height) {
canvas.allocate(width, height); canvas.allocate(width, height);
canvas.clear(ctx.paddingColor); canvas.fill(ctx.paddingColor);
parse(1, stream, offset, ctx, width, height); parse(1, stream, offset, ctx, width, height);
} }
@ -20,7 +20,7 @@ struct parser {
return true; return true;
} }
inline parser() : canvas(0, 32, 0u, 255u << 16, 255u << 8, 255u << 0) { inline parser() : canvas(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0) {
} }
private: private:

View File

@ -6,9 +6,9 @@ namespace nall {
#define autostream(...) (*makestream(__VA_ARGS__)) #define autostream(...) (*makestream(__VA_ARGS__))
inline std::unique_ptr<stream> makestream(const string& path) { inline std::unique_ptr<stream> makestream(const string& path) {
if(path.ibeginswith("http://")) return std::unique_ptr<stream>(new httpstream(path, 80)); if(path.ibeginsWith("http://")) return std::unique_ptr<stream>(new httpstream(path, 80));
if(path.iendswith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path})); if(path.iendsWith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
if(path.iendswith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path})); if(path.iendsWith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
return std::unique_ptr<stream>(new mmapstream(path)); return std::unique_ptr<stream>(new mmapstream(path));
} }

View File

@ -81,10 +81,10 @@ public:
inline bool match(rstring) const; inline bool match(rstring) const;
inline bool imatch(rstring) const; inline bool imatch(rstring) const;
inline bool beginswith(rstring) const; inline bool beginsWith(rstring) const;
inline bool ibeginswith(rstring) const; inline bool ibeginsWith(rstring) const;
inline bool endswith(rstring) const; inline bool endsWith(rstring) const;
inline bool iendswith(rstring) const; inline bool iendsWith(rstring) const;
inline string slice(unsigned offset, unsigned length = ~0u) const; inline string slice(unsigned offset, unsigned length = ~0u) const;

View File

@ -39,11 +39,11 @@ inline string evaluateExpression(Node* node) {
inline int64_t evaluateInteger(Node* node) { inline int64_t evaluateInteger(Node* node) {
if(node->type == Node::Type::Literal) { if(node->type == Node::Type::Literal) {
if(node->literal.beginswith("0b")) return nall::binary(node->literal); if(node->literal.beginsWith("0b")) return nall::binary(node->literal);
if(node->literal.beginswith("0o")) return nall::octal(node->literal); if(node->literal.beginsWith("0o")) return nall::octal(node->literal);
if(node->literal.beginswith("0x")) return nall::hex(node->literal); if(node->literal.beginsWith("0x")) return nall::hex(node->literal);
if(node->literal.beginswith("%")) return nall::binary(node->literal); if(node->literal.beginsWith("%")) return nall::binary(node->literal);
if(node->literal.beginswith("$")) return nall::hex(node->literal); if(node->literal.beginsWith("$")) return nall::hex(node->literal);
return nall::integer(node->literal); return nall::integer(node->literal);
} }

View File

@ -4,7 +4,7 @@ namespace nall {
namespace Markup { namespace Markup {
inline Node Document(const string& markup) { inline Node Document(const string& markup) {
if(markup.beginswith("<")) return XML::Document(markup); if(markup.beginsWith("<")) return XML::Document(markup);
return BML::Document(markup); return BML::Document(markup);
} }

View File

@ -131,8 +131,8 @@ struct Node {
vector<Node>::iterator begin() { return children.begin(); } vector<Node>::iterator begin() { return children.begin(); }
vector<Node>::iterator end() { return children.end(); } vector<Node>::iterator end() { return children.end(); }
const vector<Node>::const_iterator begin() const { return children.begin(); } const vector<Node>::constIterator begin() const { return children.begin(); }
const vector<Node>::const_iterator end() const { return children.end(); } const vector<Node>::constIterator end() const { return children.end(); }
Node() : attribute(false), level(0) {} Node() : attribute(false), level(0) {}

View File

@ -8,7 +8,7 @@ string activepath() {
string result = path; string result = path;
if(result.empty()) result = "."; if(result.empty()) result = ".";
result.transform("\\", "/"); result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/"); if(result.endsWith("/") == false) result.append("/");
return result; return result;
} }
@ -18,7 +18,7 @@ string realpath(const string& name) {
if(::realpath(name, path)) result = path; if(::realpath(name, path)) result = path;
if(result.empty()) result = {activepath(), name}; if(result.empty()) result = {activepath(), name};
result.transform("\\", "/"); result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/"); if(result.endsWith("/") == false) result.append("/");
return result; return result;
} }
@ -36,7 +36,7 @@ string userpath() {
result = userinfo->pw_dir; result = userinfo->pw_dir;
#endif #endif
if(result.empty()) result = "."; if(result.empty()) result = ".";
if(result.endswith("/") == false) result.append("/"); if(result.endsWith("/") == false) result.append("/");
return result; return result;
} }
@ -55,7 +55,7 @@ string configpath() {
result = {userpath(), ".config/"}; result = {userpath(), ".config/"};
#endif #endif
if(result.empty()) result = "."; if(result.empty()) result = ".";
if(result.endswith("/") == false) result.append("/"); if(result.endsWith("/") == false) result.append("/");
return result; return result;
} }
@ -72,7 +72,7 @@ string sharedpath() {
result = "/usr/share/"; result = "/usr/share/";
#endif #endif
if(result.empty()) result = "."; if(result.empty()) result = ".";
if(result.endswith("/") == false) result.append("/"); if(result.endsWith("/") == false) result.append("/");
return result; return result;
} }

View File

@ -28,22 +28,22 @@ bool string::iequals(rstring source) const {
return icompare(source) == 0; return icompare(source) == 0;
} }
bool string::beginswith(rstring source) const { bool string::beginsWith(rstring source) const {
if(source.size() > size()) return false; if(source.size() > size()) return false;
return memcmp(data(), source.data(), source.size()) == 0; return memcmp(data(), source.data(), source.size()) == 0;
} }
bool string::ibeginswith(rstring source) const { bool string::ibeginsWith(rstring source) const {
if(source.size() > size()) return false; if(source.size() > size()) return false;
return imemcmp(data(), source.data(), source.size()) == 0; return imemcmp(data(), source.data(), source.size()) == 0;
} }
bool string::endswith(rstring source) const { bool string::endsWith(rstring source) const {
if(source.size() > size()) return false; if(source.size() > size()) return false;
return memcmp(data() + size() - source.size(), source.data(), source.size()) == 0; return memcmp(data() + size() - source.size(), source.data(), source.size()) == 0;
} }
bool string::iendswith(rstring source) const { bool string::iendsWith(rstring source) const {
if(source.size() > size()) return false; if(source.size() > size()) return false;
return imemcmp(data() + size() - source.size(), source.data(), source.size()) == 0; return imemcmp(data() + size() - source.size(), source.data(), source.size()) == 0;
} }

View File

@ -102,7 +102,7 @@ public:
return last(); return last();
} }
bool appendonce(const T& data) { bool appendOnce(const T& data) {
if(find(data)) return false; if(find(data)) return false;
return append(data), true; return append(data), true;
} }
@ -136,8 +136,8 @@ public:
objectsize -= length; objectsize -= length;
} }
void removefirst() { return remove(0); } void removeFirst() { return remove(0); }
void removelast() { return remove(~0u); } void removeLast() { return remove(~0u); }
T take(unsigned position = ~0u) { T take(unsigned position = ~0u) {
if(position == ~0u) position = objectsize - 1; if(position == ~0u) position = objectsize - 1;
@ -146,8 +146,8 @@ public:
return object; return object;
} }
T takefirst() { return take(0); } T takeFirst() { return take(0); }
T takelast() { return take(~0u); } T takeLast() { return take(~0u); }
void reverse() { void reverse() {
unsigned pivot = size() / 2; unsigned pivot = size() / 2;
@ -226,19 +226,19 @@ public:
iterator begin() { return iterator(*this, 0); } iterator begin() { return iterator(*this, 0); }
iterator end() { return iterator(*this, size()); } iterator end() { return iterator(*this, size()); }
struct const_iterator { struct constIterator {
const T& operator*() const { return source.operator[](position); } const T& operator*() const { return source.operator[](position); }
bool operator!=(const const_iterator& source) const { return position != source.position; } bool operator!=(const constIterator& source) const { return position != source.position; }
const_iterator& operator++() { position++; return *this; } constIterator& operator++() { position++; return *this; }
const_iterator(const vector& source, unsigned position) : source(source), position(position) {} constIterator(const vector& source, unsigned position) : source(source), position(position) {}
private: private:
const vector& source; const vector& source;
unsigned position; unsigned position;
}; };
const const_iterator begin() const { return const_iterator(*this, 0); } const constIterator begin() const { return constIterator(*this, 0); }
const const_iterator end() const { return const_iterator(*this, size()); } const constIterator end() const { return constIterator(*this, size()); }
//copy //copy
inline vector& operator=(const vector& source) { inline vector& operator=(const vector& source) {

View File

@ -33,7 +33,7 @@ lstring DropPaths(id<NSDraggingInfo> sender) {
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for(unsigned n = 0; n < [files count]; n++) { for(unsigned n = 0; n < [files count]; n++) {
string path = [[files objectAtIndex:n] UTF8String]; string path = [[files objectAtIndex:n] UTF8String];
if(directory::exists(path) && !path.endswith("/")) path.append("/"); if(directory::exists(path) && !path.endsWith("/")) path.append("/");
paths.append(path); paths.append(path);
} }
} }

View File

@ -31,7 +31,7 @@ string pBrowserWindow::directory(BrowserWindow::State& state) {
} }
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
if(name && !name.endswith("/")) name.append("/"); if(name && !name.endsWith("/")) name.append("/");
return name; return name;
} }

View File

@ -38,7 +38,7 @@ static lstring DropPaths(GtkSelectionData* data) {
string path = pathname; string path = pathname;
g_free(pathname); g_free(pathname);
if(directory::exists(path) && !path.endswith("/")) path.append("/"); if(directory::exists(path) && !path.endsWith("/")) path.append("/");
paths.append(path); paths.append(path);
} }

View File

@ -3,7 +3,7 @@ namespace phoenix {
static void TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned selection, TabFrame* self) { static void TabFrame_change(GtkNotebook* notebook, GtkWidget* page, unsigned selection, TabFrame* self) {
self->state.selection = selection; self->state.selection = selection;
self->p.synchronizeLayout(); self->p.synchronizeLayout();
if(self->onChange) self->onChange(); if(!self->p.locked && self->onChange) self->onChange();
} }
void pTabFrame::append(string text, const image& image) { void pTabFrame::append(string text, const image& image) {
@ -73,7 +73,9 @@ void pTabFrame::setImage(unsigned selection, const image& image) {
} }
void pTabFrame::setSelection(unsigned selection) { void pTabFrame::setSelection(unsigned selection) {
locked = true;
gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkWidget), selection); gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkWidget), selection);
locked = false;
} }
void pTabFrame::setText(unsigned selection, string text) { void pTabFrame::setText(unsigned selection, string text) {

View File

@ -7,7 +7,7 @@ string pBrowserWindow::directory(BrowserWindow::State& state) {
QString::fromUtf8(state.path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks QString::fromUtf8(state.path), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks
); );
string name = directory.toUtf8().constData(); string name = directory.toUtf8().constData();
if(name && name.endswith("/") == false) name.append("/"); if(name && name.endsWith("/") == false) name.append("/");
return name; return name;
} }

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp' ** Meta object code from reading C++ file 'platform.moc.hpp'
** **
** Created: Sun Nov 24 07:06:37 2013 ** Created: Fri Nov 29 09:24:08 2013
** by: The Qt Meta Object Compiler version 63 (Qt 4.8.2) ** by: The Qt Meta Object Compiler version 63 (Qt 4.8.2)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!

View File

@ -16,7 +16,7 @@ static lstring DropPaths(QDropEvent* event) {
for(unsigned n = 0; n < urls.size(); n++) { for(unsigned n = 0; n < urls.size(); n++) {
string path = urls[n].path().toUtf8().constData(); string path = urls[n].path().toUtf8().constData();
if(path.empty()) continue; if(path.empty()) continue;
if(directory::exists(path) && !path.endswith("/")) path.append("/"); if(directory::exists(path) && !path.endsWith("/")) path.append("/");
paths.append(path); paths.append(path);
} }

View File

@ -46,8 +46,10 @@ void pTabFrame::setImage(unsigned selection, const image& image) {
} }
void pTabFrame::setSelection(unsigned selection) { void pTabFrame::setSelection(unsigned selection) {
locked = true;
qtTabFrame->setCurrentIndex(selection); qtTabFrame->setCurrentIndex(selection);
synchronizeLayout(); synchronizeLayout();
locked = false;
} }
void pTabFrame::setText(unsigned selection, string text) { void pTabFrame::setText(unsigned selection, string text) {
@ -89,7 +91,7 @@ void pTabFrame::synchronizeLayout() {
void pTabFrame::onChange(int selection) { void pTabFrame::onChange(int selection) {
tabFrame.state.selection = selection; tabFrame.state.selection = selection;
synchronizeLayout(); synchronizeLayout();
if(tabFrame.onChange) tabFrame.onChange(); if(!locked && tabFrame.onChange) tabFrame.onChange();
} }
} }

View File

@ -90,7 +90,7 @@ string pBrowserWindow::directory(BrowserWindow::State& state) {
string name = (const char*)utf8_t(wname); string name = (const char*)utf8_t(wname);
if(!name) return ""; if(!name) return "";
name.transform("\\", "/"); name.transform("\\", "/");
if(name.endswith("/") == false) name.append("/"); if(name.endsWith("/") == false) name.append("/");
return name; return name;
} }

View File

@ -42,7 +42,7 @@ static lstring DropPaths(WPARAM wparam) {
if(DragQueryFile(dropList, n, buffer, length + 1)) { if(DragQueryFile(dropList, n, buffer, length + 1)) {
string path = (const char*)utf8_t(buffer); string path = (const char*)utf8_t(buffer);
path.transform("\\", "/"); path.transform("\\", "/");
if(directory::exists(path) && !path.endswith("/")) path.append("/"); if(directory::exists(path) && !path.endsWith("/")) path.append("/");
paths.append(path); paths.append(path);
} }

View File

@ -4,9 +4,9 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin
modulo = glrModulo(node["modulo"].integer()); modulo = glrModulo(node["modulo"].integer());
string w = node["width"].text(), h = node["height"].text(); string w = node["width"].text(), h = node["height"].text();
if(w.endswith("%")) relativeWidth = real(w.rtrim<1>("%")) / 100.0; if(w.endsWith("%")) relativeWidth = real(w.rtrim<1>("%")) / 100.0;
else absoluteWidth = decimal(w); else absoluteWidth = decimal(w);
if(h.endswith("%")) relativeHeight = real(h.rtrim<1>("%")) / 100.0; if(h.endsWith("%")) relativeHeight = real(h.rtrim<1>("%")) / 100.0;
else absoluteHeight = decimal(h); else absoluteHeight = decimal(h);
if(node.name != "program") return; if(node.name != "program") return;

View File

@ -41,7 +41,7 @@ ConfigurationSettings::ConfigurationSettings() {
server.append(server.password = "", "Password"); server.append(server.password = "", "Password");
append(server, "Server"); append(server, "Server");
library.append(library.selection = 0, "Selection"); library.append(library.selection = -1, "Selection");
library.append(library.showOnStartup = true, "ShowOnStartup"); library.append(library.showOnStartup = true, "ShowOnStartup");
append(library, "Library"); append(library, "Library");

View File

@ -46,7 +46,7 @@ struct ConfigurationSettings : Configuration::Document {
} server; } server;
struct Library : Configuration::Node { struct Library : Configuration::Node {
unsigned selection; signed selection;
bool showOnStartup; bool showOnStartup;
} library; } library;

View File

@ -85,7 +85,7 @@ Program::Program(int argc, char** argv) {
presentation->setVisible(); presentation->setVisible();
utility->resize(); utility->resize();
if(config->library.showOnStartup) libraryManager->setVisible(); if(argc == 1 && config->library.showOnStartup) libraryManager->show();
video.set(Video::Handle, presentation->viewport.handle()); video.set(Video::Handle, presentation->viewport.handle());
if(!video.cap(Video::Depth) || !video.set(Video::Depth, depth = 30u)) { if(!video.cap(Video::Depth) || !video.set(Video::Depth, depth = 30u)) {

View File

@ -1,185 +1,251 @@
LibraryManager* libraryManager = nullptr; LibraryManager* libraryManager = nullptr;
LibraryBrowser::LibraryBrowser() { LibraryBrowser::LibraryBrowser(Emulator::Interface& emulator) : emulator(emulator) {
setMargin(5); setMargin(5);
informationType.setText({ informationType.setText({
"Title:\n", "Title:\n",
"Revision:\n",
"Region:\n",
"Serial:" "Serial:"
}); });
for(auto& media : emulator.media) {
mediaMode.append(media.name);
}
unsigned height = Font::size(program->normalFont, " ").height;
append(folders, {~0, ~0}, 5); append(folders, {~0, ~0}, 5);
append(informationLayout, {~0, Font::size(program->normalFont, " ").height * 4}); append(informationLayout, {~0, 0});
informationLayout.append(informationType, {0, ~0}, 5); informationLayout.append(informationType, {0, height * 2}, 5);
informationLayout.append(information, {~0, ~0}); informationLayout.append(information, {~0, height * 2}, 5);
informationLayout.append(mediaMode, {0, 0});
folders.onActivate = {&LibraryBrowser::onActivate, this}; folders.onActivate = {&LibraryBrowser::onActivate, this};
folders.onChange = {&LibraryBrowser::setInformation, this}; folders.onChange = {&LibraryBrowser::onChange, this};
mediaMode.onChange = {&LibraryBrowser::setMode, this};
} }
void LibraryBrowser::onActivate() { void LibraryBrowser::onActivate() {
if(folders.selected() == false) return; if(folders.selected() == false) return;
if(libraryManager->loadButton.enabled() == false) return;
unsigned selection = folders.selection(); unsigned selection = folders.selection();
string pathname = {this->pathname, folders.text(selection, 0), filterSuffix}; string pathname = {this->pathname, folders.text(selection, 0), typeSuffix};
libraryManager->loaded.append(folders.text(selection, 0));
libraryManager->setInformation(false);
if(libraryManager->slotLoad == false) { if(libraryManager->slotLoad == false) {
libraryManager->setStatusText(folders.text(selection, 0));
utility->loadMedia(pathname); utility->loadMedia(pathname);
} else { } else {
libraryManager->setStatusText({libraryManager->statusText(), " + ", folders.text(selection, 0)});
libraryManager->setModal(false);
libraryManager->loadPathname = pathname; libraryManager->loadPathname = pathname;
libraryManager->setModal(false);
} }
} }
void LibraryBrowser::onChange() {
if(folders.selected() == false) return information.setText("");
string manifest = {pathname, folders.text(folders.selection(), 0), typeSuffix, "manifest.bml"};
auto document = Markup::Document(file::read(manifest));
information.setText({
document["information/title"].text(), "\n",
document["information/serial"].text()
});
}
void LibraryBrowser::refresh() { void LibraryBrowser::refresh() {
folders.reset(); folders.reset();
lstring pathnames = directory::ifolders(pathname, filterMask); lstring pathnames = directory::ifolders(pathname, typeMask);
unsigned selection = 0; unsigned selection = 0;
for(auto& pathname : pathnames) { for(auto& pathname : pathnames) {
folders.append(string{pathname}.rtrim<1>(filterSuffix)); folders.append(string{pathname}.rtrim<1>(typeSuffix));
folders.setImage(selection++, 0, {resource::game, sizeof resource::game}); folders.setImage(selection++, 0, {resource::game, sizeof resource::game});
} }
folders.setSelection(0);
onChange();
} }
void LibraryBrowser::setFilter(const string& filter) { void LibraryBrowser::setMode() {
this->filter = filter; auto& media = emulator.media[mediaMode.selection()];
filterMask = {"*.", filter};
filterSuffix = {".", filter, "/"};
}
void LibraryBrowser::setInformation() { pathname = {utility->libraryPath(), media.name, "/"};
if(folders.selected() == false) { type = media.type;
information.setText(""); typeMask = {"*.", type};
} else { typeSuffix = {".", type, "/"};
string manifest = {pathname, folders.text(folders.selection(), 0), filterSuffix, "manifest.bml"};
auto document = Markup::Document(file::read(manifest));
information.setText({
document["information/title"].text(), "\n",
document["information/revision"].text(), "\n",
document["information/region"].text(), "\n",
document["information/serial"].text(), "\n"
});
}
}
void LibraryBrowser::setPath(const string& pathname) {
this->pathname = pathname;
refresh(); refresh();
folders.setFocused();
libraryManager->synchronize();
} }
LibraryManager::LibraryManager() { LibraryImport::LibraryImport() {
setTitle("Game Library"); setMargin(5);
setStatusVisible(); information.setText({
setGeometry({128, 128, 960, 640});
windowManager->append(this, "LibraryManager");
layout.setMargin(5);
libraryFrame.append("Import Games");
importLayout.setMargin(5);
importInformation.setText({
"higan manages games in a library. To play a game, you must first import the game.\n" "higan manages games in a library. To play a game, you must first import the game.\n"
"After doing so, the game will appear inside your library, and can then be loaded and played." "After doing so, the game will appear inside your library, and can then be loaded and played."
}); });
importButton.setText("Import Game ..."); importButton.setText("Import Game ...");
libraryFrame.setLayout(0, importLayout); append(information, {~0, 0}, 5);
append(importButton, {0, 0});
importButton.onActivate = {&LibraryImport::onImportActivate, this};
}
void LibraryImport::onImportActivate() {
if(program->ananke.open() == false) {
MessageWindow().setText("ananke must be installed to use this feature").warning();
return;
}
function<string ()> browse = program->ananke.sym("ananke_browse");
if(!browse) return;
string pathname = browse();
if(pathname.empty()) return;
MessageWindow().setText({"Successfully imported ", notdir(pathname.rtrim<1>("/"))}).information();
//after importing game, take user to the relevant game list to show the newly imported title
string type = extension(pathname);
for(signed bootable = 1; bootable >= 0; bootable--) {
unsigned selection = 0;
for(auto& browser : libraryManager->browsers) {
unsigned mode = 0;
for(auto& media : browser->emulator.media) {
if(type == media.type && media.bootable == bootable) {
browser->mediaMode.setSelection(mode);
libraryManager->libraryFrame.setSelection(selection);
libraryManager->onChange();
return;
}
mode++;
}
selection++;
}
}
}
LibraryManager::LibraryManager() {
setTitle("Game Library");
setGeometry({128, 128, 640, 680});
windowManager->append(this, "LibraryManager");
layout.setMargin(5);
bootstrap(); bootstrap();
libraryFrame.setSelection(config->library.selection); libraryFrame.append("Import");
libraryFrame.setLayout(browsers.size(), libraryImport);
loadButton.setText("Load");
unsigned height = Font::size(program->normalFont, " ").height;
append(layout); append(layout);
layout.append(libraryFrame, {~0, ~0}); layout.append(libraryFrame, {~0, ~0}, 5);
importLayout.append(importInformation, {0, 0}, 5); layout.append(informationLayout, {~0, 0});
importLayout.append(importButton, {0, 0}); informationLayout.append(information, {~0, height * 3}, 5);
informationLayout.append(skipButton, {80, 0}, 5);
informationLayout.append(loadButton, {80, 0});
onClose = [&] { onClose = skipButton.onActivate = [&] {
setModal(false); setModal(false);
setVisible(false); setVisible(false);
}; };
libraryFrame.onChange = [&] { libraryFrame.onChange = {&LibraryManager::onChange, this};
config->library.selection = libraryFrame.selection();
};
importButton.onActivate = [&] { //initial config value of -1 defaults to import tab on first launch of higan
if(program->ananke.open() == false) { if(config->library.selection < 0) config->library.selection = browsers.size();
MessageWindow().setText("ananke must be installed to use this feature").warning(); libraryFrame.setSelection(config->library.selection);
return;
}
function<string ()> browse = program->ananke.sym("ananke_browse");
if(!browse) return;
string pathname = browse();
if(pathname.empty()) return;
MessageWindow().setText({"Successfully imported ", notdir(pathname.rtrim<1>("/"))}).information();
string type = extension(pathname);
unsigned selection = 1;
for(auto& browser : browsers) {
if(browser->filter == type) {
browser->refresh();
libraryFrame.setSelection(selection);
break;
}
selection++;
}
};
} }
void LibraryManager::bootstrap() { void LibraryManager::bootstrap() {
unsigned selection = 1; unsigned selection = 0;
string basepath = utility->libraryPath();
vector<string> names;
for(auto& emulator : program->emulator) { for(auto& emulator : program->emulator) {
for(auto& media : emulator->media) { LibraryBrowser* browser = new LibraryBrowser(*emulator);
if(media.bootable == false) continue; libraryFrame.append(emulator->information.name);
if(names.find(media.name)) continue; libraryFrame.setLayout(selection++, *browser);
names.append(media.name); browsers.append(browser);
LibraryBrowser* browser = new LibraryBrowser;
browser->setFilter(media.type);
browser->setPath({basepath, media.name, "/"});
libraryFrame.append(media.name);
libraryFrame.setLayout(selection++, *browser);
browsers.append(browser);
}
}
for(auto& emulator : program->emulator) {
for(auto& media : emulator->media) {
if(media.bootable == true) continue;
if(names.find(media.name)) continue;
names.append(media.name);
LibraryBrowser* browser = new LibraryBrowser;
browser->setFilter(media.type);
browser->setPath({basepath, media.name, "/"});
libraryFrame.append(media.name);
libraryFrame.setLayout(selection++, *browser);
browsers.append(browser);
}
} }
} }
string LibraryManager::load(const string& type) { string LibraryManager::load(const string& type) {
setFocused(); requestedLoadType = type;
unsigned selection = 0;
unsigned selection = 1;
for(auto& browser : browsers) { for(auto& browser : browsers) {
if(browser->filter == type) { unsigned mode = 0;
libraryFrame.setSelection(selection); for(auto& media : browser->emulator.media) {
break; if(type == media.type && media.bootable == false) {
libraryFrame.setSelection(selection);
browser->mediaMode.setSelection(mode);
browser->setMode();
slotLoad = true;
loadPathname = "";
show();
setModal();
slotLoad = false;
browser->mediaMode.setSelection(0);
return loadPathname;
}
mode++;
} }
selection++; selection++;
} }
return ""; //should never occur
slotLoad = true;
loadPathname = "";
setModal(true);
slotLoad = false;
return loadPathname;
} }
void LibraryManager::setVisible(bool visible) { void LibraryManager::onChange() {
setStatusText(""); unsigned selection = libraryFrame.selection();
Window::setVisible(visible); config->library.selection = selection;
if(selection < browsers.size()) {
browsers[selection]->setMode();
} else {
loadButton.setEnabled(false);
}
}
void LibraryManager::setInformation(bool load) {
string text;
if(loaded.size() == 0) {
text = {" \nPlease select a game to load ...\n "};
} else if(loaded.size() == 1 && load == false) {
text = {" \n", loaded[0], "\n "};
} else if(loaded.size() == 1 && load == true) {
text = {loaded[0], " \nPlease select a slot game to load ...\n "};
} else if(loaded.size() == 2 && load == false) {
text = {loaded[0], "\n", loaded[1], "\n "};
} else if(loaded.size() == 2 && load == true) {
text = {loaded[0], "\n", loaded[1], "\nPlease select a slot game to load ..."};
} else if(loaded.size() == 3) {
text = {loaded[0], "\n", loaded[1], "\n", loaded[2]};
}
information.setText(text);
}
void LibraryManager::show() {
if(slotLoad == false) {
loaded.reset();
requestedLoadType.reset();
skipButton.setText("Cancel");
} else {
skipButton.setText("Skip");
}
setInformation(true);
setVisible();
setFocused();
onChange();
}
void LibraryManager::synchronize() {
if(libraryFrame.selection() < browsers.size()) {
auto& emulator = browsers[libraryFrame.selection()]->emulator;
auto& media = emulator.media[browsers[libraryFrame.selection()]->mediaMode.selection()];
if(requestedLoadType.empty()) {
loadButton.setEnabled(media.bootable);
} else {
loadButton.setEnabled(requestedLoadType == media.type);
}
} else {
loadButton.setEnabled(false);
}
} }

View File

@ -3,33 +3,49 @@ struct LibraryBrowser : VerticalLayout {
HorizontalLayout informationLayout; HorizontalLayout informationLayout;
Label informationType; Label informationType;
Label information; Label information;
ComboButton mediaMode;
LibraryBrowser(); LibraryBrowser(Emulator::Interface& emulator);
void onActivate(); void onActivate();
void onChange();
void refresh(); void refresh();
void setFilter(const string& filter); void setMode();
void setInformation();
void setPath(const string& pathname);
string filter; Emulator::Interface& emulator;
string filterMask;
string filterSuffix;
string pathname; string pathname;
string type;
string typeMask;
string typeSuffix;
};
struct LibraryImport : VerticalLayout {
Label information;
Button importButton;
LibraryImport();
void onImportActivate();
}; };
struct LibraryManager : Window { struct LibraryManager : Window {
VerticalLayout layout; VerticalLayout layout;
TabFrame libraryFrame; TabFrame libraryFrame;
VerticalLayout importLayout;
Label importInformation;
Button importButton;
vector<LibraryBrowser*> browsers; vector<LibraryBrowser*> browsers;
LibraryImport libraryImport;
HorizontalLayout informationLayout;
Label information;
Button skipButton;
Button loadButton;
LibraryManager(); LibraryManager();
void bootstrap(); void bootstrap();
string load(const string& type); string load(const string& type);
void setVisible(bool visible = true); void onChange();
void setInformation(bool load);
void show();
void synchronize();
lstring loaded;
string requestedLoadType;
bool slotLoad = false; bool slotLoad = false;
string loadPathname; string loadPathname;
}; };

View File

@ -150,7 +150,7 @@ Presentation::Presentation() {
} }
}; };
loadGame.onActivate = [&] { libraryManager->setVisible(); }; loadGame.onActivate = [&] { libraryManager->show(); };
shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); }; shaderNone.onActivate = [&] { config->video.shader = "None"; utility->updateShader(); };
shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); }; shaderBlur.onActivate = [&] { config->video.shader = "Blur"; utility->updateShader(); };
shaderEmulation.onActivate = [&] { config->video.shader = "Display Emulation"; utility->updateShader(); }; shaderEmulation.onActivate = [&] { config->video.shader = "Display Emulation"; utility->updateShader(); };

View File

@ -8,15 +8,15 @@ void AbstractInput::bind() {
for(auto& mapping : list) { for(auto& mapping : list) {
Input::Type type; Input::Type type;
if(mapping.endswith(".Up")) type = Input::Type::HatUp; if(mapping.endsWith(".Up")) type = Input::Type::HatUp;
else if(mapping.endswith(".Down")) type = Input::Type::HatDown; else if(mapping.endsWith(".Down")) type = Input::Type::HatDown;
else if(mapping.endswith(".Left")) type = Input::Type::HatLeft; else if(mapping.endsWith(".Left")) type = Input::Type::HatLeft;
else if(mapping.endswith(".Right")) type = Input::Type::HatRight; else if(mapping.endsWith(".Right")) type = Input::Type::HatRight;
else if(mapping.endswith(".Lo")) type = Input::Type::AxisLo; else if(mapping.endsWith(".Lo")) type = Input::Type::AxisLo;
else if(mapping.endswith(".Hi")) type = Input::Type::AxisHi; else if(mapping.endsWith(".Hi")) type = Input::Type::AxisHi;
else if(mapping.beginswith("JP") && mapping.find("Axis")) type = Input::Type::Axis; else if(mapping.beginsWith("JP") && mapping.find("Axis")) type = Input::Type::Axis;
else if(mapping.beginswith("MS") && mapping.endswith("axis")) type = Input::Type::MouseAxis; else if(mapping.beginsWith("MS") && mapping.endsWith("axis")) type = Input::Type::MouseAxis;
else if(mapping.beginswith("MS")) type = Input::Type::MouseButton; else if(mapping.beginsWith("MS")) type = Input::Type::MouseButton;
else type = Input::Type::Button; else type = Input::Type::Button;
string decode = mapping; string decode = mapping;

View File

@ -10,7 +10,7 @@ void Utility::setInterface(Emulator::Interface* emulator) {
//load from command-line, etc //load from command-line, etc
void Utility::loadMedia(string pathname) { void Utility::loadMedia(string pathname) {
pathname.transform("\\", "/"); pathname.transform("\\", "/");
if(pathname.endswith("/")) pathname.rtrim("/"); if(pathname.endsWith("/")) pathname.rtrim("/");
if(!directory::exists(pathname)) return; if(!directory::exists(pathname)) return;
string type = extension(pathname); string type = extension(pathname);
@ -47,7 +47,7 @@ void Utility::loadMedia(Emulator::Interface* emulator, Emulator::Interface::Medi
//request from emulation core to load non-volatile media folder //request from emulation core to load non-volatile media folder
void Utility::loadRequest(unsigned id, string name, string type) { void Utility::loadRequest(unsigned id, string name, string type) {
string pathname = libraryManager->load(type); //browser->select({"Load ", name}, type); string pathname = libraryManager->load(type);
if(pathname.empty()) return; if(pathname.empty()) return;
path(id) = pathname; path(id) = pathname;
this->pathname.append(pathname); this->pathname.append(pathname);
@ -306,7 +306,7 @@ void Utility::showMessage(string message) {
string Utility::libraryPath() { string Utility::libraryPath() {
string path = string::read({configpath(), "higan/library.bml"}).strip().ltrim<1>("Path: ").transform("\\", "/"); string path = string::read({configpath(), "higan/library.bml"}).strip().ltrim<1>("Path: ").transform("\\", "/");
if(path.empty()) path = {userpath(), "Emulation/"}; if(path.empty()) path = {userpath(), "Emulation/"};
if(path.endswith("/") == false) path.append("/"); if(path.endsWith("/") == false) path.append("/");
return path; return path;
} }