forked from Mirrors/apostrophe
Improve full-width preview workflow
parent
dc0652e3ed
commit
86cffc40ec
|
@ -22,37 +22,11 @@
|
|||
/* Main window and text colors */
|
||||
|
||||
.uberwriter-window {
|
||||
/*border-radius: 7px 7px 3px 3px;*/
|
||||
background: @theme_base_color;
|
||||
color: @theme_fg_color;
|
||||
caret-color: @theme_fg_color;
|
||||
}
|
||||
|
||||
.uberwriter-window .uberwriter-editor {
|
||||
font-family: 'Fira Mono', monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.uberwriter-window .uberwriter-editor.size14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uberwriter-window .uberwriter-editor.size15 {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.uberwriter-window .uberwriter-editor.size16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.uberwriter-window .uberwriter-editor.size17 {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.uberwriter-window .uberwriter-editor.size18 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#titlebar-revealer {
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -67,10 +41,32 @@
|
|||
}
|
||||
|
||||
.uberwriter-editor {
|
||||
-gtk-key-bindings: editor-bindings;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
text-decoration-color: @error_color;
|
||||
-gtk-key-bindings: editor-bindings;
|
||||
font-family: 'Fira Mono', monospace;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.uberwriter-editor.size14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uberwriter-editor.size15 {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.uberwriter-editor.size16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.uberwriter-editor.size17 {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.uberwriter-editor.size18 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.uberwriter-editor text {
|
||||
|
@ -96,9 +92,8 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.toggle-button {
|
||||
.inline-button {
|
||||
color: alpha(@theme_fg_color, 0.6);
|
||||
background-color: @theme_base_color;
|
||||
text-shadow: inherit;
|
||||
box-shadow: initial;
|
||||
background-clip: initial;
|
||||
|
@ -116,8 +111,8 @@
|
|||
transition: 100ms ease-in;
|
||||
}
|
||||
|
||||
.toggle-button:hover,
|
||||
.toggle-button:checked {
|
||||
.inline-button:hover,
|
||||
.inline-button:checked {
|
||||
color: @theme_fg_color;
|
||||
background-color: mix(@theme_base_color, @theme_bg_color, 0.5);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<property name="image_position">right</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<style>
|
||||
<class name="toggle-button"/>
|
||||
<class name="inline-button"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
<property name="image_position">right</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<style>
|
||||
<class name="toggle-button"/>
|
||||
<class name="inline-button"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -19,7 +19,7 @@ import gi
|
|||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
|
||||
from uberwriter import window
|
||||
from uberwriter import main_window
|
||||
from uberwriter import application
|
||||
from uberwriter.helpers import set_up_logging
|
||||
from uberwriter.config import get_version
|
||||
|
|
|
@ -15,10 +15,12 @@ from gettext import gettext as _
|
|||
|
||||
import gi
|
||||
|
||||
from uberwriter.main_window import MainWindow
|
||||
|
||||
gi.require_version('Gtk', '3.0') # pylint: disable=wrong-import-position
|
||||
from gi.repository import GLib, Gio, Gtk, GdkPixbuf
|
||||
|
||||
from uberwriter import window
|
||||
from uberwriter import main_window
|
||||
from uberwriter.settings import Settings
|
||||
from uberwriter.helpers import set_up_logging
|
||||
from uberwriter.preferences_dialog import PreferencesDialog
|
||||
|
@ -155,7 +157,7 @@ class Application(Gtk.Application):
|
|||
# Windows are associated with the application
|
||||
# when the last one is closed the application shuts down
|
||||
# self.window = Window(application=self, title="UberWriter")
|
||||
self.window = window.Window(self)
|
||||
self.window = MainWindow(self)
|
||||
if self.args:
|
||||
self.window.load_file(self.args[0])
|
||||
|
||||
|
|
|
@ -48,8 +48,32 @@ class MainHeaderbar: #pylint: disable=too-few-public-methods
|
|||
self.hb_container.add(self.hb_revealer)
|
||||
self.hb_container.show()
|
||||
|
||||
self.btns = buttons(app)
|
||||
pack_buttons(self.hb, self.btns)
|
||||
self.btns = main_buttons(app)
|
||||
pack_main_buttons(self.hb, self.btns)
|
||||
|
||||
self.hb.show_all()
|
||||
|
||||
|
||||
class PreviewHeaderbar:
|
||||
"""Sets up the preview headerbar
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.hb = Gtk.HeaderBar().new()
|
||||
self.hb.props.show_close_button = True
|
||||
self.hb.get_style_context().add_class("titlebar")
|
||||
|
||||
self.hb_revealer = Gtk.Revealer(name="titlebar-revealer")
|
||||
self.hb_revealer.add(self.hb)
|
||||
self.hb_revealer.props.transition_duration = 750
|
||||
self.hb_revealer.props.transition_type = Gtk.RevealerTransitionType.CROSSFADE
|
||||
self.hb_revealer.show()
|
||||
self.hb_revealer.set_reveal_child(True)
|
||||
|
||||
self.hb_container = Gtk.Frame(name="titlebar-container")
|
||||
self.hb_container.set_shadow_type(Gtk.ShadowType.NONE)
|
||||
self.hb_container.add(self.hb_revealer)
|
||||
self.hb_container.show()
|
||||
|
||||
self.hb.show_all()
|
||||
|
||||
|
@ -70,14 +94,14 @@ class FullscreenHeaderbar:
|
|||
self.hb.show()
|
||||
self.events.hide()
|
||||
|
||||
self.btns = buttons(app)
|
||||
self.btns = main_buttons(app)
|
||||
|
||||
fs_btn_exit = Gtk.Button().new_from_icon_name("view-restore-symbolic",
|
||||
Gtk.IconSize.BUTTON)
|
||||
fs_btn_exit.set_tooltip_text(_("Exit Fullscreen"))
|
||||
fs_btn_exit.set_action_name("app.fullscreen")
|
||||
|
||||
pack_buttons(self.hb, self.btns, fs_btn_exit)
|
||||
pack_main_buttons(self.hb, self.btns, fs_btn_exit)
|
||||
|
||||
self.hb.show_all()
|
||||
|
||||
|
@ -101,7 +125,8 @@ class FullscreenHeaderbar:
|
|||
else:
|
||||
self.revealer.set_reveal_child(False)
|
||||
|
||||
def buttons(app):
|
||||
|
||||
def main_buttons(app):
|
||||
"""constructor for the headerbar buttons
|
||||
|
||||
Returns:
|
||||
|
@ -154,7 +179,7 @@ def buttons(app):
|
|||
return btn
|
||||
|
||||
|
||||
def pack_buttons(headerbar, btn, btn_exit=None):
|
||||
def pack_main_buttons(headerbar, btn, btn_exit=None):
|
||||
"""Pack the given buttons in the given headerbar
|
||||
|
||||
Arguments:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# END LICENSE
|
||||
|
||||
import codecs
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import urllib
|
||||
|
@ -25,6 +26,7 @@ import gi
|
|||
from uberwriter.export_dialog import Export
|
||||
from uberwriter.preview_handler import PreviewHandler
|
||||
from uberwriter.stats_handler import StatsHandler
|
||||
from uberwriter.styled_window import StyledWindow
|
||||
from uberwriter.text_view import TextView
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
|
@ -51,7 +53,7 @@ LOGGER = logging.getLogger('uberwriter')
|
|||
CONFIG_PATH = os.path.expanduser("~/.config/uberwriter/")
|
||||
|
||||
|
||||
class Window(Gtk.ApplicationWindow):
|
||||
class MainWindow(StyledWindow):
|
||||
__gsignals__ = {
|
||||
'save-file': (GObject.SIGNAL_ACTION, None, ()),
|
||||
'open-file': (GObject.SIGNAL_ACTION, None, ()),
|
||||
|
@ -65,14 +67,13 @@ class Window(Gtk.ApplicationWindow):
|
|||
def __init__(self, app):
|
||||
"""Set up the main window"""
|
||||
|
||||
Gtk.ApplicationWindow.__init__(self,
|
||||
application=Gio.Application.get_default(),
|
||||
title="Uberwriter")
|
||||
super().__init__(application=Gio.Application.get_default(), title="Uberwriter")
|
||||
|
||||
self.get_style_context().add_class('uberwriter-window')
|
||||
|
||||
# Set UI
|
||||
builder = get_builder('Window')
|
||||
root = builder.get_object("FullscreenOverlay")
|
||||
root.connect('style-updated', self.apply_current_theme)
|
||||
self.connect("delete-event", self.on_delete_called)
|
||||
self.add(root)
|
||||
|
||||
|
@ -150,34 +151,6 @@ class Window(Gtk.ApplicationWindow):
|
|||
###
|
||||
self.searchreplace = SearchAndReplace(self, self.text_view, builder)
|
||||
|
||||
# Set current theme
|
||||
self.apply_current_theme()
|
||||
self.get_style_context().add_class('uberwriter-window')
|
||||
|
||||
def apply_current_theme(self, *_):
|
||||
"""Adjusts the window, CSD and preview for the current theme.
|
||||
"""
|
||||
# Get current theme
|
||||
theme, changed = Theme.get_current_changed()
|
||||
if changed:
|
||||
# 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(helpers.get_css_path("gtk/base.css"))
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
self.get_screen(), style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
# Reload preview if it exists
|
||||
self.reload_preview()
|
||||
|
||||
# Redraw contents of window
|
||||
self.queue_draw()
|
||||
|
||||
def on_text_changed(self, *_args):
|
||||
"""called when the text changes, sets the self.did_change to true and
|
||||
updates the title and the counters to reflect that
|
||||
|
@ -534,15 +507,10 @@ class Window(Gtk.ApplicationWindow):
|
|||
True -- Gtk things
|
||||
"""
|
||||
|
||||
if (self.was_motion is False
|
||||
and self.top_bottom_bars_visible
|
||||
if (not self.was_motion
|
||||
and self.buffer_modified_for_status_bar
|
||||
and self.text_view.props.has_focus): # pylint: disable=no-member
|
||||
# self.status_bar.set_state_flags(Gtk.StateFlags.INSENSITIVE, True)
|
||||
self.stats_revealer.set_reveal_child(False)
|
||||
self.headerbar.hb_revealer.set_reveal_child(False)
|
||||
self.top_bottom_bars_visible = False
|
||||
self.buffer_modified_for_status_bar = False
|
||||
and self.text_view.props.has_focus):
|
||||
self.reveal_top_bottom_bars(False)
|
||||
|
||||
self.was_motion = False
|
||||
return True
|
||||
|
@ -560,24 +528,22 @@ class Window(Gtk.ApplicationWindow):
|
|||
return
|
||||
if now - self.timestamp_last_mouse_motion > 100:
|
||||
# react on motion by fading in headerbar and statusbar
|
||||
if self.top_bottom_bars_visible is False:
|
||||
self.stats_revealer.set_reveal_child(True)
|
||||
self.headerbar.hb_revealer.set_reveal_child(True)
|
||||
self.headerbar.hb.props.opacity = 1
|
||||
self.top_bottom_bars_visible = True
|
||||
self.buffer_modified_for_status_bar = False
|
||||
# self.status_bar.set_state_flags(Gtk.StateFlags.NORMAL, True)
|
||||
self.reveal_top_bottom_bars(True)
|
||||
self.was_motion = True
|
||||
|
||||
def focus_out(self, _widget, _data=None):
|
||||
"""events called when the window losses focus
|
||||
"""
|
||||
if self.top_bottom_bars_visible is False:
|
||||
self.stats_revealer.set_reveal_child(True)
|
||||
self.headerbar.hb_revealer.set_reveal_child(True)
|
||||
self.headerbar.hb.props.opacity = 1
|
||||
self.top_bottom_bars_visible = True
|
||||
self.buffer_modified_for_status_bar = False
|
||||
self.reveal_top_bottom_bars(True)
|
||||
|
||||
def reveal_top_bottom_bars(self, reveal):
|
||||
if self.top_bottom_bars_visible != reveal:
|
||||
self.headerbar.hb_revealer.set_reveal_child(reveal)
|
||||
self.stats_revealer.set_reveal_child(reveal)
|
||||
for revealer in self.preview_handler.get_top_bottom_bar_revealers():
|
||||
revealer.set_reveal_child(reveal)
|
||||
self.top_bottom_bars_visible = reveal
|
||||
self.buffer_modified_for_status_bar = reveal
|
||||
|
||||
def draw_gradient(self, _widget, cr):
|
||||
"""draw fading gradient over the top and the bottom of the
|
|
@ -8,7 +8,7 @@ from uberwriter.helpers import get_builder
|
|||
from uberwriter.preview_renderer import PreviewRenderer
|
||||
|
||||
gi.require_version('WebKit2', '4.0')
|
||||
from gi.repository import WebKit2
|
||||
from gi.repository import WebKit2, GLib
|
||||
|
||||
from uberwriter.preview_converter import PreviewConverter
|
||||
from uberwriter.web_view import WebView
|
||||
|
@ -35,10 +35,13 @@ class PreviewHandler:
|
|||
builder = get_builder("Preview")
|
||||
preview = builder.get_object("preview")
|
||||
mode_button = builder.get_object("preview_mode_button")
|
||||
self.mode_revealer = builder.get_object("preview_mode_revealer")
|
||||
|
||||
self.preview_converter = PreviewConverter()
|
||||
self.preview_renderer = PreviewRenderer(
|
||||
window, content, editor, text_view, preview, mode_button)
|
||||
window, content, editor, text_view, preview, self.mode_revealer, mode_button)
|
||||
|
||||
window.connect("style-updated", self.reload)
|
||||
|
||||
self.web_scroll_handler_id = None
|
||||
self.text_scroll_handler_id = None
|
||||
|
@ -83,18 +86,18 @@ class PreviewHandler:
|
|||
return
|
||||
self.shown = True
|
||||
|
||||
self.web_view.set_scroll_scale(self.text_view.get_scroll_scale())
|
||||
|
||||
self.text_changed_handler_id =\
|
||||
self.text_view.get_buffer().connect("changed", self.__show)
|
||||
self.web_scroll_handler_id =\
|
||||
self.web_view.connect("scroll-scale-changed", self.on_web_view_scrolled)
|
||||
self.text_scroll_handler_id =\
|
||||
self.text_view.connect("scroll-scale-changed", self.on_text_view_scrolled)
|
||||
GLib.idle_add(self.web_view.set_scroll_scale, self.text_view.get_scroll_scale())
|
||||
|
||||
self.preview_renderer.show(self.web_view)
|
||||
|
||||
def reload(self):
|
||||
self.text_changed_handler_id = \
|
||||
self.text_view.get_buffer().connect("changed", self.__show)
|
||||
self.web_scroll_handler_id = \
|
||||
self.web_view.connect("scroll-scale-changed", self.on_web_view_scrolled)
|
||||
self.text_scroll_handler_id = \
|
||||
self.text_view.connect("scroll-scale-changed", self.on_text_view_scrolled)
|
||||
|
||||
def reload(self, *_):
|
||||
if self.shown:
|
||||
self.show()
|
||||
|
||||
|
@ -102,14 +105,14 @@ class PreviewHandler:
|
|||
if self.shown:
|
||||
self.shown = False
|
||||
|
||||
self.text_view.set_scroll_scale(self.web_view.get_scroll_scale())
|
||||
GLib.idle_add(self.text_view.set_scroll_scale, self.web_view.get_scroll_scale())
|
||||
|
||||
self.preview_renderer.hide(self.web_view)
|
||||
|
||||
self.text_view.get_buffer().disconnect(self.text_changed_handler_id)
|
||||
self.text_view.disconnect(self.text_scroll_handler_id)
|
||||
self.web_view.disconnect(self.web_scroll_handler_id)
|
||||
|
||||
self.preview_renderer.hide(self.web_view)
|
||||
|
||||
if self.loading:
|
||||
self.loading = False
|
||||
|
||||
|
@ -119,6 +122,12 @@ class PreviewHandler:
|
|||
def update_preview_mode(self):
|
||||
self.preview_renderer.update_mode(self.web_view)
|
||||
|
||||
def get_top_bottom_bar_revealers(self):
|
||||
if self.shown and not self.preview_renderer.window:
|
||||
return [self.mode_revealer]
|
||||
else:
|
||||
return []
|
||||
|
||||
def on_load_changed(self, _web_view, event):
|
||||
if event == WebKit2.LoadEvent.FINISHED:
|
||||
self.loading = False
|
||||
|
@ -133,7 +142,8 @@ class PreviewHandler:
|
|||
self.web_view.set_scroll_scale(scale)
|
||||
|
||||
def on_web_view_scrolled(self, _web_view, scale):
|
||||
if self.shown and not math.isclose(scale, self.text_view.get_scroll_scale(), rel_tol=1e-5):
|
||||
if self.shown and self.text_view.get_mapped() and \
|
||||
not math.isclose(scale, self.text_view.get_scroll_scale(), rel_tol=1e-5):
|
||||
self.text_view.set_scroll_scale(scale)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -2,7 +2,9 @@ from gettext import gettext as _
|
|||
|
||||
from gi.repository import Gtk, Gio, GLib
|
||||
|
||||
from uberwriter import headerbars
|
||||
from uberwriter.settings import Settings
|
||||
from uberwriter.styled_window import StyledWindow
|
||||
|
||||
|
||||
class PreviewRenderer:
|
||||
|
@ -14,99 +16,126 @@ class PreviewRenderer:
|
|||
HALF_HEIGHT = 2
|
||||
WINDOWED = 3
|
||||
|
||||
def __init__(self, main_window, content, editor, text_view, preview, mode_button):
|
||||
def __init__(
|
||||
self, main_window, content, editor, text_view, preview, mode_revealer, mode_button):
|
||||
self.content = content
|
||||
self.editor = editor
|
||||
self.text_view = text_view
|
||||
self.preview = preview
|
||||
self.mode_revealer = mode_revealer
|
||||
self.mode_button = mode_button
|
||||
self.mode_button.connect("clicked", self.show_mode_popover)
|
||||
self.popover = None
|
||||
self.settings = Settings.new()
|
||||
self.main_window = main_window
|
||||
self.main_window.connect("delete-event", self.on_window_closed)
|
||||
self.window = None
|
||||
self.headerbar = None
|
||||
self.mode = self.settings.get_enum("preview-mode")
|
||||
|
||||
self.update_mode()
|
||||
|
||||
def show(self, web_view):
|
||||
"""Show the preview, depending on the currently selected mode."""
|
||||
|
||||
self.preview.pack_start(web_view, True, True, 0)
|
||||
|
||||
# Full-width preview: swap editor with preview.
|
||||
if self.mode == self.FULL_WIDTH:
|
||||
self.content.remove(self.editor)
|
||||
self.content.add(self.preview)
|
||||
|
||||
# Half-width preview: set horizontal orientation and add the preview.
|
||||
# Ask for a minimum width that respects the editor's minimum requirements.
|
||||
elif self.mode == self.HALF_WIDTH:
|
||||
self.content.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.content.set_size_request(self.text_view.get_min_width() * 2, -1)
|
||||
self.content.add(self.preview)
|
||||
|
||||
# Half-height preview: set vertical orientation and add the preview.
|
||||
# Ask for a minimum height that provides a comfortable experience.
|
||||
elif self.mode == self.HALF_HEIGHT:
|
||||
self.content.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.content.set_size_request(-1, 768)
|
||||
self.content.add(self.preview)
|
||||
|
||||
# Windowed preview: create a window and show the preview in it.
|
||||
elif self.mode == self.WINDOWED:
|
||||
self.window = Gtk.Window(title=_("Preview"))
|
||||
self.window.set_application(self.main_window.get_application())
|
||||
self.window.set_default_size(
|
||||
self.main_window.get_allocated_width(), self.main_window.get_allocated_height())
|
||||
self.window.set_transient_for(self.main_window)
|
||||
self.window.set_modal(False)
|
||||
self.window.add(self.preview)
|
||||
if self.mode == self.WINDOWED:
|
||||
# Create transient window of the main window.
|
||||
self.window = StyledWindow(application=self.main_window.get_application())
|
||||
self.window.connect("delete-event", self.on_window_closed)
|
||||
|
||||
# Create a custom header bar and move the mode button there.
|
||||
headerbar = headerbars.PreviewHeaderbar()
|
||||
self.headerbar = headerbar.hb
|
||||
self.headerbar.set_title(_("Preview"))
|
||||
self.mode_button.get_style_context().remove_class("inline-button")
|
||||
self.mode_revealer.remove(self.mode_button)
|
||||
self.headerbar.pack_end(self.mode_button)
|
||||
self.window.set_titlebar(headerbar.hb_container)
|
||||
|
||||
# Position it next to the main window.
|
||||
width, height = self.main_window.get_size()
|
||||
self.window.resize(width, height)
|
||||
x, y = self.main_window.get_position()
|
||||
if x is not None and y is not None:
|
||||
self.main_window.move(x, y)
|
||||
self.window.move(x + width + 16, y)
|
||||
|
||||
# Add webview and show.
|
||||
self.window.add(web_view)
|
||||
self.window.show()
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown preview mode {}".format(self.mode))
|
||||
self.preview.pack_start(web_view, True, True, 0)
|
||||
self.content.add(self.preview)
|
||||
|
||||
# Full-width preview: swap editor with preview.
|
||||
if self.mode == self.FULL_WIDTH:
|
||||
self.content.remove(self.editor)
|
||||
|
||||
# Half-width preview: set horizontal orientation and add the preview.
|
||||
# Ask for a minimum width that respects the editor's minimum requirements.
|
||||
elif self.mode == self.HALF_WIDTH:
|
||||
self.content.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.content.set_size_request(self.text_view.get_min_width() * 2, -1)
|
||||
|
||||
# Half-height preview: set vertical orientation and add the preview.
|
||||
# Ask for a minimum height that provides a comfortable experience.
|
||||
elif self.mode == self.HALF_HEIGHT:
|
||||
self.content.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.content.set_size_request(-1, 768)
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown preview mode {}".format(self.mode))
|
||||
|
||||
web_view.show()
|
||||
|
||||
def hide(self, web_view):
|
||||
"""Hide the preview, depending on the currently selected mode."""
|
||||
|
||||
self.preview.remove(web_view)
|
||||
|
||||
# Full-width preview: swap preview with editor.
|
||||
if self.mode == self.FULL_WIDTH:
|
||||
self.content.remove(self.preview)
|
||||
self.content.add(self.editor)
|
||||
|
||||
# Half-width/height previews: remove preview and reset size requirements.
|
||||
elif self.mode == self.HALF_WIDTH or self.mode == self.HALF_HEIGHT:
|
||||
self.content.remove(self.preview)
|
||||
self.content.set_size_request(-1, -1)
|
||||
|
||||
# Windowed preview: remove preview and destroy window.
|
||||
elif self.mode == self.WINDOWED:
|
||||
self.window.remove(self.preview)
|
||||
if self.mode == self.WINDOWED:
|
||||
self.main_window.present()
|
||||
self.headerbar.remove(self.mode_button)
|
||||
self.mode_button.get_style_context().add_class("inline-button")
|
||||
self.mode_revealer.add(self.mode_button)
|
||||
self.headerbar = None
|
||||
self.window.remove(web_view)
|
||||
self.window.destroy()
|
||||
self.window = None
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown preview mode {}".format(self.mode))
|
||||
self.preview.remove(web_view)
|
||||
self.content.remove(self.preview)
|
||||
|
||||
def update_mode(self, web_view):
|
||||
# Full-width preview: swap preview with editor.
|
||||
if self.mode == self.FULL_WIDTH:
|
||||
self.content.add(self.editor)
|
||||
|
||||
# Half-width/height previews: remove preview and reset size requirements.
|
||||
elif self.mode == self.HALF_WIDTH or self.mode == self.HALF_HEIGHT:
|
||||
self.content.set_size_request(-1, -1)
|
||||
|
||||
else:
|
||||
raise ValueError("Unknown preview mode {}".format(self.mode))
|
||||
|
||||
def update_mode(self, web_view=None):
|
||||
"""Update preview mode, adjusting the mode button and the preview itself."""
|
||||
|
||||
mode = self.settings.get_enum("preview-mode")
|
||||
if mode != self.mode:
|
||||
if web_view:
|
||||
self.hide(web_view)
|
||||
self.mode = mode
|
||||
self.show(web_view)
|
||||
if web_view and mode != self.mode:
|
||||
self.hide(web_view)
|
||||
self.mode = mode
|
||||
self.show(web_view)
|
||||
else:
|
||||
self.mode = mode
|
||||
if self.mode_button:
|
||||
text = self.get_text_for_preview_mode(self.mode)
|
||||
self.mode_button.set_label(text)
|
||||
if self.popover:
|
||||
self.popover.popdown()
|
||||
if self.popover:
|
||||
self.popover.popdown()
|
||||
|
||||
def show_mode_popover(self, _button):
|
||||
def show_mode_popover(self, button):
|
||||
"""Show preview mode popover."""
|
||||
|
||||
self.mode_button.set_state_flags(Gtk.StateFlags.CHECKED, False)
|
||||
|
@ -117,7 +146,7 @@ class PreviewRenderer:
|
|||
menu_item = Gio.MenuItem.new(self.get_text_for_preview_mode(i), None)
|
||||
menu_item.set_action_and_target_value("app.preview_mode", GLib.Variant.new_string(mode))
|
||||
menu.append_item(menu_item)
|
||||
self.popover = Gtk.Popover.new_from_model(self.mode_button, menu)
|
||||
self.popover = Gtk.Popover.new_from_model(button, menu)
|
||||
self.popover.connect('closed', self.on_popover_closed)
|
||||
self.popover.popup()
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import gi
|
||||
|
||||
from uberwriter import helpers
|
||||
from uberwriter.theme import Theme
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GLib
|
||||
|
||||
|
||||
class StyledWindow(Gtk.ApplicationWindow):
|
||||
"""A window that will redraw itself upon theme changes."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.connect("style-updated", self.apply_current_theme)
|
||||
self.apply_current_theme()
|
||||
|
||||
def apply_current_theme(self, *_):
|
||||
"""Adjusts the window, CSD and preview for the current theme."""
|
||||
# Get current theme
|
||||
theme, changed = Theme.get_current_changed()
|
||||
if changed:
|
||||
# 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(helpers.get_css_path("gtk/base.css"))
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
self.get_screen(), style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
# Redraw contents of window
|
||||
self.queue_draw()
|
|
@ -1,6 +1,3 @@
|
|||
from gi.repository import Gtk
|
||||
|
||||
|
||||
class TextViewScroller:
|
||||
def __init__(self, text_view, scrolled_window):
|
||||
super().__init__()
|
||||
|
|
|
@ -37,10 +37,10 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
|
|||
self.connect("destroy", self.on_destroy)
|
||||
|
||||
self.scroll_scale = 0.0
|
||||
self.pending_scroll_scale = None
|
||||
|
||||
self.state_loaded = False
|
||||
self.state_load_failed = False
|
||||
self.state_dirty = False
|
||||
self.state_waiting = False
|
||||
|
||||
self.timeout_id = None
|
||||
|
@ -49,13 +49,13 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
|
|||
return self.scroll_scale
|
||||
|
||||
def set_scroll_scale(self, scale):
|
||||
self.state_dirty = True
|
||||
self.scroll_scale = scale
|
||||
self.pending_scroll_scale = scale
|
||||
self.state_loop()
|
||||
|
||||
def on_load_changed(self, _web_view, event):
|
||||
self.state_loaded = event >= WebKit2.LoadEvent.COMMITTED and not self.state_load_failed
|
||||
self.state_load_failed = False
|
||||
self.pending_scroll_scale = self.scroll_scale
|
||||
self.state_loop()
|
||||
|
||||
def on_load_failed(self, _web_view, _event):
|
||||
|
@ -72,10 +72,9 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
|
|||
self.run_javascript(
|
||||
self.GET_SCROLL_SCALE_JS, None, self.sync_scroll_scale)
|
||||
|
||||
def write_scroll_scale(self):
|
||||
self.state_dirty = False
|
||||
def write_scroll_scale(self, scroll_scale):
|
||||
self.run_javascript(
|
||||
self.SET_SCROLL_SCALE_JS.format(self.scroll_scale), None, None)
|
||||
self.SET_SCROLL_SCALE_JS.format(scroll_scale), None, None)
|
||||
|
||||
def sync_scroll_scale(self, _web_view, result):
|
||||
self.state_waiting = False
|
||||
|
@ -96,9 +95,11 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
|
|||
# Handle the current state
|
||||
if not self.state_loaded or self.state_load_failed or self.state_waiting:
|
||||
return
|
||||
if self.state_dirty:
|
||||
self.write_scroll_scale()
|
||||
if delay > 0:
|
||||
if self.pending_scroll_scale:
|
||||
self.write_scroll_scale(self.pending_scroll_scale)
|
||||
self.pending_scroll_scale = None
|
||||
self.read_scroll_scale()
|
||||
elif delay > 0:
|
||||
self.timeout_id = GLib.timeout_add(delay, self.state_loop, None, 0)
|
||||
else:
|
||||
self.read_scroll_scale()
|
||||
|
|
Loading…
Reference in New Issue