Ticket #1959: 0004-Implement-the-mouse-callbacks-for-grab-hands-feature.patch

File 0004-Implement-the-mouse-callbacks-for-grab-hands-feature.patch, 6.3 KB (added by manuq, 11 years ago)
  • clock.py

    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 
    5454  http://en.wikipedia.org/wiki/Date_and_time_notation_by_country
    5555
    5656"""
    57 # FIXME: remove
    58 import logging
    5957
    6058# We initialize threading in gobject. As we will detach another thread
    6159# to translate the time to text, this other thread will eventually
    _MODE_DIGITAL_CLOCK = 2 
    112110# named after our pid, to inhibit suspend.
    113111POWERD_INHIBIT_DIR = '/var/run/powerd-inhibit-suspend'
    114112
     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
    115119class ClockActivity(activity.Activity):
    116120    """The clock activity displays a simple clock widget.
    117121    """
    class ClockActivity(activity.Activity): 
    367371        or digital).
    368372        """
    369373        self._clock.set_display_mode(display_mode)
     374        self._clock.queue_draw()
    370375
    371376        is_digital = display_mode == _MODE_DIGITAL_CLOCK
    372377
    class ClockFace(gtk.DrawingArea): 
    575580        # This flag is True if the clock is in grab hands mode
    576581        self.grab_hands_mode = False
    577582
     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
    578587        # Event handlers for grabbing the hands.
    579588        self._press_id = None
    580589        self._motion_id = None
    font_desc="Sans Bold 40">%d</span></markup>') % (i + 1) 
    908917            self._old_minute = self._time.minute
    909918
    910919        # 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
    913923
    914924    def get_time(self):
    915925        """Public access to the time member of the clock face.
    font_desc="Sans Bold 40">%d</span></markup>') % (i + 1) 
    943953        """Connect or disconnect the callbacks for to grab the hands
    944954        of the clock.
    945955        """
    946         logging.debug("CHANGE GRAB %r", toggle_grab)
    947956        self.grab_hands_mode = toggle_grab
    948957
    949958        if toggle_grab:
    font_desc="Sans Bold 40">%d</span></markup>') % (i + 1) 
    962971            gobject.timeout_add(1000, self._update_cb)
    963972
    964973    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
    9661013
    9671014    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()
    9691045
    9701046    def _release_cb(self, widget, event):
    971         logging.debug("RELEASE")
     1047        self._hand_being_grabbed = None
     1048        self.queue_draw()