2013-03-15 13:11:33 +00:00
|
|
|
#if defined(PHOENIX_WINDOWS)
|
|
|
|
#include "../windows/header.hpp"
|
|
|
|
#elif defined(PHOENIX_QT)
|
|
|
|
#include "../qt/header.hpp"
|
|
|
|
#elif defined(PHOENIX_GTK)
|
|
|
|
#include "../gtk/header.hpp"
|
|
|
|
#elif defined(PHOENIX_COCOA)
|
|
|
|
#include "../cocoa/header.hpp"
|
|
|
|
#elif defined(PHOENIX_REFERENCE)
|
|
|
|
#include "../reference/header.hpp"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "core.hpp"
|
|
|
|
using namespace nall;
|
|
|
|
|
|
|
|
namespace phoenix {
|
|
|
|
#include "state.hpp"
|
|
|
|
#include "layout/fixed-layout.cpp"
|
|
|
|
#include "layout/horizontal-layout.cpp"
|
|
|
|
#include "layout/vertical-layout.cpp"
|
|
|
|
}
|
Update to v075r12 release.
byuu says:
phoenix has been completely rewritten from scratch, and bsnes/ui + bsnes/ui-gameboy have been updated to use the new API. Debugger works too. Currently, only phoenix/Qt is completed, and there are two known issues:
1: font sizes of menu items are wrong, I can fix this easily enough
2: there's some sort of multi-second lag when loading games, not sure
what's happening there yet
The new phoenix isn't exactly complete yet, still making some key
changes, and then I'll start on phoenix/Windows and phoenix/GTK+.
The most noticeable difference is that you don't have to give all of the
header paths and PHOENIX_PLATFORM defines when compiling individual GUI
object files. It's only needed for phoenix.cpp itself. The overall
structure of the phoenix source folder is much saner as well for
sync.sh.
I'm really surprised things are working as well as they are for
a two-day power rewrite of an entire phoenix target. The other targets
won't be as bad insofar as the core stuff is completed this time. And
thank god for that, I was about ready to kill myself after writing
dozens of lines like this:
HorizontalSlider::HorizontalSlider() : state(*new State),
base_from_member<pHorizontalSlider&>(*new pHorizontalSlider(*this)),
Widget(base_from_member<pHorizontalSlider&>::value),
p(base_from_member<pHorizontalSlider&>::value) {}
But each platform does have some new, unique problems. phoenix/GTK+ was
acting screwy prior to the rewrite, and will most likely still have
issues. Even more important, one of the major points of this rewrite was
having the new phoenix/core cache widget settings/data, so that I can
destroy and recreate widgets rather than relying on SetParent. This
means that simple copying of the old phoenix/Windows won't work, and
this new method is significantly more involved.
2011-02-15 12:22:37 +00:00
|
|
|
|
2011-02-24 09:25:20 +00:00
|
|
|
#if defined(PHOENIX_WINDOWS)
|
2011-09-05 03:48:23 +00:00
|
|
|
#include "../windows/platform.cpp"
|
2011-02-24 09:25:20 +00:00
|
|
|
#elif defined(PHOENIX_QT)
|
2011-09-05 03:48:23 +00:00
|
|
|
#include "../qt/platform.cpp"
|
2011-02-24 09:27:21 +00:00
|
|
|
#elif defined(PHOENIX_GTK)
|
2011-09-05 03:48:23 +00:00
|
|
|
#include "../gtk/platform.cpp"
|
2013-03-15 13:11:33 +00:00
|
|
|
#elif defined(PHOENIX_COCOA)
|
|
|
|
#include "../cocoa/platform.cpp"
|
2011-02-16 12:35:40 +00:00
|
|
|
#elif defined(PHOENIX_REFERENCE)
|
2011-09-05 03:48:23 +00:00
|
|
|
#include "../reference/platform.cpp"
|
Update to v075r12 release.
byuu says:
phoenix has been completely rewritten from scratch, and bsnes/ui + bsnes/ui-gameboy have been updated to use the new API. Debugger works too. Currently, only phoenix/Qt is completed, and there are two known issues:
1: font sizes of menu items are wrong, I can fix this easily enough
2: there's some sort of multi-second lag when loading games, not sure
what's happening there yet
The new phoenix isn't exactly complete yet, still making some key
changes, and then I'll start on phoenix/Windows and phoenix/GTK+.
The most noticeable difference is that you don't have to give all of the
header paths and PHOENIX_PLATFORM defines when compiling individual GUI
object files. It's only needed for phoenix.cpp itself. The overall
structure of the phoenix source folder is much saner as well for
sync.sh.
I'm really surprised things are working as well as they are for
a two-day power rewrite of an entire phoenix target. The other targets
won't be as bad insofar as the core stuff is completed this time. And
thank god for that, I was about ready to kill myself after writing
dozens of lines like this:
HorizontalSlider::HorizontalSlider() : state(*new State),
base_from_member<pHorizontalSlider&>(*new pHorizontalSlider(*this)),
Widget(base_from_member<pHorizontalSlider&>::value),
p(base_from_member<pHorizontalSlider&>::value) {}
But each platform does have some new, unique problems. phoenix/GTK+ was
acting screwy prior to the rewrite, and will most likely still have
issues. Even more important, one of the major points of this rewrite was
having the new phoenix/core cache widget settings/data, so that I can
destroy and recreate widgets rather than relying on SetParent. This
means that simple copying of the old phoenix/Windows won't work, and
this new method is significantly more involved.
2011-02-15 12:22:37 +00:00
|
|
|
#endif
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
namespace phoenix {
|
|
|
|
|
|
|
|
//Application
|
|
|
|
//===========
|
|
|
|
|
2013-03-21 12:59:01 +00:00
|
|
|
function<void ()> Application::main;
|
2013-03-15 13:11:33 +00:00
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
function<void ()> Application::Windows::onModalBegin;
|
|
|
|
function<void ()> Application::Windows::onModalEnd;
|
|
|
|
|
2013-03-21 12:59:01 +00:00
|
|
|
function<void ()> Application::Cocoa::onAbout;
|
|
|
|
function<void ()> Application::Cocoa::onActivate;
|
|
|
|
function<void ()> Application::Cocoa::onPreferences;
|
|
|
|
function<void ()> Application::Cocoa::onQuit;
|
2013-03-15 13:11:33 +00:00
|
|
|
|
|
|
|
void Application::run() {
|
|
|
|
return pApplication::run();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Application::pendingEvents() {
|
|
|
|
return pApplication::pendingEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Application::processEvents() {
|
|
|
|
return pApplication::processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Application::quit() {
|
|
|
|
applicationState.quit = true;
|
|
|
|
return pApplication::quit();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Application::setName(const string& name) {
|
2013-03-15 13:11:33 +00:00
|
|
|
applicationState.name = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Application::initialize() {
|
|
|
|
static bool initialized = false;
|
|
|
|
if(initialized == false) {
|
|
|
|
initialized = true;
|
|
|
|
return pApplication::initialize();
|
|
|
|
}
|
|
|
|
}
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2012-02-09 12:53:55 +00:00
|
|
|
//Color
|
|
|
|
//=====
|
|
|
|
|
|
|
|
uint32_t Color::rgb() const {
|
|
|
|
return (255 << 24) + (red << 16) + (green << 8) + (blue << 0);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
uint32_t Color::argb() const {
|
2012-02-09 12:53:55 +00:00
|
|
|
return (alpha << 24) + (red << 16) + (green << 8) + (blue << 0);
|
|
|
|
}
|
|
|
|
|
2011-12-12 10:59:53 +00:00
|
|
|
//Geometry
|
|
|
|
//========
|
|
|
|
|
Update to v084r05 release.
(note: before the post announcing this release, there had been
a discussion of a performance optimisation that made the Super Scope
emulation a lot faster, but caused problems for the Justifier perpheral)
byuu says:
Spent a good two hours trying things to no avail.
I was trying to allow the CPU to run ahead, and sync on accesses to
$4016/4017/4201/4213, but that doesn't work because the controllers have
access to strobe IObit at will.
The codebase is really starting to get difficult to work with. I am
guessing because the days of massive development are long over, and the
code is starting to age.
Jonas' fix works 98% of the time, but there's still a few missed shots
here and there. So that's not going to work either.
So ... I give up. I've disabled the speed hack, so that it works 100% of
the time.
Did the same for the Super Scope: it may not have the same problem, but
I like consistency and don't feel like taking the chance.
This doesn't affect the mouse, since the mouse does not latch the
counters to indicate its X/Y position.
Speed hit is 92->82fps (accuracy profile), but only for Super Scope and
Justifier games.
But ... at least it works now. Slow and working is better than fast and
broken.
I appreciate the help in researching the issue, Jonas and krom.
Also pulled in phoenix/Makefile, which simplifies ui/Makefile.
Linux port defaults to GTK+ now. I can't get QGtkStyle to look good on
Debian.
2011-12-18 03:19:45 +00:00
|
|
|
Position Geometry::position() const {
|
2013-03-15 13:11:33 +00:00
|
|
|
return {x, y};
|
Update to v084r05 release.
(note: before the post announcing this release, there had been
a discussion of a performance optimisation that made the Super Scope
emulation a lot faster, but caused problems for the Justifier perpheral)
byuu says:
Spent a good two hours trying things to no avail.
I was trying to allow the CPU to run ahead, and sync on accesses to
$4016/4017/4201/4213, but that doesn't work because the controllers have
access to strobe IObit at will.
The codebase is really starting to get difficult to work with. I am
guessing because the days of massive development are long over, and the
code is starting to age.
Jonas' fix works 98% of the time, but there's still a few missed shots
here and there. So that's not going to work either.
So ... I give up. I've disabled the speed hack, so that it works 100% of
the time.
Did the same for the Super Scope: it may not have the same problem, but
I like consistency and don't feel like taking the chance.
This doesn't affect the mouse, since the mouse does not latch the
counters to indicate its X/Y position.
Speed hit is 92->82fps (accuracy profile), but only for Super Scope and
Justifier games.
But ... at least it works now. Slow and working is better than fast and
broken.
I appreciate the help in researching the issue, Jonas and krom.
Also pulled in phoenix/Makefile, which simplifies ui/Makefile.
Linux port defaults to GTK+ now. I can't get QGtkStyle to look good on
Debian.
2011-12-18 03:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Size Geometry::size() const {
|
2013-03-15 13:11:33 +00:00
|
|
|
return {width, height};
|
Update to v084r05 release.
(note: before the post announcing this release, there had been
a discussion of a performance optimisation that made the Super Scope
emulation a lot faster, but caused problems for the Justifier perpheral)
byuu says:
Spent a good two hours trying things to no avail.
I was trying to allow the CPU to run ahead, and sync on accesses to
$4016/4017/4201/4213, but that doesn't work because the controllers have
access to strobe IObit at will.
The codebase is really starting to get difficult to work with. I am
guessing because the days of massive development are long over, and the
code is starting to age.
Jonas' fix works 98% of the time, but there's still a few missed shots
here and there. So that's not going to work either.
So ... I give up. I've disabled the speed hack, so that it works 100% of
the time.
Did the same for the Super Scope: it may not have the same problem, but
I like consistency and don't feel like taking the chance.
This doesn't affect the mouse, since the mouse does not latch the
counters to indicate its X/Y position.
Speed hit is 92->82fps (accuracy profile), but only for Super Scope and
Justifier games.
But ... at least it works now. Slow and working is better than fast and
broken.
I appreciate the help in researching the issue, Jonas and krom.
Also pulled in phoenix/Makefile, which simplifies ui/Makefile.
Linux port defaults to GTK+ now. I can't get QGtkStyle to look good on
Debian.
2011-12-18 03:19:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string Geometry::text() const {
|
2013-03-15 13:11:33 +00:00
|
|
|
return {x, ",", y, ",", width, ",", height};
|
2011-12-12 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
Geometry::Geometry(const string& text) {
|
2011-12-12 10:59:53 +00:00
|
|
|
lstring part = text.split(",");
|
|
|
|
x = integer(part(0, "256"));
|
|
|
|
y = integer(part(1, "256"));
|
|
|
|
width = decimal(part(2, "256"));
|
|
|
|
height = decimal(part(3, "256"));
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
//Font
|
|
|
|
//====
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Font::serif(unsigned size, const string& style) {
|
2013-03-15 13:11:33 +00:00
|
|
|
return pFont::serif(size, style);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Font::sans(unsigned size, const string& style) {
|
2013-03-15 13:11:33 +00:00
|
|
|
return pFont::sans(size, style);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Font::monospace(unsigned size, const string& style) {
|
2013-03-15 13:11:33 +00:00
|
|
|
return pFont::monospace(size, style);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
Size Font::size(const string& font, const string& text) {
|
2013-03-15 13:11:33 +00:00
|
|
|
return pFont::size(font, text);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
//Desktop
|
|
|
|
//=======
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
Size Desktop::size() {
|
|
|
|
return pDesktop::size();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
Geometry Desktop::workspace() {
|
|
|
|
return pDesktop::workspace();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2014-01-05 09:59:17 +00:00
|
|
|
//Monitor
|
|
|
|
//=======
|
|
|
|
|
|
|
|
unsigned Monitor::count() {
|
|
|
|
return pMonitor::count();
|
|
|
|
}
|
|
|
|
|
|
|
|
Geometry Monitor::geometry(unsigned monitor) {
|
|
|
|
return pMonitor::geometry(monitor);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Monitor::primary() {
|
|
|
|
return pMonitor::primary();
|
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
//Keyboard
|
|
|
|
//========
|
|
|
|
|
|
|
|
bool Keyboard::pressed(Keyboard::Scancode scancode) {
|
|
|
|
return pKeyboard::pressed(scancode);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Keyboard::released(Keyboard::Scancode scancode) {
|
|
|
|
return !pressed(scancode);
|
|
|
|
}
|
|
|
|
|
Update to v088r02 release.
byuu says:
Basically, the current implementation of nall/array is deprecated now.
The old method was for non-reference types, it acted like a vector for
POD types (raw memory allocation instead of placement new construction.)
And for reference types, it acted like an unordered set. Yeah, not good.
As of right now, nall/array is no longer used. The vector type usage was
replaced with actual vectors.
I've created nall/set, which now contains the specialization for
reference types.
nall/set basically acts much like std::unordered_set. No auto-sort, only
one of each type is allowed, automatic growth.
This will be the same both for reference and non-reference types ...
however, the non-reference type wasn't implemented just yet.
Future plans for nall/array are for it to be a statically allocated
block of memory, ala array<type, size>, which is meant for RAII memory
usage.
Have to work on the specifics, eg the size as a template parameter may
be problematic. I'd like to return allocated chunks of memory (eg
file::read) in this container so that I don't have to manually free the
data anymore.
I also removed nall/moduloarray, and moved that into the SNES DSP class,
since that's the only thing that uses it.
2012-04-26 10:56:15 +00:00
|
|
|
vector<bool> Keyboard::state() {
|
2012-01-15 08:29:57 +00:00
|
|
|
return pKeyboard::state();
|
|
|
|
}
|
|
|
|
|
|
|
|
//Mouse
|
|
|
|
//=====
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
Position Mouse::position() {
|
|
|
|
return pMouse::position();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
bool Mouse::pressed(Mouse::Button button) {
|
|
|
|
return pMouse::pressed(button);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
bool Mouse::released(Mouse::Button button) {
|
|
|
|
return !pressed(button);
|
|
|
|
}
|
|
|
|
|
2013-03-19 08:48:50 +00:00
|
|
|
//BrowserWindow
|
|
|
|
//=============
|
|
|
|
|
|
|
|
string BrowserWindow::directory() {
|
|
|
|
return pBrowserWindow::directory(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
string BrowserWindow::open() {
|
|
|
|
return pBrowserWindow::open(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
string BrowserWindow::save() {
|
|
|
|
return pBrowserWindow::save(state);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
BrowserWindow& BrowserWindow::setFilters(const lstring& filters) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.filters = filters;
|
|
|
|
return *this;
|
|
|
|
}
|
2012-01-15 08:29:57 +00:00
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
BrowserWindow& BrowserWindow::setParent(Window& parent) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.parent = &parent;
|
|
|
|
return *this;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
BrowserWindow& BrowserWindow::setPath(const string& path) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.path = path;
|
|
|
|
return *this;
|
2012-01-15 08:29:57 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
BrowserWindow& BrowserWindow::setTitle(const string& title) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.title = title;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
BrowserWindow::BrowserWindow():
|
|
|
|
state(*new State) {
|
|
|
|
}
|
|
|
|
|
|
|
|
BrowserWindow::~BrowserWindow() {
|
|
|
|
delete &state;
|
2012-01-15 08:29:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//MessageWindow
|
|
|
|
//=============
|
|
|
|
|
2013-03-19 08:48:50 +00:00
|
|
|
MessageWindow::Response MessageWindow::error(MessageWindow::Buttons buttons) {
|
|
|
|
state.buttons = buttons;
|
|
|
|
return pMessageWindow::error(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageWindow::Response MessageWindow::information(MessageWindow::Buttons buttons) {
|
|
|
|
state.buttons = buttons;
|
|
|
|
return pMessageWindow::information(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageWindow::Response MessageWindow::question(MessageWindow::Buttons buttons) {
|
|
|
|
state.buttons = buttons;
|
|
|
|
return pMessageWindow::question(state);
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
MessageWindow& MessageWindow::setParent(Window& parent) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.parent = &parent;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
MessageWindow& MessageWindow::setText(const string& text) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.text = text;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
MessageWindow& MessageWindow::setTitle(const string& title) {
|
2013-03-19 08:48:50 +00:00
|
|
|
state.title = title;
|
|
|
|
return *this;
|
2012-01-15 08:29:57 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 08:48:50 +00:00
|
|
|
MessageWindow::Response MessageWindow::warning(MessageWindow::Buttons buttons) {
|
|
|
|
state.buttons = buttons;
|
|
|
|
return pMessageWindow::warning(state);
|
2012-01-15 08:29:57 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
MessageWindow::MessageWindow(const string& text):
|
2013-03-19 08:48:50 +00:00
|
|
|
state(*new State) {
|
|
|
|
state.text = text;
|
2012-01-15 08:29:57 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 08:48:50 +00:00
|
|
|
MessageWindow::~MessageWindow() {
|
|
|
|
delete &state;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
//Object
|
|
|
|
//======
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
Object::Object(pObject& p):
|
2012-01-15 08:29:57 +00:00
|
|
|
p(p) {
|
2013-03-15 13:11:33 +00:00
|
|
|
Application::initialize();
|
2012-01-15 08:29:57 +00:00
|
|
|
p.constructor();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2012-01-15 08:29:57 +00:00
|
|
|
Object::~Object() {
|
|
|
|
p.destructor();
|
|
|
|
delete &p;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
//Timer
|
|
|
|
//=====
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Timer::enabled() const {
|
|
|
|
return state.enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Timer::interval() const {
|
|
|
|
return state.interval;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void Timer::setEnabled(bool enabled) {
|
|
|
|
state.enabled = enabled;
|
|
|
|
return p.setEnabled(enabled);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Timer::setInterval(unsigned interval) {
|
|
|
|
state.interval = interval;
|
|
|
|
return p.setInterval(interval);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Timer::Timer():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pTimer&>(*new pTimer(*this)),
|
|
|
|
Object(base_from_member<pTimer&>::value),
|
|
|
|
p(base_from_member<pTimer&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer::~Timer() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Window
|
|
|
|
//======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::append(Layout& layout) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(state.layout.append(layout)) {
|
2013-11-28 10:29:01 +00:00
|
|
|
layout.Sizable::state.parent = nullptr;
|
|
|
|
layout.Sizable::state.window = this;
|
2011-09-05 03:48:23 +00:00
|
|
|
p.append(layout);
|
Update to v082r15 release.
byuu says:
7.5 hours of power coding. Das Keyboard definitely helped (but didn't
eliminate) RSI, neato.
Okay, the NES resampler was using 315 / 88.8 by mistake, so the output
rate was wrong, causing way more video/audio stuttering than necessary.
STILL forgot the NES APU frame IRQ clear thing on $4015 reads, blah. Why
do I always remember things right after uploading the WIPs?
Recreated the input manager with a new design, works much nicer than the
old one, a whole lot less duplicated code.
Recreated the input settings window to work with the new multi-system
emulation.
All input settings are saved to their own configuration file, input.cfg.
Going to batch folder for now.
Okay, so the new input settings window ... basically there are now three
drop-downs, and I'm not even trying to label them anymore.
They are primary, secondary, tertiary selectors for the listed group
below. Examples:
"NES -> Controller Port 1 -> Gamepad"
"SNES -> Controller Port 2 -> Super Scope"
"User Interface -> Hotkeys -> Save States"
I am aware that "Clear" gets disabled when assigning. I will work on
that later, being lazy for now and disabling the entire window. Have to
add the mouse binders back, too.
Escape and modifiers are both mappable as individual keys now. If you
want to clear, click the damn clear button :P
Oh, and all input goes to all windows for now. That'll be fixed too when
input focus stuff is re-added.
2011-09-17 06:42:17 +00:00
|
|
|
layout.synchronizeLayout();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::append(Menu& menu) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(state.menu.append(menu)) {
|
2013-11-28 10:29:01 +00:00
|
|
|
menu.Action::state.window = this;
|
2011-09-05 03:48:23 +00:00
|
|
|
p.append(menu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::append(Widget& widget) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(state.widget.append(widget)) {
|
2013-11-28 10:29:01 +00:00
|
|
|
widget.Sizable::state.window = this;
|
2011-09-05 03:48:23 +00:00
|
|
|
p.append(widget);
|
2013-11-28 10:29:01 +00:00
|
|
|
widget.synchronizeLayout();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
Color Window::backgroundColor() const {
|
|
|
|
return state.backgroundColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::droppable() const {
|
|
|
|
return state.droppable;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Geometry Window::frameGeometry() {
|
|
|
|
Geometry geometry = p.geometry();
|
|
|
|
Geometry margin = p.frameMargin();
|
|
|
|
return {
|
|
|
|
geometry.x - margin.x, geometry.y - margin.y,
|
|
|
|
geometry.width + margin.width, geometry.height + margin.height
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
Geometry Window::frameMargin() {
|
|
|
|
return p.frameMargin();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::focused() {
|
|
|
|
return p.focused();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Window::fullScreen() const {
|
Update to v082r16 release.
byuu says:
Binary output is once again called bsnes. No versioning on the title
without a system cartridge loaded. Still saving config files to
.config/batch for now.
Finally fixed NES APU frame IRQ clearing on $4015 reads.
Added mouse button/axis binding through buttons on the input capture
window.
Added advanced settings window with driver selection and focus policy
settings. Will show your default driver properly if none are selected
now, unlike old bsnes.
That exposed a small bug where phoenix isn't removing widgets on
Layout::remove, worked around it for now by hiding the panels. Damn,
sick of working on phoenix.
Added all missing input controllers, which can all now be mapped, and
bound them to the main menu, and added NES support for selecting "no
connected controller."
Added mouse capture and the requisite tools menu option for it.
Added WindowManager class that keeps track of both position and size now
(eg full geometry), so now you can resize your windows and save the
settings, unlike old bsnes.
WindowManager has more stringent geometry checks. The *client area* (not
the window border) can't be below 0,0 or above the width/height of three
30" monitors. If you have 4+ 30" monitors, then fuck you :P
settings.cfg is now also saved, captures all currently available
settings. Right now, there's only one path for the file browser to
remember. I will probably make this per-system later.
FileBrowser has been made a bit more friendly. The bottom left tells you
what type of files the list is filtered by (so you see "*.sfc" for
SNES), and the bottom right has an open button that can enter folders or
load files.
Added video shader support.
Fixed nall/dsp variadic-channel support, was only outputting the left
channel.
2011-09-19 12:25:56 +00:00
|
|
|
return state.fullScreen;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Geometry Window::geometry() {
|
|
|
|
return p.geometry();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Window::menuFont() const {
|
|
|
|
return state.menuFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::menuVisible() const {
|
|
|
|
return state.menuVisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::modal() const {
|
|
|
|
return state.modal;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::remove(Layout& layout) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(state.layout.remove(layout)) {
|
|
|
|
p.remove(layout);
|
2013-11-28 10:29:01 +00:00
|
|
|
layout.Sizable::state.window = nullptr;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::remove(Menu& menu) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(state.menu.remove(menu)) {
|
|
|
|
p.remove(menu);
|
2013-11-28 10:29:01 +00:00
|
|
|
menu.Action::state.window = nullptr;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::remove(Widget& widget) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(state.widget.remove(widget)) {
|
|
|
|
p.remove(widget);
|
2013-11-28 10:29:01 +00:00
|
|
|
widget.Sizable::state.window = nullptr;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Window::resizable() const {
|
|
|
|
return state.resizable;
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Window::setBackgroundColor(Color color) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.backgroundColorOverride = true;
|
|
|
|
state.backgroundColor = color;
|
|
|
|
return p.setBackgroundColor(color);
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Window::setDroppable(bool droppable) {
|
|
|
|
state.droppable = droppable;
|
|
|
|
return p.setDroppable(droppable);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::setFrameGeometry(Geometry geometry) {
|
2011-09-05 03:48:23 +00:00
|
|
|
Geometry margin = p.frameMargin();
|
|
|
|
return setGeometry({
|
|
|
|
geometry.x + margin.x, geometry.y + margin.y,
|
|
|
|
geometry.width - margin.width, geometry.height - margin.height
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::setFocused() {
|
|
|
|
return p.setFocused();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::setFullScreen(bool fullScreen) {
|
|
|
|
state.fullScreen = fullScreen;
|
|
|
|
return p.setFullScreen(fullScreen);
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Window::setGeometry(Geometry geometry) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.geometry = geometry;
|
|
|
|
return p.setGeometry(geometry);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::setMenuFont(const string& font) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.menuFont = font;
|
|
|
|
return p.setMenuFont(font);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::setMenuVisible(bool visible) {
|
|
|
|
state.menuVisible = visible;
|
|
|
|
return p.setMenuVisible(visible);
|
|
|
|
}
|
|
|
|
|
Update to v088r11 release.
byuu says:
Changelog:
- phoenix has added Window::setModal(bool modal = true);
- file dialog is now modal. This allows emulation cores to request data
and get it immediately before continuing the loading process
- save data is hooked up for most systems, still need to handle
subsystem slot saves (Sufami Turbo, basically.)
- toggle fullscreen key binding added (Alt+Enter for now. I think F11 is
probably better though, Enter is often mapped to game start button.)
- video scaling is in (center, scale, stretch), works the same in
windowed and fullscreen mode (stretch hides resize window option), all
in the settings menu now
- enough structure to map all saved paths for the browser and to load
BS-X slotted carts, BS-X carts, single Sufami Turbo carts
Caveats / Missing:
- Super Game Boy input doesn't work yet (due to change in callback
binding)
- doesn't load secondary Sufami Turbo slot yet
- BS-X BIOS isn't show the data pack games to load for some reason (ugh,
I hate the shit out of debugging BS-X stuff ...)
- need mute audio, sync audio+video toggle, save/load state menu and
quick keys, XML mapping information window
- need cheat editor and cheat database
- need state manager
- need to sort subsystems below main systems in load menu (basically
just see if media.slot.size() > 0)
- need video shaders (will probably leave off filters for the time being
... due to that 24/30-bit thing)
- need video adjustments (contrast etc, overscan masks)
- need audio adjustments (frequency, latency, resampler, volume,
per-system frequency)
- need driver selection and input focus policy (driver crash detection
would be nice too)
- need NSS DIP switch settings (that one will be really fun)
- need to save and load window geometry settings
- need to hook up controller selection (won't be fun), create a map to
hide controllers with no inputs to reassign
2012-05-03 12:36:47 +00:00
|
|
|
void Window::setModal(bool modal) {
|
|
|
|
state.modal = modal;
|
|
|
|
return p.setModal(modal);
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void Window::setResizable(bool resizable) {
|
|
|
|
state.resizable = resizable;
|
|
|
|
return p.setResizable(resizable);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::setStatusFont(const string& font) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.statusFont = font;
|
|
|
|
return p.setStatusFont(font);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::setStatusText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.statusText = text;
|
|
|
|
return p.setStatusText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::setStatusVisible(bool visible) {
|
|
|
|
state.statusVisible = visible;
|
|
|
|
return p.setStatusVisible(visible);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::setTitle(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.title = text;
|
|
|
|
return p.setTitle(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::setVisible(bool visible) {
|
|
|
|
state.visible = visible;
|
2011-10-24 11:35:34 +00:00
|
|
|
synchronizeLayout();
|
2011-09-05 03:48:23 +00:00
|
|
|
return p.setVisible(visible);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::setWidgetFont(const string& font) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.widgetFont = font;
|
|
|
|
return p.setWidgetFont(font);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Window::setWindowGeometry(Geometry geometry) {
|
|
|
|
Geometry margin = p.frameMargin();
|
|
|
|
return setGeometry({
|
|
|
|
geometry.x + margin.x, geometry.y + margin.y,
|
|
|
|
geometry.width, geometry.height
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
string Window::statusFont() const {
|
|
|
|
return state.statusFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
string Window::statusText() const {
|
2011-09-19 12:34:18 +00:00
|
|
|
return state.statusText;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Window::statusVisible() const {
|
|
|
|
return state.statusVisible;
|
|
|
|
}
|
|
|
|
|
Update to v082r15 release.
byuu says:
7.5 hours of power coding. Das Keyboard definitely helped (but didn't
eliminate) RSI, neato.
Okay, the NES resampler was using 315 / 88.8 by mistake, so the output
rate was wrong, causing way more video/audio stuttering than necessary.
STILL forgot the NES APU frame IRQ clear thing on $4015 reads, blah. Why
do I always remember things right after uploading the WIPs?
Recreated the input manager with a new design, works much nicer than the
old one, a whole lot less duplicated code.
Recreated the input settings window to work with the new multi-system
emulation.
All input settings are saved to their own configuration file, input.cfg.
Going to batch folder for now.
Okay, so the new input settings window ... basically there are now three
drop-downs, and I'm not even trying to label them anymore.
They are primary, secondary, tertiary selectors for the listed group
below. Examples:
"NES -> Controller Port 1 -> Gamepad"
"SNES -> Controller Port 2 -> Super Scope"
"User Interface -> Hotkeys -> Save States"
I am aware that "Clear" gets disabled when assigning. I will work on
that later, being lazy for now and disabling the entire window. Have to
add the mouse binders back, too.
Escape and modifiers are both mappable as individual keys now. If you
want to clear, click the damn clear button :P
Oh, and all input goes to all windows for now. That'll be fixed too when
input focus stuff is re-added.
2011-09-17 06:42:17 +00:00
|
|
|
void Window::synchronizeLayout() {
|
2013-03-15 13:11:33 +00:00
|
|
|
if(visible() && applicationState.quit == false) setGeometry(geometry());
|
2011-10-24 11:35:34 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Window::title() const {
|
|
|
|
return state.title;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::visible() const {
|
2011-10-24 11:35:34 +00:00
|
|
|
return state.visible;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Window::widgetFont() const {
|
|
|
|
return state.widgetFont;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Window::Window():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pWindow&>(*new pWindow(*this)),
|
|
|
|
Object(base_from_member<pWindow&>::value),
|
|
|
|
p(base_from_member<pWindow&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Window::~Window() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Action
|
|
|
|
//======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Action::enabled() const {
|
2011-09-09 04:16:25 +00:00
|
|
|
return state.enabled;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void Action::setEnabled(bool enabled) {
|
|
|
|
state.enabled = enabled;
|
|
|
|
return p.setEnabled(enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Action::setVisible(bool visible) {
|
|
|
|
state.visible = visible;
|
|
|
|
return p.setVisible(visible);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Action::visible() const {
|
2011-09-09 04:16:25 +00:00
|
|
|
return state.visible;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
Action::Action(pAction& p):
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
|
|
|
Object(p),
|
|
|
|
p(p) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Action::~Action() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Menu
|
|
|
|
//====
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void Menu::append(const group<Action>& list) {
|
|
|
|
for(auto& action : list) {
|
2012-01-15 08:29:57 +00:00
|
|
|
if(state.action.append(action)) {
|
|
|
|
action.state.menu = this;
|
|
|
|
p.append(action);
|
|
|
|
}
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
image Menu::image() const {
|
|
|
|
return state.image;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void Menu::remove(const group<Action>& list) {
|
|
|
|
for(auto& action : list) {
|
2012-01-15 08:29:57 +00:00
|
|
|
if(state.action.remove(action)) {
|
2013-03-15 13:11:33 +00:00
|
|
|
action.state.menu = nullptr;
|
2012-01-15 08:29:57 +00:00
|
|
|
return p.remove(action);
|
|
|
|
}
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Menu::setImage(const nall::image& image) {
|
2012-01-26 06:50:09 +00:00
|
|
|
state.image = image;
|
|
|
|
return p.setImage(image);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Menu::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Menu::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Menu::Menu():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pMenu&>(*new pMenu(*this)),
|
|
|
|
Action(base_from_member<pMenu&>::value),
|
|
|
|
p(base_from_member<pMenu&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Menu::~Menu() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Separator
|
|
|
|
//=========
|
|
|
|
|
|
|
|
Separator::Separator():
|
|
|
|
base_from_member<pSeparator&>(*new pSeparator(*this)),
|
|
|
|
Action(base_from_member<pSeparator&>::value),
|
|
|
|
p(base_from_member<pSeparator&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Separator::~Separator() {
|
|
|
|
p.destructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
//Item
|
|
|
|
//====
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
image Item::image() const {
|
|
|
|
return state.image;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Item::setImage(const nall::image& image) {
|
2012-01-15 08:29:57 +00:00
|
|
|
state.image = image;
|
|
|
|
return p.setImage(image);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Item::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Item::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Item::Item():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pItem&>(*new pItem(*this)),
|
|
|
|
Action(base_from_member<pItem&>::value),
|
|
|
|
p(base_from_member<pItem&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Item::~Item() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//CheckItem
|
|
|
|
//=========
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool CheckItem::checked() const {
|
|
|
|
return state.checked;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CheckItem::setChecked(bool checked) {
|
|
|
|
state.checked = checked;
|
|
|
|
return p.setChecked(checked);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void CheckItem::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string CheckItem::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
CheckItem::CheckItem():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pCheckItem&>(*new pCheckItem(*this)),
|
|
|
|
Action(base_from_member<pCheckItem&>::value),
|
|
|
|
p(base_from_member<pCheckItem&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckItem::~CheckItem() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//RadioItem
|
|
|
|
//=========
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void RadioItem::group(const nall::group<RadioItem>& list) {
|
|
|
|
for(auto& item : list) item.p.setGroup(item.state.group = list);
|
|
|
|
if(list.size()) list.first().setChecked();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool RadioItem::checked() const {
|
|
|
|
return state.checked;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RadioItem::setChecked() {
|
2013-05-02 11:25:45 +00:00
|
|
|
for(auto& item : state.group) item.state.checked = false;
|
2011-09-05 03:48:23 +00:00
|
|
|
state.checked = true;
|
|
|
|
return p.setChecked();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void RadioItem::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string RadioItem::text() const {
|
Update to v088r14 release.
byuu says:
Changelog:
- added NSS DIP switch settings window (when loading NSS carts with
appropriate manifest.xml file)
- added video shader selection (they go in ~/.config/bsnes/Video
Shaders/ now)
- added driver selection
- added timing settings (not only allows video/audio settings, also has
code to dynamically compute the values for you ... and it actually
works pretty good!)
- moved "None" controller device to bottom of list (it is the least
likely to be used, after all)
- added Interface::path() to support MSU1, USART, Link
- input and hotkey mappings remember list position after assignment
- and more!
target-ethos now has all of the functionality of target-ui, and more.
Final code size for the port is 101.2KB (ethos) vs 167.6KB (ui).
A ~67% reduction in code size, yet it does even more! And you can add or
remove an entire system with only three lines of code (Makefile include,
header include, interface append.)
The only problem left is that the BS-X BIOS won't load the BS Zelda no
Densetsu file.
I can't figure out why it's not working, would appreciate any
assistance, but otherwise I'm probably just going to leave it broken for
v089, sorry.
So the show stoppers for a new release at this point are:
- fix laevateinn to compile with the new interface changes (shouldn't be
too hard, it'll still use the old, direct interface.)
- clean up Emulator::Interface as much as possible (trim down
Information, mediaRequest should use an alternate struct designed to
load firmware / slots separately)
- enhance purify to strip SNES ROM headers, and it really needs a GUI
interface
- it would be highly desirable to make a launcher that can create
a cartridge folder from an existing ROM set (* ethos will need to
accept command-line arguments for this.)
- probably need to remember which controller was selected in each port
for each system across runs
- need to fix the cursor for Super Scope / Justifier games (move from
19-bit to 32-bit colors broke it)
- have to refactor that cache.(hv)offset thing to fix ASP
2012-05-06 23:27:42 +00:00
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
RadioItem::RadioItem():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pRadioItem&>(*new pRadioItem(*this)),
|
|
|
|
Action(base_from_member<pRadioItem&>::value),
|
|
|
|
p(base_from_member<pRadioItem&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
RadioItem::~RadioItem() {
|
2013-05-02 11:25:45 +00:00
|
|
|
for(auto& item : state.group) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(&item != this) item.state.group.remove(*this);
|
|
|
|
}
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Sizable
|
|
|
|
//=======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Sizable::enabled() const {
|
|
|
|
return state.enabled;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Sizable::enabledToAll() const {
|
|
|
|
if(state.enabled == false) return false;
|
|
|
|
if(state.parent) return state.parent->enabledToAll();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Layout* Sizable::layout() const {
|
|
|
|
if(state.parent && dynamic_cast<Layout*>(state.parent)) return (Layout*)state.parent;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sizable* Sizable::parent() const {
|
|
|
|
return state.parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sizable::visible() const {
|
|
|
|
return state.visible;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sizable::visibleToAll() const {
|
|
|
|
if(state.visible == false) return false;
|
|
|
|
if(state.parent) return state.parent->visibleToAll();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Window* Sizable::window() const {
|
2011-09-05 03:48:23 +00:00
|
|
|
return state.window;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
Sizable::Sizable(pSizable& p):
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
|
|
|
Object(p),
|
|
|
|
p(p) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Sizable::~Sizable() {
|
|
|
|
if(layout()) layout()->remove(*this);
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Layout
|
|
|
|
//======
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void Layout::append(Sizable& sizable) {
|
2013-11-28 10:29:01 +00:00
|
|
|
sizable.state.parent = this;
|
|
|
|
sizable.state.window = Sizable::state.window;
|
2011-09-05 03:48:23 +00:00
|
|
|
|
|
|
|
if(dynamic_cast<Layout*>(&sizable)) {
|
2013-11-28 10:29:01 +00:00
|
|
|
Layout& layout = (Layout&)sizable;
|
Update to v082r15 release.
byuu says:
7.5 hours of power coding. Das Keyboard definitely helped (but didn't
eliminate) RSI, neato.
Okay, the NES resampler was using 315 / 88.8 by mistake, so the output
rate was wrong, causing way more video/audio stuttering than necessary.
STILL forgot the NES APU frame IRQ clear thing on $4015 reads, blah. Why
do I always remember things right after uploading the WIPs?
Recreated the input manager with a new design, works much nicer than the
old one, a whole lot less duplicated code.
Recreated the input settings window to work with the new multi-system
emulation.
All input settings are saved to their own configuration file, input.cfg.
Going to batch folder for now.
Okay, so the new input settings window ... basically there are now three
drop-downs, and I'm not even trying to label them anymore.
They are primary, secondary, tertiary selectors for the listed group
below. Examples:
"NES -> Controller Port 1 -> Gamepad"
"SNES -> Controller Port 2 -> Super Scope"
"User Interface -> Hotkeys -> Save States"
I am aware that "Clear" gets disabled when assigning. I will work on
that later, being lazy for now and disabling the entire window. Have to
add the mouse binders back, too.
Escape and modifiers are both mappable as individual keys now. If you
want to clear, click the damn clear button :P
Oh, and all input goes to all windows for now. That'll be fixed too when
input focus stuff is re-added.
2011-09-17 06:42:17 +00:00
|
|
|
layout.synchronizeLayout();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(dynamic_cast<Widget*>(&sizable)) {
|
2013-11-28 10:29:01 +00:00
|
|
|
Widget& widget = (Widget&)sizable;
|
2011-09-05 03:48:23 +00:00
|
|
|
if(sizable.window()) sizable.window()->append(widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void Layout::remove(Sizable& sizable) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(dynamic_cast<Widget*>(&sizable)) {
|
2013-11-28 10:29:01 +00:00
|
|
|
Widget& widget = (Widget&)sizable;
|
2011-09-05 03:48:23 +00:00
|
|
|
if(sizable.window()) sizable.window()->remove(widget);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
sizable.state.parent = nullptr;
|
2013-03-15 13:11:33 +00:00
|
|
|
sizable.state.window = nullptr;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Layout::reset() {
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Layout::Layout():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pLayout&>(*new pLayout(*this)),
|
|
|
|
Sizable(base_from_member<pLayout&>::value),
|
|
|
|
p(base_from_member<pLayout&>::value) {
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
Layout::Layout(pLayout& p):
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
|
|
|
base_from_member<pLayout&>(p),
|
|
|
|
Sizable(p),
|
|
|
|
p(p) {
|
|
|
|
}
|
|
|
|
|
|
|
|
Layout::~Layout() {
|
|
|
|
if(layout()) layout()->remove(*this);
|
2013-11-28 10:29:01 +00:00
|
|
|
if(window()) window()->remove(*this);
|
2011-09-05 03:48:23 +00:00
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Widget
|
|
|
|
//======
|
|
|
|
|
Update to higan v091r14 and ananke v00r03 releases.
byuu says:
higan changelog:
- generates title displayed in emulator window by asking the core
- core builds title solely from "information/title" ... if it's not
there, you don't get a title at all
- sub-system load menu is gone ... since there are multiple revisions of
the SGB, this never really worked well anyway
- to load an SGB, BS-X or ST cartridge, load the base cartridge first
- "File->Load Game" moved to "Load->Import Game" ... may cause a bit of
confusion to new users, but I don't like having a single-item menu,
we'll just have to explain it to new users
- browser window redone to look like ananke
- home button here goes to ~/Emulation rather than just ~ like ananke,
since this is the home of game folders
- game folder icon is now the executable icon for the Tango theme
(orange diamond), meant to represent a complete game rather than
a game file or archive
ananke changelog:
- outputs GBC games to "Game Boy Color/" instead of "Game Boy/"
- adds the file basename to "information/title"
Known issues:
- using ananke to load a GB game trips the Super Famicom SGB mode and
fails (need to make the full-path auto-detection ignore non-bootable
systems)
- need to dump and test some BS-X media before releasing
- ananke lacks BS-X Satellaview cartridge support
- v092 isn't going to let you retarget the ananke/higan game folder path
of ~/Emulation, you will have to wait for a future version if that
bothers you so greatly
[Later, after the v092 release, byuu posted this additional changelog:
- kill laevateinn
- add title()
- add bootable, remove load
- combine file, library
- combine [][][] paths
- fix SFC subtype handling XML->BML
- update file browser to use buttons
- update file browser keyboard handling
- update system XML->BML
- fix sufami turbo hashing
- remove Cartridge::manifest
]
2012-12-25 05:31:55 +00:00
|
|
|
bool Widget::focused() {
|
|
|
|
return p.focused();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Widget::font() const {
|
2011-09-05 03:48:23 +00:00
|
|
|
return state.font;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
Geometry Widget::geometry() const {
|
2011-09-05 03:48:23 +00:00
|
|
|
return state.geometry;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
Size Widget::minimumSize() {
|
|
|
|
return p.minimumSize();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Widget::setEnabled(bool enabled) {
|
2013-11-28 10:29:01 +00:00
|
|
|
Sizable::state.enabled = enabled;
|
2011-09-05 03:48:23 +00:00
|
|
|
return p.setEnabled(enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Widget::setFocused() {
|
|
|
|
return p.setFocused();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Widget::setFont(const string& font) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.font = font;
|
|
|
|
return p.setFont(font);
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Widget::setGeometry(Geometry geometry) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.geometry = geometry;
|
|
|
|
return p.setGeometry(geometry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Widget::setVisible(bool visible) {
|
2013-11-28 10:29:01 +00:00
|
|
|
Sizable::state.visible = visible;
|
2011-09-05 03:48:23 +00:00
|
|
|
return p.setVisible(visible);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Widget::synchronizeLayout() {
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Widget::Widget():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pWidget&>(*new pWidget(*this)),
|
|
|
|
Sizable(base_from_member<pWidget&>::value),
|
|
|
|
p(base_from_member<pWidget&>::value) {
|
|
|
|
state.abstract = true;
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
Widget::Widget(pWidget& p):
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
|
|
|
base_from_member<pWidget&>(p),
|
|
|
|
Sizable(base_from_member<pWidget&>::value),
|
|
|
|
p(base_from_member<pWidget&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget::~Widget() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Button
|
|
|
|
//======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
image Button::image() const {
|
|
|
|
return state.image;
|
|
|
|
}
|
|
|
|
|
|
|
|
Orientation Button::orientation() const {
|
|
|
|
return state.orientation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Button::setImage(const nall::image& image, Orientation orientation) {
|
2012-01-15 08:29:57 +00:00
|
|
|
state.image = image;
|
|
|
|
state.orientation = orientation;
|
|
|
|
return p.setImage(image, orientation);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Button::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
nall::string Button::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Button::Button():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pButton&>(*new pButton(*this)),
|
|
|
|
Widget(base_from_member<pButton&>::value),
|
|
|
|
p(base_from_member<pButton&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Button::~Button() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Canvas
|
|
|
|
//======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
Color Canvas::color() const {
|
|
|
|
return state.color;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t* Canvas::data() const {
|
2011-11-04 11:57:54 +00:00
|
|
|
return state.data;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Canvas::droppable() const {
|
|
|
|
return state.droppable;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<Color> Canvas::gradient() const {
|
|
|
|
return state.gradient;
|
|
|
|
}
|
|
|
|
|
|
|
|
image Canvas::image() const {
|
|
|
|
return state.image;
|
|
|
|
}
|
|
|
|
|
|
|
|
Canvas::Mode Canvas::mode() const {
|
|
|
|
return state.mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setColor(Color color) {
|
|
|
|
state.color = color;
|
|
|
|
return setMode(Canvas::Mode::Color);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setData() {
|
|
|
|
if(state.width == 0 || state.height == 0) return; //dynamic sizing not supported in Mode::Data
|
|
|
|
return setMode(Canvas::Mode::Data);
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Canvas::setDroppable(bool droppable) {
|
|
|
|
state.droppable = droppable;
|
|
|
|
return p.setDroppable(droppable);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Canvas::setGradient(Color topLeft, Color topRight, Color bottomLeft, Color bottomRight) {
|
|
|
|
state.gradient[0] = topLeft;
|
|
|
|
state.gradient[1] = topRight;
|
|
|
|
state.gradient[2] = bottomLeft;
|
|
|
|
state.gradient[3] = bottomRight;
|
|
|
|
return setMode(Canvas::Mode::Gradient);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setHorizontalGradient(Color left, Color right) {
|
|
|
|
state.gradient[0] = state.gradient[2] = left;
|
|
|
|
state.gradient[1] = state.gradient[3] = right;
|
|
|
|
return setMode(Canvas::Mode::Gradient);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setImage(const nall::image& image) {
|
|
|
|
state.image = image;
|
|
|
|
return setMode(Canvas::Mode::Image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Canvas::setMode(Mode mode) {
|
|
|
|
state.mode = mode;
|
|
|
|
return p.setMode(mode);
|
2011-11-04 11:57:54 +00:00
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Canvas::setSize(Size size) {
|
2013-11-28 10:29:01 +00:00
|
|
|
if(size.width == Size::Maximum) size.width = 0;
|
|
|
|
if(size.height == Size::Maximum) size.height = 0;
|
2011-11-04 11:57:54 +00:00
|
|
|
state.width = size.width;
|
|
|
|
state.height = size.height;
|
|
|
|
delete[] state.data;
|
2013-11-28 10:29:01 +00:00
|
|
|
state.data = new uint32_t[state.width * state.height]();
|
|
|
|
return setMode(state.mode);
|
2011-11-04 11:57:54 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Canvas::setVerticalGradient(Color top, Color bottom) {
|
|
|
|
state.gradient[0] = state.gradient[1] = top;
|
|
|
|
state.gradient[2] = state.gradient[3] = bottom;
|
|
|
|
return setMode(Canvas::Mode::Gradient);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
Size Canvas::size() const {
|
|
|
|
return {state.width, state.height};
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Canvas::Canvas():
|
2011-11-04 11:57:54 +00:00
|
|
|
state(*new State),
|
2011-09-05 03:48:23 +00:00
|
|
|
base_from_member<pCanvas&>(*new pCanvas(*this)),
|
|
|
|
Widget(base_from_member<pCanvas&>::value),
|
|
|
|
p(base_from_member<pCanvas&>::value) {
|
2013-11-28 10:29:01 +00:00
|
|
|
state.data = new uint32_t[state.width * state.height]();
|
2011-09-05 03:48:23 +00:00
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Canvas::~Canvas() {
|
|
|
|
p.destructor();
|
2011-11-04 11:57:54 +00:00
|
|
|
delete[] state.data;
|
|
|
|
delete &state;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
//CheckButton
|
|
|
|
//===========
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool CheckButton::checked() const {
|
|
|
|
return state.checked;
|
|
|
|
}
|
|
|
|
|
|
|
|
image CheckButton::image() const {
|
|
|
|
return state.image;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void CheckButton::setChecked(bool checked) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.checked = checked;
|
|
|
|
return p.setChecked(checked);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void CheckButton::setImage(const nall::image& image, Orientation orientation) {
|
|
|
|
state.image = image;
|
|
|
|
state.orientation = orientation;
|
|
|
|
return p.setImage(image, orientation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CheckButton::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string CheckButton::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
CheckButton::CheckButton():
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
2013-03-15 13:11:33 +00:00
|
|
|
base_from_member<pCheckButton&>(*new pCheckButton(*this)),
|
|
|
|
Widget(base_from_member<pCheckButton&>::value),
|
|
|
|
p(base_from_member<pCheckButton&>::value) {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
CheckButton::~CheckButton() {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
//CheckLabel
|
|
|
|
//==========
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool CheckLabel::checked() const {
|
|
|
|
return state.checked;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void CheckLabel::setChecked(bool checked) {
|
|
|
|
state.checked = checked;
|
|
|
|
return p.setChecked(checked);
|
2012-06-25 12:49:39 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void CheckLabel::setText(const string& text) {
|
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
string CheckLabel::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckLabel::CheckLabel():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pCheckLabel&>(*new pCheckLabel(*this)),
|
|
|
|
Widget(base_from_member<pCheckLabel&>::value),
|
|
|
|
p(base_from_member<pCheckLabel&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckLabel::~CheckLabel() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//ComboButton
|
|
|
|
//===========
|
|
|
|
|
|
|
|
void ComboButton::append(const string& text) {
|
|
|
|
state.text.append(text);
|
|
|
|
return p.append(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboButton::remove(unsigned selection) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.text.remove(selection);
|
|
|
|
p.remove(selection);
|
2012-06-25 12:49:39 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void ComboButton::reset() {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.selection = 0;
|
|
|
|
state.text.reset();
|
|
|
|
return p.reset();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned ComboButton::rows() const {
|
|
|
|
return state.text.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ComboButton::selection() const {
|
|
|
|
return state.selection;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ComboButton::setSelection(unsigned selection) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.selection = selection;
|
|
|
|
return p.setSelection(selection);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ComboButton::setText(unsigned selection, const string& text) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.text[selection] = text;
|
|
|
|
p.setText(selection, text);
|
Update to v088r14 release.
byuu says:
Changelog:
- added NSS DIP switch settings window (when loading NSS carts with
appropriate manifest.xml file)
- added video shader selection (they go in ~/.config/bsnes/Video
Shaders/ now)
- added driver selection
- added timing settings (not only allows video/audio settings, also has
code to dynamically compute the values for you ... and it actually
works pretty good!)
- moved "None" controller device to bottom of list (it is the least
likely to be used, after all)
- added Interface::path() to support MSU1, USART, Link
- input and hotkey mappings remember list position after assignment
- and more!
target-ethos now has all of the functionality of target-ui, and more.
Final code size for the port is 101.2KB (ethos) vs 167.6KB (ui).
A ~67% reduction in code size, yet it does even more! And you can add or
remove an entire system with only three lines of code (Makefile include,
header include, interface append.)
The only problem left is that the BS-X BIOS won't load the BS Zelda no
Densetsu file.
I can't figure out why it's not working, would appreciate any
assistance, but otherwise I'm probably just going to leave it broken for
v089, sorry.
So the show stoppers for a new release at this point are:
- fix laevateinn to compile with the new interface changes (shouldn't be
too hard, it'll still use the old, direct interface.)
- clean up Emulator::Interface as much as possible (trim down
Information, mediaRequest should use an alternate struct designed to
load firmware / slots separately)
- enhance purify to strip SNES ROM headers, and it really needs a GUI
interface
- it would be highly desirable to make a launcher that can create
a cartridge folder from an existing ROM set (* ethos will need to
accept command-line arguments for this.)
- probably need to remember which controller was selected in each port
for each system across runs
- need to fix the cursor for Super Scope / Justifier games (move from
19-bit to 32-bit colors broke it)
- have to refactor that cache.(hv)offset thing to fix ASP
2012-05-06 23:27:42 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string ComboButton::text() const {
|
|
|
|
if(state.text.empty()) return "";
|
|
|
|
return state.text[state.selection];
|
|
|
|
}
|
|
|
|
|
|
|
|
string ComboButton::text(unsigned selection) const {
|
|
|
|
if(selection >= state.text.size()) return "";
|
|
|
|
return state.text[selection];
|
Update to v088r14 release.
byuu says:
Changelog:
- added NSS DIP switch settings window (when loading NSS carts with
appropriate manifest.xml file)
- added video shader selection (they go in ~/.config/bsnes/Video
Shaders/ now)
- added driver selection
- added timing settings (not only allows video/audio settings, also has
code to dynamically compute the values for you ... and it actually
works pretty good!)
- moved "None" controller device to bottom of list (it is the least
likely to be used, after all)
- added Interface::path() to support MSU1, USART, Link
- input and hotkey mappings remember list position after assignment
- and more!
target-ethos now has all of the functionality of target-ui, and more.
Final code size for the port is 101.2KB (ethos) vs 167.6KB (ui).
A ~67% reduction in code size, yet it does even more! And you can add or
remove an entire system with only three lines of code (Makefile include,
header include, interface append.)
The only problem left is that the BS-X BIOS won't load the BS Zelda no
Densetsu file.
I can't figure out why it's not working, would appreciate any
assistance, but otherwise I'm probably just going to leave it broken for
v089, sorry.
So the show stoppers for a new release at this point are:
- fix laevateinn to compile with the new interface changes (shouldn't be
too hard, it'll still use the old, direct interface.)
- clean up Emulator::Interface as much as possible (trim down
Information, mediaRequest should use an alternate struct designed to
load firmware / slots separately)
- enhance purify to strip SNES ROM headers, and it really needs a GUI
interface
- it would be highly desirable to make a launcher that can create
a cartridge folder from an existing ROM set (* ethos will need to
accept command-line arguments for this.)
- probably need to remember which controller was selected in each port
for each system across runs
- need to fix the cursor for Super Scope / Justifier games (move from
19-bit to 32-bit colors broke it)
- have to refactor that cache.(hv)offset thing to fix ASP
2012-05-06 23:27:42 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
ComboButton::ComboButton():
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
2013-03-15 13:11:33 +00:00
|
|
|
base_from_member<pComboButton&>(*new pComboButton(*this)),
|
|
|
|
Widget(base_from_member<pComboButton&>::value),
|
|
|
|
p(base_from_member<pComboButton&>::value) {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
ComboButton::~ComboButton() {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
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.
2013-11-09 11:45:54 +00:00
|
|
|
//Console
|
|
|
|
//=======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Console::print(const string& text) {
|
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.
2013-11-09 11:45:54 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
//Frame
|
|
|
|
//=====
|
|
|
|
|
|
|
|
void Frame::setLayout(Layout& layout) {
|
|
|
|
state.layout = &layout;
|
|
|
|
synchronizeLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Frame::setText(const string& text) {
|
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Frame::synchronizeLayout() {
|
|
|
|
if(state.layout == nullptr) return;
|
|
|
|
state.layout->Sizable::state.window = Sizable::state.window;
|
|
|
|
state.layout->Sizable::state.parent = this;
|
|
|
|
state.layout->state.widget = this;
|
|
|
|
state.layout->synchronizeLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
string Frame::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
|
|
|
Frame::Frame():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pFrame&>(*new pFrame(*this)),
|
|
|
|
Widget(base_from_member<pFrame&>::value),
|
|
|
|
p(base_from_member<pFrame&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Frame::~Frame() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
//HexEdit
|
|
|
|
//=======
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned HexEdit::columns() const {
|
|
|
|
return state.columns;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned HexEdit::length() const {
|
|
|
|
return state.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned HexEdit::offset() const {
|
|
|
|
return state.offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned HexEdit::rows() const {
|
|
|
|
return state.rows;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void HexEdit::setColumns(unsigned columns) {
|
|
|
|
state.columns = columns;
|
|
|
|
return p.setColumns(columns);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HexEdit::setLength(unsigned length) {
|
|
|
|
state.length = length;
|
|
|
|
return p.setLength(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HexEdit::setOffset(unsigned offset) {
|
|
|
|
state.offset = offset;
|
|
|
|
return p.setOffset(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HexEdit::setRows(unsigned rows) {
|
|
|
|
state.rows = rows;
|
|
|
|
return p.setRows(rows);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HexEdit::update() {
|
|
|
|
return p.update();
|
|
|
|
}
|
|
|
|
|
|
|
|
HexEdit::HexEdit():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pHexEdit&>(*new pHexEdit(*this)),
|
|
|
|
Widget(base_from_member<pHexEdit&>::value),
|
|
|
|
p(base_from_member<pHexEdit&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
HexEdit::~HexEdit() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
//HorizontalScroller
|
|
|
|
//==================
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned HorizontalScroller::length() const {
|
Update to v082r18 release.
byuu says:
There we go, the GUI is nearly feature-complete once again.
All cores now output their native video format (NES={emphasis}{palette},
SNES=BGR555, GameBoy={ bright, normal, darker, darkest }), and are
transformed to RGB555 data that is passed to the video renderer.
The video renderer then uses its internal palette to apply
brightness/contrast/gamma/ramp adjustments and outputs in RGB888 color
space.
This does add in another rendering pass, unfortunately, but it's
a necessary one for universal support.
The plan is to adapt all filters to take RGB555 input, and output RGB555
data as well. By doing this, it will be possible to stack filters.
However, it's a bit complicated: I need to plan how the stacking should
occur (eg we never want to apply scanlines before HQ2x, etc.)
Added input frequency adjustments for all three systems. I can easily
get perfect video/audio sync on all three now, hooray.
Long-term, it seems like we only really need one, and we can do
a video/audio delta to get an adjusted value. But for now, this gets the
job done.
Added audio volume adjust. I left out the balance for now, since it's
obviously impossible to balance the NES' single channel audio (I can
duplicate the channel, and do twice the filtering work, but ... why?)
I replaced NTSC/PAL TV mode selection with an "Enable Overscan"
checkbox. On, you get 240 lines on NES+SNES. Off, you get 224 lines on
NES+SNES.
Also added aspect correction box back. I don't do that gross PAL
distortion shit anymore, sorry PAL people. I just scale up the
54/47*(240/224) aspect correction for overscan off mode.
All memory is loaded and saved now, for all three systems (hooray, now
you can actually play Zelda 1&2.)
Added all of the old bsnes hotkeys, with the exception of capture
screenshot. May add again later. May come up with something a bit
different for extra features.
Re-added the NSS DIP switch setting window. Since geometry is saved,
I didn't want to auto-hide rows, so now you'll see all eight possible
DIPs, and the ones not used are grayed out.
Ultimately, nobody will notice since we only have DIPs for ActRaiser
NSS, and nobody's probably even using the XML file for that anyway.
Whatever, it's nice to have anyway.
Took FitzRoy's advice and single-item combo boxes on the input selection
are disabled, so the user doesn't waste time checking them.
I wanted to leave text so that you know there's not a problem. Qt
disabled radio box items look almost exactly like enabled ones.
Fixed lots of issues in phoenix and extended it a bit. But I was still
having trouble with radio box grouping, so I said fuck it and made the
panels show/hide based instead of append/remove based.
That's all for stuff off the checklist, I did a bunch of other things
I don't recall.
So yeah, I'd say the GUI is 100% usable now. This is my opinion on how
multi-platform GUIs should be done =)
Oh, I figure I should mention, but the NES core is GPLv3, and all future
SNES+GB releases will be as well. It's a move against Microsoft's Metro
store.
2011-09-20 14:04:43 +00:00
|
|
|
return state.length;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned HorizontalScroller::position() const {
|
|
|
|
return state.position;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void HorizontalScroller::setLength(unsigned length) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.length = length;
|
|
|
|
return p.setLength(length);
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void HorizontalScroller::setPosition(unsigned position) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.position = position;
|
|
|
|
return p.setPosition(position);
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
HorizontalScroller::HorizontalScroller():
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
2013-03-15 13:11:33 +00:00
|
|
|
base_from_member<pHorizontalScroller&>(*new pHorizontalScroller(*this)),
|
|
|
|
Widget(base_from_member<pHorizontalScroller&>::value),
|
|
|
|
p(base_from_member<pHorizontalScroller&>::value) {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
HorizontalScroller::~HorizontalScroller() {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//HorizontalSlider
|
|
|
|
//================
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned HorizontalSlider::length() const {
|
Update to v082r18 release.
byuu says:
There we go, the GUI is nearly feature-complete once again.
All cores now output their native video format (NES={emphasis}{palette},
SNES=BGR555, GameBoy={ bright, normal, darker, darkest }), and are
transformed to RGB555 data that is passed to the video renderer.
The video renderer then uses its internal palette to apply
brightness/contrast/gamma/ramp adjustments and outputs in RGB888 color
space.
This does add in another rendering pass, unfortunately, but it's
a necessary one for universal support.
The plan is to adapt all filters to take RGB555 input, and output RGB555
data as well. By doing this, it will be possible to stack filters.
However, it's a bit complicated: I need to plan how the stacking should
occur (eg we never want to apply scanlines before HQ2x, etc.)
Added input frequency adjustments for all three systems. I can easily
get perfect video/audio sync on all three now, hooray.
Long-term, it seems like we only really need one, and we can do
a video/audio delta to get an adjusted value. But for now, this gets the
job done.
Added audio volume adjust. I left out the balance for now, since it's
obviously impossible to balance the NES' single channel audio (I can
duplicate the channel, and do twice the filtering work, but ... why?)
I replaced NTSC/PAL TV mode selection with an "Enable Overscan"
checkbox. On, you get 240 lines on NES+SNES. Off, you get 224 lines on
NES+SNES.
Also added aspect correction box back. I don't do that gross PAL
distortion shit anymore, sorry PAL people. I just scale up the
54/47*(240/224) aspect correction for overscan off mode.
All memory is loaded and saved now, for all three systems (hooray, now
you can actually play Zelda 1&2.)
Added all of the old bsnes hotkeys, with the exception of capture
screenshot. May add again later. May come up with something a bit
different for extra features.
Re-added the NSS DIP switch setting window. Since geometry is saved,
I didn't want to auto-hide rows, so now you'll see all eight possible
DIPs, and the ones not used are grayed out.
Ultimately, nobody will notice since we only have DIPs for ActRaiser
NSS, and nobody's probably even using the XML file for that anyway.
Whatever, it's nice to have anyway.
Took FitzRoy's advice and single-item combo boxes on the input selection
are disabled, so the user doesn't waste time checking them.
I wanted to leave text so that you know there's not a problem. Qt
disabled radio box items look almost exactly like enabled ones.
Fixed lots of issues in phoenix and extended it a bit. But I was still
having trouble with radio box grouping, so I said fuck it and made the
panels show/hide based instead of append/remove based.
That's all for stuff off the checklist, I did a bunch of other things
I don't recall.
So yeah, I'd say the GUI is 100% usable now. This is my opinion on how
multi-platform GUIs should be done =)
Oh, I figure I should mention, but the NES core is GPLv3, and all future
SNES+GB releases will be as well. It's a move against Microsoft's Metro
store.
2011-09-20 14:04:43 +00:00
|
|
|
return state.length;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned HorizontalSlider::position() const {
|
|
|
|
return state.position;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HorizontalSlider::setLength(unsigned length) {
|
|
|
|
state.length = length;
|
|
|
|
return p.setLength(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HorizontalSlider::setPosition(unsigned position) {
|
|
|
|
state.position = position;
|
|
|
|
return p.setPosition(position);
|
|
|
|
}
|
|
|
|
|
|
|
|
HorizontalSlider::HorizontalSlider():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pHorizontalSlider&>(*new pHorizontalSlider(*this)),
|
|
|
|
Widget(base_from_member<pHorizontalSlider&>::value),
|
|
|
|
p(base_from_member<pHorizontalSlider&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
HorizontalSlider::~HorizontalSlider() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Label
|
|
|
|
//=====
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void Label::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string Label::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Label::Label():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pLabel&>(*new pLabel(*this)),
|
|
|
|
Widget(base_from_member<pLabel&>::value),
|
|
|
|
p(base_from_member<pLabel&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Label::~Label() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//LineEdit
|
|
|
|
//========
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool LineEdit::editable() const {
|
|
|
|
return state.editable;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void LineEdit::setEditable(bool editable) {
|
|
|
|
state.editable = editable;
|
|
|
|
return p.setEditable(editable);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void LineEdit::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
string LineEdit::text() {
|
|
|
|
return p.text();
|
|
|
|
}
|
|
|
|
|
|
|
|
LineEdit::LineEdit():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pLineEdit&>(*new pLineEdit(*this)),
|
|
|
|
Widget(base_from_member<pLineEdit&>::value),
|
|
|
|
p(base_from_member<pLineEdit&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
LineEdit::~LineEdit() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//ListView
|
|
|
|
//========
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ListView::append(const lstring& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.checked.append(false);
|
2013-11-28 10:29:01 +00:00
|
|
|
state.image.append({});
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text.append(text);
|
|
|
|
return p.append(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::autoSizeColumns() {
|
|
|
|
return p.autoSizeColumns();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool ListView::checkable() const {
|
|
|
|
return state.checkable;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ListView::checked(unsigned selection) const {
|
|
|
|
if(selection >= state.text.size()) return false;
|
|
|
|
return state.checked[selection];
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned ListView::columns() const {
|
|
|
|
return max(1u, state.headerText.size());
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool ListView::headerVisible() const {
|
|
|
|
return state.headerVisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
image ListView::image(unsigned selection, unsigned position) const {
|
|
|
|
if(selection >= state.text.size()) return {};
|
|
|
|
return state.image[selection](position);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::remove(unsigned selection) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.checked.remove(selection);
|
|
|
|
state.image.remove(selection);
|
|
|
|
state.text.remove(selection);
|
|
|
|
return p.remove(selection);
|
2012-06-25 12:49:39 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void ListView::reset() {
|
|
|
|
state.checked.reset();
|
2012-06-18 10:13:51 +00:00
|
|
|
state.image.reset();
|
2013-12-14 06:25:12 +00:00
|
|
|
state.selected = false;
|
|
|
|
state.selection = 0;
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text.reset();
|
|
|
|
return p.reset();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned ListView::rows() const {
|
|
|
|
return state.text.size();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool ListView::selected() const {
|
|
|
|
return state.selected;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned ListView::selection() const {
|
|
|
|
return state.selection;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::setCheckable(bool checkable) {
|
|
|
|
state.checkable = checkable;
|
|
|
|
return p.setCheckable(checkable);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ListView::setChecked(unsigned selection, bool checked) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.checked[selection] = checked;
|
|
|
|
return p.setChecked(selection, checked);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ListView::setHeaderText(const lstring& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.headerText = text;
|
|
|
|
return p.setHeaderText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::setHeaderVisible(bool visible) {
|
|
|
|
state.headerVisible = visible;
|
|
|
|
return p.setHeaderVisible(visible);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ListView::setImage(unsigned selection, unsigned position, const nall::image& image) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.image[selection](position) = image;
|
|
|
|
return p.setImage(selection, position, image);
|
2012-06-18 10:13:51 +00:00
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void ListView::setSelected(bool selected) {
|
|
|
|
state.selected = selected;
|
|
|
|
return p.setSelected(selected);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void ListView::setSelection(unsigned selection) {
|
|
|
|
if(selection >= state.text.size()) return;
|
2011-09-05 03:48:23 +00:00
|
|
|
state.selected = true;
|
2013-11-28 10:29:01 +00:00
|
|
|
state.selection = selection;
|
|
|
|
return p.setSelection(selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::setText(unsigned selection, const lstring& text) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
for(unsigned position = 0; position < text.size(); position++) {
|
|
|
|
setText(selection, position, text[position]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListView::setText(unsigned selection, unsigned position, const string& text) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.text[selection](position) = text;
|
|
|
|
return p.setText(selection, position, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
string ListView::text(unsigned selection, unsigned position) const {
|
|
|
|
if(selection >= state.text.size()) return "";
|
|
|
|
return state.text[selection](position);
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ListView::ListView():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pListView&>(*new pListView(*this)),
|
|
|
|
Widget(base_from_member<pListView&>::value),
|
|
|
|
p(base_from_member<pListView&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
ListView::~ListView() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//ProgressBar
|
|
|
|
//===========
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned ProgressBar::position() const {
|
|
|
|
return state.position;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void ProgressBar::setPosition(unsigned position) {
|
|
|
|
state.position = position;
|
|
|
|
return p.setPosition(position);
|
|
|
|
}
|
|
|
|
|
|
|
|
ProgressBar::ProgressBar():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pProgressBar&>(*new pProgressBar(*this)),
|
|
|
|
Widget(base_from_member<pProgressBar&>::value),
|
|
|
|
p(base_from_member<pProgressBar&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
ProgressBar::~ProgressBar() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
//RadioButton
|
|
|
|
//===========
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
void RadioButton::group(const nall::group<RadioButton>& list) {
|
|
|
|
for(auto& item : list) item.p.setGroup(item.state.group = list);
|
|
|
|
if(list.size()) list.first().setChecked();
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool RadioButton::checked() const {
|
|
|
|
return state.checked;
|
|
|
|
}
|
|
|
|
|
|
|
|
image RadioButton::image() const {
|
|
|
|
return state.image;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void RadioButton::setChecked() {
|
2013-11-28 10:29:01 +00:00
|
|
|
for(auto& item : state.group) item.state.checked = false;
|
2011-09-05 03:48:23 +00:00
|
|
|
state.checked = true;
|
|
|
|
return p.setChecked();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void RadioButton::setImage(const nall::image& image, Orientation orientation) {
|
|
|
|
state.image = image;
|
|
|
|
state.orientation = orientation;
|
|
|
|
return p.setImage(image, orientation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RadioButton::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
string RadioButton::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
RadioButton::RadioButton():
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
2013-03-15 13:11:33 +00:00
|
|
|
base_from_member<pRadioButton&>(*new pRadioButton(*this)),
|
|
|
|
Widget(base_from_member<pRadioButton&>::value),
|
|
|
|
p(base_from_member<pRadioButton&>::value) {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
RadioButton::~RadioButton() {
|
2013-05-02 11:25:45 +00:00
|
|
|
for(auto& item : state.group) {
|
2011-09-05 03:48:23 +00:00
|
|
|
if(&item != this) item.state.group.remove(*this);
|
|
|
|
}
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
//RadioLabel
|
|
|
|
//==========
|
|
|
|
|
|
|
|
void RadioLabel::group(const nall::group<RadioLabel>& list) {
|
|
|
|
for(auto& item : list) item.p.setGroup(item.state.group = list);
|
|
|
|
if(list.size()) list.first().setChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RadioLabel::checked() const {
|
|
|
|
return state.checked;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RadioLabel::setChecked() {
|
|
|
|
for(auto &item : state.group) item.state.checked = false;
|
|
|
|
state.checked = true;
|
|
|
|
return p.setChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RadioLabel::setText(const string& text) {
|
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
string RadioLabel::text() const {
|
|
|
|
return state.text;
|
|
|
|
}
|
|
|
|
|
|
|
|
RadioLabel::RadioLabel():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pRadioLabel&>(*new pRadioLabel(*this)),
|
|
|
|
Widget(base_from_member<pRadioLabel&>::value),
|
|
|
|
p(base_from_member<pRadioLabel&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
RadioLabel::~RadioLabel() {
|
|
|
|
for(auto& item : state.group) {
|
|
|
|
if(&item != this) item.state.group.remove(*this);
|
|
|
|
}
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//TabFrame
|
|
|
|
//========
|
|
|
|
|
|
|
|
void TabFrame::append(const string& text, const nall::image& image) {
|
|
|
|
state.image.append(image);
|
|
|
|
state.layout.append(nullptr);
|
|
|
|
state.text.append(text);
|
|
|
|
return p.append(text, image);
|
|
|
|
}
|
|
|
|
|
|
|
|
image TabFrame::image(unsigned selection) const {
|
|
|
|
if(selection >= state.text.size()) return {};
|
|
|
|
return state.image[selection];
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabFrame::remove(unsigned selection) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.image.remove(selection);
|
|
|
|
state.layout.remove(selection);
|
|
|
|
state.text.remove(selection);
|
|
|
|
return p.remove(selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned TabFrame::selection() const {
|
|
|
|
return state.selection;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabFrame::setImage(unsigned selection, const nall::image& image) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.image[selection] = image;
|
|
|
|
return p.setImage(selection, image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabFrame::setLayout(unsigned selection, Layout& layout) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.layout[selection] = &layout;
|
|
|
|
synchronizeLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabFrame::setSelection(unsigned selection) {
|
|
|
|
state.selection = selection;
|
|
|
|
return p.setSelection(selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabFrame::setText(unsigned selection, const string& text) {
|
|
|
|
if(selection >= state.text.size()) return;
|
|
|
|
state.text[selection] = text;
|
|
|
|
return p.setText(selection, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabFrame::synchronizeLayout() {
|
|
|
|
for(unsigned n = 0; n < state.layout.size(); n++) {
|
|
|
|
Layout* layout = state.layout[n];
|
|
|
|
if(layout == nullptr) continue;
|
|
|
|
layout->Sizable::state.parent = this;
|
|
|
|
layout->Sizable::state.window = Sizable::state.window;
|
|
|
|
layout->state.widget = this;
|
|
|
|
layout->state.widgetSelection = n;
|
|
|
|
layout->synchronizeLayout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned TabFrame::tabs() const {
|
|
|
|
return state.text.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
string TabFrame::text(unsigned selection) const {
|
|
|
|
if(selection >= state.text.size()) return "";
|
|
|
|
return state.text[selection];
|
|
|
|
}
|
|
|
|
|
|
|
|
TabFrame::TabFrame():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pTabFrame&>(*new pTabFrame(*this)),
|
|
|
|
Widget(base_from_member<pTabFrame&>::value),
|
|
|
|
p(base_from_member<pTabFrame&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
TabFrame::~TabFrame() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
//TextEdit
|
|
|
|
//========
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool TextEdit::editable() const {
|
|
|
|
return state.editable;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
void TextEdit::setCursorPosition(unsigned position) {
|
|
|
|
state.cursorPosition = position;
|
|
|
|
return p.setCursorPosition(position);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextEdit::setEditable(bool editable) {
|
|
|
|
state.editable = editable;
|
|
|
|
return p.setEditable(editable);
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
void TextEdit::setText(const string& text) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.text = text;
|
|
|
|
return p.setText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextEdit::setWordWrap(bool wordWrap) {
|
|
|
|
state.wordWrap = wordWrap;
|
|
|
|
return p.setWordWrap(wordWrap);
|
|
|
|
}
|
|
|
|
|
|
|
|
string TextEdit::text() {
|
|
|
|
return p.text();
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool TextEdit::wordWrap() const {
|
2013-03-15 13:11:33 +00:00
|
|
|
return state.wordWrap;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
TextEdit::TextEdit():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pTextEdit&>(*new pTextEdit(*this)),
|
|
|
|
Widget(base_from_member<pTextEdit&>::value),
|
|
|
|
p(base_from_member<pTextEdit&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
TextEdit::~TextEdit() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
//VerticalScroller
|
|
|
|
//================
|
2011-09-05 03:48:23 +00:00
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned VerticalScroller::length() const {
|
Update to v082r18 release.
byuu says:
There we go, the GUI is nearly feature-complete once again.
All cores now output their native video format (NES={emphasis}{palette},
SNES=BGR555, GameBoy={ bright, normal, darker, darkest }), and are
transformed to RGB555 data that is passed to the video renderer.
The video renderer then uses its internal palette to apply
brightness/contrast/gamma/ramp adjustments and outputs in RGB888 color
space.
This does add in another rendering pass, unfortunately, but it's
a necessary one for universal support.
The plan is to adapt all filters to take RGB555 input, and output RGB555
data as well. By doing this, it will be possible to stack filters.
However, it's a bit complicated: I need to plan how the stacking should
occur (eg we never want to apply scanlines before HQ2x, etc.)
Added input frequency adjustments for all three systems. I can easily
get perfect video/audio sync on all three now, hooray.
Long-term, it seems like we only really need one, and we can do
a video/audio delta to get an adjusted value. But for now, this gets the
job done.
Added audio volume adjust. I left out the balance for now, since it's
obviously impossible to balance the NES' single channel audio (I can
duplicate the channel, and do twice the filtering work, but ... why?)
I replaced NTSC/PAL TV mode selection with an "Enable Overscan"
checkbox. On, you get 240 lines on NES+SNES. Off, you get 224 lines on
NES+SNES.
Also added aspect correction box back. I don't do that gross PAL
distortion shit anymore, sorry PAL people. I just scale up the
54/47*(240/224) aspect correction for overscan off mode.
All memory is loaded and saved now, for all three systems (hooray, now
you can actually play Zelda 1&2.)
Added all of the old bsnes hotkeys, with the exception of capture
screenshot. May add again later. May come up with something a bit
different for extra features.
Re-added the NSS DIP switch setting window. Since geometry is saved,
I didn't want to auto-hide rows, so now you'll see all eight possible
DIPs, and the ones not used are grayed out.
Ultimately, nobody will notice since we only have DIPs for ActRaiser
NSS, and nobody's probably even using the XML file for that anyway.
Whatever, it's nice to have anyway.
Took FitzRoy's advice and single-item combo boxes on the input selection
are disabled, so the user doesn't waste time checking them.
I wanted to leave text so that you know there's not a problem. Qt
disabled radio box items look almost exactly like enabled ones.
Fixed lots of issues in phoenix and extended it a bit. But I was still
having trouble with radio box grouping, so I said fuck it and made the
panels show/hide based instead of append/remove based.
That's all for stuff off the checklist, I did a bunch of other things
I don't recall.
So yeah, I'd say the GUI is 100% usable now. This is my opinion on how
multi-platform GUIs should be done =)
Oh, I figure I should mention, but the NES core is GPLv3, and all future
SNES+GB releases will be as well. It's a move against Microsoft's Metro
store.
2011-09-20 14:04:43 +00:00
|
|
|
return state.length;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned VerticalScroller::position() const {
|
|
|
|
return state.position;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void VerticalScroller::setLength(unsigned length) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.length = length;
|
|
|
|
return p.setLength(length);
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
void VerticalScroller::setPosition(unsigned position) {
|
2011-09-05 03:48:23 +00:00
|
|
|
state.position = position;
|
|
|
|
return p.setPosition(position);
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
VerticalScroller::VerticalScroller():
|
2011-09-05 03:48:23 +00:00
|
|
|
state(*new State),
|
2013-03-15 13:11:33 +00:00
|
|
|
base_from_member<pVerticalScroller&>(*new pVerticalScroller(*this)),
|
|
|
|
Widget(base_from_member<pVerticalScroller&>::value),
|
|
|
|
p(base_from_member<pVerticalScroller&>::value) {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:11:33 +00:00
|
|
|
VerticalScroller::~VerticalScroller() {
|
2011-09-05 03:48:23 +00:00
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//VerticalSlider
|
|
|
|
//==============
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned VerticalSlider::length() const {
|
Update to v082r18 release.
byuu says:
There we go, the GUI is nearly feature-complete once again.
All cores now output their native video format (NES={emphasis}{palette},
SNES=BGR555, GameBoy={ bright, normal, darker, darkest }), and are
transformed to RGB555 data that is passed to the video renderer.
The video renderer then uses its internal palette to apply
brightness/contrast/gamma/ramp adjustments and outputs in RGB888 color
space.
This does add in another rendering pass, unfortunately, but it's
a necessary one for universal support.
The plan is to adapt all filters to take RGB555 input, and output RGB555
data as well. By doing this, it will be possible to stack filters.
However, it's a bit complicated: I need to plan how the stacking should
occur (eg we never want to apply scanlines before HQ2x, etc.)
Added input frequency adjustments for all three systems. I can easily
get perfect video/audio sync on all three now, hooray.
Long-term, it seems like we only really need one, and we can do
a video/audio delta to get an adjusted value. But for now, this gets the
job done.
Added audio volume adjust. I left out the balance for now, since it's
obviously impossible to balance the NES' single channel audio (I can
duplicate the channel, and do twice the filtering work, but ... why?)
I replaced NTSC/PAL TV mode selection with an "Enable Overscan"
checkbox. On, you get 240 lines on NES+SNES. Off, you get 224 lines on
NES+SNES.
Also added aspect correction box back. I don't do that gross PAL
distortion shit anymore, sorry PAL people. I just scale up the
54/47*(240/224) aspect correction for overscan off mode.
All memory is loaded and saved now, for all three systems (hooray, now
you can actually play Zelda 1&2.)
Added all of the old bsnes hotkeys, with the exception of capture
screenshot. May add again later. May come up with something a bit
different for extra features.
Re-added the NSS DIP switch setting window. Since geometry is saved,
I didn't want to auto-hide rows, so now you'll see all eight possible
DIPs, and the ones not used are grayed out.
Ultimately, nobody will notice since we only have DIPs for ActRaiser
NSS, and nobody's probably even using the XML file for that anyway.
Whatever, it's nice to have anyway.
Took FitzRoy's advice and single-item combo boxes on the input selection
are disabled, so the user doesn't waste time checking them.
I wanted to leave text so that you know there's not a problem. Qt
disabled radio box items look almost exactly like enabled ones.
Fixed lots of issues in phoenix and extended it a bit. But I was still
having trouble with radio box grouping, so I said fuck it and made the
panels show/hide based instead of append/remove based.
That's all for stuff off the checklist, I did a bunch of other things
I don't recall.
So yeah, I'd say the GUI is 100% usable now. This is my opinion on how
multi-platform GUIs should be done =)
Oh, I figure I should mention, but the NES core is GPLv3, and all future
SNES+GB releases will be as well. It's a move against Microsoft's Metro
store.
2011-09-20 14:04:43 +00:00
|
|
|
return state.length;
|
|
|
|
}
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
unsigned VerticalSlider::position() const {
|
|
|
|
return state.position;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VerticalSlider::setLength(unsigned length) {
|
|
|
|
state.length = length;
|
|
|
|
return p.setLength(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VerticalSlider::setPosition(unsigned position) {
|
|
|
|
state.position = position;
|
|
|
|
return p.setPosition(position);
|
|
|
|
}
|
|
|
|
|
|
|
|
VerticalSlider::VerticalSlider():
|
|
|
|
state(*new State),
|
|
|
|
base_from_member<pVerticalSlider&>(*new pVerticalSlider(*this)),
|
|
|
|
Widget(base_from_member<pVerticalSlider&>::value),
|
|
|
|
p(base_from_member<pVerticalSlider&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
VerticalSlider::~VerticalSlider() {
|
|
|
|
p.destructor();
|
|
|
|
delete &state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Viewport
|
|
|
|
//========
|
|
|
|
|
2013-11-28 10:29:01 +00:00
|
|
|
bool Viewport::droppable() const {
|
|
|
|
return state.droppable;
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
uintptr_t Viewport::handle() {
|
|
|
|
return p.handle();
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
void Viewport::setDroppable(bool droppable) {
|
|
|
|
state.droppable = droppable;
|
|
|
|
return p.setDroppable(droppable);
|
|
|
|
}
|
|
|
|
|
2011-09-05 03:48:23 +00:00
|
|
|
Viewport::Viewport():
|
2013-07-29 09:42:45 +00:00
|
|
|
state(*new State),
|
2011-09-05 03:48:23 +00:00
|
|
|
base_from_member<pViewport&>(*new pViewport(*this)),
|
|
|
|
Widget(base_from_member<pViewport&>::value),
|
|
|
|
p(base_from_member<pViewport&>::value) {
|
|
|
|
p.constructor();
|
|
|
|
}
|
|
|
|
|
|
|
|
Viewport::~Viewport() {
|
|
|
|
p.destructor();
|
2013-07-29 09:42:45 +00:00
|
|
|
delete &state;
|
2011-09-05 03:48:23 +00:00
|
|
|
}
|
2013-03-15 13:11:33 +00:00
|
|
|
|
|
|
|
}
|