瀏覽代碼

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.preferences import PreferencesDialog, PropertiesDialog
 from gmodeler.toolbars import ModelerToolbar
 from gmodeler.toolbars import ModelerToolbar
 from core.giface import Notification
 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.giface import GraphicalModelerGrassInterface
 from gmodeler.model import *
 from gmodeler.model import *
 from gmodeler.dialogs import *
 from gmodeler.dialogs import *
 from gui_core.wrap import (
 from gui_core.wrap import (
     Button, EmptyBitmap, ImageFromBitmap, Menu, NewId, StaticBox,
     Button, EmptyBitmap, ImageFromBitmap, Menu, NewId, StaticBox,
-    StaticText, StockCursor, TextCtrl,
+    StaticText, StockCursor, TextCtrl, IsDark
 )
 )
 from gui_core.wrap import TextEntryDialog as wxTextEntryDialog
 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,
         self.bodyBox = StaticBox(parent=self, id=wx.ID_ANY,
                                  label=" %s " % _("Python script"))
                                  label=" %s " % _("Python script"))
         self.body = PyStc(parent=self, statusbar=self.parent.GetStatusBar())
         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 = Button(parent=self, id=wx.ID_ANY, label=_("&Run"))
         self.btnRun.SetToolTip(_("Run python script"))
         self.btnRun.SetToolTip(_("Run python script"))

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

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

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

@@ -6,12 +6,13 @@
 Classes:
 Classes:
  - pystc::PyStc
  - 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
 This program is free software under the GNU General Public License
 (>=v2). Read the file COPYING that comes with GRASS for details.
 (>=v2). Read the file COPYING that comes with GRASS for details.
 
 
 @author Martin Landa <landa.martin gmail.com>
 @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
 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):
 class PyStc(stc.StyledTextCtrl):
     """Styled Python output (see gmodeler::frame::PythonPanel for
     """Styled Python output (see gmodeler::frame::PythonPanel for
     usage)
     usage)

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

@@ -55,6 +55,21 @@ else:
     from wx import NewId
     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):
 def BitmapFromImage(image, depth=-1):
     if wxPythonPhoenix:
     if wxPythonPhoenix:
         return wx.Bitmap(img=image, depth=depth)
         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 sys
 
 
 import wx
 import wx
+from wx import stc
 from wx.py.shell import Shell as PyShell
 from wx.py.shell import Shell as PyShell
 from wx.py.version import VERSION
 from wx.py.version import VERSION
 
 
 import grass.script as grass
 import grass.script as grass
 from grass.script.utils import try_remove
 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
 from core.globalvar import CheckWxVersion
 
 
 
 
@@ -56,6 +58,8 @@ class PyShellWindow(wx.Panel):
         if sys.platform == "darwin" and CheckWxVersion([4, 0, 2]):
         if sys.platform == "darwin" and CheckWxVersion([4, 0, 2]):
             shellargs["useStockId"] = False
             shellargs["useStockId"] = False
         self.shell = PyShell(**shellargs)
         self.shell = PyShell(**shellargs)
+        if IsDark():
+            SetDarkMode(self.shell)
 
 
         sys.displayhook = self._displayhook
         sys.displayhook = self._displayhook