forked from Mirrors/apostrophe
Make characters-per-line configurable
This is in preparation for the side-by-side preview, where the editor needs to become more adaptable. It indirectly fixes #141, as users can now change the desired line-length, although there is no UI setting for it.github/fork/yochananmarqos/patch-1
parent
562cc7e200
commit
bc23fa9b0b
|
@ -69,6 +69,13 @@
|
|||
Which statistic is shown on the main window.
|
||||
</description>
|
||||
</key>
|
||||
<key name='characters-per-line' type='i'>
|
||||
<default>66</default>
|
||||
<summary>Characters per line</summary>
|
||||
<description>
|
||||
Maximum number of characters per line within the editor.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
</schema>
|
||||
|
||||
|
|
|
@ -33,11 +33,23 @@
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
.uberwriter-window.small .uberwriter-editor {
|
||||
.uberwriter-window .uberwriter-editor.size14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uberwriter-window.large .uberwriter-editor {
|
||||
.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;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@ class TextView(Gtk.TextView):
|
|||
'redo': (GObject.SignalFlags.ACTION, None, ())
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
font_sizes = [18, 17, 16, 15, 14] # Must match CSS selectors in gtk/base.css
|
||||
|
||||
def __init__(self, line_chars):
|
||||
super().__init__()
|
||||
|
||||
# Appearance
|
||||
|
@ -49,9 +51,15 @@ class TextView(Gtk.TextView):
|
|||
self.set_pixels_inside_wrap(8)
|
||||
self.get_style_context().add_class('uberwriter-editor')
|
||||
|
||||
# Text sizing
|
||||
self.props.halign = Gtk.Align.FILL
|
||||
self.font_size = 16
|
||||
self.line_chars = line_chars
|
||||
self.get_style_context().add_class('size16')
|
||||
|
||||
# General behavior
|
||||
self.get_buffer().connect('changed', self.on_text_changed)
|
||||
self.connect('size-allocate', self.on_size_allocate)
|
||||
self.get_buffer().connect('changed', self.on_text_changed)
|
||||
|
||||
# Spell checking
|
||||
self.gspell_view = Gspell.TextView.get_from_gtk_text_view(self)
|
||||
|
@ -113,18 +121,22 @@ class TextView(Gtk.TextView):
|
|||
if self.scroller:
|
||||
self.scroller.set_scroll_scale(scale)
|
||||
|
||||
def on_size_allocate(self, *_):
|
||||
self.update_horizontal_margin()
|
||||
self.update_vertical_margin()
|
||||
self.markup.update_margins_indents()
|
||||
|
||||
def on_text_changed(self, *_):
|
||||
self.markup.apply()
|
||||
self.smooth_scroll_to()
|
||||
|
||||
def on_size_allocate(self, *_):
|
||||
self.update_vertical_margin()
|
||||
self.markup.update_margins_indents()
|
||||
|
||||
def on_parent_set(self, *_):
|
||||
parent = self.get_parent()
|
||||
if parent:
|
||||
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
|
||||
|
||||
|
@ -153,6 +165,26 @@ class TextView(Gtk.TextView):
|
|||
self.markup.apply()
|
||||
self.smooth_scroll_to()
|
||||
|
||||
def update_horizontal_margin(self):
|
||||
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))
|
||||
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
|
||||
horizontal_margin = (width - line_width) / 2
|
||||
self.props.left_margin = horizontal_margin
|
||||
self.props.right_margin = horizontal_margin
|
||||
|
||||
def update_vertical_margin(self):
|
||||
if self.focus_mode:
|
||||
height = self.get_allocation().height
|
||||
|
@ -191,3 +223,16 @@ class TextView(Gtk.TextView):
|
|||
if mark is None:
|
||||
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):
|
||||
"""Returns the amount of character padding for font_size.
|
||||
|
||||
Markup can use up to 6 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."""
|
||||
|
||||
return font_size * 1 / 1.6
|
||||
|
|
|
@ -77,9 +77,10 @@ class Window(Gtk.ApplicationWindow):
|
|||
self.builder = get_builder('Window')
|
||||
root = self.builder.get_object("FullscreenOverlay")
|
||||
root.connect('style-updated', self.apply_current_theme)
|
||||
self.connect("delete-event", self.on_delete_called)
|
||||
self.add(root)
|
||||
|
||||
self.set_default_size(900, 500)
|
||||
self.set_default_size(1000, 600)
|
||||
|
||||
# Preferences
|
||||
self.settings = Settings.new()
|
||||
|
@ -155,11 +156,6 @@ class Window(Gtk.ApplicationWindow):
|
|||
###
|
||||
self.searchreplace = SearchAndReplace(self, self.text_view)
|
||||
|
||||
# Window resize
|
||||
self.window_resize(self)
|
||||
self.connect("configure-event", self.window_resize)
|
||||
self.connect("delete-event", self.on_delete_called)
|
||||
|
||||
# Set current theme
|
||||
self.apply_current_theme()
|
||||
self.get_style_context().add_class('uberwriter-window')
|
||||
|
@ -233,48 +229,6 @@ class Window(Gtk.ApplicationWindow):
|
|||
self.text_view.set_hemingway_mode(state.get_boolean())
|
||||
self.text_view.grab_focus()
|
||||
|
||||
def window_resize(self, window, event=None):
|
||||
"""set paddings dependant of the window size
|
||||
"""
|
||||
|
||||
# Ensure the window receiving the event is the one we care about, ie. the main window.
|
||||
# On Wayland (bug?), sub-windows such as the recents popover will also trigger this.
|
||||
if event and event.window != window.get_window():
|
||||
return
|
||||
|
||||
# Adjust text editor width depending on window width, so that:
|
||||
# - The number of characters per line is adequate (http://webtypography.net/2.1.2)
|
||||
# - The number of characters stays constant while resizing the window / font
|
||||
# - There is enough text margin for MarkupBuffer to apply indents / negative margins
|
||||
#
|
||||
# TODO: Avoid hard-coding. Font size is clearer than unclear dimensions, but not ideal.
|
||||
w_width = event.width if event else window.get_allocation().width
|
||||
if w_width < 900:
|
||||
font_size = 14
|
||||
self.get_style_context().add_class("small")
|
||||
self.get_style_context().remove_class("large")
|
||||
|
||||
elif w_width < 1280:
|
||||
font_size = 16
|
||||
self.get_style_context().remove_class("small")
|
||||
self.get_style_context().remove_class("large")
|
||||
|
||||
else:
|
||||
font_size = 18
|
||||
self.get_style_context().remove_class("small")
|
||||
self.get_style_context().add_class("large")
|
||||
|
||||
font_width = int(font_size * 1/1.6) # Ratio specific to Fira Mono
|
||||
width = 67 * font_width - 1 # 66 characters
|
||||
horizontal_margin = 8 * font_width # 8 characters
|
||||
width_request = width + horizontal_margin * 2
|
||||
|
||||
if self.text_view.props.width_request != width_request:
|
||||
self.text_view.props.width_request = width_request
|
||||
self.text_view.set_left_margin(horizontal_margin)
|
||||
self.text_view.set_right_margin(horizontal_margin)
|
||||
self.scrolled_window.props.width_request = width_request
|
||||
|
||||
# TODO: refactorizable
|
||||
def save_document(self, _widget=None, _data=None):
|
||||
"""provide to the user a filechooser and save the document
|
||||
|
|
Loading…
Reference in New Issue