%PDF- %PDF-
| Direktori : /lib/python3/dist-packages/orca/ |
| Current File : //lib/python3/dist-packages/orca/highlighter.py |
# Orca
#
# Copyright 2023 Igalia, S.L.
# Author: Joanmarie Diggs <jdiggs@igalia.com>
#
# This library 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 2.1 of the License, or (at your option) any later version.
#
# This library 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 this library; if not, write to the
# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
# Boston MA 02110-1301 USA.
"""Module for drawing highlights over an area of interest."""
__id__ = "$Id$"
__version__ = "$Revision$"
__date__ = "$Date$"
__copyright__ = "Copyright (c) 2023 Igalia, S.L."
__license__ = "LGPL"
from . import debug
try:
import cairo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
CAIRO_AVAILABLE = True
except Exception as error:
tokens = ["HIGHLIGHTER: GtkHighlighter unavailable:", error]
debug.printTokens(debug.LEVEL_INFO, tokens, True)
CAIRO_AVAILABLE = False
class Highlighter:
"""Base class of all highlighters supported by Orca."""
HIGHLIGHT = "highlight"
RECTANGLE = "rectangle"
UNDERLINE = "underline"
RED = (1, 0, 0)
BLUE = (0, 0, 1)
GREEN = (0, 1, 0)
YELLOW = (1, 1, 0)
PURPLE = (0.5, 0, 0.5)
ORANGE = (1, 0.5, 0)
PINK = (1, 0.75, 0.8)
CYAN = (0, 1, 1)
MAGENTA = (1, 0, 1)
LIME = (0.5, 1, 0)
NAVY = (0, 0, 0.5)
TEAL = (0, 0.5, 0.5)
BLACK = (0, 0, 0)
WHITE = (1, 1, 1)
def __init__(self, highlight_type, color, alpha, thickness, padding, fill_color, fill_alpha):
self._highlight_type = highlight_type
self._color = color
self._alpha = alpha
self._thickness = thickness
self._padding = padding
self._fill_color = fill_color
self._fill_alpha = fill_alpha
self._gui = self._create_gui()
def _create_gui(self):
"""Creates the gui for the overlay."""
return None
def _draw_highlight(self, painter):
"""Called by highlight to draw a highlight over the item."""
pass
def _draw_rectangle(self, painter):
"""Called by highlight to draw a rectangle around the item."""
pass
def _draw_underline(self, painter):
"""Called by highlight to draw an underline under the item."""
pass
def highlight(self, x, y, width, height):
"""Draws the desired indicator over the specified box."""
pass
def quit(self):
"""Quits the highlighter."""
pass
class GtkHighlighter(Highlighter):
"""Highlighter that uses a GtkWindow to highlight items."""
def __init__(self,
highlight_type=Highlighter.UNDERLINE,
color=Highlighter.GREEN,
alpha=1.0,
thickness=5,
padding=5,
fill_color=None,
fill_alpha=None):
if not CAIRO_AVAILABLE:
msg = "GTK HIGHLIGHTER: Unavailable. Is Cairo installed?"
debug.printMessage(debug.LEVEL_INFO, msg, True)
return
super().__init__(highlight_type, color, alpha, thickness, padding, fill_color, fill_alpha)
self._drawing_area = None
def _create_gui(self):
"""Creates the gui for the overlay."""
gui = Gtk.Window()
gui.set_decorated(False)
gui.set_accept_focus(False)
gui.set_app_paintable(True)
gui.set_skip_taskbar_hint(True)
gui.set_skip_pager_hint(True)
screen = gui.get_screen()
visual = screen.get_rgba_visual()
if visual and screen.is_composited():
gui.set_visual(visual)
self._drawing_area = Gtk.DrawingArea()
self._drawing_area.connect("draw", self._on_draw)
gui.add(self._drawing_area)
return gui
def _on_draw(self, widget, painter):
"""Signal handler for the 'draw' event."""
if self._highlight_type == self.HIGHLIGHT:
self._draw_highlight(painter)
elif self._highlight_type == self.RECTANGLE:
self._draw_rectangle(painter)
elif self._highlight_type == self.UNDERLINE:
self._draw_underline(painter)
def _draw_highlight(self, painter):
"""Called by highlight to draw a highlight over the item."""
if self._fill_color is None:
self._fill_color = self.YELLOW
if self._fill_alpha is None:
self._fill_alpha = 0.3
fill = (*self._fill_color, self._fill_alpha)
painter.set_source_rgba(*fill)
painter.set_operator(cairo.OPERATOR_SOURCE)
painter.paint()
painter.set_operator(cairo.OPERATOR_OVER)
def _draw_rectangle(self, painter):
"""Called by highlight to draw a rectangle around the item."""
x = self._padding
y = self._padding
width = self._gui.get_allocated_width() - 2 * self._padding
height = self._gui.get_allocated_height() - 2 * self._padding
if self._fill_color is not None and self._fill_alpha is not None:
fill = (*self._fill_color, self._fill_alpha * 255)
painter.set_source_rgba(*fill)
painter.rectangle(x, y, width, height)
painter.fill()
line = (*self._color, self._alpha)
painter.set_source_rgba(*line)
painter.set_line_width(self._thickness)
painter.rectangle(x, y, width, height)
painter.stroke()
def _draw_underline(self, painter):
"""Called by highlight to draw an underline under the item."""
line = (*self._color, self._alpha)
painter.set_source_rgba(*line)
painter.set_line_width(self._thickness)
painter.move_to(0, self._gui.get_allocated_height() - 5)
painter.line_to(self._gui.get_allocated_width(), self._gui.get_allocated_height() - 5)
painter.stroke()
def highlight(self, x, y, width, height):
"""Draws the desired indicator over the specified box."""
msg = f"GTK HIGHLIGHTER: x:{x}, y:{y}, width:{width}, height:{height}"
debug.printMessage(debug.LEVEL_INFO, msg, True)
try:
self._gui.move(x - self._padding, y - self._padding)
self._gui.resize(width + 2 * self._padding, height + 2 * self._padding)
except Exception as exc:
error_tokens = ["GTK HIGHLIGHTER: Exception:", exc]
debug.printTokens(debug.LEVEL_INFO, error_tokens, True)
else:
self._gui.show_all()
def quit(self):
"""Quits the highlighter."""
msg = "GTK HIGHLIGHTER: Quitting."
debug.printMessage(debug.LEVEL_INFO, msg, True)
self._gui.destroy()
self._drawing_area = None
self._gui = None