Internationalize platform-specific code.

pull/106/head
whitequark 2017-01-11 02:44:29 +00:00
parent aeebc3c395
commit c12672be66
9 changed files with 696 additions and 181 deletions

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: SolveSpace 3.0\n"
"Report-Msgid-Bugs-To: whitequark@whitequark.org\n"
"POT-Creation-Date: 2017-01-07 06:44+0000\n"
"POT-Creation-Date: 2017-01-11 03:01+0000\n"
"PO-Revision-Date: 2017-01-05 10:30+0000\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@ -1398,6 +1398,191 @@ msgstr "click to place bottom left of text"
msgid "NEW COMMENT -- DOUBLE-CLICK TO EDIT"
msgstr "NEW COMMENT -- DOUBLE-CLICK TO EDIT"
#: platform/cocoamain.mm:481 platform/gtkmain.cpp:582 platform/w32main.cpp:448
#: platform/w32main.cpp:1373
msgctxt "title"
msgid "(new sketch)"
msgstr "(new sketch)"
#: platform/cocoamain.mm:710 platform/gtkmain.cpp:896 platform/w32main.cpp:1292
msgid "(no recent files)"
msgstr "(no recent files)"
#: platform/cocoamain.mm:828 platform/gtkmain.cpp:1010
msgid "untitled"
msgstr "untitled"
#: platform/cocoamain.mm:859
msgid "Do you want to save the changes you made to the new sketch?"
msgstr "Do you want to save the changes you made to the new sketch?"
#: platform/cocoamain.mm:861
msgid "Your changes will be lost if you don't save them."
msgstr "Your changes will be lost if you don't save them."
#: platform/cocoamain.mm:862
msgctxt "button"
msgid "Save"
msgstr "Save"
#: platform/cocoamain.mm:863 platform/cocoamain.mm:904
msgctxt "button"
msgid "Cancel"
msgstr "Cancel"
#: platform/cocoamain.mm:864
msgctxt "button"
msgid "Don't Save"
msgstr "Don't Save"
#: platform/cocoamain.mm:879
msgid "An autosave file is availible for this project."
msgstr "An autosave file is availible for this project."
#: platform/cocoamain.mm:881
msgid "Do you want to load the autosave file instead?"
msgstr "Do you want to load the autosave file instead?"
#: platform/cocoamain.mm:882
msgctxt "button"
msgid "Load"
msgstr "Load"
#: platform/cocoamain.mm:883
msgctxt "button"
msgid "Don't Load"
msgstr "Don't Load"
#: platform/cocoamain.mm:899
msgid ""
"Do you want to locate it manually?\n"
"If you select “No”, any geometry that depends on the missing file will be "
"removed."
msgstr ""
"Do you want to locate it manually?\n"
"If you select “No”, any geometry that depends on the missing file will be "
"removed."
#: platform/cocoamain.mm:902
msgctxt "button"
msgid "Yes"
msgstr "Yes"
#: platform/cocoamain.mm:905
msgctxt "button"
msgid "No"
msgstr "No"
#: platform/cocoamain.mm:1125 platform/w32main.cpp:180
msgctxt "button"
msgid "OK"
msgstr "OK"
#: platform/cocoamain.mm:1208 platform/gtkmain.cpp:1377
#: platform/w32main.cpp:1395 platform/w32main.cpp:1435
msgctxt "title"
msgid "Property Browser"
msgstr "Property Browser"
#: platform/gtkmain.cpp:952
msgctxt "title"
msgid "Open File"
msgstr "Open File"
#: platform/gtkmain.cpp:954
msgid "_Cancel"
msgstr "_Cancel"
#: platform/gtkmain.cpp:955
msgid "_Open"
msgstr "_Open"
#: platform/gtkmain.cpp:1000
msgctxt "title"
msgid "Save File"
msgstr "Save File"
#: platform/gtkmain.cpp:1003 platform/gtkmain.cpp:1040
#: platform/gtkmain.cpp:1088
msgctxt "button"
msgid "_Cancel"
msgstr "_Cancel"
#: platform/gtkmain.cpp:1004 platform/gtkmain.cpp:1038
msgctxt "button"
msgid "_Save"
msgstr "_Save"
#: platform/gtkmain.cpp:1033 platform/w32main.cpp:1153
msgid ""
"The file has changed since it was last saved.\n"
"\n"
"Do you want to save the changes?"
msgstr ""
"The file has changed since it was last saved.\n"
"\n"
"Do you want to save the changes?"
#: platform/gtkmain.cpp:1037 platform/w32main.cpp:1155
msgctxt "title"
msgid "Modified File"
msgstr "Modified File"
#: platform/gtkmain.cpp:1039
msgctxt "button"
msgid "Do_n't Save"
msgstr "Do_n't Save"
#: platform/gtkmain.cpp:1057 platform/w32main.cpp:1179
msgid ""
"An autosave file is availible for this project.\n"
"\n"
"Do you want to load the autosave file instead?"
msgstr ""
"An autosave file is availible for this project.\n"
"\n"
"Do you want to load the autosave file instead?"
#: platform/gtkmain.cpp:1061 platform/w32main.cpp:1181
msgctxt "title"
msgid "Autosave Available"
msgstr "Autosave Available"
#: platform/gtkmain.cpp:1062
msgctxt "button"
msgid "_Load autosave"
msgstr "_Load autosave"
#: platform/gtkmain.cpp:1063
msgctxt "button"
msgid "Do_n't Load"
msgstr "Do_n't Load"
#: platform/gtkmain.cpp:1084 platform/w32main.cpp:1209
msgctxt "title"
msgid "Missing File"
msgstr "Missing File"
#: platform/gtkmain.cpp:1085
msgctxt "button"
msgid "_Yes"
msgstr "_Yes"
#: platform/gtkmain.cpp:1086
msgctxt "button"
msgid "_No"
msgstr "_No"
#: platform/gtkmain.cpp:1300 platform/w32main.cpp:176
msgctxt "title"
msgid "Error"
msgstr "Error"
#: platform/gtkmain.cpp:1300 platform/w32main.cpp:176
msgctxt "title"
msgid "Message"
msgstr "Message"
#: style.cpp:161
msgid ""
"Can't assign style to an entity that's derived from another entity; try "
@ -1558,6 +1743,66 @@ msgstr "Nearest isometric view"
msgid "Align view to active workplane"
msgstr "Align view to active workplane"
#: ui.h:69
msgid "SolveSpace models"
msgstr "SolveSpace models"
#: ui.h:74
msgid "PNG file"
msgstr "PNG file"
#: ui.h:79
msgid "STL mesh"
msgstr "STL mesh"
#: ui.h:80
msgid "Wavefront OBJ mesh"
msgstr "Wavefront OBJ mesh"
#: ui.h:81
msgid "Three.js-compatible mesh, with viewer"
msgstr "Three.js-compatible mesh, with viewer"
#: ui.h:82
msgid "Three.js-compatible mesh, mesh only"
msgstr "Three.js-compatible mesh, mesh only"
#: ui.h:87 ui.h:95 ui.h:103
msgid "STEP file"
msgstr "STEP file"
#: ui.h:92
msgid "PDF file"
msgstr "PDF file"
#: ui.h:93
msgid "Encapsulated PostScript"
msgstr "Encapsulated PostScript"
#: ui.h:94
msgid "Scalable Vector Graphics"
msgstr "Scalable Vector Graphics"
#: ui.h:96 ui.h:104
msgid "DXF file (AutoCAD 2007)"
msgstr "DXF file (AutoCAD 2007)"
#: ui.h:97
msgid "HPGL file"
msgstr "HPGL file"
#: ui.h:98
msgid "G Code"
msgstr "G Code"
#: ui.h:109
msgid "AutoCAD DXF and DWG files"
msgstr "AutoCAD DXF and DWG files"
#: ui.h:114
msgid "Comma-separated values"
msgstr "Comma-separated values"
#: view.cpp:78
msgid "Scale cannot be zero or negative."
msgstr "Scale cannot be zero or negative."

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: SolveSpace 3.0\n"
"Report-Msgid-Bugs-To: whitequark@whitequark.org\n"
"POT-Creation-Date: 2017-01-07 06:44+0000\n"
"POT-Creation-Date: 2017-01-11 03:01+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -1212,6 +1212,180 @@ msgstr ""
msgid "NEW COMMENT -- DOUBLE-CLICK TO EDIT"
msgstr ""
#: platform/cocoamain.mm:481 platform/gtkmain.cpp:582 platform/w32main.cpp:448
#: platform/w32main.cpp:1373
msgctxt "title"
msgid "(new sketch)"
msgstr ""
#: platform/cocoamain.mm:710 platform/gtkmain.cpp:896 platform/w32main.cpp:1292
msgid "(no recent files)"
msgstr ""
#: platform/cocoamain.mm:828 platform/gtkmain.cpp:1010
msgid "untitled"
msgstr ""
#: platform/cocoamain.mm:859
msgid "Do you want to save the changes you made to the new sketch?"
msgstr ""
#: platform/cocoamain.mm:861
msgid "Your changes will be lost if you don't save them."
msgstr ""
#: platform/cocoamain.mm:862
msgctxt "button"
msgid "Save"
msgstr ""
#: platform/cocoamain.mm:863 platform/cocoamain.mm:904
msgctxt "button"
msgid "Cancel"
msgstr ""
#: platform/cocoamain.mm:864
msgctxt "button"
msgid "Don't Save"
msgstr ""
#: platform/cocoamain.mm:879
msgid "An autosave file is availible for this project."
msgstr ""
#: platform/cocoamain.mm:881
msgid "Do you want to load the autosave file instead?"
msgstr ""
#: platform/cocoamain.mm:882
msgctxt "button"
msgid "Load"
msgstr ""
#: platform/cocoamain.mm:883
msgctxt "button"
msgid "Don't Load"
msgstr ""
#: platform/cocoamain.mm:899
msgid ""
"Do you want to locate it manually?\n"
"If you select “No”, any geometry that depends on the missing file will be removed."
msgstr ""
#: platform/cocoamain.mm:902
msgctxt "button"
msgid "Yes"
msgstr ""
#: platform/cocoamain.mm:905
msgctxt "button"
msgid "No"
msgstr ""
#: platform/cocoamain.mm:1125 platform/w32main.cpp:180
msgctxt "button"
msgid "OK"
msgstr ""
#: platform/cocoamain.mm:1208 platform/gtkmain.cpp:1377 platform/w32main.cpp:1395
#: platform/w32main.cpp:1435
msgctxt "title"
msgid "Property Browser"
msgstr ""
#: platform/gtkmain.cpp:952
msgctxt "title"
msgid "Open File"
msgstr ""
#: platform/gtkmain.cpp:954
msgid "_Cancel"
msgstr ""
#: platform/gtkmain.cpp:955
msgid "_Open"
msgstr ""
#: platform/gtkmain.cpp:1000
msgctxt "title"
msgid "Save File"
msgstr ""
#: platform/gtkmain.cpp:1003 platform/gtkmain.cpp:1040 platform/gtkmain.cpp:1088
msgctxt "button"
msgid "_Cancel"
msgstr ""
#: platform/gtkmain.cpp:1004 platform/gtkmain.cpp:1038
msgctxt "button"
msgid "_Save"
msgstr ""
#: platform/gtkmain.cpp:1033 platform/w32main.cpp:1153
msgid ""
"The file has changed since it was last saved.\n"
"\n"
"Do you want to save the changes?"
msgstr ""
#: platform/gtkmain.cpp:1037 platform/w32main.cpp:1155
msgctxt "title"
msgid "Modified File"
msgstr ""
#: platform/gtkmain.cpp:1039
msgctxt "button"
msgid "Do_n't Save"
msgstr ""
#: platform/gtkmain.cpp:1057 platform/w32main.cpp:1179
msgid ""
"An autosave file is availible for this project.\n"
"\n"
"Do you want to load the autosave file instead?"
msgstr ""
#: platform/gtkmain.cpp:1061 platform/w32main.cpp:1181
msgctxt "title"
msgid "Autosave Available"
msgstr ""
#: platform/gtkmain.cpp:1062
msgctxt "button"
msgid "_Load autosave"
msgstr ""
#: platform/gtkmain.cpp:1063
msgctxt "button"
msgid "Do_n't Load"
msgstr ""
#: platform/gtkmain.cpp:1084 platform/w32main.cpp:1209
msgctxt "title"
msgid "Missing File"
msgstr ""
#: platform/gtkmain.cpp:1085
msgctxt "button"
msgid "_Yes"
msgstr ""
#: platform/gtkmain.cpp:1086
msgctxt "button"
msgid "_No"
msgstr ""
#: platform/gtkmain.cpp:1300 platform/w32main.cpp:176
msgctxt "title"
msgid "Error"
msgstr ""
#: platform/gtkmain.cpp:1300 platform/w32main.cpp:176
msgctxt "title"
msgid "Message"
msgstr ""
#: style.cpp:161
msgid ""
"Can't assign style to an entity that's derived from another entity; try assigning a style to this "
@ -1370,6 +1544,66 @@ msgstr ""
msgid "Align view to active workplane"
msgstr ""
#: ui.h:69
msgid "SolveSpace models"
msgstr ""
#: ui.h:74
msgid "PNG file"
msgstr ""
#: ui.h:79
msgid "STL mesh"
msgstr ""
#: ui.h:80
msgid "Wavefront OBJ mesh"
msgstr ""
#: ui.h:81
msgid "Three.js-compatible mesh, with viewer"
msgstr ""
#: ui.h:82
msgid "Three.js-compatible mesh, mesh only"
msgstr ""
#: ui.h:87 ui.h:95 ui.h:103
msgid "STEP file"
msgstr ""
#: ui.h:92
msgid "PDF file"
msgstr ""
#: ui.h:93
msgid "Encapsulated PostScript"
msgstr ""
#: ui.h:94
msgid "Scalable Vector Graphics"
msgstr ""
#: ui.h:96 ui.h:104
msgid "DXF file (AutoCAD 2007)"
msgstr ""
#: ui.h:97
msgid "HPGL file"
msgstr ""
#: ui.h:98
msgid "G Code"
msgstr ""
#: ui.h:109
msgid "AutoCAD DXF and DWG files"
msgstr ""
#: ui.h:114
msgid "Comma-separated values"
msgstr ""
#: view.cpp:78
msgid "Scale cannot be zero or negative."
msgstr ""

View File

@ -125,10 +125,14 @@ else()
endforeach()
endif()
set(every_platform_SOURCES
platform/w32main.cpp
platform/gtkmain.cpp
platform/cocoamain.mm)
# solvespace library
set(solvespace_core_HEADERS
config.h
dsc.h
expr.h
polygon.h
@ -212,11 +216,15 @@ if(HAVE_GETTEXT)
set(output_pot ${CMAKE_CURRENT_SOURCE_DIR}/../res/messages.pot)
set(templ_po ${CMAKE_CURRENT_BINARY_DIR}/messages.po)
set(output_po ${CMAKE_CURRENT_SOURCE_DIR}/../res/locales/en_US.po)
set(inputs ${solvespace_core_SOURCES})
set(inputs
${solvespace_core_SOURCES}
${solvespace_core_HEADERS}
${every_platform_SOURCES})
add_custom_command(
OUTPUT ${output_pot}
COMMAND ${XGETTEXT}
--language=C++
--keyword --keyword=_ --keyword=N_ --keyword=C_:2,1c --keyword=CN_:2,1c
--force-po --width=100 --sort-by-file
--package-name=SolveSpace

View File

@ -13,16 +13,22 @@
using SolveSpace::dbp;
/* Utility functions */
static NSString* Wrap(const std::string &s) {
return [NSString stringWithUTF8String:s.c_str()];
}
/* Settings */
namespace SolveSpace {
void CnfFreezeInt(uint32_t val, const std::string &key) {
[[NSUserDefaults standardUserDefaults]
setInteger:val forKey:[NSString stringWithUTF8String:key.c_str()]];
setInteger:val forKey:Wrap(key)];
}
uint32_t CnfThawInt(uint32_t val, const std::string &key) {
NSString *nsKey = [NSString stringWithUTF8String:key.c_str()];
NSString *nsKey = Wrap(key);
if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey])
return [[NSUserDefaults standardUserDefaults] integerForKey:nsKey];
return val;
@ -30,11 +36,11 @@ uint32_t CnfThawInt(uint32_t val, const std::string &key) {
void CnfFreezeFloat(float val, const std::string &key) {
[[NSUserDefaults standardUserDefaults]
setFloat:val forKey:[NSString stringWithUTF8String:key.c_str()]];
setFloat:val forKey:Wrap(key)];
}
float CnfThawFloat(float val, const std::string &key) {
NSString *nsKey = [NSString stringWithUTF8String:key.c_str()];
NSString *nsKey = Wrap(key);
if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey])
return [[NSUserDefaults standardUserDefaults] floatForKey:nsKey];
return val;
@ -42,12 +48,12 @@ float CnfThawFloat(float val, const std::string &key) {
void CnfFreezeString(const std::string &val, const std::string &key) {
[[NSUserDefaults standardUserDefaults]
setObject:[NSString stringWithUTF8String:val.c_str()]
forKey:[NSString stringWithUTF8String:key.c_str()]];
setObject:Wrap(val)
forKey:Wrap(key)];
}
std::string CnfThawString(const std::string &val, const std::string &key) {
NSString *nsKey = [NSString stringWithUTF8String:key.c_str()];
NSString *nsKey = Wrap(key);
if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) {
NSString *nsNewVal = [[NSUserDefaults standardUserDefaults] stringForKey:nsKey];
return [nsNewVal UTF8String];
@ -459,45 +465,45 @@ void GetGraphicsWindowSize(int *w, int *h) {
*h = (int)size.height;
}
void InvalidateGraphics(void) {
void InvalidateGraphics() {
[GWView setNeedsDisplay:YES];
}
void PaintGraphics(void) {
void PaintGraphics() {
[GWView setNeedsDisplay:YES];
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, YES);
}
void SetCurrentFilename(const std::string &filename) {
if(!filename.empty()) {
[GW setTitleWithRepresentedFilename:[NSString stringWithUTF8String:filename.c_str()]];
[GW setTitleWithRepresentedFilename:Wrap(filename)];
} else {
[GW setTitle:@"(new sketch)"];
[GW setTitle:Wrap(C_("title", "(new sketch)"))];
[GW setRepresentedFilename:@""];
}
}
void ToggleFullScreen(void) {
void ToggleFullScreen() {
[GW toggleFullScreen:nil];
}
bool FullScreenIsActive(void) {
bool FullScreenIsActive() {
return [GWDelegate isFullscreen];
}
void ShowGraphicsEditControl(int x, int y, int fontHeight, int minWidthChars,
const std::string &str) {
[GWView startEditing:[NSString stringWithUTF8String:str.c_str()]
[GWView startEditing:Wrap(str)
at:(NSPoint){(CGFloat)x, (CGFloat)y}
withHeight:fontHeight
withMinWidthInChars:minWidthChars];
}
void HideGraphicsEditControl(void) {
void HideGraphicsEditControl() {
[GWView stopEditing];
}
bool GraphicsEditControlIsVisible(void) {
bool GraphicsEditControlIsVisible() {
return [GWView isEditing];
}
}
@ -547,13 +553,13 @@ void AddContextMenuItem(const char *label, ContextCommand cmd) {
}
}
void CreateContextSubmenu(void) {
void CreateContextSubmenu() {
ssassert(!contextSubmenu, "Unexpected nested submenu");
contextSubmenu = [[NSMenu alloc] initWithTitle:@""];
}
ContextCommand ShowContextMenu(void) {
ContextCommand ShowContextMenu() {
if(!contextMenu)
return ContextCommand::CANCELLED;
@ -629,7 +635,7 @@ void InitMainMenu(NSMenu *mainMenu) {
current_level = entry->level;
if(entry->label) {
label = [NSString stringWithUTF8String:Translate(entry->label).c_str()];
label = Wrap(Translate(entry->label));
/* OS X does not support mnemonics */
label = [label stringByReplacingOccurrencesOfString:@"&" withString:@""];
@ -668,7 +674,7 @@ void InitMainMenu(NSMenu *mainMenu) {
for(auto locale : Locales()) {
NSMenuItem *localeMenuItem =
[localeMenu addItemWithTitle:
[NSString stringWithUTF8String:locale.displayName.c_str()]
Wrap(locale.displayName)
action:NULL keyEquivalent:@""];
[localeMenuItem setTag:(NSInteger)i++];
[localeMenuItem setTarget:[MainMenuResponder class]];
@ -701,7 +707,7 @@ static void RefreshRecentMenu(SolveSpace::Command cmd, SolveSpace::Command base)
if(std::string(RecentFile[0]).empty()) {
NSMenuItem *placeholder = [[NSMenuItem alloc]
initWithTitle:@"(no recent files)" action:nil keyEquivalent:@""];
initWithTitle:Wrap(_("(no recent files)")) action:nil keyEquivalent:@""];
[placeholder setEnabled:NO];
[menu addItem:placeholder];
} else {
@ -710,7 +716,7 @@ static void RefreshRecentMenu(SolveSpace::Command cmd, SolveSpace::Command base)
break;
NSMenuItem *item = [[NSMenuItem alloc]
initWithTitle:[[NSString stringWithUTF8String:RecentFile[i].c_str()]
initWithTitle:[Wrap(RecentFile[i])
stringByAbbreviatingWithTildeInPath]
action:nil keyEquivalent:@""];
[item setTag:((uint32_t)base + i)];
@ -721,16 +727,16 @@ static void RefreshRecentMenu(SolveSpace::Command cmd, SolveSpace::Command base)
}
}
void RefreshRecentMenus(void) {
void RefreshRecentMenus() {
RefreshRecentMenu(Command::OPEN_RECENT, Command::RECENT_OPEN);
RefreshRecentMenu(Command::GROUP_RECENT, Command::RECENT_LINK);
}
void ToggleMenuBar(void) {
void ToggleMenuBar() {
[NSMenu setMenuBarVisible:![NSMenu menuBarVisible]];
}
bool MenuBarIsVisible(void) {
bool MenuBarIsVisible() {
return [NSMenu menuBarVisible];
}
}
@ -801,8 +807,8 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension,
desc += *ssPattern;
}
}
std::string title = std::string(ssFilter->name) + " (" + desc + ")";
[button addItemWithTitle:[NSString stringWithUTF8String:title.c_str()]];
std::string title = Translate(ssFilter->name) + " (" + desc + ")";
[button addItemWithTitle:Wrap(title)];
[extensions addObject:[NSString stringWithUTF8String:ssFilter->patterns[0]]];
}
[panel setAllowedFileTypes:extensions];
@ -810,8 +816,7 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension,
int extensionIndex = 0;
if(defExtension != "") {
extensionIndex = [extensions indexOfObject:
[NSString stringWithUTF8String:defExtension.c_str()]];
extensionIndex = [extensions indexOfObject:Wrap(defExtension)];
if(extensionIndex == -1) {
extensionIndex = 0;
}
@ -819,14 +824,15 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension,
[button selectItemAtIndex:extensionIndex];
if(file->empty()) {
[panel setNameFieldStringValue:[@"untitled"
stringByAppendingPathExtension:[extensions objectAtIndex:extensionIndex]]];
[panel setNameFieldStringValue:
[Wrap(_("untitled"))
stringByAppendingPathExtension:[extensions objectAtIndex:extensionIndex]]];
} else {
[panel setDirectoryURL:
[NSURL fileURLWithPath:[NSString stringWithUTF8String:Dirname(*file).c_str()]
[NSURL fileURLWithPath:Wrap(Dirname(*file))
isDirectory:NO]];
[panel setNameFieldStringValue:
[[NSString stringWithUTF8String:Basename(*file, /*stripExtension=*/true).c_str()]
[Wrap(Basename(*file, /*stripExtension=*/true))
stringByAppendingPathExtension:[extensions objectAtIndex:extensionIndex]]];
}
@ -839,22 +845,23 @@ bool SolveSpace::GetSaveFile(std::string *file, const std::string &defExtension,
}
}
SolveSpace::DialogChoice SolveSpace::SaveFileYesNoCancel(void) {
SolveSpace::DialogChoice SolveSpace::SaveFileYesNoCancel() {
NSAlert *alert = [[NSAlert alloc] init];
if(!std::string(SolveSpace::SS.saveFile).empty()) {
[alert setMessageText:
[[@"Do you want to save the changes you made to the sketch “"
stringByAppendingString:
[[NSString stringWithUTF8String:SolveSpace::SS.saveFile.c_str()]
[Wrap(SolveSpace::SS.saveFile)
stringByAbbreviatingWithTildeInPath]]
stringByAppendingString:@"”?"]];
} else {
[alert setMessageText:@"Do you want to save the changes you made to the new sketch?"];
[alert setMessageText:
Wrap(_("Do you want to save the changes you made to the new sketch?"))];
}
[alert setInformativeText:@"Your changes will be lost if you don't save them."];
[alert addButtonWithTitle:@"Save"];
[alert addButtonWithTitle:@"Cancel"];
[alert addButtonWithTitle:@"Don't Save"];
[alert setInformativeText:Wrap(_("Your changes will be lost if you don't save them."))];
[alert addButtonWithTitle:Wrap(C_("button", "Save"))];
[alert addButtonWithTitle:Wrap(C_("button", "Cancel"))];
[alert addButtonWithTitle:Wrap(C_("button", "Don't Save"))];
switch([alert runModal]) {
case NSAlertFirstButtonReturn:
return DIALOG_YES;
@ -866,14 +873,14 @@ SolveSpace::DialogChoice SolveSpace::SaveFileYesNoCancel(void) {
}
}
SolveSpace::DialogChoice SolveSpace::LoadAutosaveYesNo(void) {
SolveSpace::DialogChoice SolveSpace::LoadAutosaveYesNo() {
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:
@"An autosave file is availible for this project."];
Wrap(_("An autosave file is availible for this project."))];
[alert setInformativeText:
@"Do you want to load the autosave file instead?"];
[alert addButtonWithTitle:@"Load"];
[alert addButtonWithTitle:@"Don't Load"];
Wrap(_("Do you want to load the autosave file instead?"))];
[alert addButtonWithTitle:Wrap(C_("button", "Load"))];
[alert addButtonWithTitle:Wrap(C_("button", "Don't Load"))];
switch([alert runModal]) {
case NSAlertFirstButtonReturn:
return DIALOG_YES;
@ -886,16 +893,16 @@ SolveSpace::DialogChoice SolveSpace::LoadAutosaveYesNo(void) {
SolveSpace::DialogChoice SolveSpace::LocateImportedFileYesNoCancel(
const std::string &filename, bool canCancel) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:[NSString stringWithUTF8String:
("The linked file " + filename + " is not present.").c_str()]];
[alert setMessageText:
Wrap("The linked file " + filename + " is not present.")];
[alert setInformativeText:
@"Do you want to locate it manually?\n"
"If you select \"No\", any geometry that depends on "
"the missing file will be removed."];
[alert addButtonWithTitle:@"Yes"];
Wrap(_("Do you want to locate it manually?\n"
"If you select “No”, any geometry that depends on "
"the missing file will be removed."))];
[alert addButtonWithTitle:Wrap(C_("button", "Yes"))];
if(canCancel)
[alert addButtonWithTitle:@"Cancel"];
[alert addButtonWithTitle:@"No"];
[alert addButtonWithTitle:Wrap(C_("button", "Cancel"))];
[alert addButtonWithTitle:Wrap(C_("button", "No"))];
switch([alert runModal]) {
case NSAlertFirstButtonReturn:
return DIALOG_YES;
@ -1039,7 +1046,6 @@ void InitTextWindow() {
NSUtilityWindowMask)];
[[TW standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[TW standardWindowButton:NSWindowZoomButton] setHidden:YES];
[TW setTitle:@"Property Browser"];
[TW setFrameAutosaveName:@"TextWindow"];
[TW setFloatingPanel:YES];
[TW setBecomesKeyOnlyIfNeeded:YES];
@ -1082,7 +1088,7 @@ double GetScreenDpi() {
return (displayPixelSize.width / displayPhysicalSize.width) * 25.4f;
}
void InvalidateText(void) {
void InvalidateText() {
NSSize size = [TWView convertSizeToBacking:[TWView frame].size];
size.height = (SS.TW.top[SS.TW.rows - 1] + 1) * TextWindow::LINE_HEIGHT / 2;
[TWView setFrameSize:[TWView convertSizeFromBacking:size]];
@ -1098,15 +1104,15 @@ void SetMousePointerToHand(bool is_hand) {
}
void ShowTextEditControl(int x, int y, const std::string &str) {
return [TWView startEditing:[NSString stringWithUTF8String:str.c_str()]
return [TWView startEditing:Wrap(str)
at:(NSPoint){(CGFloat)x, (CGFloat)y}];
}
void HideTextEditControl(void) {
void HideTextEditControl() {
return [TWView stopEditing];
}
bool TextEditControlIsVisible(void) {
bool TextEditControlIsVisible() {
return [TWView isEditing];
}
};
@ -1116,10 +1122,10 @@ bool TextEditControlIsVisible(void) {
void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error) {
NSAlert *alert = [[NSAlert alloc] init];
[alert setAlertStyle:(error ? NSWarningAlertStyle : NSInformationalAlertStyle)];
[alert addButtonWithTitle:@"OK"];
[alert addButtonWithTitle:Wrap(C_("button", "OK"))];
/* do some additional formatting of the message these are
heuristics, but they are made failsafe and lead to nice results. */
/* do some additional formatting of the message;
these are heuristics, but they are made failsafe and lead to nice results. */
NSString *input = [NSString stringWithUTF8String:str];
NSRange dot = [input rangeOfCharacterFromSet:
[NSCharacterSet characterSetWithCharactersInString:@".:"]];
@ -1195,10 +1201,14 @@ std::vector<std::string> SolveSpace::GetFontFiles() {
@end
void SolveSpace::RefreshLocale() {
SS.UpdateWindowTitle();
SolveSpace::InitMainMenu([NSApp mainMenu]);
RefreshRecentMenus();
[TW setTitle:Wrap(C_("title", "Property Browser"))];
}
void SolveSpace::ExitNow(void) {
void SolveSpace::ExitNow() {
[NSApp stop:nil];
}

View File

@ -10,8 +10,6 @@
#include <unistd.h>
#include <time.h>
#include <iostream>
#include <json-c/json_object.h>
#include <json-c/json_util.h>
@ -53,6 +51,11 @@
#endif
namespace SolveSpace {
/* Utility functions */
std::string Title(const std::string &s) {
return "SolveSpace - " + s;
}
/* Settings */
/* Why not just use GSettings? Two reasons. It doesn't allow to easily see
@ -576,11 +579,7 @@ void PaintGraphics(void) {
}
void SetCurrentFilename(const std::string &filename) {
if(!filename.empty()) {
GW->set_title("SolveSpace - " + filename);
} else {
GW->set_title("SolveSpace - (not yet saved)");
}
GW->set_title(Title(filename.empty() ? C_("title", "(new sketch)") : filename.c_str()));
}
void ToggleFullScreen(void) {
@ -893,13 +892,13 @@ static void RefreshRecentMenu(Command cmd, Command base) {
Gtk::Menu *menu = new Gtk::Menu;
recent->set_submenu(*menu);
if(std::string(RecentFile[0]).empty()) {
Gtk::MenuItem *placeholder = new Gtk::MenuItem("(no recent files)");
if(RecentFile[0].empty()) {
Gtk::MenuItem *placeholder = new Gtk::MenuItem(_("(no recent files)"));
placeholder->set_sensitive(false);
menu->append(*placeholder);
} else {
for(size_t i = 0; i < MAX_RECENT; i++) {
if(std::string(RecentFile[i]).empty())
if(RecentFile[i].empty())
break;
RecentMenuItem *item = new RecentMenuItem(RecentFile[i], (uint32_t)base + i);
@ -921,7 +920,7 @@ static std::string ConvertFilters(std::string active, const FileFilter ssFilters
Gtk::FileChooser *chooser) {
for(const FileFilter *ssFilter = ssFilters; ssFilter->name; ssFilter++) {
Glib::RefPtr<Gtk::FileFilter> filter = Gtk::FileFilter::create();
filter->set_name(ssFilter->name);
filter->set_name(Translate(ssFilter->name));
bool is_active = false;
std::string desc = "";
@ -950,10 +949,10 @@ static std::string ConvertFilters(std::string active, const FileFilter ssFilters
bool GetOpenFile(std::string *filename, const std::string &activeOrEmpty,
const FileFilter filters[]) {
Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Open File");
Gtk::FileChooserDialog chooser(*GW, Title(C_("title", "Open File")));
chooser.set_filename(*filename);
chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
chooser.add_button("_Open", Gtk::RESPONSE_OK);
chooser.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
chooser.add_button(_("_Open"), Gtk::RESPONSE_OK);
chooser.set_current_folder(CnfThawString("", "FileChooserPath"));
ConvertFilters(activeOrEmpty, filters, &chooser);
@ -998,17 +997,17 @@ static void ChooserFilterChanged(Gtk::FileChooserDialog *chooser)
bool GetSaveFile(std::string *filename, const std::string &defExtension,
const FileFilter filters[]) {
Gtk::FileChooserDialog chooser(*GW, "SolveSpace - Save File",
Gtk::FileChooserDialog chooser(*GW, Title(C_("title", "Save File")),
Gtk::FILE_CHOOSER_ACTION_SAVE);
chooser.set_do_overwrite_confirmation(true);
chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
chooser.add_button("_Save", Gtk::RESPONSE_OK);
chooser.add_button(C_("button", "_Cancel"), Gtk::RESPONSE_CANCEL);
chooser.add_button(C_("button", "_Save"), Gtk::RESPONSE_OK);
std::string activeExtension = ConvertFilters(defExtension, filters, &chooser);
if(filename->empty()) {
chooser.set_current_folder(CnfThawString("", "FileChooserPath"));
chooser.set_current_name("untitled." + activeExtension);
chooser.set_current_name(std::string(_("untitled")) + "." + activeExtension);
} else {
chooser.set_current_folder(Dirname(*filename));
chooser.set_current_name(Basename(*filename, /*stripExtension=*/true) +
@ -1031,14 +1030,14 @@ bool GetSaveFile(std::string *filename, const std::string &defExtension,
DialogChoice SaveFileYesNoCancel(void) {
Glib::ustring message =
"The file has changed since it was last saved.\n"
"Do you want to save the changes?";
_("The file has changed since it was last saved.\n\n"
"Do you want to save the changes?");
Gtk::MessageDialog dialog(*GW, message, /*use_markup*/ true, Gtk::MESSAGE_QUESTION,
Gtk::BUTTONS_NONE, /*is_modal*/ true);
dialog.set_title("SolveSpace - Modified File");
dialog.add_button("_Save", Gtk::RESPONSE_YES);
dialog.add_button("Do_n't Save", Gtk::RESPONSE_NO);
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
dialog.set_title(Title(C_("title", "Modified File")));
dialog.add_button(C_("button", "_Save"), Gtk::RESPONSE_YES);
dialog.add_button(C_("button", "Do_n't Save"), Gtk::RESPONSE_NO);
dialog.add_button(C_("button", "_Cancel"), Gtk::RESPONSE_CANCEL);
switch(dialog.run()) {
case Gtk::RESPONSE_YES:
@ -1055,13 +1054,13 @@ DialogChoice SaveFileYesNoCancel(void) {
DialogChoice LoadAutosaveYesNo(void) {
Glib::ustring message =
"An autosave file is availible for this project.\n"
"Do you want to load the autosave file instead?";
_("An autosave file is availible for this project.\n\n"
"Do you want to load the autosave file instead?");
Gtk::MessageDialog dialog(*GW, message, /*use_markup*/ true, Gtk::MESSAGE_QUESTION,
Gtk::BUTTONS_NONE, /*is_modal*/ true);
dialog.set_title("SolveSpace - Autosave Available");
dialog.add_button("_Load autosave", Gtk::RESPONSE_YES);
dialog.add_button("Do_n't Load", Gtk::RESPONSE_NO);
dialog.set_title(Title(C_("title", "Autosave Available")));
dialog.add_button(C_("button", "_Load autosave"), Gtk::RESPONSE_YES);
dialog.add_button(C_("button", "Do_n't Load"), Gtk::RESPONSE_NO);
switch(dialog.run()) {
case Gtk::RESPONSE_YES:
@ -1076,17 +1075,17 @@ DialogChoice LoadAutosaveYesNo(void) {
DialogChoice LocateImportedFileYesNoCancel(const std::string &filename,
bool canCancel) {
Glib::ustring message =
"The linked file " + filename + " is not present.\n"
"Do you want to locate it manually?\n"
"The linked file " + filename + " is not present.\n\n"
"Do you want to locate it manually?\n\n"
"If you select \"No\", any geometry that depends on "
"the missing file will be removed.";
Gtk::MessageDialog dialog(*GW, message, /*use_markup*/ true, Gtk::MESSAGE_QUESTION,
Gtk::BUTTONS_NONE, /*is_modal*/ true);
dialog.set_title("SolveSpace - Missing File");
dialog.add_button("_Yes", Gtk::RESPONSE_YES);
dialog.add_button("_No", Gtk::RESPONSE_NO);
dialog.set_title(Title(C_("title", "Missing File")));
dialog.add_button(C_("button", "_Yes"), Gtk::RESPONSE_YES);
dialog.add_button(C_("button", "_No"), Gtk::RESPONSE_NO);
if(canCancel)
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
dialog.add_button(C_("button", "_Cancel"), Gtk::RESPONSE_CANCEL);
switch(dialog.run()) {
case Gtk::RESPONSE_YES:
@ -1167,7 +1166,6 @@ public:
set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
set_skip_taskbar_hint(true);
set_skip_pager_hint(true);
set_title("SolveSpace - Property Browser");
set_default_size(420, 300);
_box.pack_start(_overlay, true, true);
@ -1298,7 +1296,8 @@ void DoMessageBox(const char *message, int rows, int cols, bool error) {
Gtk::MessageDialog dialog(*GW, message, /*use_markup*/ true,
error ? Gtk::MESSAGE_ERROR : Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK,
/*is_modal*/ true);
dialog.set_title(error ? "SolveSpace - Error" : "SolveSpace - Message");
dialog.set_title(error ?
Title(C_("title", "Error")) : Title(C_("title", "Message")));
dialog.run();
}
@ -1365,13 +1364,17 @@ static GdkFilterReturn GdkSpnavFilter(GdkXEvent *gxevent, GdkEvent *, gpointer)
/* Application lifecycle */
void RefreshLocale() {
SS.UpdateWindowTitle();
for(auto menu : GW->get_menubar().get_children()) {
GW->get_menubar().remove(*menu);
}
InitMainMenu(&GW->get_menubar());
RefreshRecentMenus();
GW->get_menubar().show_all();
GW->get_menubar().accelerate(*GW);
GW->get_menubar().accelerate(*TW);
TW->set_title(Title(C_("title", "Property Browser")));
}
void ExitNow() {
@ -1390,7 +1393,7 @@ int main(int argc, char** argv) {
We set it back to C after all. */
setlocale(LC_ALL, "");
if(!Glib::get_charset()) {
std::cerr << "Sorry, only UTF-8 locales are supported." << std::endl;
dbp("Sorry, only UTF-8 locales are supported.");
return 1;
}
setlocale(LC_ALL, "C");
@ -1441,8 +1444,7 @@ int main(int argc, char** argv) {
if(argc >= 2) {
if(argc > 2) {
std::cerr << "Only the first file passed on command line will be opened."
<< std::endl;
dbp("Only the first file passed on command line will be opened.");
}
/* Make sure the argument is valid UTF-8. */

View File

@ -72,6 +72,13 @@ HFONT FixedFont;
SiHdl SpaceNavigator = SI_NO_HANDLE;
#endif
//-----------------------------------------------------------------------------
// Utility routines
//-----------------------------------------------------------------------------
std::wstring Title(const std::string &s) {
return Widen("SolveSpace - " + s);
}
//-----------------------------------------------------------------------------
// Routines to display message boxes on screen. Do our own, instead of using
// MessageBox, because that is not consistent from version to version and
@ -161,16 +168,16 @@ void SolveSpace::DoMessageBox(const char *str, int rows, int cols, bool error)
MessageString = str;
RECT r;
GetWindowRect(GraphicsWnd, &r);
const char *title = error ? "SolveSpace - Error" : "SolveSpace - Message";
int width = cols*SS.TW.CHAR_WIDTH + 20,
height = rows*SS.TW.LINE_HEIGHT + 60;
MessageWidth = width;
MessageHeight = height;
MessageWnd = CreateWindowClient(0, L"MessageWnd", Widen(title).c_str(),
MessageWnd = CreateWindowClient(0, L"MessageWnd",
(error ? Title(C_("title", "Error")) : Title(C_("title", "Message"))).c_str(),
WS_OVERLAPPED | WS_SYSMENU,
r.left + 100, r.top + 100, width, height, NULL, NULL, Instance, NULL);
OkButton = CreateWindowExW(0, WC_BUTTON, L"OK",
OkButton = CreateWindowExW(0, WC_BUTTON, Widen(C_("button", "OK")).c_str(),
WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | WS_VISIBLE | BS_DEFPUSHBUTTON,
(width - 70)/2, rows*SS.TW.LINE_HEIGHT + 20,
70, 25, MessageWnd, NULL, Instance, NULL);
@ -437,11 +444,8 @@ static void ThawWindowPos(HWND hwnd, const std::string &name)
}
void SolveSpace::SetCurrentFilename(const std::string &filename) {
if(!filename.empty()) {
SetWindowTextW(GraphicsWnd, Widen("SolveSpace - " + filename).c_str());
} else {
SetWindowTextW(GraphicsWnd, L"SolveSpace - (not yet saved)");
}
SetWindowTextW(GraphicsWnd,
Title(filename.empty() ? C_("title", "(new sketch)") : filename).c_str());
}
void SolveSpace::SetMousePointerToHand(bool yes) {
@ -1146,8 +1150,9 @@ DialogChoice SolveSpace::SaveFileYesNoCancel()
EnableWindow(TextWnd, false);
int r = MessageBoxW(GraphicsWnd,
L"The file has changed since it was last saved.\n\n"
L"Do you want to save the changes?", L"SolveSpace",
Widen(_("The file has changed since it was last saved.\n\n"
"Do you want to save the changes?")).c_str(),
Title(C_("title", "Modified File")).c_str(),
MB_YESNOCANCEL | MB_ICONWARNING);
EnableWindow(TextWnd, true);
@ -1171,8 +1176,9 @@ DialogChoice SolveSpace::LoadAutosaveYesNo()
EnableWindow(TextWnd, false);
int r = MessageBoxW(GraphicsWnd,
L"An autosave file is availible for this project.\n\n"
L"Do you want to load the autosave file instead?", L"SolveSpace",
Widen(_("An autosave file is availible for this project.\n\n"
"Do you want to load the autosave file instead?")).c_str(),
Title(C_("title", "Autosave Available")).c_str(),
MB_YESNO | MB_ICONWARNING);
EnableWindow(TextWnd, true);
@ -1199,7 +1205,8 @@ DialogChoice SolveSpace::LocateImportedFileYesNoCancel(const std::string &filena
"If you select \"No\", any geometry that depends on "
"the missing file will be removed.";
int r = MessageBoxW(GraphicsWnd, Widen(message).c_str(), L"SolveSpace",
int r = MessageBoxW(GraphicsWnd, Widen(message).c_str(),
Title(C_("title", "Missing File")).c_str(),
(canCancel ? MB_YESNOCANCEL : MB_YESNO) | MB_ICONWARNING);
EnableWindow(TextWnd, true);
@ -1282,7 +1289,7 @@ static void DoRecent(HMENU m, Command base)
c++;
}
}
if(c == 0) AppendMenuW(m, MF_STRING | MF_GRAYED, 0, L"(no recent files)");
if(c == 0) AppendMenuW(m, MF_STRING | MF_GRAYED, 0, Widen(_("(no recent files)")).c_str());
}
void SolveSpace::RefreshRecentMenus()
{
@ -1363,7 +1370,7 @@ static void CreateMainWindows()
ssassert(RegisterClassEx(&wc), "Cannot register window class");
GraphicsWnd = CreateWindowExW(0, L"GraphicsWnd",
L"SolveSpace (not yet saved)",
Title(C_("title", "(new sketch)")).c_str(),
WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX |
WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_CLIPSIBLINGS,
50, 50, 900, 600, NULL, NULL, Instance, NULL);
@ -1384,8 +1391,9 @@ static void CreateMainWindows()
// We get the desired Alt+Tab behaviour by specifying that the text
// window is a child of the graphics window.
TextWnd = CreateWindowExW(0,
L"TextWnd", L"SolveSpace - Property Browser", WS_THICKFRAME | WS_CLIPCHILDREN,
TextWnd = CreateWindowExW(0, L"TextWnd",
Title(C_("title", "Property Browser")).c_str(),
WS_THICKFRAME | WS_CLIPCHILDREN,
650, 500, 420, 300, GraphicsWnd, (HMENU)NULL, Instance, NULL);
ssassert(TextWnd != NULL, "Cannot create window");
@ -1415,11 +1423,16 @@ static void CreateMainWindows()
}
void SolveSpace::RefreshLocale() {
SS.UpdateWindowTitle();
HMENU oldMenu = GetMenu(GraphicsWnd);
SetMenu(GraphicsWnd, CreateGraphicsWindowMenus());
if(oldMenu != NULL) {
DestroyMenu(oldMenu);
}
RefreshRecentMenus();
SetWindowTextW(TextWnd, Title(C_("title", "Property Browser")).c_str());
}
#ifdef HAVE_SPACEWARE

View File

@ -1088,14 +1088,14 @@ PluralExpr::Token PluralExpr::Lex() {
if(reader.TryChar('=')) {
t.op = Token::Op::LE;
} else {
t.op = Token::Op::LT;
t.op = Token::Op::LT;
}
} else if(reader.TryChar('>')) {
t.type = Token::Type::BINARY_OP;
if(reader.TryChar('=')) {
t.op = Token::Op::GE;
} else {
t.op = Token::Op::GT;
t.op = Token::Op::GT;
}
} else if(reader.TryChar('!')) {
reader.ExpectChar('=');

View File

@ -169,67 +169,13 @@ DialogChoice LocateImportedFileYesNoCancel(const std::string &filename,
#define AUTOSAVE_SUFFIX "~"
struct FileFilter {
const char *name;
const char *patterns[3];
};
// SolveSpace native file format
const FileFilter SlvsFileFilter[] = {
{ "SolveSpace models", { "slvs" } },
{ NULL, {} }
};
// PNG format bitmap
const FileFilter PngFileFilter[] = {
{ "PNG file", { "png" } },
{ NULL, {} }
};
// Triangle mesh
const FileFilter MeshFileFilter[] = {
{ "STL mesh", { "stl" } },
{ "Wavefront OBJ mesh", { "obj" } },
{ "Three.js-compatible mesh, with viewer", { "html" } },
{ "Three.js-compatible mesh, mesh only", { "js" } },
{ NULL, {} }
};
// NURBS surfaces
const FileFilter SurfaceFileFilter[] = {
{ "STEP file", { "step", "stp" } },
{ NULL, {} }
};
// 2d vector (lines and curves) format
const FileFilter VectorFileFilter[] = {
{ "PDF file", { "pdf" } },
{ "Encapsulated PostScript", { "eps", "ps" } },
{ "Scalable Vector Graphics", { "svg" } },
{ "STEP file", { "step", "stp" } },
{ "DXF file (AutoCAD 2007)", { "dxf" } },
{ "HPGL file", { "plt", "hpgl" } },
{ "G Code", { "ngc", "txt" } },
{ NULL, {} }
};
// 3d vector (wireframe lines and curves) format
const FileFilter Vector3dFileFilter[] = {
{ "STEP file", { "step", "stp" } },
{ "DXF file (AutoCAD 2007)", { "dxf" } },
{ NULL, {} }
};
// All Importable formats
const FileFilter ImportableFileFilter[] = {
{ "AutoCAD DXF and DWG files", { "dxf", "dwg" } },
{ NULL, {} }
};
// Comma-separated value, like a spreadsheet would use
const FileFilter CsvFileFilter[] = {
{ "CSV", { "csv" } },
{ NULL, {} }
};
enum class Unit : uint32_t {
MM = 0,
INCHES
};
struct FileFilter;
bool GetSaveFile(std::string *filename, const std::string &defExtension,
const FileFilter filters[]);
bool GetOpenFile(std::string *filename, const std::string &defExtension,

View File

@ -58,6 +58,63 @@ inline const char *C_(const char *msgctxt, const char *msgid) {
}
#endif
// Filters for the file formats that we support.
struct FileFilter {
const char *name;
const char *patterns[3];
};
// SolveSpace native file format
const FileFilter SlvsFileFilter[] = {
{ N_("SolveSpace models"), { "slvs" } },
{ NULL, {} }
};
// PNG format bitmap
const FileFilter PngFileFilter[] = {
{ N_("PNG file"), { "png" } },
{ NULL, {} }
};
// Triangle mesh
const FileFilter MeshFileFilter[] = {
{ N_("STL mesh"), { "stl" } },
{ N_("Wavefront OBJ mesh"), { "obj" } },
{ N_("Three.js-compatible mesh, with viewer"), { "html" } },
{ N_("Three.js-compatible mesh, mesh only"), { "js" } },
{ NULL, {} }
};
// NURBS surfaces
const FileFilter SurfaceFileFilter[] = {
{ N_("STEP file"), { "step", "stp" } },
{ NULL, {} }
};
// 2d vector (lines and curves) format
const FileFilter VectorFileFilter[] = {
{ N_("PDF file"), { "pdf" } },
{ N_("Encapsulated PostScript"), { "eps", "ps" } },
{ N_("Scalable Vector Graphics"), { "svg" } },
{ N_("STEP file"), { "step", "stp" } },
{ N_("DXF file (AutoCAD 2007)"), { "dxf" } },
{ N_("HPGL file"), { "plt", "hpgl" } },
{ N_("G Code"), { "ngc", "txt" } },
{ NULL, {} }
};
// 3d vector (wireframe lines and curves) format
const FileFilter Vector3dFileFilter[] = {
{ N_("STEP file"), { "step", "stp" } },
{ N_("DXF file (AutoCAD 2007)"), { "dxf" } },
{ NULL, {} }
};
// All Importable formats
const FileFilter ImportableFileFilter[] = {
{ N_("AutoCAD DXF and DWG files"), { "dxf", "dwg" } },
{ NULL, {} }
};
// Comma-separated value, like a spreadsheet would use
const FileFilter CsvFileFilter[] = {
{ N_("Comma-separated values"), { "csv" } },
{ NULL, {} }
};
// This table describes the top-level menus in the graphics winodw.
enum class Command : uint32_t {
NONE = 0,