mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-02 20:32:45 +02:00
Update to v106r40 release.
byuu says: Changelog: - hiro: added BrowserDialog::openObject() [match file *or* folder by filters] - hiro: BrowserDialog accept button is now disabled when it would otherwise do nothing - eg openFile without a folder to enter or file to open selected - eg saveFile without a file name or with a file name that matches a folder name - bsnes: added support for gamepaks (game folders) - bsnes: store all save states inside per-game .bsz (ZIP) archives instead of .bst/ folders - this reduces the number of state files from 10+ to 1; without having folders sort before files - hiro: both gtk2 and gtk3 now use cairo to render Canvas; supports sx,sy [BearOso] - higan, bsnes: fast PPU/DSP are now run-time options instead of compile-time options - bsnes: disable fast PPU when loading Air Strike Patrol / Desert Fighter - bsnes: disable fast DSP when loading Koushien 2 - bsnes: added options to advanced panel to disable fast PPU and/or fast DSP
This commit is contained in:
@@ -36,28 +36,37 @@ private:
|
||||
auto BrowserDialogWindow::accept() -> void {
|
||||
auto batched = view.batched();
|
||||
|
||||
if(state.action == "openFile" && batched) {
|
||||
string name = batched.left()->cell(0)->text();
|
||||
if(state.action == "openFile" && batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(isFolder(name)) return setPath({state.path, name});
|
||||
response.selected.append(string{state.path, name});
|
||||
}
|
||||
|
||||
if(state.action == "openFiles") {
|
||||
if(state.action == "openFiles" && batched) {
|
||||
for(auto item : batched) {
|
||||
string name = item->cell(0)->text();
|
||||
response.selected.append(string{state.path, name, isFolder(name) ? "/" : ""});
|
||||
string name = item.text();
|
||||
if(isFolder(name)) {
|
||||
response.selected.reset();
|
||||
return;
|
||||
}
|
||||
response.selected.append(string{state.path, name});
|
||||
}
|
||||
}
|
||||
|
||||
if(state.action == "openFolder" && batched) {
|
||||
string name = batched.left()->cell(0)->text();
|
||||
if(state.action == "openFolder" && batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(!isMatch(name)) return setPath({state.path, name});
|
||||
response.selected.append(string{state.path, name, "/"});
|
||||
}
|
||||
|
||||
if(state.action == "openObject" && batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(!isMatch(name) && isFolder(name)) return setPath({state.path, name});
|
||||
response.selected.append(string{state.path, name, isFolder(name) ? "/" : ""});
|
||||
}
|
||||
|
||||
if(state.action == "saveFile") {
|
||||
string name = fileName.text();
|
||||
if(!name && batched) name = batched.left()->cell(0)->text();
|
||||
if(!name || isFolder(name)) return;
|
||||
if(file::exists({state.path, name})) {
|
||||
if(MessageDialog("File already exists. Overwrite it?").question() != "Yes") return;
|
||||
@@ -66,11 +75,11 @@ auto BrowserDialogWindow::accept() -> void {
|
||||
}
|
||||
|
||||
if(state.action == "selectFolder") {
|
||||
if(batched) {
|
||||
string name = batched.left()->cell(0)->text();
|
||||
if(isFolder(name)) response.selected.append(string{state.path, name, "/"});
|
||||
} else {
|
||||
if(!batched) {
|
||||
response.selected.append(state.path);
|
||||
} else if(batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(isFolder(name)) response.selected.append(string{state.path, name, "/"});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,16 +88,16 @@ auto BrowserDialogWindow::accept() -> void {
|
||||
|
||||
//table view item double-clicked, or enter pressed on selected table view item
|
||||
auto BrowserDialogWindow::activate() -> void {
|
||||
auto selectedItem = view.selected();
|
||||
auto batched = view.batched();
|
||||
|
||||
if(state.action == "saveFile" && selectedItem) {
|
||||
string name = selectedItem->cell(0)->text();
|
||||
if(state.action == "saveFile" && batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(isFolder(name)) return setPath({state.path, name});
|
||||
fileName.setText(name);
|
||||
}
|
||||
|
||||
if(state.action == "selectFolder" && selectedItem) {
|
||||
string name = selectedItem->cell(0)->text();
|
||||
if(state.action == "selectFolder" && batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(isFolder(name)) return setPath({state.path, name});
|
||||
}
|
||||
|
||||
@@ -97,13 +106,31 @@ auto BrowserDialogWindow::activate() -> void {
|
||||
|
||||
//table view item changed
|
||||
auto BrowserDialogWindow::change() -> void {
|
||||
fileName.setText("");
|
||||
auto batched = view.batched();
|
||||
if(state.action == "openFile") {
|
||||
acceptButton.setEnabled(batched.size() == 1);
|
||||
}
|
||||
if(state.action == "openFiles") {
|
||||
bool enabled = true;
|
||||
for(auto item : batched) enabled &= !isFolder(item.text());
|
||||
if(batched.size() == 1 && isFolder(batched[0].text())) enabled = true;
|
||||
acceptButton.setEnabled(enabled);
|
||||
}
|
||||
if(state.action == "openFolder") {
|
||||
acceptButton.setEnabled(batched.size() == 1);
|
||||
}
|
||||
if(state.action == "openObject") {
|
||||
acceptButton.setEnabled(batched.size() == 1);
|
||||
}
|
||||
if(state.action == "saveFile") {
|
||||
if(auto selectedItem = view.selected()) {
|
||||
string name = selectedItem->cell(0)->text();
|
||||
if(!isFolder(name)) fileName.setText(name);
|
||||
if(batched.size() == 1) {
|
||||
string name = batched[0].text();
|
||||
if(!isFolder(name)) fileName.setText(name).doChange();
|
||||
}
|
||||
}
|
||||
if(state.action == "selectFolder") {
|
||||
acceptButton.setEnabled(!batched || (batched.size() == 1 && isFolder(batched[0].text())));
|
||||
}
|
||||
}
|
||||
|
||||
auto BrowserDialogWindow::isFolder(const string& name) -> bool {
|
||||
@@ -138,11 +165,15 @@ auto BrowserDialogWindow::run() -> BrowserDialog::Response {
|
||||
optionList.append(ComboButtonItem().setText(option));
|
||||
}
|
||||
optionList.doChange(); //updates response.option to point to the default (first) option
|
||||
fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); });
|
||||
fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); }).onChange([&] {
|
||||
auto name = fileName.text();
|
||||
acceptButton.setEnabled(name && !isFolder(name));
|
||||
fileName.setBackgroundColor(acceptButton.enabled() ? Color{} : Color{255, 224, 224});
|
||||
});
|
||||
acceptButton.onActivate([&] { accept(); });
|
||||
if(state.action == "openFile" || state.action == "openFiles" || state.action == "openFolder") acceptButton.setText("Open");
|
||||
if(state.action == "saveFile") acceptButton.setText("Save");
|
||||
if(state.action == "selectFolder") acceptButton.setText("Select");
|
||||
if(state.action.beginsWith("open")) acceptButton.setText("Open");
|
||||
if(state.action.beginsWith("save")) acceptButton.setText("Save");
|
||||
if(state.action.beginsWith("select")) acceptButton.setText("Select");
|
||||
cancelButton.setText("Cancel").onActivate([&] { window.setModal(false); });
|
||||
|
||||
if(!state.filters) state.filters.append("All|*");
|
||||
@@ -170,26 +201,32 @@ auto BrowserDialogWindow::setPath(string path) -> void {
|
||||
path.transform("\\", "/");
|
||||
if((path || Path::root() == "/") && !path.endsWith("/")) path.append("/");
|
||||
pathName.setText(state.path = path);
|
||||
|
||||
view.reset();
|
||||
|
||||
auto contents = directory::icontents(path);
|
||||
bool folderMode = state.action == "openFolder";
|
||||
|
||||
for(auto content : contents) {
|
||||
if(!content.endsWith("/")) continue;
|
||||
content.trimRight("/");
|
||||
if(folderMode && isMatch(content)) continue;
|
||||
|
||||
bool isFolder = content.endsWith("/");
|
||||
if(isFolder) {
|
||||
content.trimRight("/", 1L);
|
||||
if(state.action == "openFolder" || state.action == "openObject") {
|
||||
if(isMatch(content)) continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
view.append(ListViewItem().setText(content).setIcon(Icon::Emblem::Folder));
|
||||
}
|
||||
|
||||
for(auto content : contents) {
|
||||
if(content.endsWith("/") != folderMode) continue; //file mode shows files; folder mode shows folders
|
||||
content.trimRight("/");
|
||||
bool isFolder = content.endsWith("/");
|
||||
if(isFolder) {
|
||||
content.trimRight("/", 1L);
|
||||
if(state.action != "openFolder" && state.action != "openObject") continue;
|
||||
} else {
|
||||
if(state.action == "openFolder") continue;
|
||||
}
|
||||
if(!isMatch(content)) continue;
|
||||
|
||||
view.append(ListViewItem().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File));
|
||||
view.append(ListViewItem().setText(content).setIcon(isFolder ? Icon::Action::Open : Icon::Emblem::File));
|
||||
}
|
||||
|
||||
Application::processEvents();
|
||||
@@ -223,6 +260,13 @@ auto BrowserDialog::openFolder() -> string {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto BrowserDialog::openObject() -> string {
|
||||
state.action = "openObject";
|
||||
if(!state.title) state.title = "Open Object";
|
||||
if(auto result = _run()) return result.left();
|
||||
return {};
|
||||
}
|
||||
|
||||
auto BrowserDialog::option() -> string {
|
||||
return response.option;
|
||||
}
|
||||
|
@@ -7,8 +7,9 @@ struct BrowserDialog {
|
||||
|
||||
BrowserDialog();
|
||||
auto openFile() -> string; //one existing file
|
||||
auto openFiles() -> string_vector; //any existing files or folders
|
||||
auto openFiles() -> string_vector; //any existing files
|
||||
auto openFolder() -> string; //one existing folder
|
||||
auto openObject() -> string; //one existing file or folder
|
||||
auto option() -> string;
|
||||
auto saveFile() -> string; //one file
|
||||
auto selected() -> string_vector;
|
||||
|
@@ -10,11 +10,13 @@ GtkSelectionData* data, unsigned type, unsigned timestamp, pCanvas* p) -> void {
|
||||
p->self().doDrop(paths);
|
||||
}
|
||||
|
||||
//GTK3
|
||||
static auto Canvas_draw(GtkWidget* widget, cairo_t* context, pCanvas* p) -> signed {
|
||||
p->_onDraw(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
//GTK2
|
||||
static auto Canvas_expose(GtkWidget* widget, GdkEventExpose* event, pCanvas* p) -> signed {
|
||||
p->_onExpose(event);
|
||||
return true;
|
||||
@@ -116,7 +118,8 @@ auto pCanvas::update() -> void {
|
||||
}
|
||||
|
||||
auto pCanvas::_onDraw(cairo_t* context) -> void {
|
||||
#if HIRO_GTK==3
|
||||
if(!surface) return;
|
||||
|
||||
int sx = 0, sy = 0, dx = 0, dy = 0;
|
||||
int width = surfaceWidth, height = surfaceHeight;
|
||||
auto geometry = pSizable::state().geometry;
|
||||
@@ -137,41 +140,19 @@ auto pCanvas::_onDraw(cairo_t* context) -> void {
|
||||
dy = 0;
|
||||
}
|
||||
|
||||
//TODO: support non-zero sx,sy
|
||||
gdk_cairo_set_source_pixbuf(context, surface, dx, dy);
|
||||
cairo_set_source_rgba(context, 0.0, 0.0, 0.0, 0.0);
|
||||
cairo_paint(context);
|
||||
gdk_cairo_set_source_pixbuf(context, surface, dx - sx, dy - sy);
|
||||
cairo_rectangle(context, dx, dy, width, height);
|
||||
cairo_paint(context);
|
||||
#endif
|
||||
}
|
||||
|
||||
auto pCanvas::_onExpose(GdkEventExpose* expose) -> void {
|
||||
#if HIRO_GTK==2
|
||||
if(surface == nullptr) return;
|
||||
if(!surface) return;
|
||||
|
||||
int sx = 0, sy = 0, dx = 0, dy = 0;
|
||||
int width = surfaceWidth;
|
||||
int height = surfaceHeight;
|
||||
auto geometry = pSizable::state().geometry;
|
||||
|
||||
if(width <= geometry.width()) {
|
||||
sx = 0;
|
||||
dx = (geometry.width() - width) / 2;
|
||||
} else {
|
||||
sx = (width - geometry.width()) / 2;
|
||||
dx = 0;
|
||||
width = geometry.width();
|
||||
}
|
||||
|
||||
if(height <= geometry.height()) {
|
||||
sy = 0;
|
||||
dy = (geometry.height() - height) / 2;
|
||||
} else {
|
||||
sy = (height - geometry.height()) / 2;
|
||||
dy = 0;
|
||||
height = geometry.height();
|
||||
}
|
||||
|
||||
gdk_draw_pixbuf(gtk_widget_get_window(gtkWidget), nullptr, surface, sx, sy, dx, dy, width, height, GDK_RGB_DITHER_NONE, 0, 0);
|
||||
#endif
|
||||
cairo_t* context = gdk_cairo_create(gtk_widget_get_window(gtkWidget));
|
||||
_onDraw(context);
|
||||
cairo_destroy(context);
|
||||
}
|
||||
|
||||
auto pCanvas::_rasterize() -> void {
|
||||
|
Reference in New Issue
Block a user