From e7359c5776b6b10ac3b1fbafe8c70646294c744a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Silva?= Date: Tue, 26 Mar 2019 14:18:19 +0000 Subject: [PATCH] Encapsulate theme handling The Theme class encapsulates theme handling, by listing default themes and providing means to access their gtk/web css. Besides cleaning things up, it makes it easy to support custom themes in the future. The user just needs to provide two CSS files, and we'll be able to instantiate and use a Theme from that. --- data/media/adwaita_style.css | 4 - data/media/arc_style.css | 4 - data/media/{style.css => css/_gtk_base.css} | 79 +++++------------ .../{github-md.css => css/_web_base.css} | 39 ++++---- data/media/css/gtk_adwaita.css | 5 ++ data/media/css/gtk_adwaita_dark.css | 5 ++ data/media/css/web_adwaita.css | 19 ++++ .../web_adwaita_dark.css} | 14 ++- data/media/uberwriter.css | Bin 2432 -> 0 bytes data/media/uberwriter_dark.css | Bin 2486 -> 0 bytes uberwriter/Theme.py | 49 +++++++++++ uberwriter/UberwriterExportDialog.py | 5 +- uberwriter/UberwriterWindow.py | 83 +++++++----------- uberwriter_lib/helpers.py | 31 ++++--- 14 files changed, 175 insertions(+), 162 deletions(-) delete mode 100644 data/media/adwaita_style.css delete mode 100644 data/media/arc_style.css rename data/media/{style.css => css/_gtk_base.css} (73%) rename data/media/{github-md.css => css/_web_base.css} (86%) create mode 100644 data/media/css/gtk_adwaita.css create mode 100644 data/media/css/gtk_adwaita_dark.css create mode 100644 data/media/css/web_adwaita.css rename data/media/{github-md-dark.css => css/web_adwaita_dark.css} (62%) delete mode 100644 data/media/uberwriter.css delete mode 100644 data/media/uberwriter_dark.css create mode 100644 uberwriter/Theme.py diff --git a/data/media/adwaita_style.css b/data/media/adwaita_style.css deleted file mode 100644 index 6e1b8ed..0000000 --- a/data/media/adwaita_style.css +++ /dev/null @@ -1,4 +0,0 @@ -@define-color dark_bg #353535; -@define-color light_bg #F6F5F4; - -@import url("style.css"); diff --git a/data/media/arc_style.css b/data/media/arc_style.css deleted file mode 100644 index 0fce002..0000000 --- a/data/media/arc_style.css +++ /dev/null @@ -1,4 +0,0 @@ -@define-color dark_bg #31373D; -@define-color light_bg #EDEDED; - -@import url("style.css"); diff --git a/data/media/style.css b/data/media/css/_gtk_base.css similarity index 73% rename from data/media/style.css rename to data/media/css/_gtk_base.css index 43aea46..399e8c2 100644 --- a/data/media/style.css +++ b/data/media/css/_gtk_base.css @@ -27,19 +27,8 @@ .uberwriter_window { -gtk-key-bindings: window-bindings; /*border-radius: 7px 7px 3px 3px;*/ - background: @light_bg; - caret-color: @dark_bg; -} - -.uberwriter_window.dark_mode { - background: @dark_bg; - caret-color: @light_bg; -} - -.uberwriter_window.dark_mode .uberwriter-editor text{ - background: @dark_bg; - caret-color: @light_bg; - color: @light_bg; + background: @background_color; + caret-color: @foreground_color; } .uberwriter_window.small .uberwriter-editor { @@ -47,12 +36,7 @@ font-size: 12px; } .uberwriter_window grid { - background-color: @light_bg; -} - -.uberwriter_window.dark_mode grid, -.uberwriter_window.dark_mode scrolledwindow { - background-color: @dark_bg; + background-color: @background_color; } #UberwriterWindow.medium .uberwriter-editor { @@ -75,25 +59,22 @@ } #titlebar_container { - background: @light_bg; -} - -#titlebar_container.dark_mode { - background: @dark_bg; + background: @background_color; } .uberwriter-editor { border: none; background-color: transparent; - color: #222; + text-decoration-color: #ff0000; /*-GtkWidget-cursor-color: shade(#4D9FCE, 0.9);*/ /*-GtkWidget-cursor-aspect-ratio: 0.1;*/ -gtk-key-bindings: editor-bindings; } .uberwriter-editor text { - background-color: @light_bg; - color: #222; + background-color: @background_color; + color: @foreground_color; + caret-color: @foreground_color; } .uberwriter-editor:selected { @@ -120,7 +101,7 @@ .status_bar_box button { /* finding reset */ - background-color: @light_bg; + background-color: @background_color; text-shadow: inherit; /*icon-shadow: inherit;*/ box-shadow: initial; @@ -146,13 +127,13 @@ .status_bar_box button:hover, .status_bar_box button:checked { transition: 0s ease-in; - color: @light_bg; + color: @background_color; background-color: #666; } .status_bar_box button:hover label, .status_bar_box button:checked label { - color: @light_bg; + color: @background_color; } .status_bar_box button:active { @@ -161,22 +142,7 @@ background-image: none; box-shadow: 0 0 2px rgba(0,0,0,0.4) } -.dark_mode .status_bar_box button { - background-color: @dark_bg; -} -.dark_mode .status_bar_box label { - color: @light_bg; -} -.dark_mode .status_bar_box button:hover, -.dark_mode .status_bar_box button:checked { - background-color: @light_bg; - color: #666; -} -.dark_mode .status_bar_box button:hover label, -.dark_mode .status_bar_box button:checked label{ - color: #666; -} .status_bar_box separator { border-color: #999; border-right: none; @@ -198,9 +164,9 @@ /*font: serif 10;*/ font-family: serif; font-size: 10px; - background: @light_bg; + background: @background_color; border-radius: 4px; - border-color: @light_bg; + border-color: @background_color; margin: 5px; padding: 5px; } @@ -211,7 +177,7 @@ border: 1px solid #333; background: @ligth_bg; border-radius: 3px; - border-color: @light_bg; + border-color: @background_color; } */ #LexikonBubble label { @@ -219,9 +185,8 @@ } #LexikonBubble { - background-color: @light_bg; - border: 5px solid @light_bg; - border-color: @light_bg + background-color: @background_color; + border: 5px solid @background_color; } #LexikonBubble .lexikon_heading { @@ -240,15 +205,15 @@ } .QuickPreviewPopup { - background-color: @light_bg; + background-color: @background_color; } .QuickPreviewPopup grid { - background-color: @light_bg; - color: @dark_bg; - border-color: @light_bg; + background-color: @background_color; + color: @foreground_color; + border-color: @background_color; } .QuickPreviewPopup label { - color: @dark_bg; -} + color: @foreground_color; +} \ No newline at end of file diff --git a/data/media/github-md.css b/data/media/css/_web_base.css similarity index 86% rename from data/media/github-md.css rename to data/media/css/_web_base.css index 4fa2463..3dd9ecc 100644 --- a/data/media/github-md.css +++ b/data/media/css/_web_base.css @@ -1,11 +1,11 @@ @font-face { font-family: fira-sans; - src: url("fonts/fira-sans-v9-vietnamese_latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2") format("woff2"); + src: url("../fonts/fira-sans-v9-vietnamese_latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2") format("woff2"); } @font-face { font-family: fira-mono; - src: url("fonts/fira-mono-v7-latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2") format("woff2"); + src: url("../fonts/fira-mono-v7-latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2") format("woff2"); } @font-face { @@ -14,22 +14,21 @@ } :root { - --text-color: #242424; - --background-color: #f6f5f4; - --alt-background-color: #ebebeb; + /* This is GitHub's default color scheme, which should be overridden per theme. */ + --text-color: #24292e; + --background-color: #ffffff; + --alt-background-color: #f6f8fa; --link-color: #0366d6; - --blockquote-text-color: #606060; - --blockquote-border-color: #d8d8d8; - --header-border-color: #e2e2e2; - --hr-background-color: #dadada; - --hr-border-color: #e4e4e4; - --code-background-color: #eeeeee; - --table-td-border-color: #d8d8d8; - --table-tr-border-color: #c1c1c1; - --kbd-text-color: #444444; - --kbd-background-color: #f2f2f2; - --kbd-border-color: #c1c1c1; - --kbd-shadow-color: #939393; + --blockquote-text-color: #6a737d; + --blockquote-border-color: #dfe2e5; + --header-border-color: #eaecef; + --hr-background-color: #e1e4e8; + --table-tr-border-color: #c6cbd1; + --table-td-border-color: #dfe2e5; + --kbd-text-color: #444d56; + --kbd-background-color: #fafbfc; + --kbd-border-color: #c6cbd1; + --kbd-shadow-color: #959da5; } * { @@ -55,7 +54,7 @@ html { body { color: var(--text-color); background-color: var(--background-color); - font-family: fira-sans, sans-serif, color-emoji; + font-family: "Fira Sans", fira-sans, sans-serif, color-emoji; line-height: 1.5; text-size-adjust: 100%; word-wrap: break-word; @@ -93,7 +92,6 @@ hr { overflow: hidden; background-color: var(--hr-background-color); border: 0; - border-bottom: 1px solid var(--hr-border-color); } hr::before { @@ -199,8 +197,7 @@ dd { code, kbd, pre { - font-family: fira-mono, monospace, color-emoji; - background-color: var(--code-background-color); + font-family: "Fira Mono", fira-mono, monospace, color-emoji; font-size: 1em; word-wrap: normal; } diff --git a/data/media/css/gtk_adwaita.css b/data/media/css/gtk_adwaita.css new file mode 100644 index 0000000..f75dcde --- /dev/null +++ b/data/media/css/gtk_adwaita.css @@ -0,0 +1,5 @@ +@define-color foreground_color #2e3436; +@define-color background_color #f6f5f4; +@define-color math_text_color #00364c; + +@import url("_gtk_base.css"); diff --git a/data/media/css/gtk_adwaita_dark.css b/data/media/css/gtk_adwaita_dark.css new file mode 100644 index 0000000..a41d20c --- /dev/null +++ b/data/media/css/gtk_adwaita_dark.css @@ -0,0 +1,5 @@ +@define-color foreground_color #eeeeec; +@define-color background_color #353535; +@define-color math_text_color #ffc9b3; + +@import url("_gtk_base.css"); diff --git a/data/media/css/web_adwaita.css b/data/media/css/web_adwaita.css new file mode 100644 index 0000000..ecfde17 --- /dev/null +++ b/data/media/css/web_adwaita.css @@ -0,0 +1,19 @@ +@import url("_web_base.css"); + +:root { + --text-color: #2e3436; + --background-color: #f6f5f4; + --alt-background-color: #edeeef; + --link-color: #0d71de; + --blockquote-text-color: #747e85; + --blockquote-border-color: #d6d8da; + --header-border-color: #e1e2e4; + --hr-background-color: #d8dadd; + --table-tr-border-color: #bdc1c6; + --table-td-border-color: #d6d8da; + --kbd-text-color: #4e585e; + --kbd-background-color: #f1f1f1; + --kbd-border-color: #bdc1c6; + --kbd-shadow-color: #8c939a; + +} \ No newline at end of file diff --git a/data/media/github-md-dark.css b/data/media/css/web_adwaita_dark.css similarity index 62% rename from data/media/github-md-dark.css rename to data/media/css/web_adwaita_dark.css index 928f3ca..320a657 100644 --- a/data/media/github-md-dark.css +++ b/data/media/css/web_adwaita_dark.css @@ -1,19 +1,17 @@ -@import url("github-md.css"); +@import url("_web_base.css"); :root { - --text-color: #dbdbdb; + --text-color: #eeeeec; --background-color: #353535; --alt-background-color: #3a3a3a; - --link-color: #4388d6; - --blockquote-text-color: #959595; + --link-color: #b5daff; + --blockquote-text-color: #a8a8a6; --blockquote-border-color: #525252; --header-border-color: #474747; --hr-background-color: #505050; - --hr-border-color: #464646; - --code-background-color: #3e3e3e; - --table-td-border-color: #525252; --table-tr-border-color: #696969; - --kbd-text-color: #bbbbbb; + --table-td-border-color: #525252; + --kbd-text-color: #cececc; --kbd-background-color: #3c3c3c; --kbd-border-color: #696969; --kbd-shadow-color: #979797; diff --git a/data/media/uberwriter.css b/data/media/uberwriter.css deleted file mode 100644 index 7cb0bd65a0550c89bda0c26f8a5fc8ed0c35b64c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2432 zcmcIm+iu!G5S>@@6_%nZQWTSfTch+TQd{-C{Q)o+TLt1`D50po-u9dsFWxl{$wR7@ zypUCOmu8^Qk=kwvmU z#IuCI7~Y1+DMQRVxrh7$nKHkb#<_zulCPR;0ofH+-xP%ja^=m#z-mJ%Xo1zN_~~ph1LV{1Wc?Bp<~++!vLDC|g!r_{(4=MUM2+ zlN$_QcMJI#(p2Sr=|i4_5npG4XjZV2!78oX;29#SHT+QTHy(}@`4Nj$I_2Cg=UzGY z%Xt8;J$AH!MrAuzi}?{!RX+cZr8-iB15%b9b8C*7HMQ2r7q!S8E+gfceEtAx)Mn)~ zf5#YYtiS_nDAu~0LW@}Ul?~PxxhGewm4ObQqZ~MnG04%ZW~1{0r=dq*+cLQ#W_)!9JLr+lp?eIWGv$~av;o(r^5@CqD&#o-Q?+oceave!U!hMQ z8K=*FCV$4E*=5x-BU>@AJyuoahrIeex*oG;v5lVKokT4|r+$9axvsLMg?4#rrNDWm zQMJ)AL$4q0hHAbMzQF5Te&Wq266|AM53rQs+p;Y1wM4JRuf7j@hw5!<_ZC>sVa0AC z_E*(q)j2}+TSxc7d*Luyh-)2}CT#6QH*D^4_6)Vccp^EhdH)cbiN4t<7kIAlrcXn7 z3N&V@U%TD+8YfSs*XKn${C_b!_+>6nz%=YYJE2|gn|HF3D?g0X#qIuM#E=rr8Dxw; WDKlY?hFa6TOU-lnj1$*AF57>3-(-~l diff --git a/data/media/uberwriter_dark.css b/data/media/uberwriter_dark.css deleted file mode 100644 index bae9e17125421729cd4c8e19447e5449e3de8b4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2486 zcmcIm%Wm5+5ZtT%6#{}HKoB{JUrp0ffTrlZ{Q+BkNT{u-mR-j+`s;0HmZC&TijzYM zLZawh?qg<`^xr>Ma`8r^D;?pplc~&QBYQlFZ1uY*k>nVZ-%Eh6MAnkY3erF(lFAHo zq-(CIv6X|abBUof$C|qr@(8;D_UO%qA-lxto1!pBu3Y8NC1MNtShGyDenCpB zH<;IjMub>aiU%cU@*tne$Jm&{UnJi(hDTsRoJ0KL?;8jQcLc>C$|kEl{3X~QBS(4} z$~A_oyN7%RX{_>*j3Cdzh^wH&ubuDs>%T#$LlRtnOwORSh z-!euU8}Psy3bpPQ&?43&WrOua*2xuXWvs*HC#F7~+B_v(gr3{Wiau4ZA*$`957_ ztUmjh{2307T~;kKGArhF#Hy-%pI6t%z+u){?4c)kCsE6wQ$IiITvyrBLa#WrV&J^d zsCwv_iPMkfhHAeNzQF5Be&Wq2BJ5*c_pp@U+hm#JD@Ct{uf7k4W%YKndvmN;uwrf@ z_E*(q)j2}+JB^#*y>J+rk82&5Hf+s_Zm_w-*)!1!. # END LICENSE -import locale -import subprocess -import os import codecs -import webbrowser -import urllib +import locale import logging - import mimetypes +import os import re - +import subprocess +import urllib +import webbrowser from gettext import gettext as _ import gi +from gi.repository.GObject import param_spec_string + +from uberwriter.Theme import Theme + gi.require_version('Gtk', '3.0') gi.require_version('WebKit2', '4.0') # pylint: disable=wrong-import-position from gi.repository import Gtk, Gdk, GObject, GLib, Gio @@ -181,21 +183,13 @@ class UberwriterWindow(Gtk.ApplicationWindow): # Init file name with None self.set_filename() - # self.style_provider = Gtk.CssProvider() - # self.style_provider.load_from_path(helpers.get_media_path('arc_style.css')) - - # Gtk.StyleContext.add_provider_for_screen( - # Gdk.Screen.get_default(), self.style_provider, - # Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - # ) - # Markup and Shortcuts for the TextBuffer self.markup_buffer = MarkupBuffer( self, self.text_buffer, base_leftmargin) self.markup_buffer.markup_buffer() - # Setup dark mode if so - self.toggle_dark_mode(self.settings.get_value("dark-mode")) + # Set current theme + self.apply_current_theme() # Scrolling -> Dark or not? self.textchange = False @@ -266,6 +260,22 @@ class UberwriterWindow(Gtk.ApplicationWindow): 'close-window': (GObject.SIGNAL_ACTION, None, ()) } + def apply_current_theme(self): + """Adjusts both the window and the CSD for the current theme. + """ + + theme = Theme.get_current() + if theme.is_dark: + self.markup_buffer.dark_mode(True) + else: + self.markup_buffer.dark_mode(False) + + # Reload preview if it exists, otherwise redraw contents of window (self) + if self.preview_webview: + self.show_preview() + else: + self.queue_draw() + def scrolled(self, widget): """if window scrolled + focusmode make font black again""" # if self.focusmode: @@ -387,7 +397,7 @@ class UberwriterWindow(Gtk.ApplicationWindow): else: self.remove_typewriter() self.focusmode = False - self.text_buffer.remove_tag(self.markup_buffer.grayfont, + self.text_buffer.remove_tag(self.markup_buffer.unfocused_text, self.text_buffer.get_start_iter(), self.text_buffer.get_end_iter()) self.text_buffer.remove_tag(self.markup_buffer.blackfont, @@ -865,20 +875,13 @@ class UberwriterWindow(Gtk.ApplicationWindow): base_path = '' os.environ['PANDOC_PREFIX'] = base_path + '/' - # Set the styles according the color theme - if self.settings.get_value("dark-mode"): - stylesheet = helpers.get_media_path('github-md-dark.css') - else: - stylesheet = helpers.get_media_path('github-md.css') - args = ['pandoc', '-s', '--from=markdown', '--to=html5', '--mathjax', - '--css=' + stylesheet, - '--lua-filter=' + - helpers.get_script_path('relative_to_absolute.lua'), + '--css=' + Theme.get_current().web_css_path, + '--lua-filter=' + helpers.get_script_path('relative_to_absolute.lua'), '--lua-filter=' + helpers.get_script_path('task-list.lua')] proc = subprocess.Popen( @@ -906,32 +909,6 @@ class UberwriterWindow(Gtk.ApplicationWindow): self.preview_webview.load_html(output.decode("utf-8"), 'file://localhost/') - def toggle_dark_mode(self, state): - """Toggle the dark mode, both for the window and for the CSD - - Arguments: - state {gtk bool} -- Desired state of the dark mode (enabled/disabled) - """ - - # Save state for saving settings later - if state: - # Dark Mode is on - self.get_style_context().add_class("dark_mode") - self.headerbar.hb_container.get_style_context().add_class("dark_mode") - self.markup_buffer.dark_mode(True) - else: - # Dark mode off - self.get_style_context().remove_class("dark_mode") - self.headerbar.hb_container.get_style_context().remove_class("dark_mode") - self.markup_buffer.dark_mode(False) - - # Reload preview if it exists - if self.preview_webview: - self.show_preview() - - # Redraw contents of window (self) - self.queue_draw() - def load_file(self, filename=None): """Open File from command line or open / open recent etc.""" if self.check_change() == Gtk.ResponseType.CANCEL: diff --git a/uberwriter_lib/helpers.py b/uberwriter_lib/helpers.py index f46bf52..ec682ee 100644 --- a/uberwriter_lib/helpers.py +++ b/uberwriter_lib/helpers.py @@ -49,16 +49,12 @@ def get_builder(builder_file_name): # Owais Lone : To get quick access to icons and stuff. -def get_media_file(media_file_name): +def get_media_file(media_file_path): """Return the full path of a given filename under the media dir (starts with file:///) """ - media_filename = get_data_file('media', '%s' % (media_file_name,)) - if not os.path.exists(media_filename): - media_filename = None - - return "file:///" + media_filename + return "file:///" + get_media_path(media_file_path) def get_media_path(media_file_name): @@ -66,19 +62,26 @@ def get_media_path(media_file_name): (doesn't start with file:///) """ - media_filename = get_data_file('media', '%s' % (media_file_name,)) - if not os.path.exists(media_filename): - media_filename = None - return media_filename + media_path = get_data_file('media', '%s' % (media_file_name,)) + if not os.path.exists(media_path): + media_path = None + return media_path + + +def get_css_path(css_file_name): + """Return the full path of a given filename under the css dir + (doesn't start with file:///) + """ + return get_media_path("css/{}".format(css_file_name)) def get_script_path(script_file_name): """Return the full path of a given filename under the script dir """ - script_filename = get_data_file('lua', '%s' % (script_file_name,)) - if not os.path.exists(script_filename): - script_filename = None - return script_filename + script_path = get_data_file('lua', '%s' % (script_file_name,)) + if not os.path.exists(script_path): + script_path = None + return script_path class NullHandler(logging.Handler):