1 struct MyFrame : wxFrame { 2 typedef std::vector<std::pair<wxString, wxString>> MenuString; 3 typedef MenuString::iterator MenuStringIterator; 4 wxMenu *editmenupopup; 5 wxString exepath_; 6 wxFileHistory filehistory; 7 wxTextCtrl *filter, *replaces; 8 wxToolBar *tb; 9 int refreshhack, refreshhackinstances; 10 BlinkTimer bt; 11 wxTaskBarIcon tbi; 12 wxIcon icon; 13 ImageDropdown *idd; 14 wxAuiNotebook *nb; 15 wxAuiManager *aui; 16 wxBitmap line_nw, line_sw; 17 wxBitmap foldicon; 18 bool fromclosebox; 19 MyApp *app; 20 wxFileSystemWatcher *watcher; 21 bool watcherwaitingforuser; 22 double csf, csf_orig; 23 std::vector<std::string> scripts_in_menu; 24 GetPathMyFrame25 wxString GetPath(const wxString &relpath) { 26 if (!exepath_.Length()) return relpath; 27 return exepath_ + "/" + relpath; 28 } 29 30 MenuString menustrings; 31 32 void MyAppend(wxMenu *menu, int tag, const wxString &contents, const wchar_t *help = L"") { 33 wxString item = contents; 34 wxString key = L""; 35 int pos = contents.Find("\t"); 36 if (pos >= 0) { 37 item = contents.Mid(0, pos); 38 key = contents.Mid(pos + 1); 39 } 40 key = sys->cfg->Read(item, key); 41 wxString newcontents = item; 42 if (key.Length()) newcontents += "\t" + key; 43 menu->Append(tag, newcontents, help); 44 menustrings.push_back(std::make_pair(item, key)); 45 } 46 MyFrameMyFrame47 MyFrame(wxString exename, MyApp *_app) 48 : wxFrame((wxFrame *)nullptr, wxID_ANY, L"TreeSheets", wxDefaultPosition, wxDefaultSize, 49 wxDEFAULT_FRAME_STYLE), 50 filter(nullptr), 51 replaces(nullptr), 52 tb(nullptr), 53 nb(nullptr), 54 idd(nullptr), 55 refreshhack(0), 56 refreshhackinstances(0), 57 aui(nullptr), 58 fromclosebox(true), 59 app(_app), 60 watcherwaitingforuser(false), 61 watcher(nullptr) { 62 sys->frame = this; 63 64 exepath_ = L"/usr/local/share/treesheets"; 65 #ifdef __WXMAC__ 66 int cut = exepath_.Find("/MacOS"); 67 if (cut > 0) { exepath_ = exepath_.SubString(0, cut) + "/Resources"; } 68 #endif 69 70 class MyLog : public wxLog { 71 void DoLogString(const wxChar *msg, time_t timestamp) { DoLogText(*msg); } 72 void DoLogText(const wxString &msg) { 73 #ifdef WIN32 74 OutputDebugString(msg.c_str()); 75 OutputDebugString(L"\n"); 76 #else 77 fputws(msg.c_str(), stderr); 78 fputws(L"\n", stderr); 79 #endif 80 } 81 }; 82 83 wxLog::SetActiveTarget(new MyLog()); 84 85 wxLogMessage(L"%s", wxVERSION_STRING); 86 87 wxLogMessage(L"locale: %s", std::setlocale(LC_CTYPE, nullptr)); 88 89 app->AddTranslation(GetPath("translations")); 90 91 csf = GetContentScaleFactor(); 92 wxLogMessage(L"content scale: %f", csf); 93 csf_orig = csf; 94 #ifdef __WXMSW__ 95 // On Windows, I get csf == 1.25, as indicated in the display properties. 96 // With this factor set, bitmaps display. At their same physical sizes as when 97 // TreeSheets was a non-DPI-aware app, and extra resolution is used. 98 #endif 99 #ifdef __WXMAC__ 100 // Typically csf == 2 on a retina mac. But on the mac, unlike Windows, image rendering 101 // *already* does scaling, and no way to turn that behavior off for now? 102 csf = 1.0; 103 // FIXME: This gives us low res images even though the display is capable of better! 104 // Apparently still not fixed: http://trac.wxwidgets.org/ticket/15808 105 // wxBitmap::CreateScaled could be the way to solve this, but it is not obvious 106 // how to use it, since you can't pass this scale to LoadFile etc. Could possibly 107 // blit it over via a MemoryDC? 108 #endif 109 #ifdef __WXGTK__ 110 // Currently on Linux csf is always 1, so this is useless. 111 // FIXME: On a high-DPI display we get low res images even though the display is 112 // capable of better! 113 #endif 114 115 wxInitAllImageHandlers(); 116 117 wxIconBundle icons; 118 wxIcon iconbig; 119 icon.LoadFile(GetPath(L"images/icon16.png"), wxBITMAP_TYPE_PNG); 120 iconbig.LoadFile(GetPath(L"images/icon32.png"), wxBITMAP_TYPE_PNG); 121 if (!icon.IsOk() || !iconbig.IsOk()) { 122 wxMessageBox(_(L"Error loading core data file (TreeSheets not installed correctly?)"), 123 _(L"Initialization Error"), wxOK, this); 124 exit(1); 125 } 126 #ifdef WIN32 127 int iconsmall = ::GetSystemMetrics(SM_CXSMICON); 128 int iconlarge = ::GetSystemMetrics(SM_CXICON); 129 icon.SetSize(iconsmall, iconsmall); // this shouldn't be necessary... 130 iconbig.SetSize(iconlarge, iconlarge); 131 #endif 132 icons.AddIcon(icon); 133 icons.AddIcon(iconbig); 134 SetIcons(icons); 135 136 wxImage foldiconi; 137 line_nw.LoadFile(GetPath(L"images/render/line_nw.png"), wxBITMAP_TYPE_PNG); 138 line_sw.LoadFile(GetPath(L"images/render/line_sw.png"), wxBITMAP_TYPE_PNG); 139 foldiconi.LoadFile(GetPath(L"images/nuvola/fold.png")); 140 foldicon = wxBitmap(foldiconi); 141 ScaleBitmap(foldicon, csf / 3.0, foldicon); 142 143 if (sys->singletray) 144 tbi.Connect(wxID_ANY, wxEVT_TASKBAR_LEFT_UP, 145 wxTaskBarIconEventHandler(MyFrame::OnTBIDBLClick), nullptr, this); 146 else 147 tbi.Connect(wxID_ANY, wxEVT_TASKBAR_LEFT_DCLICK, 148 wxTaskBarIconEventHandler(MyFrame::OnTBIDBLClick), nullptr, this); 149 150 aui = new wxAuiManager(this); 151 152 bool mergetbar = false; 153 154 bool showtbar, showsbar, lefttabs, iconset; 155 156 sys->cfg->Read(L"showtbar", &showtbar, true); 157 sys->cfg->Read(L"showsbar", &showsbar, true); 158 sys->cfg->Read(L"lefttabs", &lefttabs, true); 159 sys->cfg->Read(L"iconset", &iconset, false); 160 161 filehistory.Load(*sys->cfg); 162 163 wxMenu *expmenu = new wxMenu(); 164 MyAppend(expmenu, A_EXPXML, _(L"&XML..."), 165 _(L"Export the current view as XML (which can also be reimported without losing " 166 L"structure)")); 167 MyAppend(expmenu, A_EXPHTMLT, _(L"&HTML (Tables+Styling)..."), 168 _(L"Export the current view as HTML using nested tables, that will look somewhat " 169 L"like the TreeSheet")); 170 MyAppend(expmenu, A_EXPHTMLO, _(L"HTML (&Outline)..."), 171 _(L"Export the current view as HTML as nested headers, suitable for importing into " 172 L"Word's outline mode")); 173 MyAppend(expmenu, A_EXPTEXT, _(L"Indented &Text..."), 174 _(L"Export the current view as tree structured text, using spaces for each " 175 L"indentation level. " 176 L"Suitable for importing into mindmanagers and general text programs")); 177 MyAppend(expmenu, A_EXPCSV, _(L"&Comma delimited text (CSV)..."), 178 _(L"Export the current view as CSV. Good for spreadsheets and databases. Only works " 179 L"on grids " 180 L"with no sub-grids (use the Flatten operation first if need be)")); 181 MyAppend(expmenu, A_EXPIMAGE, _(L"&Image..."), 182 _(L"Export the current view as an image. Useful for faithfull renderings of the " 183 L"TreeSheet, and " 184 L"programs that don't accept any of the above options")); 185 186 wxMenu *impmenu = new wxMenu(); 187 MyAppend(impmenu, A_IMPXML, _(L"XML...")); 188 MyAppend(impmenu, A_IMPXMLA, _(L"XML (attributes too, for OPML etc)...")); 189 MyAppend(impmenu, A_IMPTXTI, _(L"Indented text...")); 190 MyAppend(impmenu, A_IMPTXTC, _(L"Comma delimited text (CSV)...")); 191 MyAppend(impmenu, A_IMPTXTS, _(L"Semi-Colon delimited text (CSV)...")); 192 MyAppend(impmenu, A_IMPTXTT, _(L"Tab delimited text...")); 193 194 wxMenu *recentmenu = new wxMenu(); 195 filehistory.UseMenu(recentmenu); 196 filehistory.AddFilesToMenu(); 197 198 wxMenu *filemenu = new wxMenu(); 199 MyAppend(filemenu, A_NEW, _(L"&New\tCTRL+n")); 200 MyAppend(filemenu, A_OPEN, _(L"&Open...\tCTRL+o")); 201 MyAppend(filemenu, A_CLOSE, _(L"&Close\tCTRL+w")); 202 filemenu->AppendSubMenu(recentmenu, _(L"&Recent files")); 203 MyAppend(filemenu, A_SAVE, _(L"&Save\tCTRL+s")); 204 MyAppend(filemenu, A_SAVEAS, _(L"Save &As...")); 205 filemenu->AppendSeparator(); 206 MyAppend(filemenu, A_PAGESETUP, _(L"Page Setup...")); 207 MyAppend(filemenu, A_PRINTSCALE, _(L"Set Print Scale...")); 208 MyAppend(filemenu, A_PREVIEW, _(L"Print preview...")); 209 MyAppend(filemenu, A_PRINT, _(L"&Print...\tCTRL+p")); 210 filemenu->AppendSeparator(); 211 filemenu->AppendSubMenu(expmenu, _(L"Export &view as")); 212 filemenu->AppendSubMenu(impmenu, _(L"Import file from")); 213 filemenu->AppendSeparator(); 214 MyAppend(filemenu, A_EXIT, _(L"&Exit\tCTRL+q")); 215 216 wxMenu *editmenu; 217 loop(twoeditmenus, 2) { 218 wxMenu *sizemenu = new wxMenu(); 219 MyAppend(sizemenu, A_INCSIZE, _(L"&Increase text size (SHIFT+mousewheel)\tSHIFT+PGUP")); 220 MyAppend(sizemenu, A_DECSIZE, _(L"&Decrease text size (SHIFT+mousewheel)\tSHIFT+PGDN")); 221 MyAppend(sizemenu, A_RESETSIZE, _(L"&Reset text sizes\tSHIFT+CTRL+s")); 222 MyAppend(sizemenu, A_MINISIZE, _(L"&Shrink text of all sub-grids\tSHIFT+CTRL+m")); 223 sizemenu->AppendSeparator(); 224 MyAppend(sizemenu, A_INCWIDTH, _(L"Increase column width (ALT+mousewheel)\tALT+PGUP")); 225 MyAppend(sizemenu, A_DECWIDTH, _(L"Decrease column width (ALT+mousewheel)\tALT+PGDN")); 226 MyAppend(sizemenu, A_INCWIDTHNH, 227 _(L"Increase column width (no sub grids)\tCTRL+ALT+PGUP")); 228 MyAppend(sizemenu, A_DECWIDTHNH, 229 _(L"Decrease column width (no sub grids)\tCTRL+ALT+PGDN")); 230 MyAppend(sizemenu, A_RESETWIDTH, _(L"Reset column widths\tSHIFT+CTRL+w")); 231 232 wxMenu *bordmenu = new wxMenu(); 233 MyAppend(bordmenu, A_BORD0, L"&0\tCTRL+SHIFT+0"); 234 MyAppend(bordmenu, A_BORD1, L"&1\tCTRL+SHIFT+1"); 235 MyAppend(bordmenu, A_BORD2, L"&2\tCTRL+SHIFT+2"); 236 MyAppend(bordmenu, A_BORD3, L"&3\tCTRL+SHIFT+3"); 237 MyAppend(bordmenu, A_BORD4, L"&4\tCTRL+SHIFT+4"); 238 MyAppend(bordmenu, A_BORD5, L"&5\tCTRL+SHIFT+5"); 239 240 wxMenu *selmenu = new wxMenu(); 241 MyAppend(selmenu, A_NEXT, _(L"Move to next cell\tTAB")); 242 MyAppend(selmenu, A_PREV, _(L"Move to previous cell\tSHIFT+TAB")); 243 selmenu->AppendSeparator(); 244 MyAppend(selmenu, A_SELALL, _(L"Select &all in current grid\tCTRL+a")); 245 selmenu->AppendSeparator(); 246 MyAppend(selmenu, A_LEFT, _(L"Move Selection Left\tLEFT")); 247 MyAppend(selmenu, A_RIGHT, _(L"Move Selection Right\tRIGHT")); 248 MyAppend(selmenu, A_UP, _(L"Move Selection Up\tUP")); 249 MyAppend(selmenu, A_DOWN, _(L"Move Selection Down\tDOWN")); 250 selmenu->AppendSeparator(); 251 MyAppend(selmenu, A_MLEFT, _(L"Move Cells Left\tCTRL+LEFT")); 252 MyAppend(selmenu, A_MRIGHT, _(L"Move Cells Right\tCTRL+RIGHT")); 253 MyAppend(selmenu, A_MUP, _(L"Move Cells Up\tCTRL+UP")); 254 MyAppend(selmenu, A_MDOWN, _(L"Move Cells Down\tCTRL+DOWN")); 255 selmenu->AppendSeparator(); 256 MyAppend(selmenu, A_SLEFT, _(L"Extend Selection Left\tSHIFT+LEFT")); 257 MyAppend(selmenu, A_SRIGHT, _(L"Extend Selection Right\tSHIFT+RIGHT")); 258 MyAppend(selmenu, A_SUP, _(L"Extend Selection Up\tSHIFT+UP")); 259 MyAppend(selmenu, A_SDOWN, _(L"Extend Selection Down\tSHIFT+DOWN")); 260 MyAppend(selmenu, A_SCOLS, _(L"Extend Selection Full Columns")); 261 MyAppend(selmenu, A_SROWS, _(L"Extend Selection Full Rows")); 262 selmenu->AppendSeparator(); 263 MyAppend(selmenu, A_CANCELEDIT, _(L"Select &Parent\tESC")); 264 MyAppend(selmenu, A_ENTERGRID, _(L"Select First &Child\tSHIFT+ENTER")); 265 selmenu->AppendSeparator(); 266 MyAppend(selmenu, A_LINK, _(L"Go To &Matching Cell\tF6")); 267 MyAppend(selmenu, A_LINKREV, _(L"Go To Matching Cell (Reverse)\tSHIFT+F6")); 268 269 wxMenu *temenu = new wxMenu(); 270 MyAppend(temenu, A_LEFT, _(L"Cursor Left\tLEFT")); 271 MyAppend(temenu, A_RIGHT, _(L"Cursor Right\tRIGHT")); 272 MyAppend(temenu, A_MLEFT, _(L"Word Left\tCTRL+LEFT")); 273 MyAppend(temenu, A_MRIGHT, _(L"Word Right\tCTRL+RIGHT")); 274 temenu->AppendSeparator(); 275 MyAppend(temenu, A_SLEFT, _(L"Extend Selection Left\tSHIFT+LEFT")); 276 MyAppend(temenu, A_SRIGHT, _(L"Extend Selection Right\tSHIFT+RIGHT")); 277 MyAppend(temenu, A_SCLEFT, _(L"Extend Selection Word Left\tSHIFT+CTRL+LEFT")); 278 MyAppend(temenu, A_SCRIGHT, _(L"Extend Selection Word Right\tSHIFT+CTRL+RIGHT")); 279 MyAppend(temenu, A_SHOME, _(L"Extend Selection to Start\tSHIFT+HOME")); 280 MyAppend(temenu, A_SEND, _(L"Extend Selection to End\tSHIFT+END")); 281 temenu->AppendSeparator(); 282 MyAppend(temenu, A_HOME, _(L"Start of line of text\tHOME")); 283 MyAppend(temenu, A_END, _(L"End of line of text\tEND")); 284 MyAppend(temenu, A_CHOME, _(L"Start of text\tCTRL+HOME")); 285 MyAppend(temenu, A_CEND, _(L"End of text\tCTRL+END")); 286 temenu->AppendSeparator(); 287 MyAppend(temenu, A_ENTERCELL, _(L"Enter/exit text edit mode\tENTER")); 288 MyAppend(temenu, A_ENTERCELL, _(L"Enter/exit text edit mode\tF2")); 289 MyAppend(temenu, A_CANCELEDIT, _(L"Cancel text edits\tESC")); 290 291 wxMenu *stmenu = new wxMenu(); 292 MyAppend(stmenu, A_BOLD, _(L"Toggle cell &BOLD\tCTRL+b")); 293 MyAppend(stmenu, A_ITALIC, _(L"Toggle cell &ITALIC\tCTRL+i")); 294 MyAppend(stmenu, A_TT, _(L"Toggle cell &typewriter\tCTRL+ALT+t")); 295 MyAppend(stmenu, A_UNDERL, _(L"Toggle cell &underlined\tCTRL+u")); 296 MyAppend(stmenu, A_STRIKET, _(L"Toggle cell &strikethrough\tCTRL+t")); 297 stmenu->AppendSeparator(); 298 MyAppend(stmenu, A_RESETSTYLE, _(L"&Reset text styles\tSHIFT+CTRL+r")); 299 MyAppend(stmenu, A_RESETCOLOR, _(L"Reset &colors\tSHIFT+CTRL+c")); 300 301 wxMenu *tagmenu = new wxMenu(); 302 MyAppend(tagmenu, A_TAGADD, _(L"&Add Cell Text as Tag")); 303 MyAppend(tagmenu, A_TAGREMOVE, _(L"&Remove Cell Text from Tags")); 304 MyAppend(tagmenu, A_NOP, _(L"&Set Cell Text to tag (use CTRL+RMB)"), 305 _(L"Hold CTRL while pressing right mouse button to quickly set a tag for the " 306 L"current cell " 307 L"using a popup menu")); 308 309 wxMenu *orgmenu = new wxMenu(); 310 MyAppend(orgmenu, A_TRANSPOSE, _(L"&Transpose\tSHIFT+CTRL+t"), 311 _(L"changes the orientation of a grid")); 312 MyAppend(orgmenu, A_SORT, _(L"Sort &Ascending"), 313 _(L"Make a 1xN selection to indicate which column to sort on, and which rows to " 314 L"affect")); 315 MyAppend(orgmenu, A_SORTD, _(L"Sort &Descending"), 316 _(L"Make a 1xN selection to indicate which column to sort on, and which rows to " 317 L"affect")); 318 MyAppend(orgmenu, A_HSWAP, _(L"Hierarchy &Swap\tF8"), 319 _(L"Swap all cells with this text at this level (or above) with the parent")); 320 MyAppend(orgmenu, A_HIFY, _(L"&Hierarchify"), 321 _(L"Convert an NxN grid with repeating elements per column into an 1xN grid " 322 L"with hierarchy, " 323 L"useful to convert data from spreadsheets")); 324 MyAppend(orgmenu, A_FLATTEN, _(L"&Flatten"), 325 _(L"Takes a hierarchy (nested 1xN or Nx1 grids) and converts it into a flat NxN " 326 L"grid, useful " 327 L"for export to spreadsheets")); 328 329 wxMenu *imgmenu = new wxMenu(); 330 MyAppend(imgmenu, A_IMAGE, _(L"&Add Image"), _(L"Adds an image to the selected cell")); 331 MyAppend(imgmenu, A_IMAGESCP, _(L"&Scale Image (re-sample pixels)"), 332 _(L"Change the image size if it is too big, by reducing the amount of " 333 L"pixels")); 334 MyAppend(imgmenu, A_IMAGESCF, _(L"&Scale Image (display only)"), 335 _(L"Change the image size if it is too big or too small, by changing the size " 336 L"shown on screen. Applies to all uses of this image.")); 337 MyAppend(imgmenu, A_IMAGESCN, _(L"&Reset Scale (display only)"), 338 _(L"Change the scale to match DPI of the current display. " 339 L"Applies to all uses of this image.")); 340 MyAppend(imgmenu, A_IMAGER, _(L"&Remove Image(s)"), 341 _(L"Remove image(s) from the selected cells")); 342 343 wxMenu *navmenu = new wxMenu(); 344 MyAppend(navmenu, A_BROWSE, _(L"Open link in &browser\tF5"), 345 _(L"Opens up the text from the selected cell in browser (should start be a " 346 L"valid URL)")); 347 MyAppend(navmenu, A_BROWSEF, _(L"Open &file\tF4"), 348 _(L"Opens up the text from the selected cell in default application for the " 349 L"file type")); 350 351 wxMenu *laymenu = new wxMenu(); 352 MyAppend(laymenu, A_V_GS, _(L"Vertical Layout with Grid Style Rendering\tALT+1")); 353 MyAppend(laymenu, A_V_BS, _(L"Vertical Layout with Bubble Style Rendering\tALT+2")); 354 MyAppend(laymenu, A_V_LS, _(L"Vertical Layout with Line Style Rendering\tALT+3")); 355 laymenu->AppendSeparator(); 356 MyAppend(laymenu, A_H_GS, _(L"Horizontal Layout with Grid Style Rendering\tALT+4")); 357 MyAppend(laymenu, A_H_BS, _(L"Horizontal Layout with Bubble Style Rendering\tALT+5")); 358 MyAppend(laymenu, A_H_LS, _(L"Horizontal Layout with Line Style Rendering\tALT+6")); 359 laymenu->AppendSeparator(); 360 MyAppend(laymenu, A_GS, _(L"Grid Style Rendering\tALT+7")); 361 MyAppend(laymenu, A_BS, _(L"Bubble Style Rendering\tALT+8")); 362 MyAppend(laymenu, A_LS, _(L"Line Style Rendering\tALT+9")); 363 laymenu->AppendSeparator(); 364 MyAppend(laymenu, A_TEXTGRID, _(L"Toggle Vertical Layout\tF7"), 365 _(L"Make a hierarchy layout more vertical (default) or more horizontal")); 366 367 editmenu = new wxMenu(); 368 MyAppend(editmenu, A_CUT, _(L"Cu&t\tCTRL+x")); 369 MyAppend(editmenu, A_COPY, _(L"&Copy\tCTRL+c")); 370 MyAppend(editmenu, A_COPYCT, _(L"Copy As Continuous Text")); 371 MyAppend(editmenu, A_PASTE, _(L"&Paste\tCTRL+v")); 372 MyAppend(editmenu, A_PASTESTYLE, _(L"Paste Style Only\tCTRL+SHIFT+v"), 373 _(L"only sets the colors and style of the copied cell, and keeps the text")); 374 editmenu->AppendSeparator(); 375 MyAppend(editmenu, A_UNDO, _(L"&Undo\tCTRL+z"), _(L"revert the changes, one step at a time")); 376 MyAppend(editmenu, A_REDO, _(L"&Redo\tCTRL+y"), 377 _(L"redo any undo steps, if you haven't made changes since")); 378 editmenu->AppendSeparator(); 379 MyAppend(editmenu, A_DELETE, _(L"&Delete After\tDEL"), 380 _(L"Deletes the column of cells after the selected grid line, or the row below")); 381 MyAppend( 382 editmenu, A_BACKSPACE, _(L"Delete Before\tBACK"), 383 _(L"Deletes the column of cells before the selected grid line, or the row above")); 384 editmenu->AppendSeparator(); 385 MyAppend(editmenu, A_NEWGRID, 386 #ifdef __WXMAC__ 387 _(L"&Insert New Grid\tCTRL+g"), 388 #else 389 _(L"&Insert New Grid\tINS"), 390 #endif 391 _(L"Adds a grid to the selected cell")); 392 MyAppend(editmenu, A_WRAP, _(L"&Wrap in new parent\tF9"), 393 _(L"Creates a new level of hierarchy around the current selection")); 394 editmenu->AppendSeparator(); 395 // F10 is tied to the OS on both Ubuntu and OS X, and SHIFT+F10 is now right 396 // click on all platforms? 397 MyAppend(editmenu, A_FOLD, 398 #ifndef WIN32 399 _(L"Toggle Fold\tCTRL+F10"), 400 #else 401 _(L"Toggle Fold\tF10"), 402 #endif 403 _("Toggles showing the grid of the selected cell(s)")); 404 MyAppend(editmenu, A_FOLDALL, _(L"Fold All\tCTRL+SHIFT+F10"), 405 _(L"Folds the grid of the selected cell(s) recursively")); 406 MyAppend(editmenu, A_UNFOLDALL, _(L"Unfold All\tCTRL+ALT+F10"), 407 _(L"Unfolds the grid of the selected cell(s) recursively")); 408 editmenu->AppendSeparator(); 409 editmenu->AppendSubMenu(selmenu, _(L"&Selection...")); 410 editmenu->AppendSubMenu(orgmenu, _(L"&Grid Reorganization...")); 411 editmenu->AppendSubMenu(laymenu, _(L"&Layout && Render Style...")); 412 editmenu->AppendSubMenu(imgmenu, _(L"&Images...")); 413 editmenu->AppendSubMenu(navmenu, _(L"&Browsing...")); 414 editmenu->AppendSubMenu(temenu, _(L"Text &Editing...")); 415 editmenu->AppendSubMenu(sizemenu, _(L"Text Sizing...")); 416 editmenu->AppendSubMenu(stmenu, _(L"Text Style...")); 417 editmenu->AppendSubMenu(bordmenu, _(L"Set Grid Border Width...")); 418 editmenu->AppendSubMenu(tagmenu, _(L"Tag...")); 419 420 if (!twoeditmenus) editmenupopup = editmenu; 421 } 422 423 wxMenu *semenu = new wxMenu(); 424 MyAppend(semenu, A_SEARCHF, _(L"&Search\tCTRL+f")); 425 MyAppend(semenu, A_SEARCHNEXT, _(L"&Go To Next Search Result\tF3")); 426 MyAppend(semenu, A_REPLACEONCE, _(L"&Replace in Current Selection\tCTRL+h")); 427 MyAppend(semenu, A_REPLACEONCEJ, _(L"&Replace in Current Selection & Jump Next\tCTRL+j")); 428 MyAppend(semenu, A_REPLACEALL, _(L"Replace &All")); 429 430 wxMenu *scrollmenu = new wxMenu(); 431 MyAppend(scrollmenu, A_AUP, _(L"Scroll Up (mousewheel)\tPGUP")); 432 MyAppend(scrollmenu, A_AUP, _(L"Scroll Up (mousewheel)\tALT+UP")); 433 MyAppend(scrollmenu, A_ADOWN, _(L"Scroll Down (mousewheel)\tPGDN")); 434 MyAppend(scrollmenu, A_ADOWN, _(L"Scroll Down (mousewheel)\tALT+DOWN")); 435 MyAppend(scrollmenu, A_ALEFT, _(L"Scroll Left\tALT+LEFT")); 436 MyAppend(scrollmenu, A_ARIGHT, _(L"Scroll Right\tALT+RIGHT")); 437 438 wxMenu *filtermenu = new wxMenu(); 439 MyAppend(filtermenu, A_FILTEROFF, _(L"Turn filter &off")); 440 MyAppend(filtermenu, A_FILTERS, _(L"Show only cells in current search")); 441 MyAppend(filtermenu, A_FILTER5, _(L"Show 5% of last edits")); 442 MyAppend(filtermenu, A_FILTER10, _(L"Show 10% of last edits")); 443 MyAppend(filtermenu, A_FILTER20, _(L"Show 20% of last edits")); 444 MyAppend(filtermenu, A_FILTER50, _(L"Show 50% of last edits")); 445 MyAppend(filtermenu, A_FILTERM, _(L"Show 1% more than the last filter")); 446 MyAppend(filtermenu, A_FILTERL, _(L"Show 1% less than the last filter")); 447 448 wxMenu *viewmenu = new wxMenu(); 449 MyAppend(viewmenu, A_ZOOMIN, _(L"Zoom &In (CTRL+mousewheel)\tCTRL+PGUP")); 450 MyAppend(viewmenu, A_ZOOMOUT, _(L"Zoom &Out (CTRL+mousewheel)\tCTRL+PGDN")); 451 MyAppend(viewmenu, A_NEXTFILE, 452 #ifndef __WXGTK__ 453 _(L"Switch to &next file/tab\tCTRL+TAB")); 454 #else 455 // On Linux, this conflicts with CTRL+I, see Document::Key() 456 // CTRL+SHIFT+TAB below still works, so that will have to be used to switch tabs. 457 _(L"Switch to &next file/tab")); 458 #endif 459 MyAppend(viewmenu, A_PREVFILE, _(L"Switch to &previous file/tab\tSHIFT+CTRL+TAB")); 460 MyAppend(viewmenu, A_FULLSCREEN, 461 #ifdef __WXMAC__ 462 _(L"Toggle &Fullscreen View\tCTRL+F11")); 463 #else 464 _(L"Toggle &Fullscreen View\tF11")); 465 #endif 466 MyAppend(viewmenu, A_SCALED, 467 #ifdef __WXMAC__ 468 _(L"Toggle &Scaled Presentation View\tCTRL+F12")); 469 #else 470 _(L"Toggle &Scaled Presentation View\tF12")); 471 #endif 472 viewmenu->AppendSubMenu(scrollmenu, _(L"Scroll Sheet...")); 473 viewmenu->AppendSubMenu(filtermenu, _(L"Filter...")); 474 475 wxMenu *roundmenu = new wxMenu(); 476 roundmenu->AppendRadioItem(A_ROUND0, _(L"Radius &0")); 477 roundmenu->AppendRadioItem(A_ROUND1, _(L"Radius &1")); 478 roundmenu->AppendRadioItem(A_ROUND2, _(L"Radius &2")); 479 roundmenu->AppendRadioItem(A_ROUND3, _(L"Radius &3")); 480 roundmenu->AppendRadioItem(A_ROUND4, _(L"Radius &4")); 481 roundmenu->AppendRadioItem(A_ROUND5, _(L"Radius &5")); 482 roundmenu->AppendRadioItem(A_ROUND6, _(L"Radius &6")); 483 roundmenu->Check(sys->roundness + A_ROUND0, true); 484 485 wxMenu *optmenu = new wxMenu(); 486 MyAppend(optmenu, A_DEFFONT, _(L"Pick Default Font...")); 487 MyAppend(optmenu, A_CUSTKEY, _(L"Change a key binding...")); 488 MyAppend(optmenu, A_CUSTCOL, _(L"Pick Custom &Color...")); 489 MyAppend(optmenu, A_COLCELL, _(L"&Set Custom Color From Cell BG")); 490 MyAppend(optmenu, A_DEFBGCOL, _(L"Pick Document Background...")); 491 optmenu->AppendSeparator(); 492 optmenu->AppendCheckItem(A_SHOWSBAR, _(L"Show Statusbar")); 493 optmenu->Check(A_SHOWSBAR, showsbar); 494 optmenu->AppendCheckItem(A_SHOWTBAR, _(L"Show Toolbar")); 495 optmenu->Check(A_SHOWTBAR, showtbar); 496 optmenu->AppendCheckItem(A_LEFTTABS, _(L"File Tabs on the bottom")); 497 optmenu->Check(A_LEFTTABS, lefttabs); 498 optmenu->AppendCheckItem(A_TOTRAY, _(L"Minimize to tray")); 499 optmenu->Check(A_TOTRAY, sys->totray); 500 optmenu->AppendCheckItem(A_MINCLOSE, _(L"Minimize on close")); 501 optmenu->Check(A_MINCLOSE, sys->minclose); 502 optmenu->AppendCheckItem(A_SINGLETRAY, _(L"Single click maximize from tray")); 503 optmenu->Check(A_SINGLETRAY, sys->singletray); 504 optmenu->AppendSeparator(); 505 optmenu->AppendCheckItem(A_ZOOMSCR, _(L"Swap mousewheel scrolling and zooming")); 506 optmenu->Check(A_ZOOMSCR, sys->zoomscroll); 507 optmenu->AppendCheckItem(A_THINSELC, _(L"Navigate in between cells with cursor keys")); 508 optmenu->Check(A_THINSELC, sys->thinselc); 509 optmenu->AppendSeparator(); 510 optmenu->AppendCheckItem(A_MAKEBAKS, _(L"Create .bak files")); 511 optmenu->Check(A_MAKEBAKS, sys->makebaks); 512 optmenu->AppendCheckItem(A_AUTOSAVE, _(L"Autosave to .tmp")); 513 optmenu->Check(A_AUTOSAVE, sys->autosave); 514 optmenu->AppendCheckItem( 515 A_FSWATCH, _(L"Auto reload documents"), 516 _(L"Reloads when another computer has changed a file (if you have made changes, asks)")); 517 optmenu->Check(A_FSWATCH, sys->fswatch); 518 optmenu->AppendCheckItem(A_AUTOEXPORT, _(L"Automatically export a .html on every save")); 519 optmenu->Check(A_AUTOEXPORT, sys->autohtmlexport); 520 optmenu->AppendSeparator(); 521 optmenu->AppendCheckItem(A_CENTERED, _(L"Render document centered")); 522 optmenu->Check(A_CENTERED, sys->centered); 523 optmenu->AppendCheckItem(A_FASTRENDER, _(L"Faster line rendering")); 524 optmenu->Check(A_FASTRENDER, sys->fastrender); 525 optmenu->AppendCheckItem(A_ICONSET, _(L"Black and white toolbar icons")); 526 optmenu->Check(A_ICONSET, iconset); 527 optmenu->AppendSubMenu(roundmenu, _(L"&Roundness of grid borders...")); 528 529 wxMenu *scriptmenu = new wxMenu(); 530 auto scriptpath = GetPath("scripts/"); 531 wxString sf = wxFindFirstFile(scriptpath + L"*.lobster"); 532 int sidx = 0; 533 while (!sf.empty()) { 534 auto fn = wxFileName::FileName(sf).GetFullName(); 535 auto ms = fn.BeforeFirst('.'); 536 if (sidx < 26) { 537 ms += L"\tCTRL+SHIFT+ALT+"; 538 ms += wxChar('A' + sidx); 539 } 540 MyAppend(scriptmenu, A_SCRIPT + sidx, ms); 541 auto ss = fn.utf8_str(); 542 scripts_in_menu.push_back(std::string(ss.data(), ss.length())); 543 sf = wxFindNextFile(); 544 sidx++; 545 } 546 547 wxMenu *markmenu = new wxMenu(); 548 MyAppend(markmenu, A_MARKDATA, _(L"&Data")); 549 MyAppend(markmenu, A_MARKCODE, _(L"&Operation")); 550 MyAppend(markmenu, A_MARKVARD, _(L"Variable &Assign")); 551 MyAppend(markmenu, A_MARKVARU, _(L"Variable &Read")); 552 MyAppend(markmenu, A_MARKVIEWH, _(L"&Horizontal View")); 553 MyAppend(markmenu, A_MARKVIEWV, _(L"&Vertical View")); 554 555 wxMenu *langmenu = new wxMenu(); 556 MyAppend(langmenu, A_RUN, _(L"&Run")); 557 langmenu->AppendSubMenu(markmenu, _(L"&Mark as")); 558 MyAppend(langmenu, A_CLRVIEW, _(L"&Clear Views")); 559 560 wxMenu *helpmenu = new wxMenu(); 561 MyAppend(helpmenu, A_ABOUT, _(L"&About...")); 562 MyAppend(helpmenu, A_HELPI, _(L"Load interactive &tutorial...\tF1")); 563 MyAppend(helpmenu, A_HELP, _(L"View tutorial &web page...")); 564 565 wxAcceleratorEntry entries[3]; 566 entries[0].Set(wxACCEL_SHIFT, WXK_DELETE, A_CUT); 567 entries[1].Set(wxACCEL_SHIFT, WXK_INSERT, A_PASTE); 568 entries[2].Set(wxACCEL_CTRL, WXK_INSERT, A_COPY); 569 wxAcceleratorTable accel(3, entries); 570 SetAcceleratorTable(accel); 571 572 if (!mergetbar) { 573 wxMenuBar *menubar = new wxMenuBar(); 574 menubar->Append(filemenu, _(L"&File")); 575 menubar->Append(editmenu, _(L"&Edit")); 576 menubar->Append(semenu, _(L"&Search")); 577 menubar->Append(viewmenu, _(L"&View")); 578 menubar->Append(optmenu, _(L"&Options")); 579 menubar->Append(scriptmenu, _(L"Script")); 580 menubar->Append(langmenu, _(L"&Program")); 581 menubar->Append(helpmenu, 582 #ifdef __WXMAC__ 583 wxApp::s_macHelpMenuTitleName // so merges with osx provided help 584 #else 585 _(L"&Help") 586 #endif 587 ); 588 #ifdef __WXMAC__ 589 // these don't seem to work anymore in the newer wxWidgets, handled in the menu event 590 // handler below instead 591 wxApp::s_macAboutMenuItemId = A_ABOUT; 592 wxApp::s_macExitMenuItemId = A_EXIT; 593 wxApp::s_macPreferencesMenuItemId = 594 A_DEFFONT; // we have no prefs, so for now just select the font 595 #endif 596 SetMenuBar(menubar); 597 } 598 599 wxColour toolbgcol(iconset ? 0xF0ECE8 : 0xD8C7BC); 600 601 if (showtbar || mergetbar) { 602 tb = CreateToolBar(wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT | wxTB_NODIVIDER); 603 tb->SetOwnBackgroundColour(toolbgcol); 604 605 #ifdef __WXMAC__ 606 #define SEPARATOR 607 #else 608 #define SEPARATOR tb->AddSeparator() 609 #endif 610 611 wxString iconpath = 612 GetPath(iconset ? L"images/webalys/toolbar/" : L"images/nuvola/toolbar/"); 613 auto sz = (iconset ? wxSize(18, 18) : wxSize(22, 22)) * csf; 614 tb->SetToolBitmapSize(sz); 615 616 double sc = iconset ? 1.0 : 22.0 / 48.0; 617 618 auto AddTBIcon = [&](const wxChar *name, int action, wxString file) { 619 wxBitmap bm; 620 if (bm.LoadFile(file, wxBITMAP_TYPE_PNG)) { 621 auto ns = csf_orig * sc; 622 ScaleBitmap(bm, ns, bm); 623 MakeInternallyScaled(bm, tb->GetBackgroundColour(), csf_orig); 624 tb->AddTool(action, name, bm, bm, wxITEM_NORMAL, name); 625 } 626 }; 627 628 AddTBIcon(_(L"New (CTRL+n)"), A_NEW, iconpath + L"filenew.png"); 629 AddTBIcon(_(L"Open (CTRL+o)"), A_OPEN, iconpath + L"fileopen.png"); 630 AddTBIcon(_(L"Save (CTRL+s)"), A_SAVE, iconpath + L"filesave.png"); 631 AddTBIcon(_(L"Save As"), A_SAVEAS, iconpath + L"filesaveas.png"); 632 SEPARATOR; 633 AddTBIcon(_(L"Undo (CTRL+z)"), A_UNDO, iconpath + L"undo.png"); 634 AddTBIcon(_(L"Copy (CTRL+c)"), A_COPY, iconpath + L"editcopy.png"); 635 AddTBIcon(_(L"Paste (CTRL+v)"), A_PASTE, iconpath + L"editpaste.png"); 636 SEPARATOR; 637 AddTBIcon(_(L"Zoom In (CTRL+mousewheel)"), A_ZOOMIN, iconpath + L"zoomin.png"); 638 AddTBIcon(_(L"Zoom Out (CTRL+mousewheel)"), A_ZOOMOUT, iconpath + L"zoomout.png"); 639 SEPARATOR; 640 AddTBIcon(_(L"New Grid (INS)"), A_NEWGRID, iconpath + L"newgrid.png"); 641 AddTBIcon(_(L"Add Image"), A_IMAGE, iconpath + L"image.png"); 642 SEPARATOR; 643 AddTBIcon(_(L"Run"), A_RUN, iconpath + L"run.png"); 644 tb->AddSeparator(); 645 tb->AddControl(new wxStaticText(tb, wxID_ANY, _(L"Search "))); 646 tb->AddControl(filter = 647 new wxTextCtrl(tb, A_SEARCH, "", wxDefaultPosition, wxSize(80, 22) * csf)); 648 SEPARATOR; 649 tb->AddControl(new wxStaticText(tb, wxID_ANY, _(L"Replace "))); 650 tb->AddControl(replaces = 651 new wxTextCtrl(tb, A_REPLACE, "", wxDefaultPosition, wxSize(60, 22) * csf)); 652 tb->AddSeparator(); 653 tb->AddControl(new wxStaticText(tb, wxID_ANY, _(L"Cell "))); 654 tb->AddControl(new ColorDropdown(tb, A_CELLCOLOR, csf, 1)); 655 SEPARATOR; 656 tb->AddControl(new wxStaticText(tb, wxID_ANY, _(L"Text "))); 657 tb->AddControl(new ColorDropdown(tb, A_TEXTCOLOR, csf, 2)); 658 SEPARATOR; 659 tb->AddControl(new wxStaticText(tb, wxID_ANY, _(L"Border "))); 660 tb->AddControl(new ColorDropdown(tb, A_BORDCOLOR, csf, 7)); 661 tb->AddSeparator(); 662 tb->AddControl(new wxStaticText(tb, wxID_ANY, _(L"Image "))); 663 wxString imagepath = GetPath("images/nuvola/dropdown/"); 664 idd = new ImageDropdown(tb, imagepath); 665 tb->AddControl(idd); 666 tb->Realize(); 667 } 668 669 if (showsbar) { 670 wxStatusBar *sb = CreateStatusBar(4); 671 sb->SetOwnBackgroundColour(toolbgcol); 672 SetStatusBarPane(0); 673 int swidths[] = {-1, 200, 120, 100}; 674 SetStatusWidths(4, swidths); 675 } 676 677 nb = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 678 wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | 679 wxAUI_NB_WINDOWLIST_BUTTON | wxAUI_NB_CLOSE_ON_ALL_TABS | 680 (lefttabs ? wxAUI_NB_BOTTOM : wxAUI_NB_TOP)); 681 nb->SetOwnBackgroundColour(toolbgcol); 682 683 int display_id = wxDisplay::GetFromWindow(this); 684 wxRect disprect = wxDisplay(display_id == wxNOT_FOUND ? 0 : display_id).GetClientArea(); 685 const int screenx = disprect.width - disprect.x; 686 const int screeny = disprect.height - disprect.y; 687 688 const int boundary = 64; 689 const int defx = screenx - 2 * boundary; 690 const int defy = screeny - 2 * boundary; 691 int resx, resy, posx, posy; 692 sys->cfg->Read(L"resx", &resx, defx); 693 sys->cfg->Read(L"resy", &resy, defy); 694 sys->cfg->Read(L"posx", &posx, boundary + disprect.x); 695 sys->cfg->Read(L"posy", &posy, boundary + disprect.y); 696 if (resx > screenx || resy > screeny || posx < disprect.x || posy < disprect.y || 697 posx + resx > disprect.width + disprect.x || 698 posy + resy > disprect.height + disprect.y) { 699 // Screen res has been resized since we last ran, set sizes to default to avoid being 700 // off-screen. 701 resx = defx; 702 resy = defy; 703 posx = posy = boundary; 704 posx += disprect.x; 705 posy += disprect.y; 706 } 707 SetSize(resx, resy); 708 SetPosition(wxPoint(posx, posy)); 709 710 bool ismax; 711 sys->cfg->Read(L"maximized", &ismax, true); 712 713 aui->AddPane(nb, wxCENTER); 714 aui->Update(); 715 716 Show(TRUE); 717 718 // needs to be after Show() to avoid scrollbars rendered in the wrong place? 719 if (ismax) Maximize(true); 720 721 SetFileAssoc(exename); 722 723 wxSafeYield(); 724 } 725 AppOnEventLoopEnterMyFrame726 void AppOnEventLoopEnter() 727 { 728 // Have to do this here, if we do it in the Frame constructor above, it crashes on OS X. 729 watcher = new wxFileSystemWatcher(); 730 watcher->SetOwner(this); 731 Connect(wxEVT_FSWATCHER, wxFileSystemWatcherEventHandler(MyFrame::OnFileSystemEvent)); 732 } 733 ~MyFrameMyFrame734 ~MyFrame() { 735 filehistory.Save(*sys->cfg); 736 if (!IsIconized()) { 737 sys->cfg->Write(L"maximized", IsMaximized()); 738 if (!IsMaximized()) { 739 sys->cfg->Write(L"resx", GetSize().x); 740 sys->cfg->Write(L"resy", GetSize().y); 741 sys->cfg->Write(L"posx", GetPosition().x); 742 sys->cfg->Write(L"posy", GetPosition().y); 743 } 744 } 745 aui->ClearEventHashTable(); 746 aui->UnInit(); 747 DELETEP(aui); 748 DELETEP(editmenupopup); 749 DELETEP(watcher); 750 } 751 752 TSCanvas *NewTab(Document *doc, bool append = false) { 753 TSCanvas *sw = new TSCanvas(this, nb); 754 sw->doc = doc; 755 doc->sw = sw; 756 sw->SetScrollRate(1, 1); 757 if (append) 758 nb->AddPage(sw, L"<unnamed>", true, wxNullBitmap); 759 else 760 nb->InsertPage(0, sw, L"<unnamed>", true, wxNullBitmap); 761 sw->SetDropTarget(new DropTarget(doc->dataobjc)); 762 sw->SetFocus(); 763 return sw; 764 } 765 GetCurTabMyFrame766 TSCanvas *GetCurTab() { 767 return nb && nb->GetSelection() >= 0 768 ? (TSCanvas *)nb->GetPage(nb->GetSelection()) 769 : nullptr; 770 } GetTabByFileNameMyFrame771 TSCanvas *GetTabByFileName(const wxString &fn) { 772 if (nb) loop(i, nb->GetPageCount()) { 773 TSCanvas *p = (TSCanvas *)nb->GetPage(i); 774 if (p->doc->filename == fn) { 775 nb->SetSelection(i); 776 return p; 777 } 778 } 779 return nullptr; 780 } 781 OnTabChangeMyFrame782 void OnTabChange(wxAuiNotebookEvent &nbe) { 783 TSCanvas *sw = (TSCanvas *)nb->GetPage(nbe.GetSelection()); 784 sw->Status(); 785 sys->TabChange(sw->doc); 786 } 787 TabsResetMyFrame788 void TabsReset() { 789 if (nb) loop(i, nb->GetPageCount()) { 790 TSCanvas *p = (TSCanvas *)nb->GetPage(i); 791 p->doc->rootgrid->ResetChildren(); 792 } 793 } 794 OnTabCloseMyFrame795 void OnTabClose(wxAuiNotebookEvent &nbe) { 796 TSCanvas *sw = (TSCanvas *)nb->GetPage(nbe.GetSelection()); 797 sys->RememberOpenFiles(); 798 if (nb->GetPageCount() <= 1) { 799 nbe.Veto(); 800 Close(); 801 } else if (sw->doc->CloseDocument()) { 802 nbe.Veto(); 803 } 804 } 805 806 void CycleTabs(int offset = 1) { 807 auto numtabs = (int)nb->GetPageCount(); 808 offset = ((offset >= 0) ? 1 : numtabs - 1); // normalize to non-negative wrt modulo 809 nb->SetSelection((nb->GetSelection() + offset) % numtabs); 810 } 811 812 void SetPageTitle(const wxString &fn, wxString mods, int page = -1) { 813 if (page < 0) page = nb->GetSelection(); 814 if (page < 0) return; 815 if (page == nb->GetSelection()) SetTitle(L"TreeSheets - " + fn + mods); 816 nb->SetPageText(page, (fn.empty() ? L"<unnamed>" : wxFileName(fn).GetName()) + mods); 817 } 818 819 void TBMenu(wxToolBar *tb, wxMenu *menu, const wxChar *name, int id = 0) { 820 tb->AddTool(id, name, wxNullBitmap, wxEmptyString, wxITEM_DROPDOWN); 821 tb->SetDropdownMenu(id, menu); 822 } 823 OnMenuMyFrame824 void OnMenu(wxCommandEvent &ce) { 825 wxTextCtrl *tc; 826 if (((tc = filter) && filter == wxWindow::FindFocus()) || 827 ((tc = replaces) && replaces == wxWindow::FindFocus())) { 828 // FIXME: have to emulate this behavior because menu always captures these events (??) 829 long from, to; 830 tc->GetSelection(&from, &to); 831 switch (ce.GetId()) { 832 case A_MLEFT: 833 case A_LEFT: 834 if (from != to) 835 tc->SetInsertionPoint(from); 836 else if (from) 837 tc->SetInsertionPoint(from - 1); 838 return; 839 case A_MRIGHT: 840 case A_RIGHT: 841 if (from != to) 842 tc->SetInsertionPoint(to); 843 else if (to < tc->GetLineLength(0)) 844 tc->SetInsertionPoint(to + 1); 845 return; 846 847 case A_SHOME: tc->SetSelection(0, to); return; 848 case A_SEND: tc->SetSelection(from, 1000); return; 849 850 case A_SCLEFT: 851 case A_SLEFT: 852 if (from) tc->SetSelection(from - 1, to); 853 return; 854 case A_SCRIGHT: 855 case A_SRIGHT: 856 if (to < tc->GetLineLength(0)) tc->SetSelection(from, to + 1); 857 return; 858 859 case A_BACKSPACE: tc->Remove(from - (from == to), to); return; 860 case A_DELETE: tc->Remove(from, to + (from == to)); return; 861 case A_HOME: tc->SetSelection(0, 0); return; 862 case A_END: tc->SetSelection(1000, 1000); return; 863 case A_SELALL: tc->SetSelection(0, 1000); return; 864 } 865 } 866 TSCanvas *sw = GetCurTab(); 867 wxClientDC dc(sw); 868 sw->DoPrepareDC(dc); 869 sw->doc->ShiftToCenter(dc); 870 auto Check = [&](const wxChar *cfg) { 871 sys->cfg->Write(cfg, ce.IsChecked()); 872 sw->Status(_(L"change will take effect next run of TreeSheets")); 873 }; 874 switch (ce.GetId()) { 875 case A_NOP: break; 876 877 case A_ALEFT: sw->CursorScroll(-g_scrollratecursor, 0); break; 878 case A_ARIGHT: sw->CursorScroll(g_scrollratecursor, 0); break; 879 case A_AUP: sw->CursorScroll(0, -g_scrollratecursor); break; 880 case A_ADOWN: sw->CursorScroll(0, g_scrollratecursor); break; 881 882 case A_ICONSET: 883 Check(L"iconset"); 884 break; 885 case A_SHOWSBAR: 886 Check(L"showsbar"); 887 break; 888 case A_SHOWTBAR: 889 Check(L"showtbar"); 890 break; 891 case A_LEFTTABS: 892 Check(L"lefttabs"); 893 break; 894 case A_SINGLETRAY: 895 Check(L"singletray"); 896 break; 897 case A_MAKEBAKS: sys->cfg->Write(L"makebaks", sys->makebaks = ce.IsChecked()); break; 898 case A_TOTRAY: sys->cfg->Write(L"totray", sys->totray = ce.IsChecked()); break; 899 case A_MINCLOSE: sys->cfg->Write(L"minclose", sys->minclose = ce.IsChecked()); break; 900 case A_ZOOMSCR: sys->cfg->Write(L"zoomscroll", sys->zoomscroll = ce.IsChecked()); break; 901 case A_THINSELC: sys->cfg->Write(L"thinselc", sys->thinselc = ce.IsChecked()); break; 902 case A_AUTOSAVE: sys->cfg->Write(L"autosave", sys->autosave = ce.IsChecked()); break; 903 case A_CENTERED: 904 sys->cfg->Write(L"centered", sys->centered = ce.IsChecked()); 905 Refresh(); 906 break; 907 case A_FSWATCH: 908 Check(L"fswatch"); 909 sys->fswatch = ce.IsChecked(); 910 break; 911 case A_AUTOEXPORT: 912 sys->cfg->Write(L"autohtmlexport", sys->autohtmlexport = ce.IsChecked()); 913 break; 914 case A_FASTRENDER: 915 sys->cfg->Write(L"fastrender", sys->fastrender = ce.IsChecked()); 916 Refresh(); 917 break; 918 case A_FULLSCREEN: 919 ShowFullScreen(!IsFullScreen()); 920 if (IsFullScreen()) sw->Status(_(L"Press F11 to exit fullscreen mode.")); 921 break; 922 case A_SEARCHF: 923 if (filter) { 924 filter->SetFocus(); 925 filter->SetSelection(0, 1000); 926 } else { 927 sw->Status(_(L"Please enable (Options -> Show Toolbar) to use search.")); 928 } 929 break; 930 #ifdef __WXMAC__ 931 case wxID_OSX_HIDE: Iconize(true); break; 932 case wxID_OSX_HIDEOTHERS: sw->Status(L"NOT IMPLEMENTED"); break; 933 case wxID_OSX_SHOWALL: Iconize(false); break; 934 case wxID_ABOUT: sw->doc->Action(dc, A_ABOUT); break; 935 case wxID_PREFERENCES: sw->doc->Action(dc, A_DEFFONT); break; 936 case wxID_EXIT: // FALL THRU: 937 #endif 938 case A_EXIT: 939 fromclosebox = false; 940 this->Close(); 941 break; 942 case A_CLOSE: sw->doc->Action(dc, ce.GetId()); break; // sw dangling pointer on return 943 default: 944 if (ce.GetId() >= wxID_FILE1 && ce.GetId() <= wxID_FILE9) { 945 wxString f(filehistory.GetHistoryFile(ce.GetId() - wxID_FILE1)); 946 sw->Status(sys->Open(f)); 947 } else if (ce.GetId() >= A_TAGSET && ce.GetId() < A_SCRIPT) { 948 sw->Status(sw->doc->TagSet(ce.GetId() - A_TAGSET)); 949 } else if (ce.GetId() >= A_SCRIPT && ce.GetId() < A_MAXACTION) { 950 auto msg = tssi.ScriptRun(scripts_in_menu[ce.GetId() - A_SCRIPT].c_str()); 951 sw->Status(wxString(msg)); 952 } else { 953 sw->Status(sw->doc->Action(dc, ce.GetId())); 954 break; 955 } 956 } 957 } 958 OnSearchMyFrame959 void OnSearch(wxCommandEvent &ce) { 960 sys->searchstring = ce.GetString().Lower(); 961 Document *doc = GetCurTab()->doc; 962 doc->selected.g = nullptr; 963 if (doc->searchfilter) 964 doc->SetSearchFilter(sys->searchstring.Len() != 0); 965 else 966 doc->Refresh(); 967 GetCurTab()->Status(); 968 } 969 ReFocusMyFrame970 void ReFocus() { 971 if (GetCurTab()) GetCurTab()->SetFocus(); 972 } 973 OnCellColorMyFrame974 void OnCellColor(wxCommandEvent &ce) { 975 GetCurTab()->doc->ColorChange(A_CELLCOLOR, ce.GetInt()); 976 ReFocus(); 977 } OnTextColorMyFrame978 void OnTextColor(wxCommandEvent &ce) { 979 GetCurTab()->doc->ColorChange(A_TEXTCOLOR, ce.GetInt()); 980 ReFocus(); 981 } OnBordColorMyFrame982 void OnBordColor(wxCommandEvent &ce) { 983 GetCurTab()->doc->ColorChange(A_BORDCOLOR, ce.GetInt()); 984 ReFocus(); 985 } OnDDImageMyFrame986 void OnDDImage(wxCommandEvent &ce) { 987 GetCurTab()->doc->ImageChange(idd->as[ce.GetInt()], dd_icon_res_scale); 988 ReFocus(); 989 } 990 OnSizingMyFrame991 void OnSizing(wxSizeEvent &se) { se.Skip(); } OnMaximizeMyFrame992 void OnMaximize(wxMaximizeEvent &me) { 993 ReFocus(); 994 me.Skip(); 995 } OnActivateMyFrame996 void OnActivate(wxActivateEvent &ae) { 997 // This causes warnings in the debug log, but without it keyboard entry upon window select 998 // doesn't work. 999 ReFocus(); 1000 } 1001 OnIconizeMyFrame1002 void OnIconize(wxIconizeEvent &me) { 1003 if (me.IsIconized()) { 1004 #ifdef WIN32 1005 if (sys->totray) { 1006 tbi.SetIcon(icon, L"TreeSheets"); 1007 Show(false); 1008 Iconize(); 1009 } 1010 #endif 1011 } else { 1012 if (GetCurTab()) GetCurTab()->SetFocus(); 1013 } 1014 } 1015 DeIconizeMyFrame1016 void DeIconize() { 1017 if (!IsIconized()) { 1018 RequestUserAttention(); 1019 return; 1020 } 1021 Show(true); 1022 Iconize(false); 1023 tbi.RemoveIcon(); 1024 } 1025 OnTBIDBLClickMyFrame1026 void OnTBIDBLClick(wxTaskBarIconEvent &e) { DeIconize(); } 1027 OnClosingMyFrame1028 void OnClosing(wxCloseEvent &ce) { 1029 bool fcb = fromclosebox; 1030 fromclosebox = true; 1031 if (fcb && sys->minclose) { 1032 ce.Veto(); 1033 Iconize(); 1034 return; 1035 } 1036 sys->RememberOpenFiles(); 1037 if (ce.CanVeto()) 1038 while (nb->GetPageCount()) { 1039 if (GetCurTab()->doc->CloseDocument()) { 1040 ce.Veto(); 1041 sys->RememberOpenFiles(); // may have closed some, but not all 1042 return; 1043 } else { 1044 nb->DeletePage(nb->GetSelection()); 1045 } 1046 } 1047 bt.Stop(); 1048 sys->savechecker.Stop(); 1049 Destroy(); 1050 } 1051 1052 #ifdef WIN32 SetRegKeyMyFrame1053 void SetRegKey(wxChar *key, wxString val) { 1054 wxRegKey rk(key); 1055 rk.Create(); 1056 rk.SetValue(L"", val); 1057 } 1058 #endif 1059 SetFileAssocMyFrame1060 void SetFileAssoc(wxString &exename) { 1061 #ifdef WIN32 1062 SetRegKey(L"HKEY_CLASSES_ROOT\\.cts", L"TreeSheets"); 1063 SetRegKey(L"HKEY_CLASSES_ROOT\\TreeSheets", L"TreeSheets file"); 1064 SetRegKey(L"HKEY_CLASSES_ROOT\\TreeSheets\\Shell\\Open\\Command", 1065 wxString(L"\"") + exename + L"\" \"%1\""); 1066 SetRegKey(L"HKEY_CLASSES_ROOT\\TreeSheets\\DefaultIcon", 1067 wxString(L"\"") + exename + L"\",0"); 1068 #else 1069 // TODO: do something similar for mac/kde/gnome? 1070 #endif 1071 } 1072 OnFileSystemEventMyFrame1073 void OnFileSystemEvent(wxFileSystemWatcherEvent &event) { 1074 // 0xF == create/delete/rename/modify 1075 if ((event.GetChangeType() & 0xF) == 0 || watcherwaitingforuser || !nb) return; 1076 const wxString &modfile = event.GetPath().GetFullPath(); 1077 loop(i, nb->GetPageCount()) { 1078 Document *doc = ((TSCanvas *)nb->GetPage(i))->doc; 1079 if (modfile == doc->filename) { 1080 wxDateTime modtime = wxFileName(modfile).GetModificationTime(); 1081 // Compare with last modified to trigger multiple times. 1082 if (!modtime.IsValid() || 1083 !doc->lastmodificationtime.IsValid() || 1084 modtime == doc->lastmodificationtime) { 1085 return; 1086 } 1087 if (doc->modified) { 1088 // TODO: this dialog is problematic since it may be on an unattended 1089 // computer and more of these events may fire. since the occurrence of this 1090 // situation is rare, it may be better to just take the most 1091 // recently changed version (which is the one that has just been modified 1092 // on disk) this potentially throws away local changes, but this can only 1093 // happen if the user left changes unsaved, then decided to go edit an older 1094 // version on another computer. 1095 // for now, we leave this code active, and guard it with 1096 // watcherwaitingforuser 1097 wxString msg = wxString::Format( 1098 _(L"%s\nhas been modified on disk by another program / computer:\nWould " 1099 L"you like to discard " 1100 L"your changes and re-load from disk?"), 1101 doc->filename); 1102 watcherwaitingforuser = true; 1103 int res = wxMessageBox(msg, _(L"File modification conflict!"), 1104 wxYES_NO | wxICON_QUESTION, this); 1105 watcherwaitingforuser = false; 1106 if (res != wxYES) return; 1107 } 1108 auto msg = sys->LoadDB(doc->filename, false, true); 1109 assert(msg); 1110 if (*msg) { 1111 GetCurTab()->Status(msg); 1112 } else { 1113 loop(j, nb->GetPageCount()) if (((TSCanvas *)nb->GetPage(j))->doc == doc) 1114 nb->DeletePage(j); 1115 ::wxRemoveFile(sys->TmpName(modfile)); 1116 GetCurTab()->Status( 1117 _(L"File has been re-loaded because of modifications of another program / " 1118 L"computer")); 1119 } 1120 return; 1121 } 1122 } 1123 } 1124 1125 DECLARE_EVENT_TABLE() 1126 }; 1127