Upgraded region select interface

This commit is contained in:
itdominator 2025-04-05 02:40:14 -05:00
parent b527d8ed9f
commit f731796c99
11 changed files with 395 additions and 12 deletions

View File

@ -1,4 +1,5 @@
# Python imports
import time
# Lib imports
import gi
@ -76,9 +77,30 @@ class ScreenshotController:
window = settings.get_main_window()
window.show()
def _grab_region(self, region_window):
def _grab_region(self, region_window, x1, y1, x2, y2):
def show_region_window():
# NOTE: No clue why showing window has it move outta prior place.
# So, move back to original spot before showing...
region_window.move(0, 0)
region_window.show()
@daemon_threaded
def do_bounding_box_grab(x1, y1, x2, y2):
while region_window.is_visible():
...
time.sleep(0.5)
im = capture.grab(bbox = (x1, y1, x2, y2), childprocess = False)
im.save( settings.generate_screenshot_name() )
GLib.idle_add(show_region_window)
region_window.hide()
offset = 1
do_bounding_box_grab(x1 - offset, y1 - offset, x2 + offset, y2 + offset)
def _old_grab_region(self, region_window):
logger.info("Grabbing Selected Region...")
x, y = region_window.get_position()
x1, y1 = region_window.get_position()
w, h = region_window.get_size()
x2 = x + w
y2 = y + h
@ -94,13 +116,14 @@ class ScreenshotController:
while region_window.is_visible():
...
time.sleep(0.5)
im = capture.grab(bbox = (x1, y1, x2, y2), childprocess = False)
im.save( settings.generate_screenshot_name() )
GLib.idle_add(show_region_window)
region_window.hide()
offset = 1
do_bounding_box_grab(x - offset, y - offset, x2 + offset, y2 + offset)
do_bounding_box_grab(x1 - offset, y1 - offset, x2 + offset, y2 + offset)
def grab_selected_monitor(self):

View File

@ -0,0 +1,3 @@
"""
Widgets Module
"""

View File

@ -0,0 +1,72 @@
# Python imports
# Lib imports
import gi
import cairo
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
# Application imports
from .body_grid import BodyGrid
class RegionWindow(Gtk.Window):
def __init__(self):
super(RegionWindow, self).__init__()
self._set_window_data()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
def _setup_styling(self):
self.set_default_size(600, 480)
self.set_keep_above(True)
self.set_deletable(False)
self.set_decorated(False)
self.set_resizable(True)
self.set_skip_pager_hint(True)
self.set_skip_taskbar_hint(True)
self.set_has_resize_grip(True)
def _setup_signals(self):
...
def _subscribe_to_events(self):
event_system.subscribe("show_region_window", self._show_region_window)
def _load_widgets(self):
gdk_window = self.get_screen().get_root_window()
self.add( BodyGrid(self, gdk_window) )
def _set_window_data(self) -> None:
screen = self.get_screen()
visual = screen.get_rgba_visual()
if visual != None and screen.is_composited():
self.set_visual(visual)
self.set_app_paintable(True)
self.connect("draw", self._area_draw)
# bind css file
cssProvider = Gtk.CssProvider()
cssProvider.load_from_path( settings.get_css_file() )
screen = Gdk.Screen.get_default()
styleContext = Gtk.StyleContext()
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
cr.set_source_rgba( *(0, 0, 0, 0.0) )
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.paint()
cr.set_operator(cairo.OPERATOR_OVER)
def _show_region_window(self):
self.show()

View File

@ -1,3 +1,3 @@
"""
Widgets Module
Region Module
"""

View File

@ -0,0 +1,167 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
# Application imports
from .draw_types.draw_cross import DrawCross
from .draw_types.draw_grab_region import DrawGrabRegion
class DrawArea(Gtk.DrawingArea):
def __init__(self):
super(DrawArea, self).__init__()
self.draw_type: DrawType = DrawCross()
self.region_mode: bool = False
self.grab_mode: bool = False
self.mouse_x: int = 0
self.mouse_y: int = 0
self._setup_style()
self._setup_signals()
self._load_widgets()
self.show()
self._render_start_cross_hair()
def _setup_style(self):
self.set_property("can-focus", True)
def _setup_signals(self):
self.add_events( Gdk.EventMask.ALL_EVENTS_MASK )
self.connect("motion-notify-event", self._motion_notify_event)
self.connect("button-press-event", self._button_press_event)
self.connect("button-release-event", self._button_release_event)
self.connect("realize", self._realize)
self.connect("draw", self._draw)
def _load_widgets(self):
...
def _render_start_cross_hair(self):
self.mouse_x = self.get_allocated_width() / 2
self.mouse_y = self.get_allocated_height() / 2
self.queue_draw()
def _realize(self, widget):
self._hide_cursor()
def _draw(self, area, cr):
self.draw_type.draw(area, cr)
def _motion_notify_event(self, widget, eve):
if self.grab_mode: return
self._set_coords(eve)
self.queue_draw()
def _button_press_event(self, widget, eve):
if self.grab_mode: return
if not eve.button == 1: return
self._set_to_region_mode(eve)
def _button_release_event(self, widget, eve):
if self.grab_mode and eve.button == 2: # m-click
self._do_grab()
return
if not eve.button in [1, 3]: return # l or r-click
self._show_cursor()
if eve.button == 3: # r-click
event_system.emit("grab_region_hide", (self.get_parent(),))
return
if self.grab_mode:
self._hide_cursor()
self._unset_grab_mode(eve)
return
self._set_to_grab_mode(eve)
def _show_cursor(self):
window = self.get_parent()
watch_cursor = Gdk.Cursor(Gdk.CursorType.ARROW)
window.get_window().set_cursor(watch_cursor)
def _hide_cursor(self):
window = self.get_parent()
watch_cursor = Gdk.Cursor(Gdk.CursorType.BLANK_CURSOR )
window.get_window().set_cursor(watch_cursor)
def _set_to_region_mode(self, eve):
self.region_mode = True
self.draw_type = DrawGrabRegion()
self._set_coords(eve)
def _set_to_grab_mode(self, eve):
self._set_coords(eve)
self.region_mode = False
self.grab_mode = True
def _unset_grab_mode(self, eve):
self.grab_mode = False
self.draw_type = DrawCross()
self._set_coords(eve)
self.queue_draw()
def _set_coords(self, eve):
if not self.region_mode:
self.mouse_x = int(eve.x)
self.mouse_y = int(eve.y)
self.region_start_x = int(eve.x)
self.region_start_y = int(eve.y)
else:
self.region_end_x = int(eve.x)
self.region_end_y = int(eve.y)
def _do_grab(self):
sx = self.region_start_x
sy = self.region_start_y
ex = self.region_end_x
ey = self.region_end_y
x1 = sx
y1 = sy
x2 = ex
y2 = ey
if sx > ex and sy < ey: # NE to SW
x1 = sx - (sx - ex)
y1 = sy
x2 = sx
y2 = sy + (ey - sy)
elif not ex > sx and not ey > sy: # SE to NW
x1 = ex
y1 = ey
x2 = sx
y2 = sy
elif ex > sx and ey < sy: # SW to NE
x1 = ex - (ex - sx)
y1 = ey
x2 = ex
y2 = ey + (sy - ey)
event_system.emit(
"grab_region",
(
self.get_parent(),
x1,
y1,
x2,
y2,
)
)

View File

@ -0,0 +1,3 @@
"""
Draw Types Module
"""

View File

@ -0,0 +1,31 @@
# Python imports
# Lib imports
# Application imports
from .draw_type_base import DrawTypeBase
class DrawCross(DrawTypeBase):
def __init__(self):
super(DrawCross, self).__init__()
def draw(self, area, cr):
if not area.mouse_x or not area.mouse_y: return
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.set_line_width(1.0)
cr.set_line_cap(2) # 0 = BUTT, 1 = ROUND, 2 = SQUARE
cr.set_line_join(1) # 0 = BEVEL, 1 = MITER, 2 = ROUND
# Horizon
cr.move_to(0, area.mouse_y)
cr.line_to(area.get_allocated_width(), area.mouse_y)
cr.stroke()
# Vertical
cr.move_to(area.mouse_x, 0)
cr.line_to(area.mouse_x, area.get_allocated_height())
cr.stroke()

View File

@ -0,0 +1,48 @@
# Python imports
# Lib imports
# Application imports
from .draw_type_base import DrawTypeBase
class DrawGrabRegion(DrawTypeBase):
def __init__(self):
super(DrawGrabRegion, self).__init__()
def draw(self, area, cr):
cr.set_source_rgba(1.0, 1.0, 0.0, 1.0)
cr.set_line_width(1.0)
cr.set_line_cap(2) # 0 = BUTT, 1 = ROUND, 2 = SQUARE
cr.set_line_join(1) # 0 = BEVEL, 1 = MITER, 2 = ROUND
self._draw_start_cross(area, cr)
self._draw_end_cross(area, cr)
def _draw_start_cross(self, area, cr):
# Horizon
cr.move_to(0, area.region_start_y)
cr.line_to(area.get_allocated_width(), area.region_start_y)
cr.stroke()
# Vertical
cr.move_to(area.region_start_x, 0)
cr.line_to(area.region_start_x, area.get_allocated_height())
cr.stroke()
def _draw_end_cross(self, area, cr):
# Horizon
cr.move_to(0, area.region_end_y)
cr.line_to(area.get_allocated_width(), area.region_end_y)
cr.stroke()
# Vertical
cr.move_to(area.region_end_x, 0)
cr.line_to(area.region_end_x, area.get_allocated_height())
cr.stroke()

View File

@ -0,0 +1,15 @@
# Python imports
# Lib imports
# Application imports
class OverrideExceptionw(Exception):
...
class DrawTypeBase:
def draw(self, widget, cr):
raise OverrideException("Method hasn't been overriden...")

View File

@ -9,7 +9,7 @@ from gi.repository import Gtk
from gi.repository import Gdk
# Application imports
from .body_grid import BodyGrid
from .draw_area import DrawArea
@ -25,7 +25,9 @@ class RegionWindow(Gtk.Window):
def _setup_styling(self):
self.set_default_size(600, 480)
screen = Gdk.Screen.get_default()
ctx = self.get_style_context()
self.set_keep_above(True)
self.set_deletable(False)
self.set_decorated(False)
@ -34,6 +36,14 @@ class RegionWindow(Gtk.Window):
self.set_skip_taskbar_hint(True)
self.set_has_resize_grip(True)
self.move(0, 0)
self.set_size_request(
*self.get_screen_size(
Gdk.Display.get_default()
)
)
def _setup_signals(self):
...
@ -41,8 +51,7 @@ class RegionWindow(Gtk.Window):
event_system.subscribe("show_region_window", self._show_region_window)
def _load_widgets(self):
gdk_window = self.get_screen().get_root_window()
self.add( BodyGrid(self, gdk_window) )
self.add( DrawArea() )
def _set_window_data(self) -> None:
screen = self.get_screen()
@ -51,7 +60,6 @@ class RegionWindow(Gtk.Window):
if visual != None and screen.is_composited():
self.set_visual(visual)
self.set_app_paintable(True)
self.connect("draw", self._area_draw)
# bind css file
cssProvider = Gtk.CssProvider()
@ -60,6 +68,19 @@ class RegionWindow(Gtk.Window):
styleContext = Gtk.StyleContext()
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
def get_screen_size(self, display):
mon_geoms = [
display.get_monitor(i).get_geometry()
for i in range(display.get_n_monitors())
]
x0 = min(r.x for r in mon_geoms)
y0 = min(r.y for r in mon_geoms)
x1 = max(r.x + r.width for r in mon_geoms)
y1 = max(r.y + r.height for r in mon_geoms)
return x1 - x0, y1 - y0
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
cr.set_source_rgba( *(0, 0, 0, 0.0) )
cr.set_operator(cairo.OPERATOR_SOURCE)