implement hack to fade away the headerbar

ui
Manuel Genovés 2019-11-23 02:11:32 +01:00
parent f766c3703d
commit 8ac8728e3b
4 changed files with 169 additions and 92 deletions

View File

@ -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>

View File

@ -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

View File

@ -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)

View File

@ -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):