mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-01-18 05:08:55 +01:00
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:
parent
ec7e4087fb
commit
8618334356
@ -125,7 +125,10 @@
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
@ -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; }
|
||||
|
||||
string& string::operator=(const string &value) {
|
||||
if(&value == this) return *this;
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
string& string::operator=(string &&source) {
|
||||
if(&source == this) return *this;
|
||||
if(data) free(data);
|
||||
size = source.size;
|
||||
data = source.data;
|
||||
@ -87,11 +89,13 @@ template<typename... Args> string::string(Args&&... args) {
|
||||
}
|
||||
|
||||
string::string(const string &value) {
|
||||
if(&value == this) return;
|
||||
size = strlen(value);
|
||||
data = strdup(value);
|
||||
}
|
||||
|
||||
string::string(string &&source) {
|
||||
if(&source == this) return;
|
||||
size = source.size;
|
||||
data = source.data;
|
||||
source.data = 0;
|
||||
|
@ -306,6 +306,10 @@ Window::~Window() {
|
||||
//Action
|
||||
//======
|
||||
|
||||
bool Action::enabled() {
|
||||
return state.enabled;
|
||||
}
|
||||
|
||||
void Action::setEnabled(bool enabled) {
|
||||
state.enabled = enabled;
|
||||
return p.setEnabled(enabled);
|
||||
@ -316,6 +320,10 @@ void Action::setVisible(bool visible) {
|
||||
return p.setVisible(visible);
|
||||
}
|
||||
|
||||
bool Action::visible() {
|
||||
return state.visible;
|
||||
}
|
||||
|
||||
Action::Action(pAction &p):
|
||||
state(*new State),
|
||||
Object(p),
|
||||
|
@ -162,8 +162,10 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
|
||||
};
|
||||
|
||||
struct Action : Object {
|
||||
bool enabled();
|
||||
void setEnabled(bool enabled = true);
|
||||
void setVisible(bool visible = true);
|
||||
bool visible();
|
||||
|
||||
Action(pAction &p);
|
||||
~Action();
|
||||
|
@ -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;
|
||||
GdkWindow *gdkWindow = gtk_widget_get_window(widget);
|
||||
|
||||
//update geometry settings
|
||||
GdkRectangle border, client;
|
||||
gdk_window_get_frame_extents(gdkWindow, &border);
|
||||
gdk_window_get_geometry(gdkWindow, 0, 0, &client.width, &client.height, 0);
|
||||
gdk_window_get_origin(gdkWindow, &client.x, &client.y);
|
||||
|
||||
settings.frameGeometryX = client.x - border.x;
|
||||
settings.frameGeometryY = client.y - border.y;
|
||||
settings.frameGeometryWidth = border.width - client.width;
|
||||
settings.frameGeometryHeight = border.height - client.height;
|
||||
if(window->state.fullScreen == false) {
|
||||
//update geometry settings
|
||||
settings.frameGeometryX = client.x - border.x;
|
||||
settings.frameGeometryY = client.y - border.y;
|
||||
settings.frameGeometryWidth = border.width - client.width;
|
||||
settings.frameGeometryHeight = border.height - client.height;
|
||||
}
|
||||
|
||||
//move
|
||||
if(event->configure.x != window->p.lastConfigure.x
|
||||
@ -167,10 +169,20 @@ void pWindow::setFullScreen(bool fullScreen) {
|
||||
}
|
||||
|
||||
void pWindow::setGeometry(const Geometry &geometry) {
|
||||
OS::processEvents();
|
||||
|
||||
Geometry margin = frameMargin();
|
||||
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_window_resize(GTK_WINDOW(widget), geometry.width + margin.width, geometry.height + margin.height);
|
||||
|
||||
foreach(layout, window.state.layout) {
|
||||
Geometry geometry = this->geometry();
|
||||
geometry.x = geometry.y = 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
** 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)
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost!
|
||||
|
@ -97,6 +97,8 @@ void pWindow::setGeometry(const Geometry &geometry_) {
|
||||
setResizable(window.state.resizable);
|
||||
qtWindow->move(geometry.x - margin.x, geometry.y - margin.y);
|
||||
qtWindow->adjustSize();
|
||||
qtWindow->setMinimumSize(1u, 1u);
|
||||
qtContainer->setMinimumSize(1u, 1u);
|
||||
|
||||
foreach(layout, window.state.layout) {
|
||||
geometry = geometry_;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "widget/viewport.cpp"
|
||||
|
||||
static void OS_keyboardProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static void OS_processDialogMessage(MSG&);
|
||||
static LRESULT CALLBACK OS_windowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
Geometry pOS::availableGeometry() {
|
||||
@ -129,13 +130,7 @@ string pOS::folderSelect(Window &parent, const string &path) {
|
||||
void pOS::main() {
|
||||
MSG msg;
|
||||
while(GetMessage(&msg, 0, 0, 0)) {
|
||||
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) {
|
||||
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);
|
||||
}
|
||||
OS_processDialogMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,17 +143,35 @@ void pOS::processEvents() {
|
||||
while(pendingEvents()) {
|
||||
MSG msg;
|
||||
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||
if(msg.message == WM_KEYDOWN || msg.message == WM_KEYUP) {
|
||||
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);
|
||||
}
|
||||
OS_processDialogMessage(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() {
|
||||
PostQuitMessage(0);
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ void pWindow::append(Layout &layout) {
|
||||
}
|
||||
|
||||
void pWindow::append(Menu &menu) {
|
||||
menu.p.parentWindow = &window;
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
@ -192,7 +193,9 @@ void pWindow::updateMenu() {
|
||||
|
||||
foreach(menu, window.state.menu) {
|
||||
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);
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "082.04";
|
||||
static const char Version[] = "082.05";
|
||||
static const unsigned SerializerVersion = 21;
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ using namespace ruby;
|
||||
#include "general/general.hpp"
|
||||
|
||||
struct Application {
|
||||
bool quit;
|
||||
|
||||
string title;
|
||||
string normalFont;
|
||||
string boldFont;
|
||||
|
||||
Timer timer;
|
||||
|
||||
void run();
|
||||
Application(int argc, char **argv);
|
||||
~Application();
|
||||
|
83
bsnes/ui/general/file-browser.cpp
Executable file
83
bsnes/ui/general/file-browser.cpp
Executable 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);
|
||||
}
|
23
bsnes/ui/general/file-browser.hpp
Executable file
23
bsnes/ui/general/file-browser.hpp
Executable 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;
|
@ -1,2 +1,3 @@
|
||||
#include "../base.hpp"
|
||||
#include "main-window.cpp"
|
||||
#include "file-browser.cpp"
|
||||
|
@ -1 +1,2 @@
|
||||
#include "main-window.hpp"
|
||||
#include "file-browser.hpp"
|
||||
|
@ -31,6 +31,9 @@ MainWindow::MainWindow() {
|
||||
settingsSynchronizeAudio.setChecked();
|
||||
settingsMuteAudio.setText("Mute Audio");
|
||||
|
||||
toolsMenu.setText("Tools");
|
||||
toolsShrinkWindow.setText("Shrink Window");
|
||||
|
||||
helpMenu.setText("Help");
|
||||
helpAbout.setText("About ...");
|
||||
|
||||
@ -61,6 +64,9 @@ MainWindow::MainWindow() {
|
||||
settingsMenu.append(settingsSynchronizeAudio);
|
||||
settingsMenu.append(settingsMuteAudio);
|
||||
|
||||
append(toolsMenu);
|
||||
toolsMenu.append(toolsShrinkWindow);
|
||||
|
||||
append(helpMenu);
|
||||
helpMenu.append(helpAbout);
|
||||
|
||||
@ -74,25 +80,25 @@ MainWindow::MainWindow() {
|
||||
layout.append(viewport, { 0, 0, 512, 480 });
|
||||
append(layout);
|
||||
|
||||
onClose = &OS::quit;
|
||||
onSize = { &Utility::resizeMainWindow, utility };
|
||||
|
||||
cartridgeLoadSNES.onTick = [&] {
|
||||
string filename = OS::fileLoad(*this, "/media/sdb1/root/snes_roms/", "SNES images (*.sfc)");
|
||||
if(filename == "") return;
|
||||
interface->loadCartridgeSNES(filename);
|
||||
};
|
||||
onClose = [&] { application->quit = true; };
|
||||
onSize = [&] { utility->resizeMainWindow(); };
|
||||
|
||||
cartridgeLoadNES.onTick = [&] {
|
||||
string filename = OS::fileLoad(*this, "/media/sdb1/root/nes_images/", "NES images (*.nes)");
|
||||
if(filename == "") return;
|
||||
interface->loadCartridgeNES(filename);
|
||||
fileBrowser->open("Load NES Cartridge", { "*.nes" }, [](string filename) {
|
||||
interface->loadCartridgeNES(filename);
|
||||
});
|
||||
};
|
||||
|
||||
cartridgeLoadSNES.onTick = [&] {
|
||||
fileBrowser->open("Load SNES Cartridge", { "*.sfc" }, [](string filename) {
|
||||
interface->loadCartridgeSNES(filename);
|
||||
});
|
||||
};
|
||||
|
||||
cartridgeLoadGameBoy.onTick = [&] {
|
||||
string filename = OS::fileLoad(*this, "/media/sdb1/root/gameboy_images/", "Game Boy images (*.gb, *.gbc)");
|
||||
if(filename == "") return;
|
||||
interface->loadCartridgeGameBoy(filename);
|
||||
fileBrowser->open("Load Game Boy Cartridge", { "*.gb", "*.gbc" }, [](string filename) {
|
||||
interface->loadCartridgeGameBoy(filename);
|
||||
});
|
||||
};
|
||||
|
||||
nesPower.onTick = { &Interface::power, interface };
|
||||
@ -118,6 +124,8 @@ MainWindow::MainWindow() {
|
||||
dspaudio.setVolume(settingsMuteAudio.checked() ? 0.0 : 1.0);
|
||||
};
|
||||
|
||||
toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); };
|
||||
|
||||
helpAbout.onTick = [&] {
|
||||
MessageWindow::information(*this, {
|
||||
application->title, "\n\n",
|
||||
|
@ -29,6 +29,9 @@ struct MainWindow : Window {
|
||||
CheckItem settingsSynchronizeAudio;
|
||||
CheckItem settingsMuteAudio;
|
||||
|
||||
Menu toolsMenu;
|
||||
Item toolsShrinkWindow;
|
||||
|
||||
Menu helpMenu;
|
||||
Item helpAbout;
|
||||
|
||||
|
@ -3,12 +3,23 @@
|
||||
Application *application = 0;
|
||||
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;
|
||||
interface = new Interface;
|
||||
utility = new Utility;
|
||||
|
||||
title = "batch v000";
|
||||
title = "batch";
|
||||
|
||||
#if defined(PLATFORM_WIN)
|
||||
string videoDriver = "Direct3D", audioDriver = "XAudio2", inputDriver = "RawInput";
|
||||
@ -21,6 +32,7 @@ Application::Application(int argc, char **argv) {
|
||||
#endif
|
||||
|
||||
mainWindow = new MainWindow;
|
||||
fileBrowser = new FileBrowser;
|
||||
utility->setMode(Interface::Mode::None);
|
||||
mainWindow->setVisible();
|
||||
|
||||
@ -47,30 +59,19 @@ Application::Application(int argc, char **argv) {
|
||||
input.set(Input::Handle, mainWindow->viewport.handle());
|
||||
input.init();
|
||||
|
||||
timer.onTimeout = { &Application::run, this };
|
||||
timer.setInterval(0);
|
||||
timer.setEnabled();
|
||||
|
||||
OS::main();
|
||||
while(quit == false) {
|
||||
OS::processEvents();
|
||||
Application::run();
|
||||
}
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
delete fileBrowser;
|
||||
delete mainWindow;
|
||||
delete utility;
|
||||
delete interface;
|
||||
}
|
||||
|
||||
void Application::run() {
|
||||
interface->input_poll();
|
||||
|
||||
if(interface->loaded() == false) {
|
||||
usleep(20 * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
interface->run();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
new Application(argc, argv);
|
||||
delete application;
|
||||
|
@ -37,7 +37,7 @@ void Utility::setMode(Interface::Mode mode) {
|
||||
resizeMainWindow();
|
||||
}
|
||||
|
||||
void Utility::resizeMainWindow() {
|
||||
void Utility::resizeMainWindow(bool shrink) {
|
||||
Geometry geometry = mainWindow->geometry();
|
||||
unsigned width = geometry.width, height = geometry.height;
|
||||
|
||||
@ -54,10 +54,18 @@ void Utility::resizeMainWindow() {
|
||||
width = width * maxM;
|
||||
height = height * maxM;
|
||||
|
||||
mainWindow->viewport.setGeometry({
|
||||
(geometry.width - width) / 2, (geometry.height - height) / 2,
|
||||
width, height
|
||||
});
|
||||
if(shrink == false) {
|
||||
mainWindow->viewport.setGeometry({
|
||||
(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() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
struct Utility {
|
||||
void setMode(Interface::Mode mode);
|
||||
void resizeMainWindow();
|
||||
void resizeMainWindow(bool shrink = false);
|
||||
void shrinkMainWindow();
|
||||
void toggleFullScreen();
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user