forked from Mirrors/apostrophe
implement hack to fade away the headerbar
parent
f766c3703d
commit
8ac8728e3b
|
@ -417,14 +417,7 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkRevealer" id="FullscreenHbPlaceholder">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
@ -16,46 +16,121 @@
|
|||
"""Manage all the headerbars related stuff
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
from gettext import gettext as _
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gtk, GLib
|
||||
from uberwriter.helpers import get_descendant
|
||||
|
||||
|
||||
class MainHeaderbar: #pylint: disable=too-few-public-methods
|
||||
class BaseHeaderbar:
|
||||
"""Base class for all headerbars
|
||||
"""
|
||||
def __init__(self, app):
|
||||
|
||||
self.builder = Gtk.Builder()
|
||||
self.builder.add_from_resource(
|
||||
"/de/wolfvollprecht/UberWriter/ui/Headerbar.ui")
|
||||
|
||||
self.hb = self.builder.get_object("Headerbar")
|
||||
self.hb_revealer = self.builder.get_object("titlebar_revealer")
|
||||
|
||||
self.menu_button = self.builder.get_object("menu_button")
|
||||
self.recents_button = self.builder.get_object("recents_button")
|
||||
|
||||
|
||||
class MainHeaderbar(BaseHeaderbar): # pylint: disable=too-few-public-methods
|
||||
"""Sets up the main application headerbar
|
||||
"""
|
||||
|
||||
def __init__(self, app):
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_resource(
|
||||
"/de/wolfvollprecht/UberWriter/ui/Headerbar.ui")
|
||||
BaseHeaderbar.__init__(self, app)
|
||||
|
||||
self.hb = builder.get_object("Headerbar")
|
||||
|
||||
self.menu_button = builder.get_object("menu_button")
|
||||
self.recents_button = builder.get_object("recents_button")
|
||||
self.hb.set_show_close_button(True)
|
||||
|
||||
add_menus(self, app)
|
||||
|
||||
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.props.transition_duration = 0
|
||||
|
||||
|
||||
class FullscreenHeaderbar(BaseHeaderbar):
|
||||
"""Sets up and manages the fullscreen headerbar and his events
|
||||
"""
|
||||
|
||||
def __init__(self, fs_builder, app):
|
||||
|
||||
BaseHeaderbar.__init__(self, app)
|
||||
|
||||
self.hb.set_show_close_button(False)
|
||||
|
||||
self.exit_fs_button = self.builder.get_object("exit_fs_button")
|
||||
self.exit_fs_button.set_visible(True)
|
||||
|
||||
add_menus(self, app)
|
||||
|
||||
self.events = fs_builder.get_object("FullscreenEventbox")
|
||||
self.events.add(self.hb_revealer)
|
||||
|
||||
# this is a little tricky
|
||||
# we show hb when the cursor enters an area of 1px at the top
|
||||
# as the hb is shown the height of the eventbox grows to accomodate it
|
||||
self.events.connect('enter_notify_event', self.show_fs_hb)
|
||||
self.events.connect('leave_notify_event', self.hide_fs_hb)
|
||||
self.menu_button.get_popover().connect('closed', self.hide_fs_hb)
|
||||
|
||||
def show_fs_hb(self, _widget, _data=None):
|
||||
"""show headerbar of the fullscreen mode
|
||||
"""
|
||||
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()
|
||||
def hide_fs_hb(self, _widget, _data=None):
|
||||
"""hide headerbar of the fullscreen mode
|
||||
"""
|
||||
if self.menu_button.get_active():
|
||||
pass
|
||||
else:
|
||||
self.hb_revealer.set_reveal_child(False)
|
||||
|
||||
self.hb.show_all()
|
||||
|
||||
class DummyHeaderbar(BaseHeaderbar):
|
||||
"""Sets up and manages the dummy headerbar wich fades away when entering
|
||||
the free-distracting mode
|
||||
"""
|
||||
|
||||
def __init__(self, app):
|
||||
|
||||
BaseHeaderbar.__init__(self, app)
|
||||
|
||||
self.hb.set_show_close_button(True)
|
||||
self.hb_revealer.set_transition_type(
|
||||
Gtk.RevealerTransitionType.CROSSFADE)
|
||||
self.hb_revealer.set_reveal_child(False)
|
||||
|
||||
self.menu_button.set_sensitive(True)
|
||||
self.recents_button.set_sensitive(True)
|
||||
|
||||
def show_dm_hb(self):
|
||||
"""show dummy headerbar:
|
||||
It appears instantly to inmediatly fade away
|
||||
"""
|
||||
self.hb_revealer.set_transition_duration(0)
|
||||
self.hb_revealer.set_reveal_child(True)
|
||||
self.hb_revealer.set_transition_duration(600)
|
||||
self.hb_revealer.set_reveal_child(False)
|
||||
|
||||
def hide_dm_hb(self):
|
||||
"""hide dummy headerbar
|
||||
It appears slowly to inmediatly dissapear
|
||||
"""
|
||||
self.hb_revealer.set_transition_duration(400)
|
||||
self.hb_revealer.set_reveal_child(True)
|
||||
GLib.timeout_add(400, self.hide_dm_hb_with_wait)
|
||||
|
||||
def hide_dm_hb_with_wait(self):
|
||||
self.hb_revealer.set_transition_duration(0)
|
||||
self.hb_revealer.set_reveal_child(False)
|
||||
return False
|
||||
|
||||
|
||||
class PreviewHeaderbar:
|
||||
|
@ -67,10 +142,11 @@ class PreviewHeaderbar:
|
|||
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 = Gtk.Revealer(name="titlebar-revealer-pv")
|
||||
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.set_transition_type(
|
||||
Gtk.RevealerTransitionType.CROSSFADE)
|
||||
self.hb_revealer.show()
|
||||
self.hb_revealer.set_reveal_child(True)
|
||||
|
||||
|
@ -82,55 +158,9 @@ class PreviewHeaderbar:
|
|||
self.hb.show_all()
|
||||
|
||||
|
||||
class FullscreenHeaderbar:
|
||||
"""Sets up and manages the fullscreen headerbar and his events
|
||||
"""
|
||||
|
||||
def __init__(self, fs_builder, app):
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_resource(
|
||||
"/de/wolfvollprecht/UberWriter/ui/Headerbar.ui")
|
||||
|
||||
self.hb = builder.get_object("Headerbar")
|
||||
self.hb.set_show_close_button(False)
|
||||
self.hb.show_all()
|
||||
|
||||
self.menu_button = builder.get_object("menu_button")
|
||||
self.recents_button = builder.get_object("recents_button")
|
||||
|
||||
self.exit_fs_button = builder.get_object("exit_fs_button")
|
||||
self.exit_fs_button.set_visible(True)
|
||||
|
||||
add_menus(self, app)
|
||||
|
||||
self.events = fs_builder.get_object("FullscreenEventbox")
|
||||
self.revealer = fs_builder.get_object(
|
||||
"FullscreenHbPlaceholder")
|
||||
self.revealer.add(self.hb)
|
||||
|
||||
# this is a little tricky
|
||||
# we show hb when the cursor enters an area of 1 px at the top of the window
|
||||
# as the hb is shown the height of the eventbox grows to accomodate it
|
||||
self.events.connect('enter_notify_event', self.show_fs_hb)
|
||||
self.events.connect('leave_notify_event', self.hide_fs_hb)
|
||||
self.menu_button.get_popover().connect('closed', self.hide_fs_hb)
|
||||
|
||||
def show_fs_hb(self, _widget, _data=None):
|
||||
"""show headerbar of the fullscreen mode
|
||||
"""
|
||||
self.revealer.set_reveal_child(True)
|
||||
|
||||
def hide_fs_hb(self, _widget, _data=None):
|
||||
"""hide headerbar of the fullscreen mode
|
||||
"""
|
||||
if self.menu_button.get_active():
|
||||
pass
|
||||
else:
|
||||
self.revealer.set_reveal_child(False)
|
||||
|
||||
|
||||
def add_menus(headerbar, app):
|
||||
""" Add menu models to hb buttons
|
||||
"""
|
||||
|
||||
# Add menu model to the menu button
|
||||
|
||||
|
|
|
@ -84,10 +84,21 @@ class MainWindow(StyledWindow):
|
|||
self.settings = Settings.new()
|
||||
|
||||
# Headerbars
|
||||
self.last_height = 0
|
||||
self.headerbar = headerbars.MainHeaderbar(app)
|
||||
self.set_titlebar(self.headerbar.hb_container)
|
||||
self.headerbar.hb_revealer.connect(
|
||||
"size_allocate", self.header_size_allocate)
|
||||
self.set_titlebar(self.headerbar.hb_revealer)
|
||||
|
||||
self.fs_headerbar = headerbars.FullscreenHeaderbar(builder, app)
|
||||
|
||||
# The dummy headerbar is a cosmetic hack to be able to
|
||||
# crossfade the hb on top of the window
|
||||
self.dm_headerbar = headerbars.DummyHeaderbar(app)
|
||||
root.add_overlay(self.dm_headerbar.hb_revealer)
|
||||
root.reorder_overlay(self.dm_headerbar.hb_revealer, 0)
|
||||
root.set_overlay_pass_through(self.dm_headerbar.hb_revealer, True)
|
||||
|
||||
self.title_end = " – UberWriter"
|
||||
self.set_headerbar_title("New File" + self.title_end)
|
||||
|
||||
|
@ -103,6 +114,7 @@ class MainWindow(StyledWindow):
|
|||
|
||||
# Setup text editor
|
||||
self.text_view = TextView(self.settings.get_int("characters-per-line"))
|
||||
self.text_view.set_top_margin(80)
|
||||
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()
|
||||
|
@ -151,6 +163,24 @@ class MainWindow(StyledWindow):
|
|||
###
|
||||
self.searchreplace = SearchAndReplace(self, self.text_view, builder)
|
||||
|
||||
def header_size_allocate(self, widget, allocation):
|
||||
""" When the main hb starts to shrink its size, add that size
|
||||
to the textview margin, so it stays in place
|
||||
"""
|
||||
|
||||
# prevent 1px jumps
|
||||
if allocation.height == 1 and not widget.get_child_revealed():
|
||||
allocation.height = 0
|
||||
|
||||
height = self.headerbar.hb.get_allocated_height() - allocation.height
|
||||
if height == self.last_height:
|
||||
return
|
||||
|
||||
self.last_height = height
|
||||
|
||||
self.text_view.update_vertical_margin(height)
|
||||
self.text_view.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
|
||||
|
@ -183,7 +213,7 @@ class MainWindow(StyledWindow):
|
|||
"""toggle focusmode
|
||||
"""
|
||||
|
||||
self.text_view.set_focus_mode(state.get_boolean())
|
||||
self.text_view.set_focus_mode(state.get_boolean(), self.headerbar.hb.get_allocated_height())
|
||||
self.text_view.grab_focus()
|
||||
|
||||
def set_hemingway_mode(self, state):
|
||||
|
@ -519,7 +549,6 @@ class MainWindow(StyledWindow):
|
|||
def open_recent(self, _widget, data=None):
|
||||
"""open the given recent document
|
||||
"""
|
||||
print("open")
|
||||
|
||||
if data:
|
||||
if self.check_change() == Gtk.ResponseType.CANCEL:
|
||||
|
@ -563,8 +592,30 @@ class MainWindow(StyledWindow):
|
|||
self.reveal_top_bottom_bars(True)
|
||||
|
||||
def reveal_top_bottom_bars(self, reveal):
|
||||
"""handles (in conjunction with header_size_allocate)
|
||||
the fading in and out of the headerbar
|
||||
"""
|
||||
# The logic may seem confusing because similar things are
|
||||
# handled in headerbars.py, but for convenience (adding classes
|
||||
# to the main window, and delayed calls) some functions are split
|
||||
# between here and there
|
||||
|
||||
# TODO: rework this logic?
|
||||
|
||||
def reveal_hb():
|
||||
self.headerbar.hb_revealer.set_reveal_child(True)
|
||||
self.get_style_context().remove_class("focus")
|
||||
return False
|
||||
|
||||
if self.top_bottom_bars_visible != reveal:
|
||||
self.headerbar.hb_revealer.set_reveal_child(reveal)
|
||||
if reveal:
|
||||
self.dm_headerbar.hide_dm_hb()
|
||||
GLib.timeout_add(400, reveal_hb)
|
||||
else:
|
||||
self.headerbar.hb_revealer.set_reveal_child(False)
|
||||
self.dm_headerbar.show_dm_hb()
|
||||
self.get_style_context().add_class("focus")
|
||||
|
||||
self.stats_revealer.set_reveal_child(reveal)
|
||||
for revealer in self.preview_handler.get_top_bottom_bar_revealers():
|
||||
revealer.set_reveal_child(reveal)
|
||||
|
|
|
@ -54,6 +54,9 @@ class TextView(Gtk.TextView):
|
|||
self.set_pixels_inside_wrap(8)
|
||||
self.get_style_context().add_class('uberwriter-editor')
|
||||
|
||||
self.set_margin_left(8)
|
||||
self.set_margin_right(8)
|
||||
|
||||
# Text sizing
|
||||
self.props.halign = Gtk.Align.FILL
|
||||
self.line_chars = line_chars
|
||||
|
@ -144,7 +147,6 @@ class TextView(Gtk.TextView):
|
|||
|
||||
def on_size_allocate(self, *_):
|
||||
self.update_horizontal_margin()
|
||||
self.update_vertical_margin()
|
||||
self.markup.update_margins_indents()
|
||||
self.queue_draw()
|
||||
|
||||
|
@ -192,14 +194,14 @@ class TextView(Gtk.TextView):
|
|||
self.frozen_scroll_scale = None
|
||||
self.queue_draw()
|
||||
|
||||
def set_focus_mode(self, focus_mode):
|
||||
def set_focus_mode(self, focus_mode, hb_height):
|
||||
"""Toggle focus mode.
|
||||
|
||||
When in focus mode, the cursor sits in the middle of the text view,
|
||||
and the surrounding text is greyed out."""
|
||||
|
||||
self.focus_mode = focus_mode
|
||||
self.update_vertical_margin()
|
||||
self.update_vertical_margin(hb_size=hb_height)
|
||||
self.markup.apply()
|
||||
self.smooth_scroll_to()
|
||||
self.set_spellcheck(self.spellcheck)
|
||||
|
@ -227,13 +229,14 @@ class TextView(Gtk.TextView):
|
|||
self.props.left_margin = horizontal_margin
|
||||
self.props.right_margin = horizontal_margin
|
||||
|
||||
def update_vertical_margin(self):
|
||||
def update_vertical_margin(self, top_margin=0, hb_size=0):
|
||||
if self.focus_mode:
|
||||
height = self.get_allocation().height
|
||||
self.props.top_margin = height / 2
|
||||
self.props.bottom_margin = height / 2
|
||||
height = self.get_allocation().height + top_margin + hb_size
|
||||
|
||||
self.props.top_margin = height / 2 + top_margin
|
||||
self.props.bottom_margin = height / 2 - top_margin
|
||||
else:
|
||||
self.props.top_margin = 80
|
||||
self.props.top_margin = 80 + top_margin
|
||||
self.props.bottom_margin = 64
|
||||
|
||||
def set_hemingway_mode(self, hemingway_mode):
|
||||
|
|
Loading…
Reference in New Issue