Update to v082r05 release.

byuu says:

Okay, I fixed up many outstanding phoenix issues.
* Windows/GTK+ fixed by using processEvents instead of main(); Windows can run unthrottled, and GTK+ shows the window contents now
* fixed keyboard beeping once and for all on Windows: I now whitelist tabbable controls
* fixed main menubar setVisible calls
* Qt and GTK+ now allow you to resize windows smaller than they initially were

Both Qt and GTK+ still fuck up the geometry a bit when toggling fullscreen mode. I have tried, and tried, and tried and tried and tried to fix it all. Nothing works. I give up.
Easier to destroy and recreate the fucking window than figure out how to resize it on Linux (and no, I can't do that. ruby would not like the handle changing.)

As for the GUI:
* file browser is back in, still need remember place and open folder code; that needs to be extended to handle multiple systems now
* shrink window command added to tools menu.
This commit is contained in:
Tim Allen 2011-09-09 14:16:25 +10:00
parent ec7e4087fb
commit 8618334356
20 changed files with 240 additions and 64 deletions

View File

@ -125,7 +125,10 @@
} }
inline char *getcwd(char *path) { inline char *getcwd(char *path) {
return getcwd(path, PATH_MAX); auto unused = getcwd(path, PATH_MAX);
unsigned length = strlen(path);
if(path[length] != '/') strcpy(path + length, "/");
return path;
} }
#endif #endif

View File

@ -66,11 +66,13 @@ bool string::operator> (const char *str) const { return strcmp(data, str) > 0;
bool string::operator>=(const char *str) const { return strcmp(data, str) >= 0; } bool string::operator>=(const char *str) const { return strcmp(data, str) >= 0; }
string& string::operator=(const string &value) { string& string::operator=(const string &value) {
if(&value == this) return *this;
assign(value); assign(value);
return *this; return *this;
} }
string& string::operator=(string &&source) { string& string::operator=(string &&source) {
if(&source == this) return *this;
if(data) free(data); if(data) free(data);
size = source.size; size = source.size;
data = source.data; data = source.data;
@ -87,11 +89,13 @@ template<typename... Args> string::string(Args&&... args) {
} }
string::string(const string &value) { string::string(const string &value) {
if(&value == this) return;
size = strlen(value); size = strlen(value);
data = strdup(value); data = strdup(value);
} }
string::string(string &&source) { string::string(string &&source) {
if(&source == this) return;
size = source.size; size = source.size;
data = source.data; data = source.data;
source.data = 0; source.data = 0;

View File

@ -306,6 +306,10 @@ Window::~Window() {
//Action //Action
//====== //======
bool Action::enabled() {
return state.enabled;
}
void Action::setEnabled(bool enabled) { void Action::setEnabled(bool enabled) {
state.enabled = enabled; state.enabled = enabled;
return p.setEnabled(enabled); return p.setEnabled(enabled);
@ -316,6 +320,10 @@ void Action::setVisible(bool visible) {
return p.setVisible(visible); return p.setVisible(visible);
} }
bool Action::visible() {
return state.visible;
}
Action::Action(pAction &p): Action::Action(pAction &p):
state(*new State), state(*new State),
Object(p), Object(p),

View File

@ -162,8 +162,10 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
}; };
struct Action : Object { struct Action : Object {
bool enabled();
void setEnabled(bool enabled = true); void setEnabled(bool enabled = true);
void setVisible(bool visible = true); void setVisible(bool visible = true);
bool visible();
Action(pAction &p); Action(pAction &p);
~Action(); ~Action();

View File

@ -31,16 +31,18 @@ static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *win
if(gtk_widget_get_realized(window->p.widget) == false) return false; if(gtk_widget_get_realized(window->p.widget) == false) return false;
GdkWindow *gdkWindow = gtk_widget_get_window(widget); GdkWindow *gdkWindow = gtk_widget_get_window(widget);
//update geometry settings
GdkRectangle border, client; GdkRectangle border, client;
gdk_window_get_frame_extents(gdkWindow, &border); gdk_window_get_frame_extents(gdkWindow, &border);
gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0); gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0);
gdk_window_get_origin(gdkWindow, &client.x, &client.y); gdk_window_get_origin(gdkWindow, &client.x, &client.y);
settings.frameGeometryX = client.x - border.x; if(window->state.fullScreen == false) {
settings.frameGeometryY = client.y - border.y; //update geometry settings
settings.frameGeometryWidth = border.width - client.width; settings.frameGeometryX = client.x - border.x;
settings.frameGeometryHeight = border.height - client.height; settings.frameGeometryY = client.y - border.y;
settings.frameGeometryWidth = border.width - client.width;
settings.frameGeometryHeight = border.height - client.height;
}
//move //move
if(event->configure.x != window->p.lastConfigure.x if(event->configure.x != window->p.lastConfigure.x
@ -167,10 +169,20 @@ void pWindow::setFullScreen(bool fullScreen) {
} }
void pWindow::setGeometry(const Geometry &geometry) { void pWindow::setGeometry(const Geometry &geometry) {
OS::processEvents();
Geometry margin = frameMargin(); Geometry margin = frameMargin();
gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y); gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y);
gtk_window_resize(GTK_WINDOW(widget), 1, 1);
//GdkGeometry geom;
//geom.min_width = 1;
//geom.min_height = 1;
//gtk_window_set_geometry_hints(GTK_WINDOW(widget), GTK_WIDGET(widget), &geom, GDK_HINT_MIN_SIZE);
gtk_window_set_policy(GTK_WINDOW(widget), true, true, false);
gtk_widget_set_size_request(formContainer, geometry.width, geometry.height); gtk_widget_set_size_request(formContainer, geometry.width, geometry.height);
gtk_window_resize(GTK_WINDOW(widget), geometry.width + margin.width, geometry.height + margin.height);
foreach(layout, window.state.layout) { foreach(layout, window.state.layout) {
Geometry geometry = this->geometry(); Geometry geometry = this->geometry();
geometry.x = geometry.y = 0; geometry.x = geometry.y = 0;

View File

@ -1,7 +1,7 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp' ** Meta object code from reading C++ file 'platform.moc.hpp'
** **
** Created: Tue Aug 30 09:38:15 2011 ** Created: Thu Sep 8 17:34:23 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0) ** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!

View File

@ -97,6 +97,8 @@ void pWindow::setGeometry(const Geometry &geometry_) {
setResizable(window.state.resizable); setResizable(window.state.resizable);
qtWindow->move(geometry.x - margin.x, geometry.y - margin.y); qtWindow->move(geometry.x - margin.x, geometry.y - margin.y);
qtWindow->adjustSize(); qtWindow->adjustSize();
qtWindow->setMinimumSize(1u, 1u);
qtContainer->setMinimumSize(1u, 1u);
foreach(layout, window.state.layout) { foreach(layout, window.state.layout) {
geometry = geometry_; geometry = geometry_;

View File

@ -32,6 +32,7 @@
#include "widget/viewport.cpp" #include "widget/viewport.cpp"
static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM); static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM);
static void OS_processDialogMessage(MSG&);
static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM);
Geometry pOS::availableGeometry() { Geometry pOS::availableGeometry() {
@ -129,13 +130,7 @@ string pOS::folderSelect(Window &parent, const string &path) {
void pOS::main() { void pOS::main() {
MSG msg; MSG msg;
while(GetMessage(&msg, 0, 0, 0)) { while(GetMessage(&msg, 0, 0, 0)) {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) { OS_processDialogMessage(msg);
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} }
} }
@ -148,17 +143,35 @@ void pOS::processEvents() {
while(pendingEvents()) { while(pendingEvents()) {
MSG msg; MSG msg;
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) { OS_processDialogMessage(msg);
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
if(!IsDialogMessage(GetParent(msg.hwnd) ? GetParent(msg.hwnd) : msg.hwnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} }
} }
} }
void OS_processDialogMessage(MSG &msg) {
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) {
OS_keyboardProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
}
wchar_t className[256];
GetClassName(msg.hwnd, className, 255);
//if this HWND accepts tabs to move between controls ...
if(!wcscmp(className, L"BUTTON") //Button, CheckBox, RadioBox
|| !wcscmp(className, L"COMBOBOX") //ComboBox
|| !wcscmp(className, L"EDIT") //HexEdit, LineEdit, TextEdit
|| !wcscmp(className, L"SCROLLBAR") //HorizontalScrollBar, VerticalScrollBar
|| !wcscmp(className, TRACKBAR_CLASS) //HorizontalSlider, VerticalSlider
|| !wcscmp(className, WC_LISTVIEW) //ListView
) {
//... return if the message is a dialog command
if(IsDialogMessage(msg.hwnd, &msg)) return;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
void pOS::quit() { void pOS::quit() {
PostQuitMessage(0); PostQuitMessage(0);
} }

View File

@ -8,6 +8,7 @@ void pWindow::append(Layout &layout) {
} }
void pWindow::append(Menu &menu) { void pWindow::append(Menu &menu) {
menu.p.parentWindow = &window;
updateMenu(); updateMenu();
} }
@ -192,7 +193,9 @@ void pWindow::updateMenu() {
foreach(menu, window.state.menu) { foreach(menu, window.state.menu) {
menu.p.update(window); menu.p.update(window);
AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text)); if(menu.visible()) {
AppendMenu(hmenu, MF_STRING | MF_POPUP, (UINT_PTR)menu.p.hmenu, utf16_t(menu.state.text));
}
} }
SetMenu(hwnd, window.state.menuVisible ? hmenu : 0); SetMenu(hwnd, window.state.menuVisible ? hmenu : 0);

View File

@ -4,7 +4,7 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "082.04"; static const char Version[] = "082.05";
static const unsigned SerializerVersion = 21; static const unsigned SerializerVersion = 21;
} }
} }

View File

@ -24,12 +24,12 @@ using namespace ruby;
#include "general/general.hpp" #include "general/general.hpp"
struct Application { struct Application {
bool quit;
string title; string title;
string normalFont; string normalFont;
string boldFont; string boldFont;
Timer timer;
void run(); void run();
Application(int argc, char **argv); Application(int argc, char **argv);
~Application(); ~Application();

View File

@ -0,0 +1,83 @@
FileBrowser *fileBrowser = 0;
FileBrowser::FileBrowser() {
setGeometry({ 128, 128, 640, 400 });
setWidgetFont(application->normalFont);
pathBrowse.setText("Browse ...");
pathUp.setText("..");
layout.setMargin(5);
append(layout);
layout.append(pathLayout, ~0, 0, 5);
pathLayout.append(pathEdit, ~0, 0, 5);
pathLayout.append(pathBrowse, 0, 0, 5);
pathLayout.append(pathUp, 0, 0);
layout.append(fileList, ~0, ~0);
pathEdit.onActivate = [&] {
string path = pathEdit.text();
path.transform("\\", "/");
if(path.endswith("/") == false) path.append("/");
setPath(path);
};
pathBrowse.onTick = [&] {
string path = OS::folderSelect(*this, activePath);
if(path != "") setPath(path);
};
pathUp.onTick = [&] {
if(activePath == "/") return;
string path = activePath;
path.rtrim<1>("/");
path = dir(path);
setPath(path);
};
fileList.onActivate = { &FileBrowser::fileListActivate, this };
char path[PATH_MAX];
auto unused = getcwd(path);
setPath(path);
}
void FileBrowser::open(const string &title, const lstring &filterList, function<void (string)> callback) {
this->callback = callback;
this->filterList = filterList;
setTitle(title);
setPath(activePath);
setVisible();
}
void FileBrowser::setPath(const string &path) {
activePath = path;
pathEdit.setText(activePath);
fileList.reset();
fileNameList.reset();
lstring contentsList = directory::contents(path);
foreach(fileName, contentsList) {
if(fileName.endswith("/")) {
fileNameList.append(fileName);
} else foreach(filter, filterList) {
if(fileName.wildcard(filter)) fileNameList.append(fileName);
}
}
foreach(fileName, fileNameList) fileList.append(fileName);
fileList.setSelection(0);
fileList.setFocused();
}
void FileBrowser::fileListActivate() {
unsigned selection = fileList.selection();
string fileName = fileNameList[selection];
if(fileName.endswith("/")) return setPath({ activePath, fileName });
if(callback) callback({ activePath, fileName });
setVisible(false);
}

View File

@ -0,0 +1,23 @@
struct FileBrowser : Window {
VerticalLayout layout;
HorizontalLayout pathLayout;
LineEdit pathEdit;
Button pathBrowse;
Button pathUp;
ListView fileList;
lstring fileNameList;
void open(const string &title, const lstring &filterList, function<void (string)> callback);
FileBrowser();
private:
string activePath;
lstring filterList;
function<void (string)> callback;
void setPath(const string &path);
void fileListActivate();
};
extern FileBrowser *fileBrowser;

View File

@ -1,2 +1,3 @@
#include "../base.hpp" #include "../base.hpp"
#include "main-window.cpp" #include "main-window.cpp"
#include "file-browser.cpp"

View File

@ -1 +1,2 @@
#include "main-window.hpp" #include "main-window.hpp"
#include "file-browser.hpp"

View File

@ -31,6 +31,9 @@ MainWindow::MainWindow() {
settingsSynchronizeAudio.setChecked(); settingsSynchronizeAudio.setChecked();
settingsMuteAudio.setText("Mute Audio"); settingsMuteAudio.setText("Mute Audio");
toolsMenu.setText("Tools");
toolsShrinkWindow.setText("Shrink Window");
helpMenu.setText("Help"); helpMenu.setText("Help");
helpAbout.setText("About ..."); helpAbout.setText("About ...");
@ -61,6 +64,9 @@ MainWindow::MainWindow() {
settingsMenu.append(settingsSynchronizeAudio); settingsMenu.append(settingsSynchronizeAudio);
settingsMenu.append(settingsMuteAudio); settingsMenu.append(settingsMuteAudio);
append(toolsMenu);
toolsMenu.append(toolsShrinkWindow);
append(helpMenu); append(helpMenu);
helpMenu.append(helpAbout); helpMenu.append(helpAbout);
@ -74,25 +80,25 @@ MainWindow::MainWindow() {
layout.append(viewport, { 0, 0, 512, 480 }); layout.append(viewport, { 0, 0, 512, 480 });
append(layout); append(layout);
onClose = &OS::quit; onClose = [&] { application->quit = true; };
onSize = { &Utility::resizeMainWindow, utility }; onSize = [&] { utility->resizeMainWindow(); };
cartridgeLoadSNES.onTick = [&] {
string filename = OS::fileLoad(*this, "/media/sdb1/root/snes_roms/", "SNES images (*.sfc)");
if(filename == "") return;
interface->loadCartridgeSNES(filename);
};
cartridgeLoadNES.onTick = [&] { cartridgeLoadNES.onTick = [&] {
string filename = OS::fileLoad(*this, "/media/sdb1/root/nes_images/", "NES images (*.nes)"); fileBrowser->open("Load NES Cartridge", { "*.nes" }, [](string filename) {
if(filename == "") return; interface->loadCartridgeNES(filename);
interface->loadCartridgeNES(filename); });
};
cartridgeLoadSNES.onTick = [&] {
fileBrowser->open("Load SNES Cartridge", { "*.sfc" }, [](string filename) {
interface->loadCartridgeSNES(filename);
});
}; };
cartridgeLoadGameBoy.onTick = [&] { cartridgeLoadGameBoy.onTick = [&] {
string filename = OS::fileLoad(*this, "/media/sdb1/root/gameboy_images/", "Game Boy images (*.gb, *.gbc)"); fileBrowser->open("Load Game Boy Cartridge", { "*.gb", "*.gbc" }, [](string filename) {
if(filename == "") return; interface->loadCartridgeGameBoy(filename);
interface->loadCartridgeGameBoy(filename); });
}; };
nesPower.onTick = { &Interface::power, interface }; nesPower.onTick = { &Interface::power, interface };
@ -118,6 +124,8 @@ MainWindow::MainWindow() {
dspaudio.setVolume(settingsMuteAudio.checked() ? 0.0 : 1.0); dspaudio.setVolume(settingsMuteAudio.checked() ? 0.0 : 1.0);
}; };
toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); };
helpAbout.onTick = [&] { helpAbout.onTick = [&] {
MessageWindow::information(*this, { MessageWindow::information(*this, {
application->title, "\n\n", application->title, "\n\n",

View File

@ -29,6 +29,9 @@ struct MainWindow : Window {
CheckItem settingsSynchronizeAudio; CheckItem settingsSynchronizeAudio;
CheckItem settingsMuteAudio; CheckItem settingsMuteAudio;
Menu toolsMenu;
Item toolsShrinkWindow;
Menu helpMenu; Menu helpMenu;
Item helpAbout; Item helpAbout;

View File

@ -3,12 +3,23 @@
Application *application = 0; Application *application = 0;
nall::DSP dspaudio; nall::DSP dspaudio;
Application::Application(int argc, char **argv) { void Application::run() {
interface->input_poll();
if(interface->loaded() == false) {
usleep(20 * 1000);
return;
}
interface->run();
}
Application::Application(int argc, char **argv) : quit(false) {
application = this; application = this;
interface = new Interface; interface = new Interface;
utility = new Utility; utility = new Utility;
title = "batch v000"; title = "batch";
#if defined(PLATFORM_WIN) #if defined(PLATFORM_WIN)
string videoDriver = "Direct3D", audioDriver = "XAudio2", inputDriver = "RawInput"; string videoDriver = "Direct3D", audioDriver = "XAudio2", inputDriver = "RawInput";
@ -21,6 +32,7 @@ Application::Application(int argc, char **argv) {
#endif #endif
mainWindow = new MainWindow; mainWindow = new MainWindow;
fileBrowser = new FileBrowser;
utility->setMode(Interface::Mode::None); utility->setMode(Interface::Mode::None);
mainWindow->setVisible(); mainWindow->setVisible();
@ -47,30 +59,19 @@ Application::Application(int argc, char **argv) {
input.set(Input::Handle, mainWindow->viewport.handle()); input.set(Input::Handle, mainWindow->viewport.handle());
input.init(); input.init();
timer.onTimeout = { &Application::run, this }; while(quit == false) {
timer.setInterval(0); OS::processEvents();
timer.setEnabled(); Application::run();
}
OS::main();
} }
Application::~Application() { Application::~Application() {
delete fileBrowser;
delete mainWindow; delete mainWindow;
delete utility; delete utility;
delete interface; delete interface;
} }
void Application::run() {
interface->input_poll();
if(interface->loaded() == false) {
usleep(20 * 1000);
return;
}
interface->run();
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
new Application(argc, argv); new Application(argc, argv);
delete application; delete application;

View File

@ -37,7 +37,7 @@ void Utility::setMode(Interface::Mode mode) {
resizeMainWindow(); resizeMainWindow();
} }
void Utility::resizeMainWindow() { void Utility::resizeMainWindow(bool shrink) {
Geometry geometry = mainWindow->geometry(); Geometry geometry = mainWindow->geometry();
unsigned width = geometry.width, height = geometry.height; unsigned width = geometry.width, height = geometry.height;
@ -54,10 +54,18 @@ void Utility::resizeMainWindow() {
width = width * maxM; width = width * maxM;
height = height * maxM; height = height * maxM;
mainWindow->viewport.setGeometry({ if(shrink == false) {
(geometry.width - width) / 2, (geometry.height - height) / 2, mainWindow->viewport.setGeometry({
width, height (geometry.width - width) / 2, (geometry.height - height) / 2,
}); width, height
});
} else {
mainWindow->setGeometry({ geometry.x, geometry.y, width, height });
mainWindow->viewport.setGeometry({ 0, 0, width, height });
}
}
void Utility::shrinkMainWindow() {
} }
void Utility::toggleFullScreen() { void Utility::toggleFullScreen() {

View File

@ -1,6 +1,7 @@
struct Utility { struct Utility {
void setMode(Interface::Mode mode); void setMode(Interface::Mode mode);
void resizeMainWindow(); void resizeMainWindow(bool shrink = false);
void shrinkMainWindow();
void toggleFullScreen(); void toggleFullScreen();
}; };