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
31 def build_style_sheet(self
, app_palette
):
32 if self
.style_sheet
== EStylesheet
.CUSTOM
:
33 return self
.style_sheet_custom(app_palette
)
34 elif self
.style_sheet
== EStylesheet
.FLAT
:
35 return self
.style_sheet_flat()
37 return self
.style_sheet_default(app_palette
)
39 def build_palette(self
, app_palette
):
40 QPalette
= QtGui
.QPalette
41 palette_dark
= app_palette
.color(QPalette
.Base
).lightnessF() < 0.5
43 if palette_dark
and self
.is_dark
:
45 if not palette_dark
and not self
.is_dark
:
48 bg_color
= QtGui
.QColor('#202025')
50 bg_color
= QtGui
.QColor('#edeef3')
52 txt_color
= QtGui
.QColor('#777')
53 palette
= QPalette(bg_color
)
54 palette
.setColor(QPalette
.Base
, bg_color
)
55 palette
.setColor(QPalette
.Disabled
, QPalette
.Text
, txt_color
)
59 def style_sheet_default(palette
):
60 window
= palette
.color(QtGui
.QPalette
.Window
)
61 highlight
= palette
.color(QtGui
.QPalette
.Highlight
)
62 shadow
= palette
.color(QtGui
.QPalette
.Shadow
)
63 base
= palette
.color(QtGui
.QPalette
.Base
)
65 window_rgb
= qtutils
.rgb_css(window
)
66 highlight_rgb
= qtutils
.rgb_css(highlight
)
67 shadow_rgb
= qtutils
.rgb_css(shadow
)
68 base_rgb
= qtutils
.rgb_css(base
)
71 QCheckBox::indicator {
72 width: %(checkbox_size)spx;
73 height: %(checkbox_size)spx;
75 QCheckBox::indicator::unchecked {
76 border: %(checkbox_border)spx solid %(shadow_rgb)s;
77 background: %(base_rgb)s;
79 QCheckBox::indicator::checked {
80 image: url(%(checkbox_icon)s);
81 border: %(checkbox_border)spx solid %(shadow_rgb)s;
82 background: %(base_rgb)s;
85 QRadioButton::indicator {
86 width: %(radio_size)spx;
87 height: %(radio_size)spx;
89 QRadioButton::indicator::unchecked {
90 border: %(radio_border)spx solid %(shadow_rgb)s;
91 border-radius: %(radio_radius)spx;
92 background: %(base_rgb)s;
94 QRadioButton::indicator::checked {
95 image: url(%(radio_icon)s);
96 border: %(radio_border)spx solid %(shadow_rgb)s;
97 border-radius: %(radio_radius)spx;
98 background: %(base_rgb)s;
101 QSplitter::handle:hover {
102 background: %(highlight_rgb)s;
105 QMainWindow::separator {
106 background: %(window_rgb)s;
107 width: %(separator)spx;
108 height: %(separator)spx;
110 QMainWindow::separator:hover {
111 background: %(highlight_rgb)s;
115 separator
=defs
.separator
,
116 window_rgb
=window_rgb
,
117 highlight_rgb
=highlight_rgb
,
118 shadow_rgb
=shadow_rgb
,
120 checkbox_border
=defs
.border
,
121 checkbox_icon
=icons
.check_name(),
122 checkbox_size
=defs
.checkbox
,
123 radio_border
=defs
.radio_border
,
124 radio_icon
=icons
.dot_name(),
125 radio_radius
=defs
.radio
// 2,
126 radio_size
=defs
.radio
,
129 def style_sheet_flat(self
):
130 main_color
= self
.main_color
131 color
= QtGui
.QColor(main_color
)
132 color_rgb
= qtutils
.rgb_css(color
)
135 background
= '#2e2f30'
138 button_text
= '#000000'
139 field_text
= '#d0d0d0'
140 darker
= qtutils
.hsl_css(
141 color
.hslHueF(), color
.hslSaturationF() * 0.3, color
.lightnessF() * 1.3
143 lighter
= qtutils
.hsl_css(
144 color
.hslHueF(), color
.hslSaturationF() * 0.7, color
.lightnessF() * 0.6
146 focus
= qtutils
.hsl_css(
147 color
.hslHueF(), color
.hslSaturationF() * 0.7, color
.lightnessF() * 0.7
150 background
= '#edeef3'
153 button_text
= '#ffffff'
154 field_text
= '#000000'
155 darker
= qtutils
.hsl_css(
156 color
.hslHueF(), color
.hslSaturationF(), color
.lightnessF() * 0.4
158 lighter
= qtutils
.hsl_css(color
.hslHueF(), color
.hslSaturationF() * 2, 0.92)
162 /* regular widgets */
164 background-color: %(background)s;
165 color: %(field_text)s;
166 selection-background-color: %(lighter)s;
167 alternate-background-color: %(field)s;
168 selection-color: %(field_text)s;
169 show-decoration-selected: 1;
173 /* Focused widths get a thin border */
174 QTreeView:focus, QListView:focus,
175 QLineEdit:focus, QTextEdit:focus, QPlainTextEdit:focus {
178 border-color: %(focus)s;
182 border-color: %(grayed)s;
185 QDockWidget > QFrame {
186 margin: 0 2px 2px 2px;
189 QPlainTextEdit, QLineEdit, QTextEdit, QAbstractItemView,
191 background-color: %(field)s;
192 border-color: %(grayed)s;
196 QAbstractItemView::item:selected {
197 background-color: %(lighter)s;
199 QAbstractItemView::item:hover {
200 background-color: %(lighter)s;
204 background-color: transparent;
211 QPushButton[flat="false"] {
212 background-color: %(button)s;
213 color: %(button_text)s;
220 QPushButton[flat="true"], QToolButton {
221 background-color: transparent;
224 QPushButton[flat="true"] {
227 QPushButton:hover, QToolButton:hover {
228 background-color: %(darker)s;
230 QPushButton[flat="false"]:pressed, QToolButton:pressed {
231 background-color: %(darker)s;
232 margin: 1px 1px 2px 1px;
234 QPushButton:disabled {
235 background-color: %(grayed)s;
240 QPushButton[flat="true"]:disabled {
241 background-color: transparent;
246 background-color: %(background)s;
247 color: %(field_text)s;
252 background: transparent;
254 QMenuBar::item:selected {
255 background: %(button)s;
257 QMenuBar::item:pressed {
258 background: %(button)s;
261 background-color: %(field)s;
264 background: %(background)s;
270 background-color: %(field)s;
271 border-color: %(grayed)s;
273 color: %(field_text)s;
279 QComboBox::drop-down {
280 border-color: %(field_text)s %(field)s %(field)s %(field)s;
282 subcontrol-position: right;
283 border-width: 4px 3px 0 3px;
288 QComboBox::drop-down:hover {
289 border-color: %(button)s %(field)s %(field)s %(field)s;
292 background-color: %(button)s;
293 color: %(button_text)s;
297 QComboBox:item:selected {
298 background-color: %(darker)s;
299 color: %(button_text)s;
301 QComboBox:item:checked {
302 background-color: %(darker)s;
303 color: %(button_text)s;
306 /* MainWindow separator */
307 QMainWindow::separator {
308 width: %(separator)spx;
309 height: %(separator)spx;
311 QMainWindow::separator:hover {
312 background: %(focus)s;
317 background-color: %(field)s;
321 background: %(background)s
323 QScrollBar::handle:hover {
324 background: %(button)s
326 QScrollBar:horizontal {
327 margin: 0 11px 0 11px;
330 QScrollBar:vertical {
331 margin: 11px 0 11px 0;
334 QScrollBar::add-line, QScrollBar::sub-line {
335 background: %(background)s;
336 subcontrol-origin: margin;
338 QScrollBar::sub-line:horizontal { /*required by a buggy Qt version*/
339 subcontrol-position: left;
341 QScrollBar::add-line:hover, QScrollBar::sub-line:hover {
342 background: %(button)s;
344 QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
347 QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
350 QScrollBar:left-arrow, QScrollBar::right-arrow,
351 QScrollBar::up-arrow, QScrollBar::down-arrow {
356 QScrollBar:right-arrow {
357 border-color: %(background)s %(background)s
358 %(background)s %(darker)s;
359 border-width: 3px 0 3px 4px;
361 QScrollBar:left-arrow {
362 border-color: %(background)s %(darker)s
363 %(background)s %(background)s;
364 border-width: 3px 4px 3px 0;
366 QScrollBar:up-arrow {
367 border-color: %(background)s %(background)s
368 %(darker)s %(background)s;
369 border-width: 0 3px 4px 3px;
371 QScrollBar:down-arrow {
372 border-color: %(darker)s %(background)s
373 %(background)s %(background)s;
374 border-width: 4px 3px 0 3px;
376 QScrollBar:right-arrow:hover {
377 border-color: %(button)s %(button)s
378 %(button)s %(darker)s;
380 QScrollBar:left-arrow:hover {
381 border-color: %(button)s %(darker)s
382 %(button)s %(button)s;
384 QScrollBar:up-arrow:hover {
385 border-color: %(button)s %(button)s
386 %(darker)s %(button)s;
388 QScrollBar:down-arrow:hover {
389 border-color: %(darker)s %(button)s
390 %(button)s %(button)s;
393 /* tab bar (stacked & docked widgets) */
395 background: transparent;
396 border-color: %(darker)s;
401 QTabBar::tab:selected {
402 background: %(grayed)s;
409 background-color: transparent;
411 QCheckBox::indicator {
412 background-color: %(field)s;
413 border-color: %(darker)s;
415 subcontrol-position: left;
420 QCheckBox::indicator:unchecked:hover {
421 background-color: %(button)s;
423 QCheckBox::indicator:unchecked:pressed {
424 background-color: %(darker)s;
426 QCheckBox::indicator:checked {
427 background-color: %(darker)s;
429 QCheckBox::indicator:checked:hover {
430 background-color: %(button)s;
432 QCheckBox::indicator:checked:pressed {
433 background-color: %(field)s;
441 QRadioButton::indicator {
448 background-color: %(field)s;
449 border: 1px solid %(darker)s;
451 QProgressBar::chunk {
452 background-color: %(button)s;
457 QAbstractSpinBox::up-button, QAbstractSpinBox::down-button {
458 background-color: transparent;
460 QAbstractSpinBox::up-arrow, QAbstractSpinBox::down-arrow {
465 QAbstractSpinBox::up-arrow {
466 border-color: %(field)s %(field)s %(darker)s %(field)s;
467 border-width: 0 3px 4px 3px;
469 QAbstractSpinBox::up-arrow:hover {
470 border-color: %(field)s %(field)s %(button)s %(field)s;
471 border-width: 0 3px 4px 3px;
473 QAbstractSpinBox::down-arrow {
474 border-color: %(darker)s %(field)s %(field)s %(field)s;
475 border-width: 4px 3px 0 3px;
477 QAbstractSpinBox::down-arrow:hover {
478 border-color: %(button)s %(field)s %(field)s %(field)s;
479 border-width: 4px 3px 0 3px;
484 margin: 2px 2px 2px 2px;
489 color: %(field_text)s;
491 border-width: 0 0 1px 0;
492 border-color: %(grayed)s;
494 QHeaderView::section {
496 border-right: 1px solid %(grayed)s;
497 background-color: %(background)s;
498 color: %(field_text)s;
504 color: %(field_text)s;
506 border-width: 0 0 1px 0;
507 border-color: %(grayed)s;
509 QHeaderView::section {
511 border-right: 1px solid %(grayed)s;
512 background-color: %(background)s;
513 color: %(field_text)s;
518 background
=background
,
524 button_text
=button_text
,
525 field_text
=field_text
,
526 separator
=defs
.separator
,
530 def style_sheet_custom(self
, app_palette
):
531 """Get custom style sheet.
532 File name is saved in variable self.name.
533 If user has deleted file, use default style"""
535 # check if path exists
536 filename
= resources
.config_home('themes', self
.name
+ '.qss')
537 if not core
.exists(filename
):
538 return self
.style_sheet_default(app_palette
)
540 return core
.read(filename
)
541 except (IOError, OSError) as err
:
543 'warning: unable to read custom theme %s: %s' % (filename
, err
)
545 return self
.style_sheet_default(app_palette
)
548 def get_all_themes():
550 Theme('default', N_('Default'), False, EStylesheet
.DEFAULT
, None),
552 'flat-light-blue', N_('Flat light blue'), False, EStylesheet
.FLAT
, '#5271cc'
555 'flat-light-red', N_('Flat light red'), False, EStylesheet
.FLAT
, '#cc5452'
558 'flat-light-grey', N_('Flat light grey'), False, EStylesheet
.FLAT
, '#707478'
562 N_('Flat light green'),
568 'flat-dark-blue', N_('Flat dark blue'), True, EStylesheet
.FLAT
, '#5271cc'
570 Theme('flat-dark-red', N_('Flat dark red'), True, EStylesheet
.FLAT
, '#cc5452'),
572 'flat-dark-grey', N_('Flat dark grey'), True, EStylesheet
.FLAT
, '#aaaaaa'
575 'flat-dark-green', N_('Flat dark green'), True, EStylesheet
.FLAT
, '#42a65c'
579 # check if themes path exists in user folder
580 path
= resources
.config_home('themes')
581 if not os
.path
.isdir(path
):
584 # Gather Qt .qss stylesheet themes
586 filenames
= core
.listdir(path
)
590 for filename
in filenames
:
591 name
, ext
= os
.path
.splitext(filename
)
593 themes
.append(Theme(name
, N_(name
), False, EStylesheet
.CUSTOM
, None))
599 """Return a dictionary mapping display names to theme names"""
600 items
= get_all_themes()
601 return [(item
.hr_name
, item
.name
) for item
in items
]
604 def find_theme(name
):
605 themes
= get_all_themes()
607 if item
.name
== name
: