1 """Themes generators"""
2 from __future__
import absolute_import
, division
, print_function
, unicode_literals
8 from .widgets
import defs
12 from . import resources
15 class EStylesheet(object):
18 CUSTOM
= 3 # Files located in ~/.config/git-cola/themes/*.qss
23 self
, name
, hr_name
, is_dark
, style_sheet
=EStylesheet
.DEFAULT
, main_color
=None
26 self
.hr_name
= hr_name
27 self
.is_dark
= is_dark
28 self
.style_sheet
= style_sheet
29 self
.main_color
= main_color
30 self
.disabled_text_color
= None
31 self
.text_color
= None
32 self
.highlight_color
= None
34 def build_style_sheet(self
, app_palette
):
35 if self
.style_sheet
== EStylesheet
.CUSTOM
:
36 return self
.style_sheet_custom(app_palette
)
37 elif self
.style_sheet
== EStylesheet
.FLAT
:
38 return self
.style_sheet_flat()
40 return style_sheet_default(app_palette
)
42 def build_palette(self
, app_palette
):
43 QPalette
= QtGui
.QPalette
44 palette_dark
= app_palette
.color(QPalette
.Base
).lightnessF() < 0.5
46 if palette_dark
and self
.is_dark
:
48 if not palette_dark
and not self
.is_dark
:
51 bg_color
= QtGui
.QColor('#202025')
53 bg_color
= QtGui
.QColor('#edeef3')
55 txt_color
= QtGui
.QColor('#777')
56 palette
= QPalette(bg_color
)
57 palette
.setColor(QPalette
.Base
, bg_color
)
58 palette
.setColor(QPalette
.Disabled
, QPalette
.Text
, txt_color
)
61 def style_sheet_flat(self
):
62 main_color
= self
.main_color
63 color
= QtGui
.QColor(main_color
)
64 color_rgb
= qtutils
.rgb_css(color
)
67 background
= '#2e2f30'
70 button_text
= '#000000'
71 field_text
= '#d0d0d0'
72 darker
= qtutils
.hsl_css(
73 color
.hslHueF(), color
.hslSaturationF() * 0.3, color
.lightnessF() * 1.3
75 lighter
= qtutils
.hsl_css(
76 color
.hslHueF(), color
.hslSaturationF() * 0.7, color
.lightnessF() * 0.6
78 focus
= qtutils
.hsl_css(
79 color
.hslHueF(), color
.hslSaturationF() * 0.7, color
.lightnessF() * 0.7
82 background
= '#edeef3'
85 button_text
= '#ffffff'
86 field_text
= '#000000'
87 darker
= qtutils
.hsl_css(
88 color
.hslHueF(), color
.hslSaturationF(), color
.lightnessF() * 0.4
90 lighter
= qtutils
.hsl_css(color
.hslHueF(), color
.hslSaturationF() * 2, 0.92)
93 self
.disabled_text_color
= grayed
94 self
.text_color
= field_text
95 self
.highlight_color
= lighter
100 background-color: %(background)s;
101 color: %(field_text)s;
102 selection-background-color: %(lighter)s;
103 alternate-background-color: %(field)s;
104 selection-color: %(field_text)s;
105 show-decoration-selected: 1;
109 /* Focused widths get a thin border */
110 QTreeView:focus, QListView:focus,
111 QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {
114 border-color: %(focus)s;
118 border-color: %(grayed)s;
121 QDockWidget > QFrame {
122 margin: 0 2px 2px 2px;
125 QPlainTextEdit, QLineEdit, QTextEdit, QAbstractItemView,
127 background-color: %(field)s;
128 border-color: %(grayed)s;
132 QAbstractItemView::item:selected {
133 background-color: %(lighter)s;
135 QAbstractItemView::item:hover {
136 background-color: %(lighter)s;
140 background-color: transparent;
147 QPushButton[flat="false"] {
148 background-color: %(button)s;
149 color: %(button_text)s;
156 QPushButton[flat="true"], QToolButton {
157 background-color: transparent;
160 QPushButton[flat="true"] {
163 QPushButton:hover, QToolButton:hover {
164 background-color: %(darker)s;
166 QPushButton[flat="false"]:pressed, QToolButton:pressed {
167 background-color: %(darker)s;
168 margin: 1px 1px 2px 1px;
170 QPushButton:disabled {
171 background-color: %(grayed)s;
176 QPushButton[flat="true"]:disabled {
177 background-color: transparent;
182 background-color: %(background)s;
183 color: %(field_text)s;
188 background: transparent;
190 QMenuBar::item:selected {
191 background: %(button)s;
193 QMenuBar::item:pressed {
194 background: %(button)s;
197 background-color: %(field)s;
200 background: %(background)s;
206 background-color: %(field)s;
207 border-color: %(grayed)s;
209 color: %(field_text)s;
215 QComboBox::drop-down {
216 border-color: %(field_text)s %(field)s %(field)s %(field)s;
218 subcontrol-position: right;
219 border-width: 4px 3px 0 3px;
224 QComboBox::drop-down:hover {
225 border-color: %(button)s %(field)s %(field)s %(field)s;
228 background-color: %(button)s;
229 color: %(button_text)s;
233 QComboBox:item:selected {
234 background-color: %(darker)s;
235 color: %(button_text)s;
237 QComboBox:item:checked {
238 background-color: %(darker)s;
239 color: %(button_text)s;
242 /* MainWindow separator */
243 QMainWindow::separator {
244 width: %(separator)spx;
245 height: %(separator)spx;
247 QMainWindow::separator:hover {
248 background: %(focus)s;
253 background-color: %(field)s;
257 background: %(background)s
259 QScrollBar::handle:hover {
260 background: %(button)s
262 QScrollBar:horizontal {
263 margin: 0 11px 0 11px;
266 QScrollBar:vertical {
267 margin: 11px 0 11px 0;
270 QScrollBar::add-line, QScrollBar::sub-line {
271 background: %(background)s;
272 subcontrol-origin: margin;
274 QScrollBar::sub-line:horizontal { /*required by a buggy Qt version*/
275 subcontrol-position: left;
277 QScrollBar::add-line:hover, QScrollBar::sub-line:hover {
278 background: %(button)s;
280 QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
283 QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
286 QScrollBar:left-arrow, QScrollBar::right-arrow,
287 QScrollBar::up-arrow, QScrollBar::down-arrow {
292 QScrollBar:right-arrow {
293 border-color: %(background)s %(background)s
294 %(background)s %(darker)s;
295 border-width: 3px 0 3px 4px;
297 QScrollBar:left-arrow {
298 border-color: %(background)s %(darker)s
299 %(background)s %(background)s;
300 border-width: 3px 4px 3px 0;
302 QScrollBar:up-arrow {
303 border-color: %(background)s %(background)s
304 %(darker)s %(background)s;
305 border-width: 0 3px 4px 3px;
307 QScrollBar:down-arrow {
308 border-color: %(darker)s %(background)s
309 %(background)s %(background)s;
310 border-width: 4px 3px 0 3px;
312 QScrollBar:right-arrow:hover {
313 border-color: %(button)s %(button)s
314 %(button)s %(darker)s;
316 QScrollBar:left-arrow:hover {
317 border-color: %(button)s %(darker)s
318 %(button)s %(button)s;
320 QScrollBar:up-arrow:hover {
321 border-color: %(button)s %(button)s
322 %(darker)s %(button)s;
324 QScrollBar:down-arrow:hover {
325 border-color: %(darker)s %(button)s
326 %(button)s %(button)s;
329 /* tab bar (stacked & docked widgets) */
331 background: transparent;
332 border-color: %(darker)s;
337 QTabBar::tab:selected {
338 background: %(grayed)s;
345 background-color: transparent;
347 QCheckBox::indicator {
348 background-color: %(field)s;
349 border-color: %(darker)s;
351 subcontrol-position: left;
356 QCheckBox::indicator:unchecked:hover {
357 background-color: %(button)s;
359 QCheckBox::indicator:unchecked:pressed {
360 background-color: %(darker)s;
362 QCheckBox::indicator:checked {
363 background-color: %(darker)s;
365 QCheckBox::indicator:checked:hover {
366 background-color: %(button)s;
368 QCheckBox::indicator:checked:pressed {
369 background-color: %(field)s;
377 QRadioButton::indicator {
384 background-color: %(field)s;
385 border: 1px solid %(darker)s;
387 QProgressBar::chunk {
388 background-color: %(button)s;
393 QAbstractSpinBox::up-button, QAbstractSpinBox::down-button {
394 background-color: transparent;
396 QAbstractSpinBox::up-arrow, QAbstractSpinBox::down-arrow {
401 QAbstractSpinBox::up-arrow {
402 border-color: %(field)s %(field)s %(darker)s %(field)s;
403 border-width: 0 3px 4px 3px;
405 QAbstractSpinBox::up-arrow:hover {
406 border-color: %(field)s %(field)s %(button)s %(field)s;
407 border-width: 0 3px 4px 3px;
409 QAbstractSpinBox::down-arrow {
410 border-color: %(darker)s %(field)s %(field)s %(field)s;
411 border-width: 4px 3px 0 3px;
413 QAbstractSpinBox::down-arrow:hover {
414 border-color: %(button)s %(field)s %(field)s %(field)s;
415 border-width: 4px 3px 0 3px;
420 margin: 2px 2px 2px 2px;
425 color: %(field_text)s;
427 border-width: 0 0 1px 0;
428 border-color: %(grayed)s;
430 QHeaderView::section {
432 border-right: 1px solid %(grayed)s;
433 background-color: %(background)s;
434 color: %(field_text)s;
440 color: %(field_text)s;
442 border-width: 0 0 1px 0;
443 border-color: %(grayed)s;
445 QHeaderView::section {
447 border-right: 1px solid %(grayed)s;
448 background-color: %(background)s;
449 color: %(field_text)s;
454 background
=background
,
460 button_text
=button_text
,
461 field_text
=field_text
,
462 separator
=defs
.separator
,
466 def style_sheet_custom(self
, app_palette
):
467 """Get custom style sheet.
468 File name is saved in variable self.name.
469 If user has deleted file, use default style"""
471 # check if path exists
472 filename
= resources
.config_home('themes', self
.name
+ '.qss')
473 if not core
.exists(filename
):
474 return style_sheet_default(app_palette
)
476 return core
.read(filename
)
477 except (IOError, OSError) as err
:
479 'warning: unable to read custom theme %s: %s' % (filename
, err
)
481 return style_sheet_default(app_palette
)
484 def style_sheet_default(palette
):
485 window
= palette
.color(QtGui
.QPalette
.Window
)
486 highlight
= palette
.color(QtGui
.QPalette
.Highlight
)
487 shadow
= palette
.color(QtGui
.QPalette
.Shadow
)
488 base
= palette
.color(QtGui
.QPalette
.Base
)
490 window_rgb
= qtutils
.rgb_css(window
)
491 highlight_rgb
= qtutils
.rgb_css(highlight
)
492 shadow_rgb
= qtutils
.rgb_css(shadow
)
493 base_rgb
= qtutils
.rgb_css(base
)
496 QCheckBox::indicator {
497 width: %(checkbox_size)spx;
498 height: %(checkbox_size)spx;
500 QCheckBox::indicator::unchecked {
501 border: %(checkbox_border)spx solid %(shadow_rgb)s;
502 background: %(base_rgb)s;
504 QCheckBox::indicator::checked {
505 image: url(%(checkbox_icon)s);
506 border: %(checkbox_border)spx solid %(shadow_rgb)s;
507 background: %(base_rgb)s;
510 QRadioButton::indicator {
511 width: %(radio_size)spx;
512 height: %(radio_size)spx;
514 QRadioButton::indicator::unchecked {
515 border: %(radio_border)spx solid %(shadow_rgb)s;
516 border-radius: %(radio_radius)spx;
517 background: %(base_rgb)s;
519 QRadioButton::indicator::checked {
520 image: url(%(radio_icon)s);
521 border: %(radio_border)spx solid %(shadow_rgb)s;
522 border-radius: %(radio_radius)spx;
523 background: %(base_rgb)s;
526 QSplitter::handle:hover {
527 background: %(highlight_rgb)s;
530 QMainWindow::separator {
531 background: %(window_rgb)s;
532 width: %(separator)spx;
533 height: %(separator)spx;
535 QMainWindow::separator:hover {
536 background: %(highlight_rgb)s;
540 separator
=defs
.separator
,
541 window_rgb
=window_rgb
,
542 highlight_rgb
=highlight_rgb
,
543 shadow_rgb
=shadow_rgb
,
545 checkbox_border
=defs
.border
,
546 checkbox_icon
=icons
.check_name(),
547 checkbox_size
=defs
.checkbox
,
548 radio_border
=defs
.radio_border
,
549 radio_icon
=icons
.dot_name(),
550 radio_radius
=defs
.radio
// 2,
551 radio_size
=defs
.radio
,
555 def get_all_themes():
557 Theme('default', N_('Default'), False, EStylesheet
.DEFAULT
, None),
559 'flat-light-blue', N_('Flat light blue'), False, EStylesheet
.FLAT
, '#5271cc'
562 'flat-light-red', N_('Flat light red'), False, EStylesheet
.FLAT
, '#cc5452'
565 'flat-light-grey', N_('Flat light grey'), False, EStylesheet
.FLAT
, '#707478'
569 N_('Flat light green'),
575 'flat-dark-blue', N_('Flat dark blue'), True, EStylesheet
.FLAT
, '#5271cc'
577 Theme('flat-dark-red', N_('Flat dark red'), True, EStylesheet
.FLAT
, '#cc5452'),
579 'flat-dark-grey', N_('Flat dark grey'), True, EStylesheet
.FLAT
, '#aaaaaa'
582 'flat-dark-green', N_('Flat dark green'), True, EStylesheet
.FLAT
, '#42a65c'
586 # check if themes path exists in user folder
587 path
= resources
.config_home('themes')
588 if not os
.path
.isdir(path
):
591 # Gather Qt .qss stylesheet themes
593 filenames
= core
.listdir(path
)
597 for filename
in filenames
:
598 name
, ext
= os
.path
.splitext(filename
)
600 themes
.append(Theme(name
, N_(name
), False, EStylesheet
.CUSTOM
, None))
606 """Return a dictionary mapping display names to theme names"""
607 items
= get_all_themes()
608 return [(item
.hr_name
, item
.name
) for item
in items
]
611 def find_theme(name
):
612 themes
= get_all_themes()
614 if item
.name
== name
: