From df0d686413ed05a0b8031c6b49d6144e2a5ead9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20Qui=C3=B1ones?= <manuq@laptop.org>
Date: Fri, 15 Feb 2013 00:30:00 -0300
Subject: [PATCH 4/6] Implement the mouse callbacks for grab hands feature - SL
#1959
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Mail-Followup-To: <sugar-devel@lists.sugarlabs.org>
- On mouse press, check if a hand is close to the mouse pointer and
select it
- On mouse move, point the selected hand to the mouse pointer, if
there is one
- On mouse release, free the selected hand, if there is one
- In the mouse events callbacks, listen only to button 1, return
otherwise
- Force redraw after the display mode changes (simple clock, nice or
digital) because the timer that refreshes the clock is stopped in
grab hands mode
Signed-off-by: Manuel Quiñones <manuq@laptop.org>
---
clock.py | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 85 insertions(+), 8 deletions(-)
diff --git a/clock.py b/clock.py
index bcebf3e..5bbb90a 100755
a
|
b
|
More about clocks and time in the World |
54 | 54 | http://en.wikipedia.org/wiki/Date_and_time_notation_by_country |
55 | 55 | |
56 | 56 | """ |
57 | | # FIXME: remove |
58 | | import logging |
59 | 57 | |
60 | 58 | # We initialize threading in gobject. As we will detach another thread |
61 | 59 | # to translate the time to text, this other thread will eventually |
… |
… |
_MODE_DIGITAL_CLOCK = 2 |
112 | 110 | # named after our pid, to inhibit suspend. |
113 | 111 | POWERD_INHIBIT_DIR = '/var/run/powerd-inhibit-suspend' |
114 | 112 | |
| 113 | # Tolerance for grabbing hands, in radians. Each hand can be grabbed |
| 114 | # if the user press on a piece of the circle that is the angle of the |
| 115 | # hand +- the tolerance angle. |
| 116 | _ANGLE_TOLERANCE = 0.3 |
| 117 | |
| 118 | |
115 | 119 | class ClockActivity(activity.Activity): |
116 | 120 | """The clock activity displays a simple clock widget. |
117 | 121 | """ |
… |
… |
class ClockActivity(activity.Activity): |
367 | 371 | or digital). |
368 | 372 | """ |
369 | 373 | self._clock.set_display_mode(display_mode) |
| 374 | self._clock.queue_draw() |
370 | 375 | |
371 | 376 | is_digital = display_mode == _MODE_DIGITAL_CLOCK |
372 | 377 | |
… |
… |
class ClockFace(gtk.DrawingArea): |
575 | 580 | # This flag is True if the clock is in grab hands mode |
576 | 581 | self.grab_hands_mode = False |
577 | 582 | |
| 583 | # When grabbing a hand, this is the name of the hand. If |
| 584 | # None, it means that no hand is being grabbed |
| 585 | self._hand_being_grabbed = None |
| 586 | |
578 | 587 | # Event handlers for grabbing the hands. |
579 | 588 | self._press_id = None |
580 | 589 | self._motion_id = None |
… |
… |
font_desc="Sans Bold 40">%d</span></markup>') % (i + 1) |
908 | 917 | self._old_minute = self._time.minute |
909 | 918 | |
910 | 919 | # Keep running this timer as long as the clock is active |
911 | | # (ie. visible) |
912 | | return self._active |
| 920 | # (ie. visible) or the mode changes to dragging the hands of |
| 921 | # the clock |
| 922 | return self._active and not self.grab_hands_mode |
913 | 923 | |
914 | 924 | def get_time(self): |
915 | 925 | """Public access to the time member of the clock face. |
… |
… |
font_desc="Sans Bold 40">%d</span></markup>') % (i + 1) |
943 | 953 | """Connect or disconnect the callbacks for to grab the hands |
944 | 954 | of the clock. |
945 | 955 | """ |
946 | | logging.debug("CHANGE GRAB %r", toggle_grab) |
947 | 956 | self.grab_hands_mode = toggle_grab |
948 | 957 | |
949 | 958 | if toggle_grab: |
… |
… |
font_desc="Sans Bold 40">%d</span></markup>') % (i + 1) |
962 | 971 | gobject.timeout_add(1000, self._update_cb) |
963 | 972 | |
964 | 973 | def _press_cb(self, widget, event): |
965 | | logging.debug("PRESS") |
| 974 | mouse_x, mouse_y, state = event.window.get_pointer() |
| 975 | |
| 976 | # Only pay attention to the button 1 |
| 977 | if not (state & gtk.gdk.BUTTON1_MASK): |
| 978 | return |
| 979 | |
| 980 | # Calculate the angle from the center of the clock to the |
| 981 | # mouse pointer |
| 982 | adjacent = mouse_x - self._center_x |
| 983 | opposite = -1 * (mouse_y - self._center_y) |
| 984 | pointer_angle = math.atan2(adjacent, opposite) |
| 985 | |
| 986 | # Calculate the distance from the center of the clock to the |
| 987 | # mouse pointer |
| 988 | pointer_distance = math.hypot(adjacent, opposite) |
| 989 | |
| 990 | # If the angle is negative, convert it to the equal angle |
| 991 | # between 0 and 2 PI |
| 992 | if pointer_angle < 0: |
| 993 | pointer_angle += math.pi * 2 |
| 994 | |
| 995 | def in_range(hand_angle, angle): |
| 996 | """Return True if the given angle is in a range of the |
| 997 | hand_angle +- the angle tolerance. |
| 998 | """ |
| 999 | # This is the normalized angle, the equal angle that is |
| 1000 | # minor than 2 PI |
| 1001 | hand_normal = (hand_angle - |
| 1002 | (math.pi * 2) * int(hand_angle / (math.pi * 2))) |
| 1003 | |
| 1004 | return (hand_normal >= angle - _ANGLE_TOLERANCE and |
| 1005 | hand_normal < angle + _ANGLE_TOLERANCE) |
| 1006 | |
| 1007 | # Check if we can start grabbing a hand of the clock: |
| 1008 | for hand in ['hour', 'minutes', 'seconds']: |
| 1009 | if in_range(self._hand_angles[hand], pointer_angle): |
| 1010 | if pointer_distance <= self._hand_sizes[hand]: |
| 1011 | self._hand_being_grabbed = hand |
| 1012 | break |
966 | 1013 | |
967 | 1014 | def _motion_cb(self, widget, event): |
968 | | logging.debug("MOTION") |
| 1015 | if self._hand_being_grabbed is None: |
| 1016 | return |
| 1017 | |
| 1018 | if event.is_hint: |
| 1019 | mouse_x, mouse_y, state = event.window.get_pointer() |
| 1020 | else: |
| 1021 | mouse_x = event.x |
| 1022 | mouse_y = event.y |
| 1023 | state = event.state |
| 1024 | |
| 1025 | # Only pay attention to the button 1 |
| 1026 | if not state & gtk.gdk.BUTTON1_MASK: |
| 1027 | return |
| 1028 | |
| 1029 | # Calculate the angle from the center of the clock to the |
| 1030 | # mouse pointer |
| 1031 | adjacent = mouse_x - self._center_x |
| 1032 | opposite = -1 * (mouse_y - self._center_y) |
| 1033 | pointer_angle = math.atan2(adjacent, opposite) |
| 1034 | |
| 1035 | # If the angle is negative, convert it to the equal angle |
| 1036 | # between 0 and 2 PI |
| 1037 | if pointer_angle < 0: |
| 1038 | pointer_angle += math.pi * 2 |
| 1039 | |
| 1040 | # Update the angle of the hand being grabbed |
| 1041 | self._hand_angles[self._hand_being_grabbed] = pointer_angle |
| 1042 | |
| 1043 | # Force redraw of the clock: |
| 1044 | self.queue_draw() |
969 | 1045 | |
970 | 1046 | def _release_cb(self, widget, event): |
971 | | logging.debug("RELEASE") |
| 1047 | self._hand_being_grabbed = None |
| 1048 | self.queue_draw() |