Add support for side-by-side preview

Fixes #59
github/fork/yochananmarqos/patch-1
Gonçalo Silva 2019-04-22 02:19:57 +01:00
parent bc23fa9b0b
commit 5e770510ee
5 changed files with 128 additions and 99 deletions

View File

@ -76,6 +76,13 @@
Maximum number of characters per line within the editor.
</description>
</key>
<key name='preview-side-by-side' type='b'>
<default>false</default>
<summary>Side-by-side preview</summary>
<description>
Show the preview side by side, instead of full-width.
</description>
</key>
</schema>

View File

@ -96,7 +96,7 @@
padding: 0;
}
.stats-counter {
.stats-button {
color: alpha(@theme_fg_color, 0.6);
background-color: @theme_base_color;
text-shadow: inherit;
@ -116,8 +116,8 @@
transition: 100ms ease-in;
}
.stats-counter:hover,
.stats-counter:checked {
.stats-button :hover,
.stats-button :checked {
color: @theme_fg_color;
background-color: mix(@theme_base_color, @theme_bg_color, 0.5);
}

View File

@ -8,32 +8,32 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkImage" id="amunt">
<object class="GtkImage" id="edit-find-replace">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-replace-symbolic</property>
</object>
<object class="GtkImage" id="go-up">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-up-symbolic</property>
</object>
<object class="GtkImage" id="avall">
<object class="GtkImage" id="go_down">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-down-symbolic</property>
</object>
<object class="GtkImage" id="ortografia1">
<object class="GtkImage" id="pan-down">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">pan-down-symbolic</property>
<property name="icon_size">2</property>
</object>
<object class="GtkImage" id="spell-check">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-spell-check</property>
</object>
<object class="GtkRecentFilter" id="recentfilter1">
<mime-types>
<mime-type>text/plain</mime-type>
<mime-type>text/x-markdown</mime-type>
</mime-types>
</object>
<object class="GtkImage" id="reemplaza">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-replace-symbolic</property>
</object>
<object class="GtkOverlay" id="FullscreenOverlay">
<property name="name">FullscreenOverlay</property>
<property name="visible">True</property>
@ -43,10 +43,10 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkPaned" id="main_pained">
<object class="GtkPaned" id="main_paned">
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox" id="sidebar_box">
<property name="width_request">200</property>
@ -70,45 +70,17 @@
</packing>
</child>
<child>
<object class="GtkGrid" id="grid2">
<object class="GtkBox" id="content">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkRevealer" id="stats_counter_revealer">
<object class="GtkBox" id="editor">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">crossfade</property>
<property name="transition_duration">750</property>
<property name="reveal_child">True</property>
<child>
<object class="GtkButton" id="stats_counter">
<property name="label" translatable="yes">0 Words</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Show Statistics</property>
<property name="halign">end</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkViewport" id="editor_viewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="hscroll_policy">natural</property>
<property name="vscroll_policy">natural</property>
<property name="shadow_type">none</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="editor_scrolledwindow">
<property name="height_request">500</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@ -119,16 +91,52 @@
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRevealer" id="editor_stats_revealer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">crossfade</property>
<property name="transition_duration">750</property>
<property name="reveal_child">True</property>
<child>
<object class="GtkButton" id="editor_stats_button">
<property name="label" translatable="yes">0 Words</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Show Statistics</property>
<property name="halign">end</property>
<property name="image">pan-down</property>
<property name="image_position">right</property>
<property name="always_show_image">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="resize">False</property>
<property name="resize">True</property>
<property name="shrink">False</property>
</packing>
</child>
@ -191,7 +199,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Previous Match</property>
<property name="image">amunt</property>
<property name="image">go-up</property>
</object>
<packing>
<property name="expand">False</property>
@ -205,7 +213,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Next Match</property>
<property name="image">avall</property>
<property name="image">go_down</property>
</object>
<packing>
<property name="expand">False</property>
@ -264,7 +272,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Open Replace</property>
<property name="image">reemplaza</property>
<property name="image">edit-find-replace</property>
</object>
<packing>
<property name="expand">False</property>
@ -345,7 +353,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">ortografia1</property>
<property name="image">spell-check</property>
</object>
<packing>
<property name="expand">False</property>

View File

@ -12,6 +12,7 @@ gi.require_version('Gspell', '1')
from gi.repository import Gtk, Gdk, GObject, GLib, Gspell
import logging
LOGGER = logging.getLogger('uberwriter')
@ -53,8 +54,8 @@ class TextView(Gtk.TextView):
# Text sizing
self.props.halign = Gtk.Align.FILL
self.font_size = 16
self.line_chars = line_chars
self.font_size = 16
self.get_style_context().add_class('size16')
# General behavior
@ -133,10 +134,8 @@ class TextView(Gtk.TextView):
def on_parent_set(self, *_):
parent = self.get_parent()
if parent:
parent.set_size_request(self.get_min_width(), 500)
self.scroller = TextViewScroller(self, parent)
# Request a size that fits the minimum font size comfortably.
parent.set_size_request(
self.pad_chars(self.font_sizes[-1]) * self.font_width(self.font_sizes[-1]), 500)
else:
self.scroller = None
@ -169,18 +168,17 @@ class TextView(Gtk.TextView):
width = self.get_allocation().width
# Ensure the appropriate font size is being used
for size in self.font_sizes:
min_width = (self.line_chars + self.pad_chars(size) + 1) * self.font_width(size) - 1
if width >= min_width:
if size != self.font_size:
self.font_size = size
for s in self.font_sizes:
self.get_style_context().remove_class("size{}".format(s))
self.get_style_context().add_class("size{}".format(size))
for font_size in self.font_sizes:
if width >= self.get_min_width(font_size) or font_size == self.font_sizes[-1]:
if font_size != self.font_size:
self.font_size = font_size
for fs in self.font_sizes:
self.get_style_context().remove_class("size{}".format(fs))
self.get_style_context().add_class("size{}".format(font_size))
break
# Apply margin with the remaining space to allow for markup
line_width = (self.line_chars + 1) * int(self.font_width(self.font_size)) - 1
line_width = (self.line_chars + 1) * int(self.get_char_width(self.font_size)) - 1
horizontal_margin = (width - line_width) / 2
self.props.left_margin = horizontal_margin
self.props.right_margin = horizontal_margin
@ -224,15 +222,23 @@ class TextView(Gtk.TextView):
mark = self.get_buffer().get_insert()
GLib.idle_add(self.scroller.smooth_scroll_to_mark, mark, self.focus_mode)
def pad_chars(self, font_size):
def get_min_width(self, font_size=None):
"""Returns the minimum width of this text view."""
if font_size is None:
font_size = self.font_sizes[-1]
return (self.line_chars + self.get_pad_chars(font_size) + 1) \
* self.get_char_width(font_size) - 1
def get_pad_chars(self, font_size):
"""Returns the amount of character padding for font_size.
Markup can use up to 6 in normal conditions."""
Markup can use up to 7 in normal conditions."""
return 8 * (1 + font_size - self.font_sizes[-1])
@staticmethod
def font_width(font_size):
"""Returns the font width for a given size. Specific to Fira Mono."""
def get_char_width(font_size):
"""Returns the font width for a given size. Note: specific to Fira Mono!"""
return font_size * 1 / 1.6

View File

@ -101,29 +101,29 @@ class Window(Gtk.ApplicationWindow):
self.accel_group = Gtk.AccelGroup()
self.add_accel_group(self.accel_group)
self.content = self.builder.get_object('content')
self.scrolled_window = self.builder.get_object('editor_scrolledwindow')
self.scrolled_window.get_style_context().add_class('uberwriter-scrolled-window')
# Setup text editor
self.text_view = TextView()
self.text_view.props.halign = Gtk.Align.CENTER
self.text_view = TextView(self.settings.get_int("characters-per-line"))
self.text_view.connect('focus-out-event', self.focus_out)
self.text_view.get_buffer().connect('changed', self.on_text_changed)
self.text_view.show()
self.text_view.grab_focus()
self.scrolled_window.add(self.text_view)
# Stats stats counter
self.stats_revealer = self.builder.get_object('editor_stats_revealer')
self.stats_button = self.builder.get_object('editor_stats_button')
self.stats_button.get_style_context().add_class('stats-button')
self.stats_handler = StatsHandler(self.stats_button, self.text_view)
# Setup preview webview
self.web_view = None
self.web_view_scroller = None
self.scrolled_window = self.builder.get_object('editor_scrolledwindow')
self.scrolled_window.get_style_context().add_class('uberwriter-scrolled-window')
self.scrolled_window.add(self.text_view)
self.editor_viewport = self.builder.get_object('editor_viewport')
# Stats counter
self.stats_counter_revealer = self.builder.get_object('stats_counter_revealer')
self.stats_button = self.builder.get_object('stats_counter')
self.stats_button.get_style_context().add_class('stats-counter')
self.stats_handler = StatsHandler(self.stats_button, self.text_view)
# Setup header/stats bar hide after 3 seconds
self.top_bottom_bars_visible = True
self.was_motion = True
@ -145,7 +145,7 @@ class Window(Gtk.ApplicationWindow):
###
# Sidebar initialization test
###
self.paned_window = self.builder.get_object("main_pained")
self.paned_window = self.builder.get_object("main_paned")
self.sidebar_box = self.builder.get_object("sidebar_box")
self.sidebar = Sidebar(self)
self.sidebar_box.hide()
@ -466,10 +466,14 @@ class Window(Gtk.ApplicationWindow):
return True
def show_text_editor(self):
# Swap web view with text view
self.scrolled_window.remove(self.scrolled_window.get_child())
self.scrolled_window.add(self.text_view)
self.text_view.show()
# Remove web view
if self.settings.get_boolean("preview-side-by-side"):
self.set_size_request(-1, -1)
self.content.remove(self.web_view)
else:
self.scrolled_window.remove(self.scrolled_window.get_child())
self.scrolled_window.add(self.text_view)
self.text_view.show()
self.queue_draw()
# Sync scroll between web view and text view
@ -485,9 +489,13 @@ class Window(Gtk.ApplicationWindow):
# Sync scroll between text view and web view
self.web_view_scroller.set_scroll_scale(self.text_view.get_scroll_scale())
# Swap text view with web view
self.scrolled_window.remove(self.scrolled_window.get_child())
self.scrolled_window.add(self.web_view)
# Show web view
if self.settings.get_boolean("preview-side-by-side"):
self.content.add(self.web_view)
self.set_size_request(self.text_view.get_min_width() * 2, -1)
else:
self.scrolled_window.remove(self.scrolled_window.get_child())
self.scrolled_window.add(self.web_view)
self.web_view.show()
self.queue_draw()
else:
@ -590,7 +598,7 @@ class Window(Gtk.ApplicationWindow):
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_counter_revealer.set_reveal_child(False)
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
@ -612,7 +620,7 @@ class Window(Gtk.ApplicationWindow):
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_counter_revealer.set_reveal_child(True)
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
@ -624,7 +632,7 @@ class Window(Gtk.ApplicationWindow):
"""events called when the window losses focus
"""
if self.top_bottom_bars_visible is False:
self.stats_counter_revealer.set_reveal_child(True)
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