1 // -*- mode: c++; c-file-style: "linux"; c-basic-offset: 2; indent-tabs-mode: nil -*-
2 //
3 //  Copyright (C) 2004-2015 Andrej Vodopivec <andrej.vodopivec@gmail.com>
4 //            (C) 2016-2018 Gunter Königsmann <wxMaxima@physikbuch.de>
5 //
6 //  This program is free software; you can redistribute it and/or modify
7 //  it under the terms of the GNU General Public License as published by
8 //  the Free Software Foundation; either version 2 of the License, or
9 //  (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 //
21 //  SPDX-License-Identifier: GPL-2.0+
22 
23 /*! \file
24   This file defines the class Configuration which serves as a fast configuration storage.
25  */
26 
27 #include "Configuration.h"
28 #include "Dirstructure.h"
29 #include "ErrorRedirector.h"
30 #include <wx/wx.h>
31 #include <wx/string.h>
32 #include <wx/font.h>
33 #include <wx/config.h>
34 #include <wx/wfstream.h>
35 #include <wx/fileconf.h>
36 #include "Cell.h"
37 
Configuration(wxDC * dc)38 Configuration::Configuration(wxDC *dc) :
39   m_dc(dc),
40   m_mathJaxURL("https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js?config=TeX-AMS_HTML"),
41   m_documentclass("article"),
42   m_documentclassOptions("fleqn"),
43   m_symbolPaneAdditionalChars("Øü§")
44 {
45   SetBackgroundBrush(*wxWHITE_BRUSH);
46   m_hidemultiplicationsign = true;
47   m_autoSaveAsTempFile = false;
48   m_inLispMode = false;
49   m_htmlEquationFormat = mathJaX_TeX;
50   m_autodetectMaxima = true;
51   m_clipToDrawRegion = true;
52   m_fontChanged = true;
53   m_mathJaxURL_UseUser = false;
54   m_TOCshowsSectionNumbers = false;
55   m_invertBackground = false;
56   m_antialiassingDC = NULL;
57   m_parenthesisDrawMode = unknown;
58   m_zoomFactor = 1.0; // affects returned fontsizes
59   m_useSVG = false;
60   m_changeAsterisk = true;
61   m_workSheet = NULL;
62   m_latin2greek = false;
63   m_enterEvaluates = false;
64   m_printScale = 1.0;
65   m_forceUpdate = false;
66   m_outdated = false;
67   m_printing = false;
68   m_TeXFonts = false;
69   m_notifyIfIdle = true;
70   m_fixReorderedIndices = true;
71   m_showBrackets = true;
72   m_printBrackets = false;
73   m_hideBrackets = true;
74   m_language = wxLANGUAGE_DEFAULT;
75   m_lineWidth_em = 88;
76   m_adjustWorksheetSizeNeeded = false;
77   m_showLabelChoice = labels_prefer_user;
78   m_abortOnError = true;
79   m_defaultPort = 49152;
80   m_maxGnuplotMegabytes = 12;
81   m_clientWidth = 1024;
82   m_clientHeight = 768;
83   m_indentMaths=true;
84   if(m_maximaLocation_override != wxEmptyString)
85     m_maximaUserLocation = m_maximaLocation_override;
86   else
87     m_maximaUserLocation = Dirstructure::Get()->MaximaDefaultLocation();
88   m_indent = -1;
89   m_autoSubscript = 1;
90   m_antiAliasLines = true;
91   m_showCodeCells = true;
92   m_greekSidebar_ShowLatinLookalikes = false;
93   m_greekSidebar_Show_mu = false;
94   m_copyBitmap = false; // Otherwise MS Office, OpenOffice and LibreOffice prefer the bitmap
95   // to Mathml and RTF. Also mail programs prefer bitmaps to text - which is counter-productive
96   // for maxima-discuss.
97   m_copyMathML = true;
98   m_copyMathMLHTML = false;
99   m_copyRTF = true;
100   m_copySVG = true;
101   m_copyEMF = false;
102   m_showLength = 2;
103   m_useUnicodeMaths = true;
104   m_offerKnownAnswers = true;
105   m_escCodes["pm"]    = wxT("\u00B1");
106   m_escCodes["+/-"]   = wxT("\u00B1");
107   m_escCodes["alpha"] = wxT("\u03B1");
108   m_escCodes["beta"]  = wxT("\u03B2");
109   m_escCodes["gamma"] = wxT("\u03B3");
110   m_escCodes["delta"] = wxT("\u03B4");
111   m_escCodes["epsilon"] = wxT("\u03B5");
112   m_escCodes["zeta"] = wxT("\u03B6");
113   m_escCodes["eta"] = wxT("\u03B7");
114   m_escCodes["theta"] = wxT("\u03B8");
115   m_escCodes["iota"] = wxT("\u03B9");
116   m_escCodes["kappa"] = wxT("\u03BA");
117   m_escCodes["lambda"] = wxT("\u03BB");
118   m_escCodes["mu"] = wxT("\u03BC");
119   m_escCodes["nu"] = wxT("\u03BD");
120   m_escCodes["xi"] = wxT("\u03BE");
121   m_escCodes["om"] = wxT("\u03BF");
122   m_escCodes["omicron"] = wxT("\u03BF");
123   m_escCodes["nabla"] = wxT("\u2207");
124   m_escCodes["pi"] = wxT("\u03C0");
125   m_escCodes["rho"] = wxT("\u03C1");
126   m_escCodes["sigma"] = wxT("\u03C3");
127   m_escCodes["tau"] = wxT("\u03C4");
128   m_escCodes["upsilon"] = wxT("\u03C5");
129   m_escCodes["phi"] = wxT("\u03C6");
130   m_escCodes["chi"] = wxT("\u03C7");
131   m_escCodes["psi"] = wxT("\u03C8");
132   m_escCodes["omega"] = wxT("\u03C9");
133   m_escCodes["Alpha"] = wxT("\u0391");
134   m_escCodes["Beta"] = wxT("\u0392");
135   m_escCodes["Gamma"] = wxT("\u0393");
136   m_escCodes["Delta"] = wxT("\u0394");
137   m_escCodes["Epsilon"] = wxT("\u0395");
138   m_escCodes["Zeta"] = wxT("\u0396");
139   m_escCodes["Eta"] = wxT("\u0397");
140   m_escCodes["Theta"] = wxT("\u0398");
141   m_escCodes["Iota"] = wxT("\u0399");
142   m_escCodes["Kappa"] = wxT("\u039A");
143   m_escCodes["Lambda"] = wxT("\u039B");
144   m_escCodes["Mu"] = wxT("\u039C");
145   m_escCodes["Nu"] = wxT("\u039D");
146   m_escCodes["Xi"] = wxT("\u039E");
147   m_escCodes["Omicron"] = wxT("\u039F");
148   m_escCodes["Pi"] = wxT("\u03A0");
149   m_escCodes["Rho"] = wxT("\u03A1");
150   m_escCodes["Sigma"] = wxT("\u03A3");
151   m_escCodes["Tau"] = wxT("\u03A4");
152   m_escCodes["Upsilon"] = wxT("\u03A5");
153   m_escCodes["Phi"] = wxT("\u03A6");
154   m_escCodes["Chi"] = wxT("\u03A7");
155   m_escCodes["Psi"] = wxT("\u03A8");
156   m_escCodes["Omega"] = wxT("\u03A9");
157   m_escCodes["Ohm"] = wxT("\u03A9");
158   //////////////////////////
159   m_escCodes["^2"] = wxT("\u00B2");
160   m_escCodes["^3"] = wxT("\u00B3");
161   m_escCodes["/2"] = wxT("\u00BD");
162   m_escCodes["sq"] = wxT("\u221A");
163   m_escCodes["ii"] = wxT("\u2148");
164   m_escCodes["ee"] = wxT("\u2147");
165   m_escCodes["hb"] = wxT("\u210F");
166   m_escCodes["in"] = wxT("\u2208");
167   m_escCodes["impl"] = wxT("\u21D2");
168   m_escCodes["inf"] = wxT("\u221e");
169   m_escCodes["empty"] = wxT("\u2205");
170   m_escCodes["TB"] = wxT("\u25b6");
171   m_escCodes["tb"] = wxT("\u25b8");
172   m_escCodes["and"] = wxT("\u22C0");
173   m_escCodes["or"] = wxT("\u22C1");
174   m_escCodes["xor"] = wxT("\u22BB");
175   m_escCodes["nand"] = wxT("\u22BC");
176   m_escCodes["nor"] = wxT("\u22BD");
177   m_escCodes["implies"] = wxT("\u21D2");
178   m_escCodes["=>"] = wxT("\u21D2");
179   m_escCodes["equiv"] = wxT("\u21D4");
180   m_escCodes["<=>"] = wxT("\u21D4");
181   m_escCodes["not"] = wxT("\u00AC");
182   m_escCodes["union"] = wxT("\u22C3");
183   m_escCodes["inter"] = wxT("\u22C2");
184   m_escCodes["subseteq"] = wxT("\u2286");
185   m_escCodes["subset"] = wxT("\u2282");
186   m_escCodes["notsubseteq"] = wxT("\u2288");
187   m_escCodes["notsubset"] = wxT("\u2284");
188   m_escCodes["hbar"] = wxT("\u0127");
189   m_escCodes["Hbar"] = wxT("\u0126");
190   m_escCodes["partial"] = wxT("\u2202");
191   m_escCodes["integral"] = wxT("\u222b");
192   m_escCodes["approx"] = wxT("\u2245");
193   m_escCodes["prop"] = wxT("\u221d");
194   m_escCodes["propto"] = wxT("\u221d");
195   m_escCodes["neq"] = wxT("\u2260");
196   m_escCodes["!="] = wxT("\u2260");
197   m_escCodes["/="] = wxT("\u2260");
198   m_escCodes["#"] = wxT("\u2260");
199   m_escCodes["<="] = wxT("\u2264");
200   m_escCodes["leq"] = wxT("\u2264");
201   m_escCodes[">="] = wxT("\u2265");
202   m_escCodes["geq"] = wxT("\u2265");
203   m_escCodes["ll"] = wxT("\u226A");
204   m_escCodes["<<"] = wxT("\u226A");
205   m_escCodes["gg"] = wxT("\u226B");
206   m_escCodes[">>"] = wxT("\u226B");
207   m_escCodes["qed"] = wxT("\u220E");
208   m_escCodes["equiv"] = wxT("\u2263");
209   m_escCodes["sum"] = wxT("\u2211");
210   m_escCodes["prod"] = wxT("\u220F");
211   m_escCodes["product"] = wxT("\u220F");
212   m_escCodes["exists"] = wxT("\u2203");
213   m_escCodes["nexists"] = wxT("\u2204");
214   m_escCodes["parallel"] = wxT("\u2225");
215   m_escCodes["perp"] = wxT("\u27C2");
216   m_escCodes["perpendicular"] = wxT("\u27C2");
217   m_escCodes["bot"] = wxT("\u27C2");
218   m_escCodes["leadsto"] = wxT("\u219D");
219   m_escCodes["->"] = wxT("\u2192");
220   m_escCodes["-->"] = wxT("\u27F6");
221   m_escCodes[" --> "] = wxT("\u27F6");
222 
223   m_parenthesisDrawMode = unknown;
224 
225   #ifdef __WXMSW__
226   wxFont font;
227   font.SetFamily(wxFONTFAMILY_MODERN);
228   font.SetFaceName(wxT("Linux Libertine O"));
229   font.SetStyle(wxFONTSTYLE_NORMAL );
230   if(font.IsOk())
231     m_fontName = wxT("Linux Libertine O");
232   if(font.IsOk())
233     m_mathFontName = wxT("Linux Libertine O");
234   else
235     m_mathFontName = wxEmptyString;
236   #endif
237   m_mathFontSize = 12;
238   m_fontEncoding = wxFONTENCODING_DEFAULT;
239   m_styles[TS_DEFAULT].Set(_("Default"),*wxBLACK, true, true, false, 12);
240   m_styles[TS_TEXT].Set(_("Text cell"),*wxBLACK, false, false, false, 12);
241   m_styles[TS_CODE_VARIABLE].Set(_("Code highlighting: Variables"),wxColor(0,128,0), false, true, false);
242   m_styles[TS_CODE_FUNCTION].Set(_("Code highlighting: Functions"),wxColor(128,0,0), false, true, false);
243   m_styles[TS_CODE_COMMENT].Set(_("Code highlighting: Comments"),wxColor(64,64,64), false, true, false);
244   m_styles[TS_CODE_NUMBER].Set(_("Code highlighting: Numbers"),wxColor(128,64,0), false, true, false);
245   m_styles[TS_CODE_STRING].Set(_("Code highlighting: Strings"),wxColor(0,0,128), false, true, false);
246   m_styles[TS_CODE_OPERATOR].Set(_("Code highlighting: Operators"),*wxBLACK, false, true, false);
247   m_styles[TS_CODE_LISP].Set(_("Code highlighting: Lisp"),wxColor(255,0,128), false, true, false);
248   m_styles[TS_CODE_ENDOFLINE].Set(_("Code highlighting: End of line"),wxColor(128,128,128), false, true, false);
249   m_styles[TS_GREEK_CONSTANT].Set(_("Greek constants"),*wxBLACK, false, true, false);
250   m_styles[TS_HEADING6].Set(_("Heading 6"),*wxBLACK, true, false, false, 14);
251   m_styles[TS_HEADING5].Set(_("Heading 5"),*wxBLACK, true, false, false, 15);
252   m_styles[TS_SUBSUBSECTION].Set(_("Subsubsection cell (Heading 4)"),*wxBLACK, true, false, false, 16);
253   m_styles[TS_SUBSECTION].Set(_("Subsection cell (Heading 3)"),*wxBLACK, true, false, false, 16);
254   m_styles[TS_SECTION].Set(_("Section cell (Heading 2)"),*wxBLACK, true, true, false, 18);
255   m_styles[TS_TITLE].Set(_("Title cell (Heading 1)"),*wxBLACK, true, false, true, 24);
256   m_styles[TS_WARNING].Set(_("Maxima warnings"),wxColor(wxT("orange")), true, false, false, 12);
257   m_styles[TS_ERROR].Set(_("Maxima errors"),*wxRED, false, false, false, 12);
258   m_styles[TS_MAIN_PROMPT].Set(_("Input labels"),wxColor(wxT("rgb(255,128,128)")), false, false, false);
259   m_styles[TS_OTHER_PROMPT].Set(_("Maxima questions"),*wxRED, false, true, false);
260   m_styles[TS_LABEL].Set(_("Output labels"),wxColor(wxT("rgb(255,192,128)")), false, false, false);
261   m_styles[TS_USERLABEL].Set(_("User-defined labels"),wxColor(wxT("rgb(255,64,0)")), false, false, false);
262   m_styles[TS_SPECIAL_CONSTANT].Set(_("Special constants"),*wxBLACK, false, false, false);
263   m_styles[TS_INPUT].Set(_("Maxima input"),*wxBLUE, false, false, false);
264   m_styles[TS_NUMBER].Set(_("Numbers"),*wxBLACK, false, false, false);
265   m_styles[TS_STRING].Set(_("Strings"),*wxBLACK, false, true, false);
266   m_styles[TS_GREEK_CONSTANT].Set(_("Greek Constants"),*wxBLACK, false, false, false);
267   m_styles[TS_VARIABLE].Set(_("Variables"),*wxBLACK, false, true, false);
268   m_styles[TS_FUNCTION].Set(_("Function names"),*wxBLACK);
269   m_styles[TS_HIGHLIGHT].Set(_("Highlight (dpart)"),*wxRED);
270   m_styles[TS_TEXT_BACKGROUND].Set(_("Text cell background"),*wxWHITE);
271   m_styles[TS_DOCUMENT_BACKGROUND].Set(_("Document background"),*wxWHITE);
272   m_styles[TS_CELL_BRACKET].Set(_("Cell bracket"),wxColour(wxT("rgb(0,0,0)")));
273   m_styles[TS_ACTIVE_CELL_BRACKET].Set(_("Active cell bracket"),wxT("rgb(255,0,0)"));
274   m_styles[TS_CURSOR].Set(_("Cursor"),wxT("rgb(0,0,0)"));
275   m_styles[TS_SELECTION].Set(_("Selection"),wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
276   m_styles[TS_EQUALSSELECTION].Set(_("Text equal to selection"),wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT).ChangeLightness(150));
277   m_styles[TS_OUTDATED].Set(_("Outdated cells"),wxColor(wxT("rgb(153,153,153)")));
278   ReadConfig();
279 }
280 
GetPPI(wxWindow * win) const281 wxSize Configuration::GetPPI(wxWindow *win) const
282 {
283   if(win == NULL)
284     return wxSize(96,96);
285 
286   wxSize ppi(-1,-1);
287 #if wxCHECK_VERSION(3, 1, 1)
288   wxDisplay display;
289 
290   int display_idx = wxDisplay::GetFromWindow(win);
291   if (display_idx < 0)
292     ppi = wxSize(72,72);
293   else
294     ppi = wxDisplay(display_idx).GetPPI();
295 #endif
296 
297   if((ppi.x < 10) || (ppi.y < 10))
298     ppi = wxGetDisplayPPI();
299   if((ppi.x <= 10) || (ppi.y <= 10))
300     ppi = wxSize(72,72);
301 
302   return ppi;
303 }
304 
GetAutosubscript_string() const305 wxString Configuration::GetAutosubscript_string() const
306 {
307   switch (m_autoSubscript)
308   {
309   case 0:
310     return "nil";
311   case 1:
312     return "t";
313   default:
314     return "'all";
315   }
316 }
317 
ShowCodeCells(bool show)318 void Configuration::ShowCodeCells(bool show)
319 {
320   m_showCodeCells = show;
321 }
322 
SetBackgroundBrush(wxBrush brush)323 void Configuration::SetBackgroundBrush(wxBrush brush)
324 {
325   m_BackgroundBrush = brush;
326   m_tooltipBrush = brush;
327   m_tooltipBrush.SetColour(wxColour(255, 255, 192, 128));
328 }
329 
MaximaFound(wxString location)330 bool Configuration::MaximaFound(wxString location)
331 {
332   if(location == wxEmptyString)
333     return false;
334 
335   bool maximaFound = false;
336   if (wxFileExists(location))
337     maximaFound = true;
338 
339   // Find a maxima within an application package.
340   if (wxFileExists(location + wxT("/Contents/Resources/maxima.sh")))
341     maximaFound = true;
342 
343   // Don't complain if PATH doesn't yield a result.
344   SuppressErrorDialogs logNull;
345 
346   if(!(location.EndsWith("/") || location.EndsWith("\\")))
347   {
348     wxPathList pathlist;
349     pathlist.AddEnvList(wxT("PATH"));
350     wxString path = pathlist.FindAbsoluteValidPath(location);
351     if (!path.empty())
352       maximaFound = true;
353   }
354   return maximaFound;
355 }
356 
ReadConfig()357 void Configuration::ReadConfig()
358 {
359   wxConfigBase *config = wxConfig::Get();
360   m_autoWrap = 3;
361 
362   if(!config->Read(wxT("AutoSaveAsTempFile"), &m_autoSaveAsTempFile))
363   {
364     long autoSaveMinutes = 0;
365     config->Read(wxT("autoSaveMinutes"), &autoSaveMinutes);
366     m_autoSaveAsTempFile = (autoSaveMinutes == 0);
367   }
368   config->Read("language", &m_language);
369   if (m_language == wxLANGUAGE_UNKNOWN)
370     m_language = wxLANGUAGE_DEFAULT;
371 
372   config->Read("invertBackground", &m_invertBackground);
373   config->Read("maxGnuplotMegabytes", &m_maxGnuplotMegabytes);
374   config->Read("offerKnownAnswers", &m_offerKnownAnswers);
375   config->Read(wxT("documentclass"), &m_documentclass);
376   config->Read(wxT("documentclassoptions"), &m_documentclassOptions);
377   config->Read(wxT("latin2greek"), &m_latin2greek);
378   config->Read(wxT("enterEvaluates"), &m_enterEvaluates);
379   config->Read(wxT("hidemultiplicationsign"), &m_hidemultiplicationsign);
380   config->Read("greekSidebar_ShowLatinLookalikes", &m_greekSidebar_ShowLatinLookalikes);
381   config->Read("greekSidebar_Show_mu", &m_greekSidebar_Show_mu);
382   config->Read("symbolPaneAdditionalChars", &m_symbolPaneAdditionalChars);
383   config->Read("parameters", &m_maximaParameters);
384 
385   {
386     int tmp;
387     config->Read("HTMLequationFormat", &tmp);
388     m_htmlEquationFormat = (Configuration::htmlExportFormat)tmp;
389   }
390 
391   config->Read(wxT("TOCshowsSectionNumbers"), &m_TOCshowsSectionNumbers);
392   config->Read(wxT("autoWrapMode"), &m_autoWrap);
393   config->Read(wxT("mathJaxURL_UseUser"), &m_mathJaxURL_UseUser);
394   config->Read(wxT("useUnicodeMaths"), &m_useUnicodeMaths);
395   config->Read(wxT("mathJaxURL"), &m_mathJaxURL);
396   config->Read(wxT("autosubscript"), &m_autoSubscript);
397   config->Read(wxT("antiAliasLines"), &m_antiAliasLines);
398   config->Read(wxT("indentMaths"), &m_indentMaths);
399   config->Read(wxT("abortOnError"),&m_abortOnError);
400   config->Read("defaultPort",&m_defaultPort);
401   config->Read(wxT("fixReorderedIndices"), &m_fixReorderedIndices);
402   config->Read(wxT("showLength"), &m_showLength);
403   config->Read(wxT("printScale"), &m_printScale);
404   config->Read(wxT("useSVG"), &m_useSVG);
405   config->Read(wxT("copyBitmap"), &m_copyBitmap);
406   config->Read(wxT("copyMathML"), &m_copyMathML);
407   config->Read(wxT("copyMathMLHTML"), &m_copyMathMLHTML);
408   config->Read(wxT("copyRTF"), &m_copyRTF);
409   config->Read(wxT("copySVG"), &m_copySVG );
410   config->Read(wxT("copyEMF"), &m_copyEMF );
411   config->Read(wxT("autodetectMaxima"), &m_autodetectMaxima);
412   config->Read(wxT("maxima"), &m_maximaUserLocation);
413   // Fix wrong" maxima=1" parameter in ~/.wxMaxima if upgrading from 0.7.0a
414   if (m_maximaUserLocation.IsSameAs(wxT("1")))
415     m_maximaUserLocation = Dirstructure::Get()->MaximaDefaultLocation();
416 
417   m_autoIndent = true;
418   config->Read(wxT("autoIndent"), &m_autoIndent);
419 
420   int showLabelChoice;
421   config->Read(wxT("showLabelChoice"), &showLabelChoice);
422   m_showLabelChoice = (showLabels) showLabelChoice;
423 
424   config->Read(wxT("changeAsterisk"), &m_changeAsterisk);
425 
426   config->Read(wxT("notifyIfIdle"), &m_notifyIfIdle);
427 
428   config->Read(wxT("hideBrackets"), &m_hideBrackets);
429 
430   m_displayedDigits = 100;
431   config->Read(wxT("displayedDigits"), &m_displayedDigits);
432   if (m_displayedDigits <= 20)
433     m_displayedDigits = 20;
434 
435   m_restartOnReEvaluation = true;
436   config->Read(wxT("restartOnReEvaluation"), &m_restartOnReEvaluation);
437 
438   m_matchParens = true;
439   config->Read(wxT("matchParens"), &m_matchParens);
440 
441   m_insertAns = false;
442   config->Read(wxT("insertAns"), &m_insertAns);
443 
444   m_openHCaret = false;
445   config->Read(wxT("openHCaret"), &m_openHCaret);
446 
447   m_labelWidth = 4;
448   config->Read(wxT("labelWidth"), &m_labelWidth);
449 
450   config->Read(wxT("printBrackets"), &m_printBrackets);
451 
452   m_zoomFactor = 1.0;
453   config->Read(wxT("ZoomFactor"), &m_zoomFactor);
454 
455   if (wxFontEnumerator::IsValidFacename(m_fontCMEX = CMEX10) &&
456       wxFontEnumerator::IsValidFacename(m_fontCMSY = CMSY10) &&
457       wxFontEnumerator::IsValidFacename(m_fontCMRI = CMR10) &&
458       wxFontEnumerator::IsValidFacename(m_fontCMMI = CMMI10) &&
459       wxFontEnumerator::IsValidFacename(m_fontCMTI = CMTI10))
460   {
461     m_TeXFonts = true;
462     config->Read(wxT("usejsmath"), &m_TeXFonts);
463   }
464 
465   m_keepPercent = true;
466   wxConfig::Get()->Read(wxT("keepPercent"), &m_keepPercent);
467 
468   ReadStyles();
469 }
470 
GetFont(TextStyle textStyle,long fontSize) const471 wxFont Configuration::GetFont(TextStyle textStyle, long fontSize) const
472 {
473   wxString fontName;
474   wxFontStyle fontStyle;
475   wxFontWeight fontWeight;
476   wxFontEncoding fontEncoding;
477   bool underlined = IsUnderlined(textStyle);
478 
479   if ((textStyle == TS_TITLE) ||
480       (textStyle == TS_SECTION) ||
481       (textStyle == TS_SUBSECTION) ||
482       (textStyle == TS_SUBSUBSECTION) ||
483       (textStyle == TS_HEADING5) ||
484       (textStyle == TS_HEADING6))
485   {
486     // While titles and section names may be underlined the section number
487     // isn't. Else the space between section number and section title
488     // would look weird.
489     underlined = false;
490 
491     // Besides that these items have a fixed font size.
492     fontSize = GetFontSize(textStyle);
493   }
494   if (fontSize < 4)
495     fontSize = 4;
496 
497   // The font size scales with the worksheet
498   long fontSize1 = Scale_Px(fontSize);
499 
500   // Ensure a sane minimum font size
501   if (fontSize1 < 4)
502     fontSize1 = 4;
503 
504 
505   fontName = GetFontName(textStyle);
506   fontStyle = IsItalic(textStyle);
507   fontWeight = IsBold(textStyle);
508 
509   fontEncoding = GetFontEncoding();
510 
511   wxFont font;
512   font.SetFamily(wxFONTFAMILY_MODERN);
513   font.SetFaceName(fontName);
514   font.SetEncoding(fontEncoding);
515   font.SetStyle(fontStyle);
516   font.SetWeight(fontWeight);
517   font.SetUnderlined(underlined);
518   font.SetEncoding(fontEncoding);
519   if (!font.IsOk())
520   {
521     font.SetFamily(wxFONTFAMILY_MODERN);
522     font.SetEncoding(fontEncoding);
523     font.SetStyle(fontStyle);
524     font.SetWeight(fontWeight);
525     font.SetUnderlined(underlined);
526   }
527 
528   if (!font.IsOk())
529     font = *wxNORMAL_FONT;
530 
531   font.SetPointSize(fontSize1);
532 
533   return font;
534 }
535 
DefaultBackgroundColor()536 wxColor Configuration::DefaultBackgroundColor()
537 {
538   if(InvertBackground())
539     return InvertColour(m_styles[TS_DOCUMENT_BACKGROUND].GetColor());
540   else
541     return m_styles[TS_DOCUMENT_BACKGROUND].GetColor();
542 }
543 
EditorBackgroundColor()544 wxColor Configuration::EditorBackgroundColor()
545 {
546   if(InvertBackground())
547     return InvertColour(m_styles[TS_TEXT_BACKGROUND].GetColor());
548   else
549     return m_styles[TS_TEXT_BACKGROUND].GetColor();
550 }
551 
SetPrinting(bool printing)552 void Configuration::SetPrinting(bool printing)
553 {
554   m_printing = printing;
555   if(printing)
556     m_invertBackground = false;
557   else
558     wxConfig::Get()->Read("invertBackground", m_invertBackground);
559   if(printing)
560     ClipToDrawRegion(false);
561 }
562 
InvertColour(wxColour col)563 wxColour Configuration::InvertColour(wxColour col)
564 {
565   return wxColour(
566     255 - col.Red(),
567     255 - col.Green(),
568     255 - col.Blue(),
569     col.Alpha());
570 }
571 
GetLineWidth() const572 long Configuration::GetLineWidth() const
573 {
574   // The default line width is the width of the viewport minus the indentation minus
575   // roughly one char
576   long lineWidth = m_clientWidth - Scale_Px(GetLabelWidth() +
577                                            GetCellBracketWidth() + GetDefaultFontSize());
578 
579   // If that was suspiciously wide we reduce the default line width again.
580   if((lineWidth >= Scale_Px(double(GetDefaultFontSize())) * LineWidth_em()) &&
581      (!m_printing))
582     lineWidth = Scale_Px(double(GetDefaultFontSize())) * LineWidth_em();
583   return lineWidth;
584 }
585 
GetParenthesisDrawMode()586 Configuration::drawMode Configuration::GetParenthesisDrawMode()
587 {
588   if(m_parenthesisDrawMode == unknown)
589   {
590     m_parenthesisDrawMode = handdrawn;
591     wxFont font = GetFont(TS_FUNCTION,20);
592     if (CharsExistInFont(font,
593                          wxT(PAREN_OPEN_TOP_UNICODE),
594                          wxT(PAREN_OPEN_EXTEND_UNICODE),
595                          wxT(PAREN_OPEN_BOTTOM_UNICODE))
596       )
597     {
598       m_parenthesisDrawMode = assembled_unicode;
599       return m_parenthesisDrawMode;
600     }
601     font.SetFaceName(wxT("Linux Libertine"));
602     if (CharsExistInFont(font,
603                          wxT(PAREN_OPEN_TOP_UNICODE),
604                          wxT(PAREN_OPEN_EXTEND_UNICODE),
605                          wxT(PAREN_OPEN_BOTTOM_UNICODE))
606       )
607     {
608       m_parenthesisDrawMode = assembled_unicode_fallbackfont;
609       return m_parenthesisDrawMode;
610     }
611 
612     font.SetFaceName(wxT("Linux Libertine O"));
613     if (CharsExistInFont(font,
614                          wxT(PAREN_OPEN_TOP_UNICODE),
615                          wxT(PAREN_OPEN_EXTEND_UNICODE),
616                          wxT(PAREN_OPEN_BOTTOM_UNICODE))
617       )
618     {
619       m_parenthesisDrawMode = assembled_unicode_fallbackfont2;
620       return m_parenthesisDrawMode;
621     }
622   }
623   return m_parenthesisDrawMode;
624 }
625 
IsEqual(wxBitmap bitmap1,wxBitmap bitmap2)626 bool Configuration::IsEqual(wxBitmap bitmap1, wxBitmap bitmap2)
627 {
628   if (bitmap1.GetSize() != bitmap2.GetSize())
629     return false;
630 
631   wxImage img1=bitmap1.ConvertToImage();
632   wxImage img2=bitmap2.ConvertToImage();
633   long bytes = img1.GetWidth()*img1.GetHeight()*3;
634 
635   if(bytes < 0)
636     return false;
637 
638   bool equal = (memcmp(img1.GetData(),img2.GetData(),bytes) == 0);
639   return equal;
640 }
641 
SetZoomFactor(double newzoom)642 void Configuration::SetZoomFactor(double newzoom)
643 {
644   if (newzoom > GetMaxZoomFactor())
645     newzoom = GetMaxZoomFactor();
646   if (newzoom < GetMinZoomFactor())
647     newzoom = GetMinZoomFactor();
648 
649   m_zoomFactor = newzoom;
650   wxConfig::Get()->Write(wxT("ZoomFactor"), m_zoomFactor);
651   RecalculationForce(true);
652 }
653 
~Configuration()654 Configuration::~Configuration()
655 {
656   WriteStyles();
657   wxConfigBase *config = wxConfig::Get();
658 }
659 
CharsExistInFont(wxFont font,wxString char1,wxString char2,wxString char3)660 bool Configuration::CharsExistInFont(wxFont font, wxString char1,wxString char2, wxString char3)
661 {
662   wxString name = char1 + char2 + char3;
663   CharsInFontMap::const_iterator it = m_charsInFontMap.find(name);
664   if(it != m_charsInFontMap.end())
665     return it->second;
666 
667   if(!font.IsOk())
668   {
669     m_charsInFontMap[name] = false;
670     return false;
671   }
672   // Seems like Apple didn't hold to their high standards as the maths part of this font
673   // don't form nice big mathematical symbols => Blacklisting this font.
674   if (font.GetFaceName() == wxT("Monaco"))
675   {
676     m_charsInFontMap[name] = false;
677     return false;
678   }
679 
680   if(!m_useUnicodeMaths)
681   {
682     m_charsInFontMap[name] = false;
683     return false;
684   }
685 
686   // Letters with width or height = 0 don't exist in the current font
687   wxCoord width1,height1,descent1;
688   GetDC()->SetFont(font);
689   GetDC()->GetTextExtent(char1,&width1,&height1,&descent1);
690   if((width1 < 1) || (height1-descent1 < 1))
691   {
692     m_charsInFontMap[name] = false;
693     return false;
694   }
695   wxCoord width2,height2,descent2;
696   GetDC()->GetTextExtent(char2,&width2,&height2,&descent2);
697   if((width2 < 1) || (height2-descent2 < 1))
698   {
699     m_charsInFontMap[name] = false;
700     return false;
701   }
702   wxCoord width3,height3,descent3;
703   GetDC()->GetTextExtent(char3,&width3,&height3,&descent3);
704   if((width3 < 1) || (height3-descent3 < 1))
705   {
706     m_charsInFontMap[name] = false;
707     return false;
708   }
709 
710   if(((width1 != width2) &&
711       (width1 != width3) &&
712       (width2 != width3))||
713      ((height1 != height2) &&
714       (height1 != height3) &&
715       (height2 != height3)))
716   {
717     m_charsInFontMap[name] = true;
718     return true;
719   }
720 
721   wxBitmap bmp1(width1,height1);
722   wxMemoryDC dc1(bmp1);
723   dc1.SetFont(font);
724   dc1.SelectObject(bmp1);
725   dc1.Clear();
726   dc1.DrawText(char1,wxPoint(0,0));
727 
728   wxBitmap bmp2(width2,height2);
729   wxMemoryDC dc2(bmp2);
730   dc2.SetFont(font);
731   dc2.SelectObject(bmp2);
732   dc2.Clear();
733   dc2.DrawText(char2,wxPoint(0,0));
734 
735   wxBitmap bmp3(width3,height3);
736   wxMemoryDC dc3(bmp3);
737   dc3.SetFont(font);
738   dc3.SelectObject(bmp3);
739   dc3.Clear();
740   dc3.DrawText(char3,wxPoint(0,0));
741 
742   if(IsEqual(bmp1,bmp2) || IsEqual(bmp2,bmp3) || IsEqual(bmp1,bmp3))
743   {
744     m_charsInFontMap[name] = false;
745     return false;
746   }
747   else
748   {
749     m_charsInFontMap[name] = false;
750     return true;
751   }
752 }
753 
GetFontName(long type) const754 wxString Configuration::GetFontName(long type) const
755 {
756   wxString retval = FontName();
757   if (type == TS_TITLE || type == TS_SUBSECTION || type == TS_SUBSUBSECTION ||
758       type == TS_HEADING5 || type == TS_HEADING6 || type == TS_SECTION || type == TS_TEXT)
759     retval = m_styles[type].FontName();
760   if(retval == wxEmptyString)
761     retval = m_fontName;
762 
763   if (type == TS_NUMBER || type == TS_VARIABLE || type == TS_FUNCTION ||
764       type == TS_SPECIAL_CONSTANT || type == TS_STRING)
765     retval = m_mathFontName;
766   return retval;
767 }
768 
MaximaLocation() const769 wxString Configuration::MaximaLocation() const
770 {
771   if(m_autodetectMaxima)
772     return MaximaDefaultLocation();
773   else
774     return m_maximaUserLocation;
775 }
776 
MaximaDefaultLocation()777 wxString Configuration::MaximaDefaultLocation()
778 {
779   return Dirstructure::Get()->MaximaDefaultLocation();
780 }
781 
ReadStyles(wxString file)782 void Configuration::ReadStyles(wxString file)
783 {
784   wxConfigBase *config = NULL;
785   if (file == wxEmptyString)
786     config = wxConfig::Get();
787   else
788   {
789     wxFileInputStream str(file);
790     config = new wxFileConfig(str);
791   }
792 
793   // Font
794   config->Read(wxT("Style/Default/Style/Text/fontname"), &m_fontName);
795 #ifdef __WXOSX_MAC__
796   if (m_fontName.IsEmpty())
797   {
798     m_fontName = "Monaco";
799   }
800 #endif
801 
802   config->Read(wxT("mathfontsize"), &m_mathFontSize);
803   long encoding = m_fontEncoding;
804   config->Read(wxT("fontEncoding"), &encoding);
805   m_fontEncoding = (wxFontEncoding) encoding;
806   config->Read(wxT("Style/Math/fontname"), &m_mathFontName);
807 #ifdef __WXOSX_MAC__
808   if (m_mathFontName.IsEmpty())
809   {
810     m_mathFontName = "Monaco";
811   }
812 #endif
813 
814   m_styles[TS_DEFAULT].Read(config, "Style/Default/");
815   m_styles[TS_TEXT].Read(config, "Style/Text/");
816   m_styles[TS_CODE_VARIABLE].Read(config, "Style/CodeHighlighting/Variable/");
817   m_styles[TS_CODE_FUNCTION].Read(config, "Style/CodeHighlighting/Function/");
818   m_styles[TS_CODE_COMMENT].Read(config, "Style/CodeHighlighting/Comment/");
819   m_styles[TS_CODE_NUMBER].Read(config, "Style/CodeHighlighting/Number/");
820   m_styles[TS_CODE_STRING].Read(config, "Style/CodeHighlighting/String/");
821   m_styles[TS_CODE_OPERATOR].Read(config, "Style/CodeHighlighting/Operator/");
822   m_styles[TS_CODE_LISP].Read(config, "Style/CodeHighlighting/Lisp/");
823   m_styles[TS_CODE_ENDOFLINE].Read(config, "Style/CodeHighlighting/EndOfLine/");
824   m_styles[TS_HEADING6].Read(config, "Style/Heading6/");
825   m_styles[TS_HEADING5].Read(config, "Style/Heading5/");
826   m_styles[TS_SUBSUBSECTION].Read(config, "Style/Subsubsection/");
827   m_styles[TS_SUBSECTION].Read(config, "Style/Subsection/");
828   m_styles[TS_SECTION].Read(config, "Style/Section/");
829   m_styles[TS_TITLE].Read(config, "Style/Title/");
830   m_styles[TS_WARNING].Read(config, "Style/Warning/");
831   m_styles[TS_MAIN_PROMPT].Read(config, "Style/MainPrompt/");
832   m_styles[TS_OTHER_PROMPT].Read(config, "Style/OtherPrompt/");
833   m_styles[TS_LABEL].Read(config, "Style/Label/");
834   m_styles[TS_USERLABEL].Read(config, "Style/UserDefinedLabel/");
835   m_styles[TS_SPECIAL_CONSTANT].Read(config, "Style/Special/");
836   m_styles[TS_GREEK_CONSTANT].Read(config, "Style/Greek/");
837   m_styles[TS_INPUT].Read(config, "Style/Input/");
838   m_styles[TS_NUMBER].Read(config, "Style/Number/");
839   m_styles[TS_STRING].Read(config, "Style/String/");
840   m_styles[TS_GREEK_CONSTANT].Read(config, "Style/Greek/");
841   m_styles[TS_VARIABLE].Read(config, "Style/Variable/");
842   m_styles[TS_FUNCTION].Read(config, "Style/Function/");
843   m_styles[TS_HIGHLIGHT].Read(config, "Style/Highlight/");
844   m_styles[TS_TEXT_BACKGROUND].Read(config, "Style/Background/");
845   m_styles[TS_DOCUMENT_BACKGROUND].Read(config, "Style/DocumentBackground/");
846   m_styles[TS_ERROR].Read(config, "Style/Error/");
847   m_styles[TS_CELL_BRACKET].Read(config, "Style/CellBracket/");
848   m_styles[TS_ACTIVE_CELL_BRACKET].Read(config,wxT("Style/ActiveCellBracket/"));
849   m_styles[TS_CURSOR].Read(config,wxT("Style/ActiveCellBracket/"));
850   m_styles[TS_SELECTION].Read(config,wxT("Style/Selection/"));
851   m_styles[TS_EQUALSSELECTION].Read(config,wxT("Style/EqualsSelection/"));
852   m_styles[TS_OUTDATED].Read(config,wxT("Style/Outdated/"));
853   m_BackgroundBrush = *wxTheBrushList->FindOrCreateBrush(m_styles[TS_DOCUMENT_BACKGROUND].GetColor(), wxBRUSHSTYLE_SOLID);
854 
855 }
856 
857 //! Saves the style settings to a file.
WriteStyles(wxString file)858 void Configuration::WriteStyles(wxString file)
859 {
860   wxConfigBase *config = NULL;
861   if (file == wxEmptyString)
862     config = wxConfig::Get();
863   else
864     config = new wxFileConfig(wxT("wxMaxima"), wxEmptyString, file);
865 
866   // Font
867   config->Write("Style/Default/Style/Text/fontname", m_fontName);
868   config->Write(wxT("mathfontsize"), m_mathFontSize);
869   config->Write(wxT("fontEncoding"), static_cast<int>(m_fontEncoding));
870   config->Write("Style/Math/fontname", m_mathFontName);
871 
872   m_styles[TS_DEFAULT].Write(config, "Style/Default/");
873   m_styles[TS_TEXT].Write(config, "Style/Text/");
874   m_styles[TS_CODE_VARIABLE].Write(config, "Style/CodeHighlighting/Variable/");
875   m_styles[TS_CODE_FUNCTION].Write(config, "Style/CodeHighlighting/Function/");
876   m_styles[TS_CODE_COMMENT].Write(config, "Style/CodeHighlighting/Comment/");
877   m_styles[TS_CODE_NUMBER].Write(config, "Style/CodeHighlighting/Number/");
878   m_styles[TS_CODE_STRING].Write(config, "Style/CodeHighlighting/String/");
879   m_styles[TS_CODE_OPERATOR].Write(config, "Style/CodeHighlighting/Operator/");
880   m_styles[TS_CODE_LISP].Write(config, "Style/CodeHighlighting/Lisp/");
881   m_styles[TS_CODE_ENDOFLINE].Write(config, "Style/CodeHighlighting/EndOfLine/");
882   m_styles[TS_HEADING6].Write(config, "Style/Heading6/");
883   m_styles[TS_HEADING5].Write(config, "Style/Heading5/");
884   m_styles[TS_SUBSUBSECTION].Write(config, "Style/Subsubsection/");
885   m_styles[TS_SUBSECTION].Write(config, "Style/Subsection/");
886   m_styles[TS_SECTION].Write(config, "Style/Section/");
887   m_styles[TS_TITLE].Write(config, "Style/Title/");
888   m_styles[TS_WARNING].Write(config, "Style/Warning/");
889   m_styles[TS_MAIN_PROMPT].Write(config, "Style/MainPrompt/");
890   m_styles[TS_OTHER_PROMPT].Write(config, "Style/OtherPrompt/");
891   m_styles[TS_LABEL].Write(config, "Style/Label/");
892   m_styles[TS_USERLABEL].Write(config, "Style/UserDefinedLabel/");
893   m_styles[TS_SPECIAL_CONSTANT].Write(config, "Style/Special/");
894   m_styles[TS_GREEK_CONSTANT].Write(config, "Style/Greek/");
895   m_styles[TS_INPUT].Write(config, "Style/Input/");
896   m_styles[TS_NUMBER].Write(config, "Style/Number/");
897   m_styles[TS_STRING].Write(config, "Style/String/");
898   m_styles[TS_GREEK_CONSTANT].Write(config, "Style/Greek/");
899   m_styles[TS_VARIABLE].Write(config, "Style/Variable/");
900   m_styles[TS_FUNCTION].Write(config, "Style/Function/");
901   m_styles[TS_HIGHLIGHT].Write(config, "Style/Highlight/");
902   m_styles[TS_TEXT_BACKGROUND].Write(config, "Style/Background/");
903   m_styles[TS_DOCUMENT_BACKGROUND].Write(config, "Style/DocumentBackground/");
904   m_styles[TS_ERROR].Write(config, "Style/Error/");
905   m_styles[TS_CELL_BRACKET].Write(config, "Style/CellBracket/");
906   m_styles[TS_ACTIVE_CELL_BRACKET].Write(config,wxT("Style/ActiveCellBracket/"));
907   m_styles[TS_CURSOR].Write(config,wxT("Style/ActiveCellBracket/"));
908   m_styles[TS_SELECTION].Write(config,wxT("Style/Selection/"));
909   m_styles[TS_EQUALSSELECTION].Write(config,wxT("Style/EqualsSelection/"));
910   m_styles[TS_OUTDATED].Write(config,wxT("Style/Outdated/"));
911   if(file != wxEmptyString)
912   {
913     config->Flush();
914     delete config;
915   }
916 }
917 
IsBold(long st) const918 wxFontWeight Configuration::IsBold(long st) const
919 {
920   if (m_styles[st].Bold())
921     return wxFONTWEIGHT_BOLD;
922   return wxFONTWEIGHT_NORMAL;
923 }
924 
IsItalic(long st) const925 wxFontStyle Configuration::IsItalic(long st) const
926 {
927   if (m_styles[st].Italic())
928     return wxFONTSTYLE_SLANT;
929   return wxFONTSTYLE_NORMAL;
930 }
931 
GetSymbolFontName() const932 wxString Configuration::GetSymbolFontName() const
933 {
934 #if defined __WXMSW__
935   return wxT("Symbol");
936 #else
937   return m_fontName;
938 #endif
939 }
940 
GetColor(TextStyle style)941 wxColour Configuration::GetColor(TextStyle style)
942 {
943   wxColour col = m_styles[style].GetColor();
944   if (m_outdated)
945     col = m_styles[TS_OUTDATED].Color();
946 
947   if(InvertBackground() &&
948      (style != TS_TEXT_BACKGROUND) &&
949      (style != TS_DOCUMENT_BACKGROUND))
950     col = MakeColorDifferFromBackground(col);
951     return col;
952 }
953 
Scale_Px(double px) const954 long Configuration::Scale_Px(double px) const
955 {
956   long retval = round(px * GetZoomFactor());
957   if (retval < 1)
958     retval = 1;
959   return retval;
960 }
961 
MakeColorDifferFromBackground(wxColor color)962 wxColor Configuration::MakeColorDifferFromBackground(wxColor color)
963 {
964   int newBrightness = 255 - (color.Red() + color.Green() + color.Blue()) / 3;
965   if(color == DefaultBackgroundColor())
966   {
967     return InvertColour(color);
968   }
969   else
970   {
971     int maxOldCol = wxMax(wxMax(color.Red(), color.Green()), color.Blue());
972     return wxColour(
973       newBrightness * color.Red() / maxOldCol,
974       newBrightness * color.Green() / maxOldCol,
975       newBrightness * color.Blue() / maxOldCol
976       );
977   }
978 }
979 
980 wxString Configuration::m_maximaLocation_override;
981 wxString Configuration::m_configfileLocation_override;
982