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/css/_web_base.css b/data/media/css/_web_base.css
new file mode 100644
index 0000000..3dd9ecc
--- /dev/null
+++ b/data/media/css/_web_base.css
@@ -0,0 +1,501 @@
+@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");
+}
+
+@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");
+}
+
+@font-face {
+ font-family: color-emoji;
+ src: local("Noto Color Emoji"), local("Apple Color Emoji"), local("Segoe UI Emoji"), local("Segoe UI Symbol");
+}
+
+:root {
+ /* 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: #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", fira-sans, sans-serif, color-emoji;
+ line-height: 1.5;
+ text-size-adjust: 100%;
+ word-wrap: break-word;
+ padding: 2em;
+}
+
+a {
+ background-color: transparent;
+ color: var(--link-color);
+ text-decoration: none;
+}
+
+a:active,
+a:hover {
+ outline-width: 0;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+strong {
+ font-weight: 600;
+}
+
+img {
+ border-style: none;
+}
+
+hr {
+ box-sizing: content-box;
+ height: 0.25em;
+ padding: 0;
+ margin: 1.5em 0;
+ overflow: hidden;
+ background-color: var(--hr-background-color);
+ border: 0;
+}
+
+hr::before {
+ display: table;
+ content: "";
+}
+
+hr::after {
+ display: table;
+ clear: both;
+ content: "";
+}
+
+input {
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ margin: 0;
+ overflow: visible;
+}
+
+[type="checkbox"] {
+ box-sizing: border-box;
+ padding: 0;
+}
+
+table {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+td,
+th {
+ padding: 0;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-weight: 600;
+ margin: 0;
+}
+
+h1 {
+ font-size: 2em;
+}
+
+h2 {
+ font-size: 1.5em;
+}
+
+h3 {
+ font-size: 1.25em;
+}
+
+h4 {
+ font-size: 1em;
+}
+
+h5 {
+ font-size: 0.875em;
+}
+
+h6 {
+ font-size: 0.85em;
+}
+
+p {
+ margin-top: 0;
+ margin-bottom: 0.625em;
+}
+
+blockquote {
+ margin: 0;
+}
+
+ul,
+ol {
+ padding-left: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+ol ol,
+ul ol {
+ list-style-type: lower-roman;
+}
+
+ul ul ol,
+ul ol ol,
+ol ul ol,
+ol ol ol {
+ list-style-type: lower-alpha;
+}
+
+dd {
+ margin-left: 0;
+}
+
+code,
+kbd,
+pre {
+ font-family: "Fira Mono", fira-mono, monospace, color-emoji;
+ font-size: 1em;
+ word-wrap: normal;
+}
+
+code {
+ border-radius: 0.1875em;
+ font-size: 0.85em;
+ padding: 0.2em 0.4em;
+ margin: 0;
+}
+
+pre {
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 0.75em;
+}
+
+pre>code {
+ padding: 0;
+ margin: 0;
+ font-size: 1em;
+ word-break: normal;
+ white-space: pre;
+ background: transparent;
+ border: 0;
+}
+
+.highlight {
+ margin-bottom: 1em;
+}
+
+.highlight pre {
+ margin-bottom: 0;
+ word-break: normal;
+}
+
+.highlight pre,
+pre {
+ padding: 1em;
+ overflow: auto;
+ font-size: 0.85em;
+ line-height: 1.5;
+ background-color: var(--alt-background-color);
+ border-radius: 0.1875em;
+}
+
+pre code {
+ background-color: transparent;
+ border: 0;
+ display: inline;
+ padding: 0;
+ margin: 0;
+ overflow: visible;
+ line-height: inherit;
+ word-wrap: normal;
+}
+
+.pl-0 {
+ padding-left: 0 !important;
+}
+
+.pl-1 {
+ padding-left: 0.25em !important;
+}
+
+.pl-2 {
+ padding-left: 0.5em !important;
+}
+
+.pl-3 {
+ padding-left: 1em !important;
+}
+
+.pl-4 {
+ padding-left: 1.5em !important;
+}
+
+.pl-5 {
+ padding-left: 2em !important;
+}
+
+.pl-6 {
+ padding-left: 2.5em !important;
+}
+
+.markdown-body::before {
+ display: table;
+ content: "";
+}
+
+.markdown-body::after {
+ display: table;
+ clear: both;
+ content: "";
+}
+
+.markdown-body>*:first-child {
+ margin-top: 0 !important;
+}
+
+.markdown-body>*:last-child {
+ margin-bottom: 0 !important;
+}
+
+a:not([href]) {
+ color: inherit;
+ text-decoration: none;
+}
+
+.anchor {
+ float: left;
+ padding-right: 0.25em;
+ margin-left: -1.25em;
+ line-height: 1;
+}
+
+.anchor:focus {
+ outline: none;
+}
+
+p,
+blockquote,
+ul,
+ol,
+dl,
+table,
+pre {
+ margin-top: 0;
+ margin-bottom: 1em;
+}
+
+blockquote {
+ padding: 0 1em;
+ color: var(--blockquote-text-color);
+ border-left: 0.25em solid var(--blockquote-border-color);
+}
+
+blockquote>:first-child {
+ margin-top: 0;
+}
+
+blockquote>:last-child {
+ margin-bottom: 0;
+}
+
+kbd {
+ display: inline-block;
+ padding: 0.1875em 0.3125em;
+ font-size: 0.6875em;
+ line-height: 1;
+ color: var(--kbd-text-color);
+ vertical-align: middle;
+ background-color: var(--kbd-background-color);
+ border: solid 1px var(--kbd-border-color);
+ border-bottom-color: var(--kbd-shadow-color);
+ border-radius: 3px;
+ box-shadow: inset 0 -1px 0 var(--kbd-shadow-color);;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-top: 1.5em;
+ margin-bottom: 1em;
+ font-weight: 600;
+ line-height: 1.25;
+}
+
+h1:hover .anchor,
+h2:hover .anchor,
+h3:hover .anchor,
+h4:hover .anchor,
+h5:hover .anchor,
+h6:hover .anchor {
+ text-decoration: none;
+}
+
+h1 {
+ padding-bottom: 0.3em;
+ font-size: 2em;
+ border-bottom: 1px solid var(--header-border-color);
+}
+
+h2 {
+ padding-bottom: 0.3em;
+ font-size: 1.5em;
+ border-bottom: 1px solid var(--header-border-color);
+}
+
+h3 {
+ font-size: 1.25em;
+}
+
+h4 {
+ font-size: 1em;
+}
+
+h5 {
+ font-size: 0.875em;
+}
+
+h6 {
+ font-size: 0.85em;
+ opacity: 0.67;
+}
+
+ul,
+ol {
+ padding-left: 2em;
+}
+
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+li {
+ overflow-wrap: break-word;
+}
+
+li>p {
+ margin-top: 1em;
+}
+
+li+li {
+ margin-top: 0.25em;
+}
+
+dl {
+ padding: 0;
+}
+
+dl dt {
+ padding: 0;
+ margin-top: 1em;
+ font-size: 1em;
+ font-style: italic;
+ font-weight: 600;
+}
+
+dl dd {
+ padding: 0 1em;
+ margin-bottom: 1em;
+}
+
+table {
+ display: block;
+ width: 100%;
+ overflow: auto;
+}
+
+table th {
+ font-weight: 600;
+}
+
+table th,
+table td {
+ padding: 0.375em 0.8125em;
+ border: 1px solid var(--table-td-border-color);
+}
+
+table tr {
+ background-color: var(--background-color);
+ border-top: 1px solid var(--table-tr-border-color);
+}
+
+table tr:nth-child(2n) {
+ background-color: var(--alt-background-color);
+}
+
+img {
+ max-width: 100%;
+ box-sizing: content-box;
+}
+
+img[align=right] {
+ padding-left: 1.25em;
+}
+
+img[align=left] {
+ padding-right: 1.25em;
+}
+
+.task-list-item {
+ list-style-type: none;
+}
+
+.task-list-item+.task-list-item {
+ margin-top: 0.1875em;
+}
+
+.task-list-item input {
+ margin: 0 0.2em 0.25em -1.6em;
+ vertical-align: middle;
+}
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/css/web_adwaita_dark.css b/data/media/css/web_adwaita_dark.css
new file mode 100644
index 0000000..320a657
--- /dev/null
+++ b/data/media/css/web_adwaita_dark.css
@@ -0,0 +1,18 @@
+@import url("_web_base.css");
+
+:root {
+ --text-color: #eeeeec;
+ --background-color: #353535;
+ --alt-background-color: #3a3a3a;
+ --link-color: #b5daff;
+ --blockquote-text-color: #a8a8a6;
+ --blockquote-border-color: #525252;
+ --header-border-color: #474747;
+ --hr-background-color: #505050;
+ --table-tr-border-color: #696969;
+ --table-td-border-color: #525252;
+ --kbd-text-color: #cececc;
+ --kbd-background-color: #3c3c3c;
+ --kbd-border-color: #696969;
+ --kbd-shadow-color: #979797;
+}
\ No newline at end of file
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/github-md-dark.css b/data/media/github-md-dark.css
deleted file mode 100644
index 2dfd3eb..0000000
--- a/data/media/github-md-dark.css
+++ /dev/null
@@ -1,567 +0,0 @@
-@font-face {
- font-family: octicons-link;
- src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
-}
-
-body {
- -ms-text-size-adjust: 100%;
- -webkit-text-size-adjust: 100%;
- line-height: 1.5;
- color: #EDEDED;
- background-color: #31373D;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
- font-size: 16px;
- line-height: 1.5;
- word-wrap: break-word;
-}
-
-a {
- background-color: transparent;
-}
-
-a:active,
-a:hover {
- outline-width: 0;
-}
-
-strong {
- font-weight: inherit;
-}
-
-strong {
- font-weight: bolder;
-}
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-img {
- border-style: none;
-}
-
-code,
-kbd,
-pre {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-hr {
- box-sizing: content-box;
- height: 0;
- overflow: visible;
-}
-
-input {
- font: inherit;
- margin: 0;
-}
-
-input {
- overflow: visible;
-}
-
-[type="checkbox"] {
- box-sizing: border-box;
- padding: 0;
-}
-
-* {
- box-sizing: border-box;
-}
-
-input {
- font-family: inherit;
- font-size: inherit;
- line-height: inherit;
-}
-
-a {
- color: #0366d6;
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-strong {
- font-weight: 600;
-}
-
-hr {
- height: 0;
- margin: 15px 0;
- overflow: hidden;
- background: transparent;
- border: 0;
- border-bottom: 1px solid #dfe2e5;
-}
-
-hr::before {
- display: table;
- content: "";
-}
-
-hr::after {
- display: table;
- clear: both;
- content: "";
-}
-
-table {
- border-spacing: 0;
- border-collapse: collapse;
-}
-
-td,
-th {
- padding: 0;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-h1 {
- font-size: 32px;
- font-weight: 600;
-}
-
-h2 {
- font-size: 24px;
- font-weight: 600;
-}
-
-h3 {
- font-size: 20px;
- font-weight: 600;
-}
-
-h4 {
- font-size: 16px;
- font-weight: 600;
-}
-
-h5 {
- font-size: 14px;
- font-weight: 600;
-}
-
-h6 {
- font-size: 12px;
- font-weight: 600;
-}
-
-p {
- margin-top: 0;
- margin-bottom: 10px;
-}
-
-blockquote {
- margin: 0;
-}
-
-ul,
-ol {
- padding-left: 0;
- margin-top: 0;
- margin-bottom: 0;
-}
-
-ol ol,
-ul ol {
- list-style-type: lower-roman;
-}
-
-ul ul ol,
-ul ol ol,
-ol ul ol,
-ol ol ol {
- list-style-type: lower-alpha;
-}
-
-dd {
- margin-left: 0;
-}
-
-code {
- font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
- font-size: 12px;
-}
-
-pre {
- margin-top: 0;
- margin-bottom: 0;
- font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
- font-size: 12px;
-}
-
-.octicon {
- vertical-align: text-bottom;
-}
-
-.pl-0 {
- padding-left: 0 !important;
-}
-
-.pl-1 {
- padding-left: 4px !important;
-}
-
-.pl-2 {
- padding-left: 8px !important;
-}
-
-.pl-3 {
- padding-left: 16px !important;
-}
-
-.pl-4 {
- padding-left: 24px !important;
-}
-
-.pl-5 {
- padding-left: 32px !important;
-}
-
-.pl-6 {
- padding-left: 40px !important;
-}
-
-.markdown-body::before {
- display: table;
- content: "";
-}
-
-.markdown-body::after {
- display: table;
- clear: both;
- content: "";
-}
-
-.markdown-body>*:first-child {
- margin-top: 0 !important;
-}
-
-.markdown-body>*:last-child {
- margin-bottom: 0 !important;
-}
-
-a:not([href]) {
- color: inherit;
- text-decoration: none;
-}
-
-.anchor {
- float: left;
- padding-right: 4px;
- margin-left: -20px;
- line-height: 1;
-}
-
-.anchor:focus {
- outline: none;
-}
-
-p,
-blockquote,
-ul,
-ol,
-dl,
-table,
-pre {
- margin-top: 0;
- margin-bottom: 16px;
-}
-
-hr {
- height: 0.25em;
- padding: 0;
- margin: 24px 0;
- background-color: #e1e4e8;
- border: 0;
-}
-
-blockquote {
- padding: 0 1em;
- color: #6a737d;
- border-left: 0.25em solid #dfe2e5;
-}
-
-blockquote>:first-child {
- margin-top: 0;
-}
-
-blockquote>:last-child {
- margin-bottom: 0;
-}
-
-kbd {
- display: inline-block;
- padding: 3px 5px;
- font-size: 11px;
- line-height: 10px;
- color: #444d56;
- vertical-align: middle;
- background-color: #fafbfc;
- border: solid 1px #c6cbd1;
- border-bottom-color: #959da5;
- border-radius: 3px;
- box-shadow: inset 0 -1px 0 #959da5;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin-top: 24px;
- margin-bottom: 16px;
- font-weight: 600;
- line-height: 1.25;
-}
-
-h1 .octicon-link,
-h2 .octicon-link,
-h3 .octicon-link,
-h4 .octicon-link,
-h5 .octicon-link,
-h6 .octicon-link {
- color: #1b1f23;
- vertical-align: middle;
- visibility: hidden;
-}
-
-h1:hover .anchor,
-h2:hover .anchor,
-h3:hover .anchor,
-h4:hover .anchor,
-h5:hover .anchor,
-h6:hover .anchor {
- text-decoration: none;
-}
-
-h1:hover .anchor .octicon-link,
-h2:hover .anchor .octicon-link,
-h3:hover .anchor .octicon-link,
-h4:hover .anchor .octicon-link,
-h5:hover .anchor .octicon-link,
-h6:hover .anchor .octicon-link {
- visibility: visible;
-}
-
-h1 {
- padding-bottom: 0.3em;
- font-size: 2em;
- border-bottom: 1px solid #eaecef;
-}
-
-h2 {
- padding-bottom: 0.3em;
- font-size: 1.5em;
- border-bottom: 1px solid #eaecef;
-}
-
-h3 {
- font-size: 1.25em;
-}
-
-h4 {
- font-size: 1em;
-}
-
-h5 {
- font-size: 0.875em;
-}
-
-h6 {
- font-size: 0.85em;
- color: #6a737d;
-}
-
-ul,
-ol {
- padding-left: 2em;
-}
-
-ul ul,
-ul ol,
-ol ol,
-ol ul {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-li {
- word-wrap: break-all;
-}
-
-li>p {
- margin-top: 16px;
-}
-
-li+li {
- margin-top: 0.25em;
-}
-
-dl {
- padding: 0;
-}
-
-dl dt {
- padding: 0;
- margin-top: 16px;
- font-size: 1em;
- font-style: italic;
- font-weight: 600;
-}
-
-dl dd {
- padding: 0 16px;
- margin-bottom: 16px;
-}
-
-table {
- display: block;
- width: 100%;
- overflow: auto;
-}
-
-table th {
- font-weight: 600;
-}
-
-table th,
-table td {
- padding: 6px 13px;
- border: 1px solid #dfe2e5;
-}
-
-table tr {
- background-color: #fff;
- border-top: 1px solid #c6cbd1;
-}
-
-table tr:nth-child(2n) {
- background-color: #f6f8fa;
-}
-
-img {
- max-width: 100%;
- box-sizing: content-box;
- background-color: #fff;
-}
-
-img[align=right] {
- padding-left: 20px;
-}
-
-img[align=left] {
- padding-right: 20px;
-}
-
-code {
- padding: 0.2em 0.4em;
- margin: 0;
- font-size: 85%;
- background-color: #fafbfc9d;
- color: #1b1f23;
- border-radius: 3px;
-}
-
-pre {
- word-wrap: normal;
-}
-
-pre>code {
- padding: 0;
- margin: 0;
- font-size: 100%;
- word-break: normal;
- white-space: pre;
- background: transparent;
- border: 0;
-}
-
-.highlight {
- margin-bottom: 16px;
-}
-
-.highlight pre {
- margin-bottom: 0;
- word-break: normal;
-}
-
-.highlight pre,
-pre {
- padding: 16px;
- overflow: auto;
- font-size: 85%;
- line-height: 1.45;
- background-color: #f6f8faf1;
- border-radius: 3px;
-}
-
-pre code {
- display: inline;
- max-width: auto;
- padding: 0;
- margin: 0;
- overflow: visible;
- line-height: inherit;
- word-wrap: normal;
- background-color: transparent;
- border: 0;
-}
-
-.full-commit .btn-outline:not(:disabled):hover {
- color: #005cc5;
- border-color: #005cc5;
-}
-
-kbd {
- display: inline-block;
- padding: 3px 5px;
- font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
- line-height: 10px;
- color: #444d56;
- vertical-align: middle;
- background-color: #fafbfc;
- border: solid 1px #d1d5da;
- border-bottom-color: #c6cbd1;
- border-radius: 3px;
- box-shadow: inset 0 -1px 0 #c6cbd1;
-}
-
-:checked+.radio-label {
- position: relative;
- z-index: 1;
- border-color: #0366d6;
-}
-
-.task-list-item {
- list-style-type: none;
-}
-
-.task-list-item+.task-list-item {
- margin-top: 3px;
-}
-
-.task-list-item input {
- margin: 0 0.2em 0.25em -1.6em;
- vertical-align: middle;
-}
-
-hr {
- border-bottom-color: #eee;
-}
diff --git a/data/media/github-md.css b/data/media/github-md.css
deleted file mode 100644
index c014dd6..0000000
--- a/data/media/github-md.css
+++ /dev/null
@@ -1,566 +0,0 @@
-@font-face {
- font-family: octicons-link;
- src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
-}
-
-body {
- -ms-text-size-adjust: 100%;
- -webkit-text-size-adjust: 100%;
- line-height: 1.5;
- color: #31373D;
- background-color: #EDEDED;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
- font-size: 16px;
- line-height: 1.5;
- word-wrap: break-word;
-}
-
-a {
- background-color: transparent;
-}
-
-a:active,
-a:hover {
- outline-width: 0;
-}
-
-strong {
- font-weight: inherit;
-}
-
-strong {
- font-weight: bolder;
-}
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-img {
- border-style: none;
-}
-
-code,
-kbd,
-pre {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-hr {
- box-sizing: content-box;
- height: 0;
- overflow: visible;
-}
-
-input {
- font: inherit;
- margin: 0;
-}
-
-input {
- overflow: visible;
-}
-
-[type="checkbox"] {
- box-sizing: border-box;
- padding: 0;
-}
-
-* {
- box-sizing: border-box;
-}
-
-input {
- font-family: inherit;
- font-size: inherit;
- line-height: inherit;
-}
-
-a {
- color: #0366d6;
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-strong {
- font-weight: 600;
-}
-
-hr {
- height: 0;
- margin: 15px 0;
- overflow: hidden;
- background: transparent;
- border: 0;
- border-bottom: 1px solid #dfe2e5;
-}
-
-hr::before {
- display: table;
- content: "";
-}
-
-hr::after {
- display: table;
- clear: both;
- content: "";
-}
-
-table {
- border-spacing: 0;
- border-collapse: collapse;
-}
-
-td,
-th {
- padding: 0;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-h1 {
- font-size: 32px;
- font-weight: 600;
-}
-
-h2 {
- font-size: 24px;
- font-weight: 600;
-}
-
-h3 {
- font-size: 20px;
- font-weight: 600;
-}
-
-h4 {
- font-size: 16px;
- font-weight: 600;
-}
-
-h5 {
- font-size: 14px;
- font-weight: 600;
-}
-
-h6 {
- font-size: 12px;
- font-weight: 600;
-}
-
-p {
- margin-top: 0;
- margin-bottom: 10px;
-}
-
-blockquote {
- margin: 0;
-}
-
-ul,
-ol {
- padding-left: 0;
- margin-top: 0;
- margin-bottom: 0;
-}
-
-ol ol,
-ul ol {
- list-style-type: lower-roman;
-}
-
-ul ul ol,
-ul ol ol,
-ol ul ol,
-ol ol ol {
- list-style-type: lower-alpha;
-}
-
-dd {
- margin-left: 0;
-}
-
-code {
- font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
- font-size: 12px;
-}
-
-pre {
- margin-top: 0;
- margin-bottom: 0;
- font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
- font-size: 12px;
-}
-
-.octicon {
- vertical-align: text-bottom;
-}
-
-.pl-0 {
- padding-left: 0 !important;
-}
-
-.pl-1 {
- padding-left: 4px !important;
-}
-
-.pl-2 {
- padding-left: 8px !important;
-}
-
-.pl-3 {
- padding-left: 16px !important;
-}
-
-.pl-4 {
- padding-left: 24px !important;
-}
-
-.pl-5 {
- padding-left: 32px !important;
-}
-
-.pl-6 {
- padding-left: 40px !important;
-}
-
-.markdown-body::before {
- display: table;
- content: "";
-}
-
-.markdown-body::after {
- display: table;
- clear: both;
- content: "";
-}
-
-.markdown-body>*:first-child {
- margin-top: 0 !important;
-}
-
-.markdown-body>*:last-child {
- margin-bottom: 0 !important;
-}
-
-a:not([href]) {
- color: inherit;
- text-decoration: none;
-}
-
-.anchor {
- float: left;
- padding-right: 4px;
- margin-left: -20px;
- line-height: 1;
-}
-
-.anchor:focus {
- outline: none;
-}
-
-p,
-blockquote,
-ul,
-ol,
-dl,
-table,
-pre {
- margin-top: 0;
- margin-bottom: 16px;
-}
-
-hr {
- height: 0.25em;
- padding: 0;
- margin: 24px 0;
- background-color: #e1e4e8;
- border: 0;
-}
-
-blockquote {
- padding: 0 1em;
- color: #6a737d;
- border-left: 0.25em solid #dfe2e5;
-}
-
-blockquote>:first-child {
- margin-top: 0;
-}
-
-blockquote>:last-child {
- margin-bottom: 0;
-}
-
-kbd {
- display: inline-block;
- padding: 3px 5px;
- font-size: 11px;
- line-height: 10px;
- color: #444d56;
- vertical-align: middle;
- background-color: #fafbfc;
- border: solid 1px #c6cbd1;
- border-bottom-color: #959da5;
- border-radius: 3px;
- box-shadow: inset 0 -1px 0 #959da5;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin-top: 24px;
- margin-bottom: 16px;
- font-weight: 600;
- line-height: 1.25;
-}
-
-h1 .octicon-link,
-h2 .octicon-link,
-h3 .octicon-link,
-h4 .octicon-link,
-h5 .octicon-link,
-h6 .octicon-link {
- color: #1b1f23;
- vertical-align: middle;
- visibility: hidden;
-}
-
-h1:hover .anchor,
-h2:hover .anchor,
-h3:hover .anchor,
-h4:hover .anchor,
-h5:hover .anchor,
-h6:hover .anchor {
- text-decoration: none;
-}
-
-h1:hover .anchor .octicon-link,
-h2:hover .anchor .octicon-link,
-h3:hover .anchor .octicon-link,
-h4:hover .anchor .octicon-link,
-h5:hover .anchor .octicon-link,
-h6:hover .anchor .octicon-link {
- visibility: visible;
-}
-
-h1 {
- padding-bottom: 0.3em;
- font-size: 2em;
- border-bottom: 1px solid #eaecef;
-}
-
-h2 {
- padding-bottom: 0.3em;
- font-size: 1.5em;
- border-bottom: 1px solid #eaecef;
-}
-
-h3 {
- font-size: 1.25em;
-}
-
-h4 {
- font-size: 1em;
-}
-
-h5 {
- font-size: 0.875em;
-}
-
-h6 {
- font-size: 0.85em;
- color: #6a737d;
-}
-
-ul,
-ol {
- padding-left: 2em;
-}
-
-ul ul,
-ul ol,
-ol ol,
-ol ul {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-li {
- word-wrap: break-all;
-}
-
-li>p {
- margin-top: 16px;
-}
-
-li+li {
- margin-top: 0.25em;
-}
-
-dl {
- padding: 0;
-}
-
-dl dt {
- padding: 0;
- margin-top: 16px;
- font-size: 1em;
- font-style: italic;
- font-weight: 600;
-}
-
-dl dd {
- padding: 0 16px;
- margin-bottom: 16px;
-}
-
-table {
- display: block;
- width: 100%;
- overflow: auto;
-}
-
-table th {
- font-weight: 600;
-}
-
-table th,
-table td {
- padding: 6px 13px;
- border: 1px solid #dfe2e5;
-}
-
-table tr {
- background-color: #fff;
- border-top: 1px solid #c6cbd1;
-}
-
-table tr:nth-child(2n) {
- background-color: #f6f8fa;
-}
-
-img {
- max-width: 100%;
- box-sizing: content-box;
- background-color: #fff;
-}
-
-img[align=right] {
- padding-left: 20px;
-}
-
-img[align=left] {
- padding-right: 20px;
-}
-
-code {
- padding: 0.2em 0.4em;
- margin: 0;
- font-size: 85%;
- background-color: rgba(27,31,35,0.05);
- border-radius: 3px;
-}
-
-pre {
- word-wrap: normal;
-}
-
-pre>code {
- padding: 0;
- margin: 0;
- font-size: 100%;
- word-break: normal;
- white-space: pre;
- background: transparent;
- border: 0;
-}
-
-.highlight {
- margin-bottom: 16px;
-}
-
-.highlight pre {
- margin-bottom: 0;
- word-break: normal;
-}
-
-.highlight pre,
-pre {
- padding: 16px;
- overflow: auto;
- font-size: 85%;
- line-height: 1.45;
- background-color: #f6f8fa;
- border-radius: 3px;
-}
-
-pre code {
- display: inline;
- max-width: auto;
- padding: 0;
- margin: 0;
- overflow: visible;
- line-height: inherit;
- word-wrap: normal;
- background-color: transparent;
- border: 0;
-}
-
-.full-commit .btn-outline:not(:disabled):hover {
- color: #005cc5;
- border-color: #005cc5;
-}
-
-kbd {
- display: inline-block;
- padding: 3px 5px;
- font: 11px "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
- line-height: 10px;
- color: #444d56;
- vertical-align: middle;
- background-color: #fafbfc;
- border: solid 1px #d1d5da;
- border-bottom-color: #c6cbd1;
- border-radius: 3px;
- box-shadow: inset 0 -1px 0 #c6cbd1;
-}
-
-:checked+.radio-label {
- position: relative;
- z-index: 1;
- border-color: #0366d6;
-}
-
-.task-list-item {
- list-style-type: none;
-}
-
-.task-list-item+.task-list-item {
- margin-top: 3px;
-}
-
-.task-list-item input {
- margin: 0 0.2em 0.25em -1.6em;
- vertical-align: middle;
-}
-
-hr {
- border-bottom-color: #eee;
-}
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/data/ui/Menu.ui b/data/ui/Menu.ui
index 55319df..e07092c 100644
--- a/data/ui/Menu.ui
+++ b/data/ui/Menu.ui
@@ -6,6 +6,10 @@
Focus Mode
app.focus_mode
+ -
+ Hemingway Mode
+ app.hemingway_mode
+
-
Preview
app.preview
diff --git a/data/ui/Shortcuts.ui b/data/ui/Shortcuts.ui
index d3c6dee..3234844 100644
--- a/data/ui/Shortcuts.ui
+++ b/data/ui/Shortcuts.ui
@@ -55,20 +55,27 @@
+
+
+
-
-
+
True
Search
<Primary>f
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/UberwriterTextEditor.py b/uberwriter/UberwriterTextEditor.py
index 6965b54..63673d4 100644
--- a/uberwriter/UberwriterTextEditor.py
+++ b/uberwriter/UberwriterTextEditor.py
@@ -122,6 +122,9 @@ class TextEditor(Gtk.TextView):
self.not_undoable_action = False
self.undo_in_progress = False
+ self.can_delete = True
+ self.connect('key-press-event', self.on_key_press_event)
+
self.format_shortcuts = FormatShortcuts(self.get_buffer(), self)
self.connect('insert-italic', self.set_italic)
@@ -393,6 +396,12 @@ class TextEditor(Gtk.TextView):
toggles self.not_undoable_action"""
self.not_undoable_action = False
+ def on_key_press_event(self, widget, event):
+ if widget == self and not self.can_delete:
+ return event.keyval == Gdk.KEY_BackSpace or event.keyval == Gdk.KEY_Delete
+ else:
+ return False
+
def set_italic(self, _widget, _data=None):
"""Ctrl + I"""
self.format_shortcuts.italic()
diff --git a/uberwriter/UberwriterWindow.py b/uberwriter/UberwriterWindow.py
index 0b3fa87..188e857 100644
--- a/uberwriter/UberwriterWindow.py
+++ b/uberwriter/UberwriterWindow.py
@@ -14,23 +14,25 @@
# 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
+from gi.repository import Gtk, Gdk, GObject, GLib, Gio
from gi.repository import WebKit2 as WebKit
from gi.repository import Pango # pylint: disable=E0611
@@ -113,7 +115,7 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.accel_group = Gtk.AccelGroup()
self.add_accel_group(self.accel_group)
- # Setup light background
+ # Setup text editor
self.text_editor = TextEditor()
self.text_editor.set_name('UberwriterEditor')
self.get_style_context().add_class('uberwriter_window')
@@ -143,6 +145,9 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.text_editor.show()
self.text_editor.grab_focus()
+ # Setup preview webview
+ self.preview_webview = None
+
self.editor_alignment = self.builder.get_object('editor_alignment')
self.scrolled_window = self.builder.get_object('editor_scrolledwindow')
self.scrolled_window.props.width_request = 600
@@ -150,7 +155,7 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.alignment_padding = 40
self.editor_viewport = self.builder.get_object('editor_viewport')
- # some people seems to have performance problems with the overlay.
+ # some people seems to have performance problems with the overlay.
# Let them disable it
if self.settings.get_value("gradient-overlay"):
@@ -178,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
@@ -263,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:
@@ -349,7 +358,7 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.update_line_and_char_count()
self.check_scroll(self.text_buffer.get_insert())
- def toggle_fullscreen(self, state):
+ def set_fullscreen(self, state):
"""Puts the application in fullscreen mode and show/hides
the poller for motion in the top border
@@ -367,7 +376,7 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.text_editor.grab_focus()
- def set_focusmode(self, state):
+ def set_focus_mode(self, state):
"""toggle focusmode
"""
@@ -384,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,
@@ -399,6 +408,12 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.spell_checker._misspelled.set_property('underline', 4)
_click_event = self.text_editor.disconnect(self.click_event)
+ def set_hemingway_mode(self, state):
+ """toggle hemingwaymode
+ """
+ self.text_editor.can_delete = not state.get_boolean()
+ self.text_editor.grab_focus()
+
def on_focusmode_click(self, *_args):
"""call MarkupBuffer to mark as bold the line where the cursor is
"""
@@ -484,8 +499,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
@@ -495,8 +510,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
@@ -505,9 +520,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")
@@ -818,7 +833,7 @@ class UberwriterWindow(Gtk.ApplicationWindow):
self.present()
return False
- def toggle_preview(self, state, opts):
+ def toggle_preview(self, state):
"""Toggle the preview mode
Arguments:
@@ -826,7 +841,27 @@ class UberwriterWindow(Gtk.ApplicationWindow):
"""
if state.get_boolean():
+ self.show_preview()
+ else:
+ self.show_text_editor()
+ return True
+
+ def show_text_editor(self):
+ self.scrolled_window.remove(self.scrolled_window.get_child())
+ self.scrolled_window.add(self.text_editor)
+ self.text_editor.show()
+ self.preview_webview.destroy()
+ self.preview_webview = None
+ self.queue_draw()
+
+ def show_preview(self, loaded=False):
+ if loaded:
+ self.scrolled_window.remove(self.scrolled_window.get_child())
+ self.scrolled_window.add(self.preview_webview)
+ self.preview_webview.show()
+ self.queue_draw()
+ else:
# Insert a tag with ID to scroll to
# self.TextBuffer.insert_at_cursor('')
# TODO
@@ -841,81 +876,44 @@ 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,
+ '--quiet',
+ '--lua-filter=' + helpers.get_script_path('relative_to_absolute.lua'),
'--lua-filter=' + helpers.get_script_path('task-list.lua')]
+ # TODO: find a way to pass something like this instead of the quiet arg
+ #'--metadata pagetitle="test"',
+
proc = subprocess.Popen(
args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
text = bytes(self.get_text(), "utf-8")
output = proc.communicate(text)[0]
- # Load in Webview and scroll to #ID
- self.preview_webview = WebKit.WebView()
- webview_settings = self.preview_webview.get_settings()
- webview_settings.set_allow_universal_access_from_file_urls(
- True)
- webview_settings.set_enable_developer_extras(opts.debug)
+ if self.preview_webview is None:
+ self.preview_webview = WebKit.WebView()
+ self.preview_webview.get_settings().set_allow_universal_access_from_file_urls(True)
+
+ # Delete the cursor-scroll mark again
+ # cursor_iter = self.TextBuffer.get_iter_at_mark(self.TextBuffer.get_insert())
+ # begin_del = cursor_iter.copy()
+ # begin_del.backward_chars(30)
+ # self.TextBuffer.delete(begin_del, cursor_iter)
+
+ # Show preview once the load is finished
+ self.preview_webview.connect("load-changed", self.on_preview_load_change)
+
+ # This saying that all links will be opened in default browser, \
+ # but local files are opened in appropriate apps:
+ self.preview_webview.connect("decide-policy", self.on_click_link)
+
self.preview_webview.load_html(output.decode("utf-8"), 'file://localhost/')
- # Delete the cursor-scroll mark again
- # cursor_iter = self.TextBuffer.get_iter_at_mark(self.TextBuffer.get_insert())
- # begin_del = cursor_iter.copy()
- # begin_del.backward_chars(30)
- # self.TextBuffer.delete(begin_del, cursor_iter)
-
- self.scrolled_window.remove(self.text_editor)
- self.scrolled_window.add(self.preview_webview)
- self.preview_webview.show()
-
- # This saying that all links will be opened in default browser, \
- # but local files are opened in appropriate apps:
- self.preview_webview.connect("decide-policy", self.on_click_link)
- else:
- self.scrolled_window.remove(self.preview_webview)
- self.preview_webview.destroy()
- self.scrolled_window.add(self.text_editor)
- self.text_editor.show()
-
- self.queue_draw()
- return True
-
- 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)
-
- # 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:
@@ -1125,6 +1123,12 @@ class UberwriterWindow(Gtk.ApplicationWindow):
base_path = "/"
self.settings.set_value("open-file-path", GLib.Variant("s", base_path))
+ def on_preview_load_change(self, webview, event):
+ """swaps text editor with preview once the load is complete
+ """
+ if event == WebKit.LoadEvent.FINISHED:
+ self.show_preview(loaded=True)
+
def on_click_link(self, web_view, decision, _decision_type):
"""provide ability for self.webview to open links in default browser
"""
diff --git a/uberwriter_lib/AppWindow.py b/uberwriter_lib/AppWindow.py
index 060dbc5..f286761 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)
@@ -95,6 +72,12 @@ class Application(Gtk.Application):
action.connect("change-state", self.on_focus_mode)
self.add_action(action)
+ action = Gio.SimpleAction.new_stateful("hemingway_mode",
+ None,
+ GLib.Variant.new_boolean(False))
+ action.connect("change-state", self.on_hemingway_mode)
+ self.add_action(action)
+
action = Gio.SimpleAction.new_stateful("fullscreen",
None,
GLib.Variant.new_boolean(False))
@@ -166,6 +149,7 @@ class Application(Gtk.Application):
# Shortcuts
self.set_accels_for_action("app.focus_mode", ["d"])
+ self.set_accels_for_action("app.hemingway_mode", ["t"])
self.set_accels_for_action("app.fullscreen", ["F11"])
self.set_accels_for_action("app.preview", ["p"])
self.set_accels_for_action("app.search", ["f"])
@@ -176,7 +160,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
@@ -202,10 +186,6 @@ class Application(Gtk.Application):
"-e", "--experimental-features", help=_("Use experimental features"),
action='store_true'
)
- parser.add_argument(
- "-d", "--debug", help=_("Debug options"), action='store_true',
- dest="debug"
- )
(self.options, self.args) = parser.parse_known_args()
set_up_logging(self.options)
@@ -213,6 +193,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")
@@ -238,26 +235,29 @@ 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)
- self.window.set_focusmode(value)
+ self.window.set_focus_mode(value)
+
+ def on_hemingway_mode(self, action, value):
+ action.set_state(value)
+ self.window.set_hemingway_mode(value)
def on_fullscreen(self, action, value):
action.set_state(value)
- self.window.toggle_fullscreen(value)
+ self.window.set_fullscreen(value)
def on_preview(self, action, value):
action.set_state(value)
- self.window.toggle_preview(value, self.options)
+ self.window.toggle_preview(value)
def on_search(self, _action, _value):
self.window.open_search_and_replace()
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):