浏览代码

wxGUI: dark theme for Python shell and editor (#1220)

Anna Petrasova 4 年之前
父节点
当前提交
4b574682da

+ 4 - 2
gui/wxpython/gmodeler/frame.py

@@ -59,13 +59,13 @@ from gui_core.forms import GUI
 from gmodeler.preferences import PreferencesDialog, PropertiesDialog
 from gmodeler.toolbars import ModelerToolbar
 from core.giface import Notification
-from gui_core.pystc import PyStc
+from gui_core.pystc import PyStc, SetDarkMode
 from gmodeler.giface import GraphicalModelerGrassInterface
 from gmodeler.model import *
 from gmodeler.dialogs import *
 from gui_core.wrap import (
     Button, EmptyBitmap, ImageFromBitmap, Menu, NewId, StaticBox,
-    StaticText, StockCursor, TextCtrl,
+    StaticText, StockCursor, TextCtrl, IsDark
 )
 from gui_core.wrap import TextEntryDialog as wxTextEntryDialog
 
@@ -1987,6 +1987,8 @@ class PythonPanel(wx.Panel):
         self.bodyBox = StaticBox(parent=self, id=wx.ID_ANY,
                                  label=" %s " % _("Python script"))
         self.body = PyStc(parent=self, statusbar=self.parent.GetStatusBar())
+        if IsDark():
+            SetDarkMode(self.body)
 
         self.btnRun = Button(parent=self, id=wx.ID_ANY, label=_("&Run"))
         self.btnRun.SetToolTip(_("Run python script"))

+ 4 - 1
gui/wxpython/gui_core/pyedit.py

@@ -30,11 +30,12 @@ if __name__ == '__main__':
     set_gui_path()
 
 from core.gcmd import GError
-from gui_core.pystc import PyStc
+from gui_core.pystc import PyStc, SetDarkMode
 from core import globalvar
 from core.menutree import MenuTreeModelBuilder
 from gui_core.menu import RecentFilesMenu, Menu
 from gui_core.toolbars import BaseToolbar, BaseIcons
+from gui_core.wrap import IsDark
 from icons.icon import MetaIcon
 from core.debug import Debug
 
@@ -706,6 +707,8 @@ class PyEditFrame(wx.Frame):
             self.SetToolBar(self.toolbar)
 
         self.panel = PyStc(parent=self)
+        if IsDark():
+            SetDarkMode(self.panel)
         self.controller = PyEditController(
             panel=self.panel, guiparent=self, giface=giface)
 

+ 56 - 1
gui/wxpython/gui_core/pystc.py

@@ -6,12 +6,13 @@
 Classes:
  - pystc::PyStc
 
-(C) 2012-2013 by the GRASS Development Team
+(C) 2012-2020 by the GRASS Development Team
 
 This program is free software under the GNU General Public License
 (>=v2). Read the file COPYING that comes with GRASS for details.
 
 @author Martin Landa <landa.martin gmail.com>
+@author Anna Petrasova <kratochanna gmail.com> (dark theme)
 """
 
 
@@ -21,6 +22,60 @@ import wx
 from wx import stc
 
 
+def SetDarkMode(pystc):
+    """Configure color for dark mode. Adapted from Monokai theme in Spyder."""
+    dark = {
+        "background": "#282828",
+        "foreground": "#ddddda",
+        "line_foreground": "#C8C8C8",
+        "line_background": "#4D4D4D",
+        "comment": "#75715e",
+        "string": "#e6db74",
+        "keyword": "#f92672",
+        "definition": "#a6e22e",
+        "number": "#ae81ff",
+        "builtin": "#ae81ff",
+        "instance": "#ddddda",
+        "whitespace": "#969696",
+    }
+
+    # Default style
+    pystc.StyleSetSpec(
+        stc.STC_STYLE_DEFAULT,
+        "back:{b},fore:{f}".format(b=dark["background"], f=dark["foreground"]),
+    )
+
+    pystc.StyleClearAll()
+    pystc.SetSelForeground(
+        True, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)
+    )
+    pystc.SetSelBackground(True, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT))
+    pystc.SetCaretForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT))
+    pystc.SetWhitespaceForeground(True, wx.Colour(dark["whitespace"]))
+
+    # Built in styles
+    pystc.StyleSetSpec(
+        stc.STC_STYLE_LINENUMBER,
+        "fore:{f},back:{b}".format(
+            f=dark["line_foreground"], b=dark["line_background"]
+        ),
+    )
+    pystc.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
+    pystc.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
+
+    # Python styles
+    pystc.StyleSetSpec(stc.STC_P_DEFAULT, "fore:{}".format(dark["foreground"]))
+    pystc.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:{}".format(dark["comment"]))
+    pystc.StyleSetSpec(stc.STC_P_STRING, "fore:{}".format(dark["string"]))
+    pystc.StyleSetSpec(stc.STC_P_CHARACTER, "fore:{}".format(dark["string"]))
+    pystc.StyleSetSpec(stc.STC_P_WORD, "fore:{}".format(dark["keyword"]))
+    pystc.StyleSetSpec(stc.STC_P_TRIPLE, "fore:{}".format(dark["string"]))
+    pystc.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:{}".format(dark["string"]))
+    pystc.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:{}".format(dark["definition"]))
+    pystc.StyleSetSpec(stc.STC_P_DEFNAME, "fore:{}".format(dark["definition"]))
+    pystc.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:{}".format(dark["comment"]))
+
+
 class PyStc(stc.StyledTextCtrl):
     """Styled Python output (see gmodeler::frame::PythonPanel for
     usage)

+ 15 - 0
gui/wxpython/gui_core/wrap.py

@@ -55,6 +55,21 @@ else:
     from wx import NewId
 
 
+def IsDark():
+    """Detects if used theme is dark.
+    Wraps wx method for different versions."""
+    def luminance(c):
+        return (0.299 * c.Red() + 0.587 * c.Green() + 0.114 * c.Blue()) / 255
+
+    if hasattr(wx.SystemSettings, 'GetAppearance'):
+        return wx.SystemSettings.GetAppearance().IsDark()
+
+    # for older wx
+    bg = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)
+    fg = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
+    return luminance(fg) - luminance(bg) > 0.2
+
+
 def BitmapFromImage(image, depth=-1):
     if wxPythonPhoenix:
         return wx.Bitmap(img=image, depth=depth)

+ 5 - 1
gui/wxpython/lmgr/pyshell.py

@@ -23,13 +23,15 @@ from __future__ import print_function
 import sys
 
 import wx
+from wx import stc
 from wx.py.shell import Shell as PyShell
 from wx.py.version import VERSION
 
 import grass.script as grass
 from grass.script.utils import try_remove
 
-from gui_core.wrap import Button, ClearButton
+from gui_core.wrap import Button, ClearButton, IsDark
+from gui_core.pystc import SetDarkMode
 from core.globalvar import CheckWxVersion
 
 
@@ -56,6 +58,8 @@ class PyShellWindow(wx.Panel):
         if sys.platform == "darwin" and CheckWxVersion([4, 0, 2]):
             shellargs["useStockId"] = False
         self.shell = PyShell(**shellargs)
+        if IsDark():
+            SetDarkMode(self.shell)
 
         sys.displayhook = self._displayhook