# Copyright 2017 The Tangram Developers. See the AUTHORS file at the
# top-level directory of this distribution and at
# https://github.com/renatoGarcia/tangram/blob/master/AUTHORS.
#
# This file is part of Tangram.
#
# Tangram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Tangram 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Tangram in the COPYING and COPYING.LESSER files.
# If not, see <http://www.gnu.org/licenses/>.
from typing import Union
from gi.repository import Gtk, Clutter
from .._base import Base
from .._gui_thread import on_gtk_thread
from ._zoomable_canvas import _ZoomableCanvas
class _SceneViewer(Gtk.Grid):
def __init__(self):
super().__init__()
self.set_orientation(Gtk.Orientation.VERTICAL)
self._scrolled_window = Gtk.ScrolledWindow()
# self._scrolled_window.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.AUTOMATIC)
self._canvas = _ZoomableCanvas()
self._scrolled_window.add(self._canvas)
self._build_message_bar()
self.add(self._scrolled_window)
self.add(self._message_bar)
self._scene = Clutter.ScrollActor()
self._scene_signal_connections = []
self._canvas.connect('zoom-event', self._on_zoom_event)
def _build_message_bar(self):
self._message_bar = Gtk.Grid()
self._message_bar.set_orientation(Gtk.Orientation.HORIZONTAL)
self._position_format = "({:.2f}, {:.2f})"
self._empty_position = "(-, -)"
self._position_label = Gtk.Label(self._empty_position)
self._color_format = "(<span foreground='red'>{:03}</span>,"\
" <span foreground='green'>{:03}</span>,"\
" <span foreground='blue'>{:03}</span>)"
self._empty_color = "(<span foreground='red'> - </span>,"\
" <span foreground='green'> - </span>,"\
" <span foreground='blue'> - </span>)"
self._color_label = Gtk.Label(self._empty_color, use_markup=True)
self._zoom_format = "Zoom: {:.2f}"
self._zoom_label = Gtk.Label("Zoom: 1.0")
self._message_bar.add(self._position_label)
self._message_bar.add(self._color_label)
self._message_bar.add(self._zoom_label)
def set_scene(self, scene: Union[Clutter.ScrollActor, None]):
for signal_id in self._scene_signal_connections:
image = self._scene.get_first_child()
image.disconnect(signal_id)
self._scene_signal_connections.clear()
if scene is None:
self._scene = Clutter.ScrollActor()
else:
# Only the image is allowed as root node children.
assert scene.get_n_children() == 1
image = scene.get_first_child()
self._scene_signal_connections.append(
image.connect('motion-event', self._on_motion_event)
)
self._scene_signal_connections.append(
image.connect('leave-event', self._on_leave_event)
)
self._scene = scene
self._canvas.set_scene(self._scene)
def _on_motion_event(self, actor, event):
_, x, y = actor.transform_stage_point(event.x, event.y)
r, g, b = actor._ndarray[int(y), int(x)]
self._color_label.set_markup(self._color_format.format(r, g, b))
self._position_label.set_text(self._position_format.format(x, y))
return False
def _on_leave_event(self, actor, event):
self._position_label.set_text(self._empty_position)
self._color_label.set_markup(self._empty_color)
return False
def _on_zoom_event(self, widget, zoom):
self._zoom_label.set_text(self._zoom_format.format(zoom))
[docs]class ImageViewer(Base):
[docs] @on_gtk_thread
def __init__(self, image=None, **kwargs):
super().__init__(**kwargs)
self._gtk_obj = _SceneViewer()
self._image = image
if self._image:
self._gtk_obj.set_scene(self._image._root_actor)
@on_gtk_thread
def set_image(self, image):
self._image = image
if self._image is None:
self._gtk_obj.set_scene(None)
else:
self._gtk_obj.set_scene(self._image._root_actor)