Skip to content

Commit

Permalink
Rudimentary decoupling
Browse files Browse the repository at this point in the history
  • Loading branch information
kra-mo committed Dec 25, 2023
1 parent 927f5d9 commit 80d9420
Show file tree
Hide file tree
Showing 14 changed files with 300 additions and 197 deletions.
4 changes: 2 additions & 2 deletions hyperplane/editable_row.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def start_edit(self) -> None:
self.check_revealer.set_reveal_child(True)

def end_edit(self) -> None:
"""Saves the edits and updates self accordingly."""
"""Saves the edits and updates the row accordingly."""
self.check_revealer.set_reveal_child(False)
GLib.timeout_add(
self.check_revealer.get_transition_duration(),
Expand Down Expand Up @@ -136,7 +136,7 @@ def set_active(self) -> None:

@GObject.Property(type=str)
def identifier(self) -> str:
"""The identifier for self used in dconf."""
"""The identifier for the row used in dconf."""
return self._identifier

@identifier.setter
Expand Down
12 changes: 12 additions & 0 deletions hyperplane/gtk/path-entry.blp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Gtk 4.0;

template $HypPathEntry : Entry {
hexpand: true;

ShortcutController {
Shortcut {
trigger: "Escape";
action: "action(win.hide-path-entry)";
}
}
}
4 changes: 4 additions & 0 deletions hyperplane/gtk/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ and that looks ugly.
filter: contrast(50%) brightness(130%);
}

.sidebar-drop-target {
border-bottom: @accent_bg_color 3px solid;
}

.sidebar-check-button > check {
color: @sidebar_fg_color;
background-color: @sidebar_shade_color;
Expand Down
11 changes: 1 addition & 10 deletions hyperplane/gtk/window.blp
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,7 @@ template $HypWindow : Adw.ApplicationWindow {
}

Adw.Clamp path_entry_clamp {
Entry path_entry {
hexpand: true;

ShortcutController {
Shortcut {
trigger: "Escape";
action: "action(win.hide-path-entry)";
}
}
}
$HypPathEntry path_entry {}
}

Adw.Clamp search_entry_clamp {
Expand Down
1 change: 1 addition & 0 deletions hyperplane/hyperplane.gresource.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<file preprocess="xml-stripblanks">gtk/item.ui</file>
<file preprocess="xml-stripblanks">gtk/items-page.ui</file>
<file preprocess="xml-stripblanks">gtk/path-bar.ui</file>
<file preprocess="xml-stripblanks">gtk/path-entry.ui</file>
<file preprocess="xml-stripblanks">gtk/path-segment.ui</file>
<file preprocess="xml-stripblanks">gtk/preferences.ui</file>
<file preprocess="xml-stripblanks">gtk/volumes-box.ui</file>
Expand Down
8 changes: 2 additions & 6 deletions hyperplane/item_sorter.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,5 @@ def do_compare(

def __ordering_from_cmpfunc(self, cmpfunc_result: int) -> Gtk.Ordering:
"""Converts the result of a `GCompareFunc` like `strcmp()` to a `GtkOrdering` value."""
# HACK: https://gitlab.gnome.org/GNOME/gtk/-/issues/6298
if cmpfunc_result > 0:
return Gtk.Ordering.LARGER
if cmpfunc_result < 0:
return Gtk.Ordering.SMALLER
return Gtk.Ordering.EQUAL
# https://gitlab.gnome.org/GNOME/gtk/-/issues/6298
return Gtk.Ordering((cmpfunc_result > 0) - (cmpfunc_result < 0))
5 changes: 2 additions & 3 deletions hyperplane/items_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ def __right_click(self, _gesture, _n, x, y) -> None:
GLib.timeout_add(10, self.__popup_menu)

def __drop_file(
self, _drop_target: Gtk.DropTarget, file_list: GObject.Value, _x, _y
self, _drop_target: Gtk.DropTarget, file_list: Gdk.FileList, _x, _y
) -> None:
# TODO: This is copy-paste from __paste()
for src in file_list:
Expand Down Expand Up @@ -516,7 +516,7 @@ def __drop_texture(
output.write_bytes(texture_bytes)

def __drop_text(
self, _drop_target: Gtk.DropTarget, text: GObject.Value, _x, _y
self, _drop_target: Gtk.DropTarget, text: str, _x, _y
) -> None:
# TODO: Again again, copy-paste from __paste()
if not text: # If text is an empty string
Expand Down Expand Up @@ -895,7 +895,6 @@ def delete():
case 0:
return
case 1:
# TODO: Blocking I/O for this? Really?
msg = _("Are you sure you want to permanently delete {}?").format(
f'"{get_gfile_display_name(gfiles[0])}"'
)
Expand Down
2 changes: 2 additions & 0 deletions hyperplane/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ blueprints = custom_target('blueprints',
'gtk/item.blp',
'gtk/items-page.blp',
'gtk/path-bar.blp',
'gtk/path-entry.blp',
'gtk/path-segment.blp',
'gtk/preferences.blp',
'gtk/volumes-box.blp',
Expand Down Expand Up @@ -54,6 +55,7 @@ hyperplane_sources = [
'main.py',
'navigation_bin.py',
'path_bar.py',
'path_entry.py',
'path_segment.py',
'postmaster_general.py',
'preferences.py',
Expand Down
128 changes: 117 additions & 11 deletions hyperplane/path_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
# SPDX-License-Identifier: GPL-3.0-or-later

"""The path bar in a HypWindow."""
from typing import Optional
from os import sep
from pathlib import Path
from typing import Iterable, Optional
from urllib.parse import unquote, urlparse

from gi.repository import GLib, Gtk
from gi.repository import Gio, GLib, Gtk

from hyperplane import shared
from hyperplane.path_segment import HypPathSegment
Expand Down Expand Up @@ -57,15 +60,15 @@ def remove(self, n: int) -> None:
child,
)

if not (sep := self.separators[child]):
if not (separator := self.separators[child]):
return

sep.set_reveal_child(False)
separator.set_reveal_child(False)
GLib.timeout_add(
sep.get_transition_duration(),
separator.get_transition_duration(),
self.__remove_child,
self.segments_box,
sep,
separator,
)
self.separators.pop(child)

Expand Down Expand Up @@ -97,21 +100,21 @@ def append(
sep_label = Gtk.Label.new("+" if self.tags else "/")
sep_label.add_css_class("heading" if self.tags else "dim-label")

sep = Gtk.Revealer(
separator = Gtk.Revealer(
child=sep_label, transition_type=Gtk.RevealerTransitionType.SLIDE_RIGHT
)
self.segments_box.append(sep)
sep.set_reveal_child(True)
self.segments_box.append(separator)
separator.set_reveal_child(True)
else:
sep = None
separator = None

segment = HypPathSegment(label, icon_name, uri, tag)
self.segments_box.append(segment)

segment.set_transition_type(Gtk.RevealerTransitionType.SLIDE_RIGHT)
segment.set_reveal_child(True)

self.separators[segment] = sep
self.separators[segment] = separator
self.segments.append(segment)

last_segment = self.segments[-1]
Expand Down Expand Up @@ -140,6 +143,109 @@ def purge(self) -> None:
self.segments = []
self.separators = {}

def update(self, gfile: Optional[Gio.File], tags: Optional[Iterable[str]]) -> None:
"""Updates the bar according to a new `gfile` or new `tags`."""
if gfile:
if self.tags:
self.purge()

self.tags = False

uri = gfile.get_uri()
parse = urlparse(uri)
segments = []

# Do these automatically is shceme != "file"
if parse.scheme != "file":
scheme_uri = f"{parse.scheme}://"
try:
file_info = Gio.File.new_for_uri(scheme_uri).query_info(
",".join(
(
Gio.FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON,
Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
)
),
Gio.FileQueryInfoFlags.NONE,
)
except GLib.Error:
pass
else:
display_name = file_info.get_display_name()
symbolic = file_info.get_symbolic_icon()

segments.insert(
0,
(
display_name,
symbolic.get_names()[0] if symbolic else None,
scheme_uri,
None,
),
)

parts = unquote(parse.path).split(sep)

for index, part in enumerate(parts):
if not part:
continue

segments.append((part, "", f"file://{sep.join(parts[:index+1])}", None))

if (path := gfile.get_path()) and (
(path := Path(path)) == shared.home_path
or path.is_relative_to(shared.home_path)
):
segments = segments[len(shared.home_path.parts) - 1 :]
segments.insert(
0,
(_("Home"), "user-home-symbolic", shared.home_path.as_uri(), None),
)
elif parse.scheme == "file":
# Not relative to home, so add a root segment
segments.insert(
0,
(
"",
"drive-harddisk-symbolic",
# Fall back to sep if the GFile doesn't have a path
Path(path.anchor if path else sep).as_uri(),
None,
),
)

elif tags:
if not self.tags:
self.purge()

self.tags = True

segments = tuple((tag, "", None, tag) for tag in tags)

if (old_len := len(self.segments)) > (new_len := len(segments)):
self.remove(old_len - new_len)

append = False
for index, new_segment in enumerate(segments):
try:
old_segment = self.segments[index]
except IndexError:
old_segment = None

if (
not append
and old_segment
and new_segment[2] == old_segment.uri
and new_segment[3] == old_segment.tag
):
continue

if not append:
self.remove(len(self.segments) - index)
append = True

self.append(*new_segment)

def __remove_child(self, parent: Gtk.Box, child: Gtk.Widget) -> None:
# This is so GTK doesn't freak out when the child isn't in the parent anymore
if child.get_parent == parent:
Expand Down
78 changes: 78 additions & 0 deletions hyperplane/path_entry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# path_entry.py
#
# Copyright 2023 kramo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""An entry for navigating to paths or tags."""
from typing import Any

from gi.repository import Gio, GObject, Gtk

from hyperplane import shared


@Gtk.Template(resource_path=shared.PREFIX + "/gtk/path-entry.ui")
class HypPathEntry(Gtk.Entry):
"""An entry for navigating to paths or tags."""

__gtype_name__ = "HypPathEntry"

def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.connect("activate", self.__activate)

def __activate(self, entry, *_args: Any) -> None:
text = entry.get_text().strip()

if text.startswith("//"):
tags = list(
tag
for tag in shared.tags
if tag in text.lstrip("/").rstrip("/").split("//")
)

if not tags:
self.get_root().send_toast(_("No such tags"))
return

self.emit("hide-entry")
self.get_root().new_page(tags=tags)
return

if "://" in text:
gfile = Gio.File.new_for_uri(text)
else:
gfile = Gio.File.new_for_path(text)

if (
not gfile.query_file_type(Gio.FileQueryInfoFlags.NONE)
== Gio.FileType.DIRECTORY
):
self.get_root().send_toast(_("Unable to find path"))
return

self.emit("hide-entry")

self.get_root().new_page(gfile)

@GObject.Signal(name="hide-entry")
def hide(self) -> None:
"""
Emitted to indicate that the entry is done and should be hidden.
Containers of this widget should connect to it and react accordingly.
"""
2 changes: 1 addition & 1 deletion hyperplane/postmaster_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def tags_changed(self, change: Gtk.FilterChange) -> None:
All objects that keep an internal list of tags should connect to it
and update their list accordingly.
`change` represents whether tags were added, removed or just reordered.
`change` indicates whether tags were added, removed or just reordered.
This is only relevant for item filters.
"""

Expand Down
Loading

0 comments on commit 80d9420

Please sign in to comment.