Skip to content

Commit

Permalink
Merge pull request #8020 from dalthviz/fixes_issue_2350
Browse files Browse the repository at this point in the history
PR: Initial support for Spyder's dark theme
  • Loading branch information
ccordoba12 authored Oct 15, 2018
2 parents 43598d7 + 974c2f4 commit bdb7543
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 172 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ a Python version greater than 2.7 or 3.4 (Python <=3.3 is no longer supported).
* **Cloudpickle**: Serialize variables in the IPython kernel to send to Spyder.
* **spyder-kernels** 1.0+: Jupyter kernels for the Spyder console.
* **keyring**: Save Github credentials to report errors securely.
* **QDarkStyle**: A dark stylesheet for Qt applications, used for Spyder's dark theme.
* **pexpect**/**paramiko**: Connect to remote kernels through SSH.

### Optional dependencies
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ environment:
sympy cython keyring
PIP_DEPENDENCIES: >
pytest-qt pytest-mock pytest-timeout flaky codecov
python-language-server[all]
python-language-server[all] qdarkstyle
APPVEYOR_RDP_PASSWORD: "dcca4c4863E30d56c2e0dda6327370b3#"

matrix:
Expand Down
2 changes: 1 addition & 1 deletion continuous_integration/posix/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ else
pytest pytest-cov numpydoc scipy cython pillow jedi pycodestyle sympy \
keyring pexpect"
export PIP_DEPENDENCIES="coveralls pytest-qt pytest-mock pytest-timeout flaky \
python-language-server[all]"
python-language-server[all] qdarkstyle"
fi


Expand Down
1 change: 1 addition & 0 deletions requirements/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ pyqt5
keyring
spyder-kernels>=1.0
python-language-server
qdarkstyle
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ def run(self):
'pyqt5<5.10;python_version>="3"',
# Pyls with all its dependencies
'python-language-server[all]',
'qdarkstyle',
# Required to get SSH connections to remote kernels
'pexpect;platform_system!="Windows"',
'paramiko;platform_system=="Windows"'
Expand Down
17 changes: 15 additions & 2 deletions spyder/app/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@
from spyder.utils.misc import select_port, getcwd_or_home, get_python_executable
from spyder.widgets.fileswitcher import FileSwitcher
from spyder.plugins.lspmanager import LSPManager


from spyder.config.gui import is_dark_font_color

#==============================================================================
# Local gui imports
Expand All @@ -188,6 +187,10 @@
from spyder.otherplugins import get_spyderplugins_mods
from spyder.app import tour

#==============================================================================
# Third-party library imports
#==============================================================================
import qdarkstyle

#==============================================================================
# Get the cwd before initializing WorkingDirectory, which sets it to the one
Expand Down Expand Up @@ -553,6 +556,16 @@ def create_toolbar(self, title, object_name, iconsize=24):
def setup(self):
"""Setup main window"""
self.debug_print("*** Start of MainWindow setup ***")
self.debug_print(" ..theme configuration")
ui_theme = CONF.get('color_schemes', 'ui_theme')
color_scheme = CONF.get('color_schemes', 'selected')
if ui_theme == 'dark':
self.setStyleSheet(qdarkstyle.load_stylesheet_from_environment())
elif ui_theme == 'automatic':
if not is_dark_font_color(color_scheme):
self.setStyleSheet(
qdarkstyle.load_stylesheet_from_environment())

self.debug_print(" ..core actions")
self.close_dockwidget_action = create_action(self,
icon=ima.icon('DialogCloseButton'),
Expand Down
9 changes: 9 additions & 0 deletions spyder/config/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
from spyder.py3compat import to_text_string
from spyder.utils import syntaxhighlighters as sh

# Third-party imports
from qtconsole.styles import dark_color

# To save metadata about widget shortcuts (needed to build our
# preferences page)
Expand Down Expand Up @@ -164,5 +166,12 @@ def set_default_color_scheme(name, replace=True):
set_color_scheme(name, sh.get_color_scheme(name), replace=replace)


def is_dark_font_color(color_scheme):
"""Check if the font color used in the color scheme is dark."""
color_scheme = get_color_scheme(color_scheme)
font_color, fon_fw, fon_fs = color_scheme['normal']
return dark_color(font_color)


for _name in sh.COLOR_SCHEME_NAMES:
set_default_color_scheme(_name, replace=False)
1 change: 1 addition & 0 deletions spyder/config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@
}),
('color_schemes',
{
'ui_theme': 'automatic',
'names': ['emacs', 'idle', 'monokai', 'pydev', 'scintilla',
'spyder', 'spyder/dark', 'zenburn', 'solarized/light',
'solarized/dark'],
Expand Down
77 changes: 60 additions & 17 deletions spyder/preferences/configdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from spyder.widgets.colors import ColorLayout
from spyder.widgets.comboboxes import FileComboBox
from spyder.plugins.editor.widgets.codeeditor import CodeEditor
from spyder.config.gui import is_dark_font_color


HDPI_QT_PAGE = "https://doc.qt.io/qt-5/highdpi.html"
Expand Down Expand Up @@ -911,7 +912,6 @@ def setup_page(self):
icons_combo = self.create_combobox(_('Icon theme'), icon_choices,
'icon_theme', restart=True)


vertdock_box = newcb(_("Vertical title bars in panes"),
'vertical_dockwidget_titlebars')
verttabs_box = newcb(_("Vertical tabs in panes"),
Expand Down Expand Up @@ -1166,23 +1166,32 @@ def setup_page(self):
# Widget setup
self.scheme_choices_dict = {}
about_label.setWordWrap(True)
schemes_combobox_widget = self.create_combobox(_('Scheme:'),
schemes_combobox_widget = self.create_combobox(_('Syntax scheme:'),
[('', '')],
'selected')
self.schemes_combobox = schemes_combobox_widget.combobox

# Layouts
vlayout = QVBoxLayout()
ui_themes = ['Automatic', 'Light', 'Dark']
ui_theme_choices = list(zip(ui_themes, [ui_theme.lower()
for ui_theme in ui_themes]))
ui_theme_combo = self.create_combobox(_('Interface theme:'),
ui_theme_choices,
'ui_theme',
restart=True)

# Layouts
manage_layout = QVBoxLayout()
manage_layout.addWidget(about_label)

combo_layout = QHBoxLayout()
combo_layout.addWidget(schemes_combobox_widget.label)
combo_layout.addWidget(schemes_combobox_widget.combobox)
comboboxes_layout = QGridLayout()
comboboxes_layout.addWidget(ui_theme_combo.label, 0, 0)
comboboxes_layout.addWidget(ui_theme_combo.combobox, 0, 1)

comboboxes_layout.addWidget(schemes_combobox_widget.label, 1, 0)
comboboxes_layout.addWidget(schemes_combobox_widget.combobox, 1, 1)

buttons_layout = QVBoxLayout()
buttons_layout.addLayout(combo_layout)
buttons_layout.addLayout(comboboxes_layout)
buttons_layout.addWidget(edit_button)
buttons_layout.addWidget(self.reset_button)
buttons_layout.addWidget(self.delete_button)
Expand All @@ -1200,6 +1209,7 @@ def setup_page(self):
manage_group = QGroupBox(_("Manage color schemes"))
manage_group.setLayout(manage_layout)

vlayout = QVBoxLayout()
vlayout.addWidget(manage_group)
self.setLayout(vlayout)

Expand All @@ -1223,15 +1233,46 @@ def setup_page(self):

def apply_settings(self, options):
self.set_option('selected', self.current_scheme)
self.main.editor.apply_plugin_settings(['color_scheme_name'])
if self.main.ipyconsole is not None:
self.main.ipyconsole.apply_plugin_settings(['color_scheme_name'])
if self.main.historylog is not None:
self.main.historylog.apply_plugin_settings(['color_scheme_name'])
if self.main.help is not None:
self.main.help.apply_plugin_settings(['color_scheme_name'])
self.update_combobox()
self.update_preview()
color_scheme = self.get_option('selected')
ui_theme = self.get_option('ui_theme')
style_sheet = self.main.styleSheet()
if ui_theme == 'automatic':
if ((not is_dark_font_color(color_scheme) and not style_sheet)
or (is_dark_font_color(color_scheme) and style_sheet)):
self.changed_options.add('ui_theme')
elif 'ui_theme' in self.changed_options:
self.changed_options.remove('ui_theme')

if 'ui_theme' not in self.changed_options:
self.main.editor.apply_plugin_settings(['color_scheme_name'])
if self.main.ipyconsole is not None:
self.main.ipyconsole.apply_plugin_settings(
['color_scheme_name'])
if self.main.historylog is not None:
self.main.historylog.apply_plugin_settings(
['color_scheme_name'])
if self.main.help is not None:
self.main.help.apply_plugin_settings(['color_scheme_name'])
self.update_combobox()
self.update_preview()
else:
if 'ui_theme' in self.changed_options:
if (style_sheet and ui_theme == 'dark' or
not style_sheet and ui_theme == 'light'):
self.changed_options.remove('ui_theme')

if 'ui_theme' not in self.changed_options:
self.main.editor.apply_plugin_settings(['color_scheme_name'])
if self.main.ipyconsole is not None:
self.main.ipyconsole.apply_plugin_settings(
['color_scheme_name'])
if self.main.historylog is not None:
self.main.historylog.apply_plugin_settings(
['color_scheme_name'])
if self.main.help is not None:
self.main.help.apply_plugin_settings(['color_scheme_name'])
self.update_combobox()
self.update_preview()

# Helpers
# -------------------------------------------------------------------------
Expand Down Expand Up @@ -1532,6 +1573,8 @@ def add_color_scheme_stack(self, scheme_name, custom=False):

if not custom:
line_edit.textbox.setDisabled(True)
if not self.isVisible():
line_edit.setVisible(False)

cs_layout = QVBoxLayout()
cs_layout.addLayout(name_layout)
Expand Down
Loading

0 comments on commit bdb7543

Please sign in to comment.