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 83% rename from data/media/github-md.css rename to data/media/css/_web_base.css index dde07c6..3dd9ecc 100644 --- a/data/media/github-md.css +++ b/data/media/css/_web_base.css @@ -1,45 +1,60 @@ @font-face { font-family: fira-sans; - src: url('fonts/fira-sans-v9-greek_latin-ext_latin_cyrillic-ext_cyrillic_greek-ext_vietnamese-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-greek_latin-ext_latin_cyrillic-ext_cyrillic_greek-ext-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 { - font-family: "color-emoji"; + font-family: color-emoji; src: local("Noto Color Emoji"), local("Apple Color Emoji"), local("Segoe UI Emoji"), local("Segoe UI Symbol"); } :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; } * { box-sizing: border-box; } +html { + font-size: 16px; +} + +@media screen and (max-width: 799px) { + html { + font-size: 14px; + } +} + +@media screen and (min-width: 1000px) { + html { + font-size: 18px; + } +} + 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; @@ -77,7 +92,6 @@ hr { overflow: hidden; background-color: var(--hr-background-color); border: 0; - border-bottom: 1px solid var(--hr-border-color); } hr::before { @@ -183,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/gtk_arc.css b/data/media/css/gtk_arc.css new file mode 100644 index 0000000..967c919 --- /dev/null +++ b/data/media/css/gtk_arc.css @@ -0,0 +1,5 @@ +@define-color foreground_color #3b3e45; +@define-color background_color #f5f6f7; +@define-color math_text_color #00364c; + +@import url("_gtk_base.css"); diff --git a/data/media/css/gtk_arc_dark.css b/data/media/css/gtk_arc_dark.css new file mode 100644 index 0000000..3edd842 --- /dev/null +++ b/data/media/css/gtk_arc_dark.css @@ -0,0 +1,5 @@ +@define-color foreground_color #d3dae3; +@define-color background_color #383c4a; +@define-color math_text_color #ffc9b3; + +@import url("_gtk_base.css"); diff --git a/data/media/css/gtk_arc_darker.css b/data/media/css/gtk_arc_darker.css new file mode 100644 index 0000000..44c667b --- /dev/null +++ b/data/media/css/gtk_arc_darker.css @@ -0,0 +1,5 @@ +@define-color foreground_color #3b3e45; +@define-color background_color #f5f6f7; +@define-color math_text_color #00364C; + +@import url("_gtk_base.css"); diff --git a/data/media/css/gtk_high_contrast.css b/data/media/css/gtk_high_contrast.css new file mode 100644 index 0000000..254215e --- /dev/null +++ b/data/media/css/gtk_high_contrast.css @@ -0,0 +1,5 @@ +@define-color foreground_color #000000; +@define-color background_color #ffffff; +@define-color math_text_color #000000; + +@import url("_gtk_base.css"); diff --git a/data/media/css/gtk_high_contrast_inverse.css b/data/media/css/gtk_high_contrast_inverse.css new file mode 100644 index 0000000..b9790d4 --- /dev/null +++ b/data/media/css/gtk_high_contrast_inverse.css @@ -0,0 +1,5 @@ +@define-color foreground_color #ffffff; +@define-color background_color #000000; +@define-color math_text_color #ffffff; + +@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/css/web_arc.css b/data/media/css/web_arc.css new file mode 100644 index 0000000..c5ccb04 --- /dev/null +++ b/data/media/css/web_arc.css @@ -0,0 +1,18 @@ +@import url("_web_base.css"); + +:root { + --text-color: #3b3e45; + --background-color: #f5f6f7; + --alt-background-color: #eceff2; + --link-color: #1a7bed; + --blockquote-text-color: #818894; + --blockquote-border-color: #d5d9dd; + --header-border-color: #e0e3e7; + --hr-background-color: #d7dbe0; + --table-tr-border-color: #bcc2c9; + --table-td-border-color: #d5d9dd; + --kbd-text-color: #5b626d; + --kbd-background-color: #f0f2f4; + --kbd-border-color: #bcc2c9; + --kbd-shadow-color: #8b949d; +} \ No newline at end of file diff --git a/data/media/css/web_arc_dark.css b/data/media/css/web_arc_dark.css new file mode 100644 index 0000000..b0c6a45 --- /dev/null +++ b/data/media/css/web_arc_dark.css @@ -0,0 +1,18 @@ +@import url("_web_base.css"); + +:root { + --text-color: #d3dae3; + --background-color: #383c4a; + --alt-background-color: #3d414f; + --link-color: #9ac6ff; + --blockquote-text-color: #8d949d; + --blockquote-border-color: #555967; + --header-border-color: #4a4e5c; + --hr-background-color: #535765; + --table-tr-border-color: #6c707e; + --table-td-border-color: #555967; + --kbd-text-color: #b3bac3; + --kbd-background-color: #3f4351; + --kbd-border-color: #6c707e; + --kbd-shadow-color: #9a9eac; +} \ No newline at end of file diff --git a/data/media/css/web_arc_darker.css b/data/media/css/web_arc_darker.css new file mode 100644 index 0000000..cc6a95e --- /dev/null +++ b/data/media/css/web_arc_darker.css @@ -0,0 +1 @@ +@import url("web_arc.css"); \ No newline at end of file diff --git a/data/media/css/web_high_contrast.css b/data/media/css/web_high_contrast.css new file mode 100644 index 0000000..b9db89e --- /dev/null +++ b/data/media/css/web_high_contrast.css @@ -0,0 +1,26 @@ +@import url("_web_base.css"); + +a { + text-decoration: underline; +} + +pre { + border: 1px solid; +} + +:root { + --text-color: #000000; + --background-color: #ffffff; + --alt-background-color: #ffffff; + --link-color: #000000; + --blockquote-text-color: #000000; + --blockquote-border-color: #000000; + --header-border-color: #000000; + --hr-background-color: #000000; + --table-tr-border-color: #000000; + --table-td-border-color: #000000; + --kbd-text-color: #000000; + --kbd-background-color: #ffffff; + --kbd-border-color: #000000; + --kbd-shadow-color: #000000; +} \ No newline at end of file diff --git a/data/media/css/web_high_contrast_inverse.css b/data/media/css/web_high_contrast_inverse.css new file mode 100644 index 0000000..646e1f0 --- /dev/null +++ b/data/media/css/web_high_contrast_inverse.css @@ -0,0 +1,26 @@ +@import url("_web_base.css"); + +a { + text-decoration: underline; +} + +pre { + border: 1px solid; +} + +:root { + --text-color: #ffffff; + --background-color: #000000; + --alt-background-color: #000000; + --link-color: #ffffff; + --blockquote-text-color: #ffffff; + --blockquote-border-color: #ffffff; + --header-border-color: #ffffff; + --hr-background-color: #ffffff; + --table-tr-border-color: #ffffff; + --table-td-border-color: #ffffff; + --kbd-text-color: #ffffff; + --kbd-background-color: #000000; + --kbd-border-color: #ffffff; + --kbd-shadow-color: #ffffff; +} \ No newline at end of file diff --git a/data/media/fonts/fira-mono-v7-latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2 b/data/media/fonts/fira-mono-v7-latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2 new file mode 100644 index 0000000..7762d83 Binary files /dev/null and b/data/media/fonts/fira-mono-v7-latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2 differ diff --git a/data/media/fonts/fira-sans-v9-vietnamese_latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2 b/data/media/fonts/fira-sans-v9-vietnamese_latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2 new file mode 100644 index 0000000..c648c80 Binary files /dev/null and b/data/media/fonts/fira-sans-v9-vietnamese_latin_cyrillic-ext_cyrillic_greek-ext_latin-ext_greek-regular.woff2 differ 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/scripts/color_palette_generator.py b/scripts/color_palette_generator.py new file mode 100644 index 0000000..5a2f50f --- /dev/null +++ b/scripts/color_palette_generator.py @@ -0,0 +1,102 @@ +#!/usr/bin/python3 +# +# Generates color palettes based on the specified background/foreground colors. +# +# Usage: python color_palette_generator.py #fg_hex #bg_hex light|dark +# +# The light variant is based on GitHub's style, while the dark variant is based on pre-existing UberWriter styles. +# +# Accessibility is not accounted for, so make sure to verify contrast: https://webaim.org/resources/contrastchecker/ + +import operator +import os +import sys + + +def hex_to_tuple(h): + return tuple(int(h.lstrip('#')[i:i + 2], 16) for i in (0, 2, 4)) + + +def tuple_to_hex(t): + (r, g, b) = t + if r < 0 or g < 0 or b < 0 or r > 255 or g > 255 or b > 255: + return '#%02x%02x%02x (clamped)' % tuple(map(lambda x: max(0, min(x, 255)), t)) + else: + return '#%02x%02x%02x' % t + + +def sub_tuples(t1, t2): + return tuple(map(operator.sub, t1, t2)) + + +if __name__ == '__main__': + if len(sys.argv) != 4: + print("Usage: {} foreground_color background_color light|dark\n" + + "Both colors must be in hexadecimal format, eg. #f6f5f4".format(os.path.basename(__file__))) + exit() + + target_foreground_color = hex_to_tuple(sys.argv[1]) + target_background_color = hex_to_tuple(sys.argv[2]) + dark = sys.argv[3] == "dark" + + gh_text_color = hex_to_tuple("#dbdbdb" if dark else "#24292e") + gh_background_color = hex_to_tuple("#353535" if dark else "#ffffff") + gh_alt_background_color = hex_to_tuple("#3a3a3a" if dark else "#f6f8fa") + gh_link_color = hex_to_tuple("#a2c7f8" if dark else "#0366d6") + gh_blockquote_text_color = hex_to_tuple("#959595" if dark else "#6a737d") + gh_blockquote_border_color = hex_to_tuple("#525252" if dark else "#dfe2e5") + gh_header_border_color = hex_to_tuple("#474747" if dark else "#eaecef") + gh_hr_background_color = hex_to_tuple("#505050" if dark else "#e1e4e8") + gh_table_tr_border_color = hex_to_tuple("#696969" if dark else "#c6cbd1") + gh_table_td_border_color = hex_to_tuple("#525252" if dark else "#dfe2e5") + gh_kbd_text_color = hex_to_tuple("#bbbbbb" if dark else "#444d56") + gh_kbd_background_color = hex_to_tuple("#3c3c3c" if dark else "#fafbfc") + gh_kbd_border_color = hex_to_tuple("#696969" if dark else "#c6cbd1") + gh_kbd_shadow_color = hex_to_tuple("#979797" if dark else "#959da5") + + text_color_diff = sub_tuples(gh_text_color, target_foreground_color) + background_color_diff = sub_tuples(gh_background_color, target_background_color) + + text_color = tuple_to_hex(target_foreground_color) + background_color = tuple_to_hex(target_background_color) + alt_background_color = tuple_to_hex(sub_tuples(gh_alt_background_color, background_color_diff)) + link_color = tuple_to_hex(sub_tuples(gh_link_color, text_color_diff)) + blockquote_text_color = tuple_to_hex(sub_tuples(gh_blockquote_text_color, text_color_diff)) + blockquote_border_color = tuple_to_hex(sub_tuples(gh_blockquote_border_color, background_color_diff)) + header_border_color = tuple_to_hex(sub_tuples(gh_header_border_color, background_color_diff)) + hr_background_color = tuple_to_hex(sub_tuples(gh_hr_background_color, background_color_diff)) + table_tr_border_color = tuple_to_hex(sub_tuples(gh_table_tr_border_color, background_color_diff)) + table_td_border_color = tuple_to_hex(sub_tuples(gh_table_td_border_color, background_color_diff)) + kbd_text_color = tuple_to_hex(sub_tuples(gh_kbd_text_color, text_color_diff)) + kbd_background_color = tuple_to_hex(sub_tuples(gh_kbd_background_color, background_color_diff)) + kbd_border_color = tuple_to_hex(sub_tuples(gh_kbd_border_color, background_color_diff)) + kbd_shadow_color = tuple_to_hex(sub_tuples(gh_kbd_shadow_color, background_color_diff)) + + print(("--text-color: {};\n" + + "--background-color: {};\n" + + "--alt-background-color: {};\n" + + "--link-color: {};\n" + + "--blockquote-text-color: {};\n" + + "--blockquote-border-color: {};\n" + + "--header-border-color: {};\n" + + "--hr-background-color: {};\n" + + "--table-tr-border-color: {};\n" + + "--table-td-border-color: {};\n" + + "--kbd-text-color: {};\n" + + "--kbd-background-color: {};\n" + + "--kbd-border-color: {};\n" + + "--kbd-shadow-color: {};\n").format( + text_color, + background_color, + alt_background_color, + link_color, + blockquote_text_color, + blockquote_border_color, + header_border_color, + hr_background_color, + table_tr_border_color, + table_td_border_color, + kbd_text_color, + kbd_background_color, + kbd_border_color, + kbd_shadow_color)) diff --git a/uberwriter/MarkupBuffer.py b/uberwriter/MarkupBuffer.py index bbc762c..c413482 100644 --- a/uberwriter/MarkupBuffer.py +++ b/uberwriter/MarkupBuffer.py @@ -16,6 +16,7 @@ import re import gi + gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import Pango @@ -46,14 +47,10 @@ class MarkupBuffer(): self.normal_indent = self.text_buffer.create_tag('normal_indent', indent=100) - self.green_text = self.text_buffer.create_tag("greentext", - foreground="#00364C") + self.math_text = self.text_buffer.create_tag('math_text') - self.grayfont = self.text_buffer.create_tag('graytag', - foreground="gray") - - self.blackfont = self.text_buffer.create_tag('blacktag', - foreground="#222") + self.unfocused_text = self.text_buffer.create_tag('graytag', + foreground="gray") self.underline = self.text_buffer.create_tag("underline", underline=Pango.Underline.SINGLE) @@ -101,7 +98,8 @@ class MarkupBuffer(): self.table_env.set_property('pixels-above-lines', 0) self.table_env.set_property('pixels-below-lines', 0) - # self.ftag = self.TextBuffer.create_tag("pix_front", pixels_above_lines = 100) + self.update_style() + regex = { "ITALIC": re.compile(r"(\*|_)(.*?)\1", re.UNICODE), # *asdasd* // _asdasd asd asd_ "STRONG": re.compile(r"(\*\*|__)(.*?)\1", re.UNICODE), # **as das** // __asdasd asd ad a__ @@ -120,6 +118,13 @@ class MarkupBuffer(): "LINK": re.compile(r"\(http(.+?)\)") } + def update_style(self): + (found, color) = self.parent.get_style_context().lookup_color('math_text_color') + if not found: + (_, color) = self.parent.get_style_context().lookup_color('foreground_color') + + self.math_text.set_property("foreground", color.to_string()) + def markup_buffer(self, mode=0): buf = self.text_buffer @@ -178,13 +183,13 @@ class MarkupBuffer(): end_iter = buf.get_iter_at_offset(context_offset + match.end()) self.text_buffer.apply_tag(self.strikethrough, start_iter, end_iter) - self.text_buffer.remove_tag(self.green_text, context_start, context_end) + self.text_buffer.remove_tag(self.math_text, context_start, context_end) matches = re.finditer(self.regex["MATH"], text) for match in matches: start_iter = buf.get_iter_at_offset(context_offset + match.start()) end_iter = buf.get_iter_at_offset(context_offset + match.end()) - self.text_buffer.apply_tag(self.green_text, start_iter, end_iter) + self.text_buffer.apply_tag(self.math_text, start_iter, end_iter) for margin in self.rev_leftmargin: self.text_buffer.remove_tag(margin, context_start, context_end) @@ -266,15 +271,13 @@ class MarkupBuffer(): self.focusmode_highlight() def focusmode_highlight(self): - self.text_buffer.apply_tag( - self.grayfont, - self.text_buffer.get_start_iter(), - self.text_buffer.get_end_iter()) + start_document = self.text_buffer.get_start_iter() + end_document = self.text_buffer.get_end_iter() self.text_buffer.remove_tag( - self.blackfont, - self.text_buffer.get_start_iter(), - self.text_buffer.get_end_iter()) + self.unfocused_text, + start_document, + end_document) cursor = self.text_buffer.get_mark("insert") cursor_iter = self.text_buffer.get_iter_at_mark(cursor) @@ -293,9 +296,14 @@ class MarkupBuffer(): start_sentence = cursor_iter.copy() start_sentence.backward_sentence_start() + # grey out everything before self.text_buffer.apply_tag( - self.blackfont, - start_sentence, end_sentence) + self.unfocused_text, + self.text_buffer.get_start_iter(), start_sentence) + + self.text_buffer.apply_tag( + self.unfocused_text, + end_sentence, self.text_buffer.get_end_iter()) def set_multiplier(self, multiplier): self.multiplier = multiplier @@ -311,13 +319,3 @@ class MarkupBuffer(): new_margin = (lm - multiplier) + multiplier + multiplier * (i + 1) self.leftmargin[i].set_property("left-margin", 0 if new_margin < 0 else new_margin) self.leftmargin[i].set_property("indent", - (multiplier - 1) * (i + 1) - multiplier) - - def dark_mode(self, active=False): - if active: - self.green_text.set_property("foreground", "#FA5B0F") - self.grayfont.set_property("foreground", "#666") - self.blackfont.set_property("foreground", "#CCC") - else: - self.green_text.set_property("foreground", "#00364C") - self.grayfont.set_property("foreground", "gray") - self.blackfont.set_property("foreground", "#222") diff --git a/uberwriter/Theme.py b/uberwriter/Theme.py new file mode 100644 index 0000000..cd408bc --- /dev/null +++ b/uberwriter/Theme.py @@ -0,0 +1,61 @@ +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'), + # https://github.com/NicoHood/arc-theme/tree/master/common/gtk-3.0/3.20/sass + Theme('Arc', get_css_path('gtk_arc.css'), + get_css_path('web_arc.css'), False, 'Arc-Dark'), + Theme('Arc-Darker', get_css_path('gtk_arc_darker.css'), + get_css_path('web_arc_darker.css'), False, 'Arc-Dark'), + Theme('Arc-Dark', get_css_path('gtk_arc_dark.css'), + get_css_path('web_arc_dark.css'), True, 'Arc'), + # https://gitlab.gnome.org/GNOME/gtk/tree/master/gtk/theme/HighContrast + Theme('HighContrast', get_css_path('gtk_high_contrast.css'), + get_css_path('web_high_contrast.css'), False, 'HighContrastInverse'), + Theme('HighContrastInverse', get_css_path('gtk_high_contrast_inverse.css'), + get_css_path('web_high_contrast_inverse.css'), True, 'HighContrast'), +] 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 c51f828..f3c4429 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,18 @@ 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. + """ + + self.markup_buffer.update_style() + + # 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 +393,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, @@ -487,8 +493,8 @@ class UberwriterWindow(Gtk.ApplicationWindow): self.window_height = widget.get_allocation().height w_width = widget.get_allocation().width # Calculate left / right margin - width_request = 600 if w_width < 900: + width_request = 600 self.markup_buffer.set_multiplier(8) self.current_font_size = 12 self.alignment_padding = 30 @@ -498,8 +504,8 @@ class UberwriterWindow(Gtk.ApplicationWindow): self.get_style_context().add_class("small") elif w_width < 1400: - self.markup_buffer.set_multiplier(10) width_request = 800 + self.markup_buffer.set_multiplier(10) self.current_font_size = 15 self.alignment_padding = 40 lm = 7 * 10 @@ -508,9 +514,9 @@ class UberwriterWindow(Gtk.ApplicationWindow): self.get_style_context().add_class("medium") else: + width_request = 1000 self.markup_buffer.set_multiplier(13) self.current_font_size = 17 - width_request = 1000 self.alignment_padding = 60 lm = 7 * 13 self.get_style_context().remove_class("medium") @@ -865,20 +871,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 +905,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/AppWindow.py b/uberwriter_lib/AppWindow.py index d25161a..3e446ae 100644 --- a/uberwriter_lib/AppWindow.py +++ b/uberwriter_lib/AppWindow.py @@ -16,13 +16,14 @@ from gettext import gettext as _ import gi +from uberwriter.Theme import Theme + gi.require_version('Gtk', '3.0') # pylint: disable=wrong-import-position from gi.repository import GLib, Gio, Gtk, Gdk, GdkPixbuf from uberwriter import UberwriterWindow from uberwriter.Settings import Settings from uberwriter_lib import set_up_logging -from uberwriter_lib import helpers from uberwriter_lib.PreferencesDialog import PreferencesDialog from . helpers import get_builder, get_media_path @@ -36,30 +37,6 @@ class Application(Gtk.Application): self.window = None self.settings = Settings.new() - def init(self): - """Init main application""" - - # set theme variant (dark/light) - dark = self.settings.get_value("dark-mode") - Gtk.Settings.get_default().set_property("gtk-application-prefer-dark-theme", dark) - - # set css for current theme - self.style_provider = Gtk.CssProvider() - - themes = { - "Arc": "arc_style.css", - "Arc-Dark": "arc_style.css", - "Arc-Darker": "arc_style.css", - } - - theme = Gtk.Settings.get_default().get_property("gtk-theme-name") - self.style_provider.load_from_path(helpers.get_media_path(themes.get(theme,"adwaita_style.css"))) - - Gtk.StyleContext.add_provider_for_screen( - Gdk.Screen.get_default(), self.style_provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ) - def do_startup(self, *args, **kwargs): Gtk.Application.do_startup(self) @@ -176,7 +153,7 @@ class Application(Gtk.Application): self.set_accels_for_action("app.save", ["s"]) self.set_accels_for_action("app.save_as", ["s"]) - self.init() + self.apply_current_theme() def do_activate(self, *args, **kwargs): # We only allow a single window and raise any existing ones @@ -209,6 +186,23 @@ class Application(Gtk.Application): self.activate() return 0 + def apply_current_theme(self): + # get current theme + theme = Theme.get_current() + + # set theme variant (dark/light) + Gtk.Settings.get_default().set_property( + "gtk-application-prefer-dark-theme", + GLib.Variant("b", theme.is_dark)) + + # set theme css + style_provider = Gtk.CssProvider() + style_provider.load_from_path(theme.gtk_css_path) + Gtk.StyleContext.add_provider_for_screen( + Gdk.Screen.get_default(), style_provider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ) + def on_about(self, _action, _param): builder = get_builder('About') about_dialog = builder.get_object("AboutDialog") @@ -234,14 +228,13 @@ class Application(Gtk.Application): def on_dark_mode(self, action, value): action.set_state(value) - self.settings.set_value("dark-mode", - GLib.Variant("b", value)) - self.window.toggle_dark_mode(value) + self.settings.set_value("dark-mode", GLib.Variant("b", value)) # this changes the headerbar theme accordingly - self.dark_setting = Gtk.Settings.get_default() - self.dark_setting.set_property( - "gtk-application-prefer-dark-theme", value) + self.apply_current_theme() + + # adjust window for theme + self.window.apply_current_theme() def on_focus_mode(self, action, value): action.set_state(value) 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):