Skip to content

Instantly share code, notes, and snippets.

@cunidev
Last active April 12, 2024 19:50
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cunidev/d6e030ad576460a58f9503da44af4a55 to your computer and use it in GitHub Desktop.
Save cunidev/d6e030ad576460a58f9503da44af4a55 to your computer and use it in GitHub Desktop.
Tutorial to rotate and zoom things (an useless rectangle here) using Gtk.Gesture touchpad and touchscreen gestures in Python GTK3 (gi) bindings. Spaghetti ahead!
#!/usr/bin/python3
# Needs Wayland!
import gi, math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import cairo
dialog = Gtk.MessageDialog(None, 0, Gtk.MessageType.WARNING,
Gtk.ButtonsType.OK_CANCEL, "Press OK to test rotate")
dialog.format_secondary_text(
"Press Cancel to test zoom")
is_rotate = (dialog.run() == Gtk.ResponseType.OK)
dialog.destroy()
testing = "Testing "+("Rotation" if is_rotate else "Zoom")
win = Gtk.Window()
win.set_default_size(800, 600)
drw = Gtk.DrawingArea()
label = Gtk.Label(testing)
angle_offset = 0
angle_cur = 0
scale_offset = 0
scale = 1
if(is_rotate):
scale = 3 # otherwise it will be unreadably small
def rotate_begin(self, widget):
global label
label.set_text("Rotating!")
def rotate_follow(self, widget):
global angle_offset, angle_cur
angle_cur = self.get_angle_delta()
drw.queue_draw()
def rotate_end(self, widget):
global angle_offset, angle_cur, label, testing
angle_offset += angle_cur
angle_cur = 0
drw.queue_draw()
label.set_text(testing)
def zoom_begin(self, widget):
global label
label.set_text("Zooming!")
def zoom_follow(self, widget):
global scale
scale = self.get_scale_delta()
drw.queue_draw()
def zoom_end(self, widget):
global scale, scale_offset, label, testing
scale_offset += (scale - 1)
if(scale_offset < -0.95):
scale_offset = -0.95
scale = 1
drw.queue_draw()
label.set_text(testing)
def paint(self, cr):
scale_f = scale + scale_offset # may not be mathematically correct
if(scale_f < 0.05):
scale_f = 0.05
angle_f = angle_offset + angle_cur
fsizef = scale_f * 4
s = "Testing Zoom"
if(is_rotate):
s = "Testing Rotation"
cr.set_line_width(2 * scale_f)
cr.set_source_rgb(0, 0, 0.0)
w = self.get_allocation().width
h = self.get_allocation().height
cr.translate(w/2, h/2)
cr.rotate(angle_f)
cr.rectangle(-50 * scale_f,
-75 * scale_f,
100 * scale_f,
150 * scale_f)
cr.stroke_preserve()
cr.set_source_rgb(0.85, 0.85, 0.85)
cr.fill()
cr.set_source_rgb(0.1, 0.1, 0.1)
cr.translate(-45 * scale_f, -65 * scale_f)
cr.set_font_size(fsizef)
cr.text_path("In a hole in the ground there lived a hobbit. Not a ")
cr.translate(0, fsizef + (0.6 * fsizef))
cr.fill()
cr.text_path("nasty, dirty, wet hole, filled with the ends of worms")
cr.translate(0, fsizef + (0.6 * fsizef))
cr.fill()
cr.text_path("and an oozy smell, nor yet a dry, bare, sandy hole ")
cr.translate(0, fsizef + (0.6 * fsizef))
cr.fill()
cr.text_path("with nothing in it to sit down on or to eat: it was")
cr.translate(0, fsizef + (0.6 * fsizef))
cr.fill()
cr.text_path("a hobbit-hole, and that means comfort. ")
cr.fill()
# font size is an integer, which means font zooming won't be too smooth in this demo
drw.connect("draw", paint)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, vexpand=True, valign=Gtk.Align.FILL)
box.pack_start(label, False, False, 0)
box.pack_start(drw, True, True, 0)
win.add(box)
if is_rotate:
gesture = Gtk.GestureRotate.new(drw)
gesture.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
gesture.connect("begin", rotate_begin)
gesture.connect("update", rotate_follow)
gesture.connect("end", rotate_end)
else:
gesture = Gtk.GestureZoom.new(drw)
gesture.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
gesture.connect("begin", zoom_begin)
gesture.connect("update", zoom_follow)
gesture.connect("end", zoom_end)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
@mojiAh
Copy link

mojiAh commented Oct 8, 2019

Hi there, thanks for sharing. Can you also explain how to test it if there is not any touch device available? I mean how to test it on desktop.

@cunidev
Copy link
Author

cunidev commented Oct 8, 2019

It is actually designed for laptops/non-touch devices. You need to run it in Wayland though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment