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 7cb0bd6..0000000 Binary files a/data/media/uberwriter.css and /dev/null differ diff --git a/data/media/uberwriter_dark.css b/data/media/uberwriter_dark.css deleted file mode 100644 index bae9e17..0000000 Binary files a/data/media/uberwriter_dark.css and /dev/null differ diff --git a/uberwriter/Theme.py b/uberwriter/Theme.py new file mode 100644 index 0000000..f0c87d1 --- /dev/null +++ b/uberwriter/Theme.py @@ -0,0 +1,49 @@ +from gi.repository import Gtk + +from uberwriter.Settings import Settings +from uberwriter_lib.helpers import get_css_path + + +class Theme: + """ + The Theme enum lists all supported themes using their "gtk-theme-name" value. + + The light variant is listed first, followed by the dark variant, if any. + """ + + settings = Settings.new() + + def __init__(self, name, gtk_css_path, web_css_path, is_dark, inverse_name): + self.name = name + self.gtk_css_path = gtk_css_path + self.web_css_path = web_css_path + self.is_dark = is_dark + self.inverse_name = inverse_name + + @classmethod + def get_for_name(cls, name, default=None): + current_theme = default or defaultThemes[0] + for theme in defaultThemes: + if name == theme.name: + current_theme = theme + return current_theme + + @classmethod + def get_current(cls): + theme_name = Gtk.Settings.get_default().get_property('gtk-theme-name') + dark_mode = cls.settings.get_value('dark-mode').get_boolean() + current_theme = cls.get_for_name(theme_name) + # Technically, we could very easily allow the user to force the light ui on a dark theme. + # However, as there is no inverse of "gtk-application-prefer-dark-theme", we shouldn't do that. + if dark_mode and not current_theme.is_dark and current_theme.inverse_name: + current_theme = cls.get_for_name(current_theme.inverse_name, current_theme.name) + return current_theme + + +defaultThemes = [ + # https://gitlab.gnome.org/GNOME/gtk/tree/master/gtk/theme/Adwaita + Theme('Adwaita', get_css_path('gtk_adwaita.css'), + get_css_path('web_adwaita.css'), False, 'Adwaita-dark'), + Theme('Adwaita-dark', get_css_path('gtk_adwaita_dark.css'), + get_css_path('web_adwaita_dark.css'), True, 'Adwaita'), +] diff --git a/uberwriter/UberwriterExportDialog.py b/uberwriter/UberwriterExportDialog.py index ec6ad8b..167329a 100644 --- a/uberwriter/UberwriterExportDialog.py +++ b/uberwriter/UberwriterExportDialog.py @@ -24,6 +24,9 @@ import logging from gettext import gettext as _ import gi + +from uberwriter.Theme import Theme + gi.require_version('Gtk', '3.0') from gi.repository import Gtk @@ -215,7 +218,7 @@ class Export: args.append("-o%s.odt" % basename) elif export_format == "html": - css = helpers.get_media_file('github-md.css') + css = Theme.ADWAITA.get_gtk_css_file() relativize = helpers.get_script_path('relative_to_absolute.lua') task_list = helpers.get_script_path('task-list.lua') args.append("-c%s" % css) diff --git a/uberwriter/UberwriterWindow.py b/uberwriter/UberwriterWindow.py index 43e7111..604e4ed 100644 --- a/uberwriter/UberwriterWindow.py +++ b/uberwriter/UberwriterWindow.py @@ -14,20 +14,22 @@ # with this program. If not, see . # 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):