diff --git a/src/new-src/core/containers/base_container.py b/src/new-src/core/containers/base_container.py index bfe7ea6..a280963 100644 --- a/src/new-src/core/containers/base_container.py +++ b/src/new-src/core/containers/base_container.py @@ -8,6 +8,7 @@ from gi.repository import Gtk # Application imports from .left_box import LeftBox from .right_box import RightBox +from ..widgets.button_controls import ButtonControls from ..widgets.path_label import PathLabel @@ -29,11 +30,15 @@ class BaseContainer(Gtk.Box): ... def _load_widgets(self): - box = Gtk.Box() - box.set_orientation(Gtk.Orientation.HORIZONTAL) + box = Gtk.Box() + box2 = Gtk.Box() + box.set_orientation(Gtk.Orientation.VERTICAL) + box2.set_orientation(Gtk.Orientation.HORIZONTAL) - box.add(LeftBox()) - box.add(RightBox()) + box.add(ButtonControls()) + box.add(PathLabel()) + box2.add(LeftBox()) + box2.add(RightBox()) - self.add(PathLabel()) self.add(box) + self.add(box2) diff --git a/src/new-src/core/containers/image_list_scroll.py b/src/new-src/core/containers/image_list_scroll.py index d491a64..232b358 100644 --- a/src/new-src/core/containers/image_list_scroll.py +++ b/src/new-src/core/containers/image_list_scroll.py @@ -17,7 +17,7 @@ class ImageListScroll(Gtk.ScrolledWindow): self.image_list_widget = None self.size = 0 self.start = 0 - self.end = 9 + self.end = settings.get_max_ring_thumbnail_list() self._setup_styling() self._setup_signals() @@ -29,6 +29,7 @@ class ImageListScroll(Gtk.ScrolledWindow): def _setup_styling(self): self.set_vexpand(True) + self.set_overlay_scrolling(False) def _setup_signals(self): self.connect("edge-reached", self._handle_edge_reached) @@ -46,25 +47,34 @@ class ImageListScroll(Gtk.ScrolledWindow): def _update_list_size_constraints(self, size): self.size = size self.start = 0 - self.end = 9 + self.end = settings.get_max_ring_thumbnail_list() def _handle_edge_reached(self, widget, edge): - img_list = widget.get_children()[0].get_children()[0] - children = self.image_list_widget.get_children() + children = self.image_list_widget.get_children() + vadjustment = self.get_vadjustment() + vvalue = vadjustment.get_value() if edge == Gtk.PositionType.TOP: if self.start >= 1: self.start -= 1 - children[self.end].hide() + self._unload_image(children[self.end]) children[self.start].show() self.end -= 1 + + vadjustment.set_value(vvalue + 1) if edge == Gtk.PositionType.BOTTOM: if (self.end + 1) < self.size: self.end += 1 - children[self.start].hide() + self._unload_image(children[self.start]) if not children[self.end].is_loaded: children[self.end].load_pixbuf() children[self.end].show() self.start += 1 + vadjustment.set_value(vvalue - 1) + + def _unload_image(self, child): + child.hide() + # child.image.clear() + child.is_loaded = False diff --git a/src/new-src/core/containers/left_box.py b/src/new-src/core/containers/left_box.py index add4dd6..58cccc8 100644 --- a/src/new-src/core/containers/left_box.py +++ b/src/new-src/core/containers/left_box.py @@ -23,7 +23,7 @@ class LeftBox(Gtk.Box): def _setup_styling(self): self.set_orientation(Gtk.Orientation.VERTICAL) - self.set_size_request(settings.get_thumbnail_with(), -1) + self.set_size_request(settings.get_thumbnail_with() + 15, -1) self.set_vexpand(True) def _setup_signals(self): diff --git a/src/new-src/core/widgets/button_controls.py b/src/new-src/core/widgets/button_controls.py new file mode 100644 index 0000000..1f12881 --- /dev/null +++ b/src/new-src/core/widgets/button_controls.py @@ -0,0 +1,75 @@ +# Python imports + +# Lib imports +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +# Application imports + + + +class ButtonControls(Gtk.ButtonBox): + def __init__(self): + super(ButtonControls, self).__init__() + + self._setup_styling() + self._setup_signals() + self._load_widgets() + + self.show_all() + + + def _setup_styling(self): + ... + + def _setup_signals(self): + ... + + def _load_widgets(self): + center_widget = Gtk.ButtonBox() + lrotate_button = Gtk.Button(label = "Rotate Left") + vflip_button = Gtk.Button(label = "Flip Vertical") + one2one_button = Gtk.ToggleButton(label = "1:1") + fit_button = Gtk.ToggleButton(label = "Fit") + hflip_button = Gtk.Button(label = "Flip Horizontal") + rrotate_button = Gtk.Button(label = "Rotate Right") + + center_widget.add(lrotate_button) + center_widget.add(vflip_button) + center_widget.add(one2one_button) + center_widget.add(fit_button) + center_widget.add(hflip_button) + center_widget.add(rrotate_button) + + lrotate_button.set_image( Gtk.Image.new_from_icon_name("gtk-undelete", 4) ) + vflip_button.set_image( Gtk.Image.new_from_icon_name("gtk-orientation-reverse-portrait", 4) ) + one2one_button.set_image( Gtk.Image.new_from_icon_name("gtk-zoom-100", 4) ) + fit_button.set_image( Gtk.Image.new_from_icon_name("gtk-zoom-fit", 4) ) + hflip_button.set_image( Gtk.Image.new_from_icon_name("gtk-orientation-reverse-landscape", 4) ) + rrotate_button.set_image( Gtk.Image.new_from_icon_name("object-rotate-right", 4) ) + + # TODO: add if check against settings pull to set 1:1 or fit + one2one_button.set_active(True) + + lrotate_button.connect("clicked", self._rotate_left) + vflip_button.connect("clicked", self._vertical_flip) + one2one_button.connect("clicked", self._scale_1_two_1) + fit_button.connect("clicked", self._fit_to_container) + hflip_button.connect("clicked", self._horizontal_flip) + rrotate_button.connect("clicked", self._rotate_right) + + self.set_center_widget(center_widget) + + def _rotate_left(self, widget = None, eve = None): + event_system.emit("rotate_left") + def _vertical_flip(self, widget = None, eve = None): + event_system.emit("vertical_flip") + def _scale_1_two_1(self, widget = None, eve = None): + event_system.emit("scale_1_two_1") + def _fit_to_container(self, widget = None, eve = None): + event_system.emit("fit_to_container") + def _horizontal_flip(self, widget = None, eve = None): + event_system.emit("horizontal_flip") + def _rotate_right(self, widget = None, eve = None): + event_system.emit("rotate_right") diff --git a/src/new-src/core/widgets/image.py b/src/new-src/core/widgets/image.py index ef222b4..5689c63 100644 --- a/src/new-src/core/widgets/image.py +++ b/src/new-src/core/widgets/image.py @@ -46,9 +46,6 @@ class Image(Gtk.EventBox): self.image.show() self.add(self.image) - def set_from_pixbuf(self, pixbuf): - self.image.set_from_pixbuf(pixbuf) - def set_image_to_view(self, widget = None, eve = None): if eve.button == 1: event_system.emit("handle_file_from_dnd", (self.path, )) @@ -59,6 +56,9 @@ class Image(Gtk.EventBox): self._thumbnail_height) ) self.is_loaded = True + def set_from_pixbuf(self, pixbuf): + self.image.set_from_pixbuf(pixbuf) + def get_pixbuf_data(self, path, w = 126, h = 126): path = self.path if not path else path pixbuf = None diff --git a/src/new-src/core/widgets/image_list.py b/src/new-src/core/widgets/image_list.py index b7015c8..4a856bd 100644 --- a/src/new-src/core/widgets/image_list.py +++ b/src/new-src/core/widgets/image_list.py @@ -5,6 +5,7 @@ import os import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk +from gi.repository import GLib # Application imports from ..widgets.image import Image @@ -67,17 +68,18 @@ class ImageList(Gtk.Box): self.show_range() # TODO: Setup to load range start/end values from settings - def show_range(self, i = 0, j = 9): + def show_range(self, i = 0, j = settings.get_max_ring_thumbnail_list()): children = self.get_children() if len(children) <= j: j = len(children) - 1 while i <= j: child = children[i] - self.load_pixbuf_threaded(child) - child.show() + self.load_child_pixbuf_threaded(child) i += 1 @daemon_threaded - def load_pixbuf_threaded(self, child): - child.load_pixbuf() + def load_child_pixbuf_threaded(self, child): + GLib.idle_add(child.load_pixbuf) + GLib.idle_add(child.show) + Gtk.main_iteration() diff --git a/src/new-src/core/widgets/image_view.py b/src/new-src/core/widgets/image_view.py index 33cad98..12e44a7 100644 --- a/src/new-src/core/widgets/image_view.py +++ b/src/new-src/core/widgets/image_view.py @@ -6,6 +6,7 @@ gi.require_version('Gtk', '3.0') gi.require_version('Gdk', '3.0') from gi.repository import Gtk from gi.repository import Gdk +from gi.repository import GdkPixbuf # Application imports @@ -15,8 +16,9 @@ class ImageView(Gtk.Image): def __init__(self): super(ImageView, self).__init__() - self.pixbuf = None - self.animation = None + self.bak_pixbuf = None + self.pixbuf = None + self.animation = None self._setup_styling() self._setup_signals() @@ -35,6 +37,12 @@ class ImageView(Gtk.Image): def _subscribe_to_events(self): event_system.subscribe("handle_file_from_dnd", self._handle_file_from_dnd) + event_system.subscribe("vertical_flip", self._vertical_flip) + event_system.subscribe("rotate_left", self._rotate_left) + event_system.subscribe("scale_1_two_1", self._scale_1_two_1) + event_system.subscribe("fit_to_container", self._fit_to_container) + event_system.subscribe("horizontal_flip", self._horizontal_flip) + event_system.subscribe("rotate_right", self._rotate_right) def _load_widgets(self): ... @@ -47,8 +55,9 @@ class ImageView(Gtk.Image): logger.debug("Start animation stub...") def load_path(self, path): - self.pixbuf = None - self.animation = None + self.bak_pixbuf = None + self.pixbuf = None + self.animation = None if path.endswith(".gif"): try: @@ -63,5 +72,36 @@ class ImageView(Gtk.Image): except Exception: self.pixbuf = Gtk.Image.new_from_resource(path).get_pixbuf() + self.bak_pixbuf = self.pixbuf self.set_from_pixbuf(self.pixbuf) event_system.emit("update_path_label", (path,)) + + def _rotate_left(self): + if self.pixbuf: + self.pixbuf = self.pixbuf.rotate_simple(GdkPixbuf.PixbufRotation.COUNTERCLOCKWISE) + self.set_from_pixbuf(self.pixbuf) + + def _vertical_flip(self): + if self.pixbuf: + self.pixbuf = self.pixbuf.flip(False) + self.set_from_pixbuf(self.pixbuf) + + def _scale_1_two_1(self): + if self.pixbuf: + ... + ... + + def _fit_to_container(self): + if self.pixbuf: + ... + ... + + def _horizontal_flip(self): + if self.pixbuf: + self.pixbuf = self.pixbuf.flip(True) + self.set_from_pixbuf(self.pixbuf) + + def _rotate_right(self): + if self.pixbuf: + self.pixbuf = self.pixbuf.rotate_simple(GdkPixbuf.PixbufRotation.CLOCKWISE) + self.set_from_pixbuf(self.pixbuf) diff --git a/src/new-src/utils/settings/settings.py b/src/new-src/utils/settings/settings.py index 160074b..fed522c 100644 --- a/src/new-src/utils/settings/settings.py +++ b/src/new-src/utils/settings/settings.py @@ -145,6 +145,7 @@ class Settings(StartCheckMixin, Singleton): def get_thumbnail_with(self) -> int: return self._config["thumbnail_with"] def get_thumbnail_height(self) -> int: return self._config["thumbnail_height"] + def get_max_ring_thumbnail_list(self) -> int: return self._config["max_ring_thumbnail_list"] # Filter returns def get_office_filter(self) -> tuple: return tuple(self._settings["filters"]["office"]) diff --git a/user_config/usr/share/mirage2/settings.json b/user_config/usr/share/mirage2/settings.json index a3c58ce..17d9633 100644 --- a/user_config/usr/share/mirage2/settings.json +++ b/user_config/usr/share/mirage2/settings.json @@ -9,6 +9,7 @@ "text_app": "leafpad", "file_manager_app": "solarfm", "terminal_app": "terminator", + "max_ring_thumbnail_list": 10, "thumbnail_with": 256, "thumbnail_height": 256 }, diff --git a/user_config/usr/share/mirage2/stylesheet.css b/user_config/usr/share/mirage2/stylesheet.css index c0383f6..6cb1fd1 100644 --- a/user_config/usr/share/mirage2/stylesheet.css +++ b/user_config/usr/share/mirage2/stylesheet.css @@ -1,86 +1,5 @@ -/* Set fm to have transparent window */ -box, -iconview, -notebook, -paned, -stack, -scrolledwindow, -treeview.view, -.content-view, -.view { - background: rgba(19, 21, 25, 0.14); - color: rgba(255, 255, 255, 1); -} - -notebook > header > tabs > tab:checked { - /* Neon Blue 00e8ff */ - background-color: rgba(0, 232, 255, 0.2); +.image-view { + /* background-color: rgba(0, 0, 0, 0.0); */ /* Dark Bergundy */ - /* background-color: rgba(116, 0, 0, 0.25); */ - - color: rgba(255, 255, 255, 0.8); + border: 2px solid rgba(56, 56, 56, 1); } - -#message_view { - font: 16px "Monospace"; -} - -.view:selected, -.view:selected:hover { - box-shadow: inset 0 0 0 9999px rgba(21, 158, 167, 0.34); - color: rgba(255, 255, 255, 0.5); -} - -.alert-border { - border: 2px solid rgba(116, 0, 0, 0.64); -} - -.search-border { - border: 2px solid rgba(136, 204, 39, 1); -} - -.notebook-selected-focus { - /* Neon Blue 00e8ff border */ - border: 2px solid rgba(0, 232, 255, 0.34); - /* Dark Bergundy */ - /* border: 2px solid rgba(116, 0, 0, 0.64); */ -} - -.notebook-unselected-focus { - /* Neon Blue 00e8ff border */ - /* border: 2px solid rgba(0, 232, 255, 0.25); */ - /* Dark Bergundy */ - /* border: 2px solid rgba(116, 0, 0, 0.64); */ - /* Snow White */ - border: 2px solid rgba(255, 255, 255, 0.24); -} - - - - - -/* * { - background: rgba(0, 0, 0, 0.14); - color: rgba(255, 255, 255, 1); -} */ - -/* * selection { - background-color: rgba(116, 0, 0, 0.65); - color: rgba(255, 255, 255, 0.5); -} */ - -/* Rubberband coloring */ -/* .rubberband, -rubberband, -flowbox rubberband, -treeview.view rubberband, -.content-view rubberband, -.content-view .rubberband, -XfdesktopIconView.view .rubberband { - border: 1px solid #6c6c6c; - background-color: rgba(21, 158, 167, 0.57); -} - -XfdesktopIconView.view:active { - background-color: rgba(172, 102, 21, 1); -} */