From 802d092b13db319811886e2099f01f36648605f9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 17 Nov 2016 12:21:41 +0000 Subject: [PATCH] When exporting files, initially fill in the basename of the sketch. This is a common and convenient behavior; the basename is pre-selected, so exporting multiple views requires just one keystroke to put the cursor after the basename. --- src/platform/cocoamain.mm | 18 ++++++++++++++---- src/platform/gtkmain.cpp | 22 ++++++++++------------ src/platform/w32main.cpp | 20 ++++++++++++++++---- src/solvespace.cpp | 24 +++++++----------------- src/solvespace.h | 3 +++ src/util.cpp | 36 ++++++++++++++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 37 deletions(-) diff --git a/src/platform/cocoamain.mm b/src/platform/cocoamain.mm index 9838058a..12496991 100644 --- a/src/platform/cocoamain.mm +++ b/src/platform/cocoamain.mm @@ -769,7 +769,6 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension, [panel setAccessoryView:[controller view]]; NSMutableArray *extensions = [[NSMutableArray alloc] init]; - [controller setExtensions:extensions]; NSPopUpButton *button = [controller button]; [button removeAllItems]; @@ -787,6 +786,8 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension, [button addItemWithTitle:[NSString stringWithUTF8String:title.c_str()]]; [extensions addObject:[NSString stringWithUTF8String:ssFilter->patterns[0]]]; } + [panel setAllowedFileTypes:extensions]; + [controller setExtensions:extensions]; int extensionIndex = 0; if(defExtension != "") { @@ -796,10 +797,19 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension, extensionIndex = 0; } } - [button selectItemAtIndex:extensionIndex]; - [panel setNameFieldStringValue:[@"untitled" - stringByAppendingPathExtension:[extensions objectAtIndex:extensionIndex]]]; + + if(file->empty()) { + [panel setNameFieldStringValue:[@"untitled" + stringByAppendingPathExtension:[extensions objectAtIndex:extensionIndex]]]; + } else { + [panel setDirectoryURL: + [NSURL fileURLWithPath:[NSString stringWithUTF8String:Dirname(*file).c_str()] + isDirectory:NO]]; + [panel setNameFieldStringValue: + [[NSString stringWithUTF8String:Basename(*file, /*stripExtension=*/true).c_str()] + stringByAppendingPathExtension:[extensions objectAtIndex:extensionIndex]]]; + } if([panel runModal] == NSFileHandlingPanelOKButton) { *file = [[NSFileManager defaultManager] diff --git a/src/platform/gtkmain.cpp b/src/platform/gtkmain.cpp index 7cada7e4..60e210ac 100644 --- a/src/platform/gtkmain.cpp +++ b/src/platform/gtkmain.cpp @@ -1113,14 +1113,6 @@ bool GetOpenFile(std::string *filename, const std::string &activeOrEmpty, } } -/* Glib::path_get_basename got /removed/ in 3.0?! Come on */ -static std::string Basename(std::string filename) { - int slash = filename.rfind('/'); - if(slash >= 0) - return filename.substr(slash + 1, filename.length()); - return ""; -} - static void ChooserFilterChanged(Gtk::FileChooserDialog *chooser) { /* Extract the pattern from the filter. GtkFileFilter doesn't provide @@ -1150,7 +1142,7 @@ static void ChooserFilterChanged(Gtk::FileChooserDialog *chooser) } } -bool GetSaveFile(std::string *filename, const std::string &activeOrEmpty, +bool GetSaveFile(std::string *filename, const std::string &defExtension, const FileFilter filters[]) { Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Save File", Gtk::FILE_CHOOSER_ACTION_SAVE); @@ -1158,10 +1150,16 @@ bool GetSaveFile(std::string *filename, const std::string &activeOrEmpty, chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL); chooser.add_button("_Save", Gtk::RESPONSE_OK); - std::string active = ConvertFilters(activeOrEmpty, filters, &chooser); + std::string activeExtension = ConvertFilters(defExtension, filters, &chooser); - chooser.set_current_folder(CnfThawString("", "FileChooserPath")); - chooser.set_current_name(std::string("untitled.") + active); + if(filename->empty()) { + chooser.set_current_folder(CnfThawString("", "FileChooserPath")); + chooser.set_current_name("untitled." + activeExtension); + } else { + chooser.set_current_folder(Dirname(*filename)); + chooser.set_current_name(Basename(*filename, /*stripExtension=*/true) + + "." + activeExtension); + } /* Gtk's dialog doesn't change the extension when you change the filter, and makes it extremely hard to do so. Gtk is garbage. */ diff --git a/src/platform/w32main.cpp b/src/platform/w32main.cpp index 1460abcd..2b41b6a6 100644 --- a/src/platform/w32main.cpp +++ b/src/platform/w32main.cpp @@ -996,16 +996,28 @@ static std::string ConvertFilters(const FileFilter ssFilters[]) { static bool OpenSaveFile(bool isOpen, std::string *filename, const std::string &defExtension, const FileFilter filters[]) { + std::string activeExtension = defExtension; + if(activeExtension == "") { + activeExtension = filters[0].patterns[0]; + } + + std::wstring initialFilenameW; + if(filename->empty()) { + initialFilenameW = Widen("untitled"); + } else { + initialFilenameW = Widen(Dirname(*filename) + PATH_SEP + + Basename(*filename, /*stripExtension=*/true)); + } + std::wstring selPatternW = Widen(ConvertFilters(filters)); + std::wstring defExtensionW = Widen(defExtension); + // UNC paths may be as long as 32767 characters. // Unfortunately, the Get*FileName API does not provide any way to use it // except with a preallocated buffer of fixed size, so we use something // reasonably large. const int len = 32768; wchar_t filenameC[len] = {}; - wcsncpy(filenameC, Widen(*filename).c_str(), len - 1); - - std::wstring selPatternW = Widen(ConvertFilters(filters)); - std::wstring defExtensionW = Widen(defExtension); + wcsncpy(filenameC, initialFilenameW.c_str(), len - 1); OPENFILENAME ofn = {}; ofn.lStructSize = sizeof(ofn); diff --git a/src/solvespace.cpp b/src/solvespace.cpp index f7b8a916..50efb5fa 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -417,16 +417,6 @@ void SolveSpaceUI::UpdateWindowTitle() { SetCurrentFilename(saveFile); } -static std::string Extension(const std::string &filename) { - int dot = filename.rfind('.'); - if(dot >= 0) { - std::string ext = filename.substr(dot + 1, filename.length()); - std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); - return ext; - } - return ""; -} - void SolveSpaceUI::MenuFile(Command id) { if((uint32_t)id >= (uint32_t)Command::RECENT_OPEN && (uint32_t)id < ((uint32_t)Command::RECENT_OPEN+MAX_RECENT)) { @@ -465,14 +455,14 @@ void SolveSpaceUI::MenuFile(Command id) { break; case Command::EXPORT_PNG: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(!GetSaveFile(&exportFile, "", PngFileFilter)) break; SS.ExportAsPngTo(exportFile); break; } case Command::EXPORT_VIEW: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(!GetSaveFile(&exportFile, CnfThawString("", "ViewExportFormat"), VectorFileFilter)) break; CnfFreezeString(Extension(exportFile), "ViewExportFormat"); @@ -494,7 +484,7 @@ void SolveSpaceUI::MenuFile(Command id) { } case Command::EXPORT_WIREFRAME: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(!GetSaveFile(&exportFile, CnfThawString("", "WireframeExportFormat"), Vector3dFileFilter)) break; CnfFreezeString(Extension(exportFile), "WireframeExportFormat"); @@ -504,7 +494,7 @@ void SolveSpaceUI::MenuFile(Command id) { } case Command::EXPORT_SECTION: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(!GetSaveFile(&exportFile, CnfThawString("", "SectionExportFormat"), VectorFileFilter)) break; CnfFreezeString(Extension(exportFile), "SectionExportFormat"); @@ -514,7 +504,7 @@ void SolveSpaceUI::MenuFile(Command id) { } case Command::EXPORT_MESH: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(!GetSaveFile(&exportFile, CnfThawString("", "MeshExportFormat"), MeshFileFilter)) break; CnfFreezeString(Extension(exportFile), "MeshExportFormat"); @@ -524,7 +514,7 @@ void SolveSpaceUI::MenuFile(Command id) { } case Command::EXPORT_SURFACES: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(!GetSaveFile(&exportFile, CnfThawString("", "SurfacesExportFormat"), SurfaceFileFilter)) break; CnfFreezeString(Extension(exportFile), "SurfacesExportFormat"); @@ -759,7 +749,7 @@ void SolveSpaceUI::MenuAnalyze(Command id) { break; case Command::STOP_TRACING: { - std::string exportFile; + std::string exportFile = SS.saveFile; if(GetSaveFile(&exportFile, "", CsvFileFilter)) { FILE *f = ssfopen(exportFile, "wb"); if(f) { diff --git a/src/solvespace.h b/src/solvespace.h index 1593952d..3c1e30be 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -367,6 +367,9 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14, double a41, double a42, double a43, double a44); std::string MakeAcceleratorLabel(int accel); bool FilenameHasExtension(const std::string &str, const char *ext); +std::string Extension(const std::string &filename); +std::string Basename(std::string filename, bool stripExtension = false); +std::string Dirname(std::string filename); bool ReadFile(const std::string &filename, std::string *data); bool WriteFile(const std::string &filename, const std::string &data); void Message(const char *str, ...); diff --git a/src/util.cpp b/src/util.cpp index f12693bf..ecff190f 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -62,6 +62,42 @@ bool SolveSpace::FilenameHasExtension(const std::string &str, const char *ext) return true; } +std::string SolveSpace::Extension(const std::string &filename) { + int dot = filename.rfind('.'); + if(dot >= 0) { + std::string ext = filename.substr(dot + 1, filename.length()); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + return ext; + } + + return ""; +} + +std::string SolveSpace::Basename(std::string filename, bool stripExtension) { + int slash = filename.rfind(PATH_SEP); + if(slash >= 0) { + filename = filename.substr(slash + 1, filename.length()); + } + + if(stripExtension) { + int dot = filename.rfind('.'); + if(dot >= 0) { + filename = filename.substr(0, dot); + } + } + + return filename; +} + +std::string SolveSpace::Dirname(std::string filename) { + int slash = filename.rfind(PATH_SEP); + if(slash >= 0) { + return filename.substr(0, slash); + } + + return ""; +} + bool SolveSpace::ReadFile(const std::string &filename, std::string *data) { FILE *f = ssfopen(filename.c_str(), "rb");