Exemplo n.º 1
0
    def on_mouse(self, event):
        '''EVT_MOUSE_EVENTS handler.'''
        # todo: maybe right click should give context menu with 'Sensitivity...'
        # todo: make check: if left up and has capture, release capture

        self.Refresh()
        
        (w, h) = self.GetClientSize()
        (x, y) = event.GetPositionTuple()
        
        
        if event.LeftDown():
            self.being_dragged = True
            self.snap_map = SnapMap(
                snap_point_ratios=self._get_snap_points_as_ratios(),
                base_drag_radius=self.base_drag_radius,
                snap_point_drag_well=self.snap_point_drag_well,
                initial_y=y,
                initial_ratio=self.current_ratio
            )
            
            self.SetCursor(cursor_collection.get_closed_grab())
            # SetCursor must be before CaptureMouse because of wxPython/GTK
            # weirdness
            self.CaptureMouse()
            
            return
        
        if event.LeftIsDown() and self.HasCapture():
            ratio = self.snap_map.y_to_ratio(y)
            value = self._ratio_to_value(ratio)
            self.value_setter(value)
            
                
        if event.LeftUp():
            # todo: make sure that when leaving
            # entire app, things don't get f****d
            if self.HasCapture():
                self.ReleaseMouse()
            # SetCursor must be after ReleaseMouse because of wxPython/GTK
            # weirdness
            self.SetCursor(cursor_collection.get_open_grab())
            self.being_dragged = False
            self.snap_map = None
            
            
        return
Exemplo n.º 2
0
    def on_mouse(self, event):
        '''EVT_MOUSE_EVENTS handler.'''
        # todo: maybe right click should give context menu with
        # 'Sensitivity...'
        # todo: make check: if left up and has capture, release capture

        self.Refresh()

        (w, h) = self.GetClientSize()
        (x, y) = event.GetPositionTuple()

        if event.LeftDown():
            self.being_dragged = True
            self.snap_map = SnapMap(
                snap_point_ratios=self._get_snap_points_as_ratios(),
                base_drag_radius=self.base_drag_radius,
                snap_point_drag_well=self.snap_point_drag_well,
                initial_y=y,
                initial_ratio=self.current_ratio)

            self.SetCursor(cursor_collection.get_closed_grab())
            # SetCursor must be before CaptureMouse because of wxPython/GTK
            # weirdness
            self.CaptureMouse()

            return

        if event.LeftIsDown() and self.HasCapture():
            ratio = self.snap_map.y_to_ratio(y)
            value = self._ratio_to_value(ratio)
            self.value_setter(value)

        if event.LeftUp():
            # todo: make sure that when leaving
            # entire app, things don't get f****d
            if self.HasCapture():
                self.ReleaseMouse()
            # SetCursor must be after ReleaseMouse because of wxPython/GTK
            # weirdness
            self.SetCursor(cursor_collection.get_open_grab())
            self.being_dragged = False
            self.snap_map = None

        return
Exemplo n.º 3
0
 def __init__(self, parent, gui_project, *args, **kwargs):
     
     if 'style' in kwargs:
         kwargs['style'] |= wx.SUNKEN_BORDER
     else:
         kwargs['style'] = wx.SUNKEN_BORDER
         
     wx.Panel.__init__(self, parent, *args, **kwargs)
     
     self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
     
     self.Bind(wx.EVT_PAINT, self.on_paint)
     self.Bind(wx.EVT_SIZE, self.on_size)
     self.Bind(wx.EVT_MOUSE_EVENTS, self.on_mouse_event)
     self.Unbind(wx.EVT_ERASE_BACKGROUND) # Good or bad?
     
     self.SetCursor(cursor_collection.get_open_grab())
     
     self.gui_project = gui_project
     '''The gui project that this scratch wheel is attached to.'''
     
     assert isinstance(self.gui_project, garlicsim_wx.GuiProject)
     
     self.current_frame_number = -1
     '''Serial number of the frame that is currently drawn.'''
     # Set to -1 to make sure first drawing won't f**k up
     
     self.current_blur_alpha = 0.
     '''The current level of motion blur. Between 0 and 1.'''
     
     self.current_bitmap = None
     '''Current bitmap of the wheel.'''
     
     self.image_size = images.get_image_size()
     '''The size of the gear image.'''
     
     self.clock_factor = 0.05 # todo: maybe rename
     '''
     Factor for converting from simulations seconds to radians in the gear.
     '''
     
     self.being_dragged = False
     '''Flag that says whether the gear is currently being dragged.'''
     
     self.grabbed_angle = None
     '''The angle that the user grabbed when starting to drag.'''
     
     self.grabbed_pseudoclock = None
     '''The pseudoclock that the user grabbed when starting to drag.'''
     
     self.angle_while_dragging = None
     
     self.d_angle_while_dragging = None
     
     self.desired_clock_while_dragging = None
             
     self.last_tracked_time_and_angle = (0, 0)
     '''A tuple of (time, angle) that was recorded for velocity tracking.'''
     
     self.current_velocity_estimate = 0
     '''
     The current estimate of the gear's velocity.
     
     The units are radian per second, and that's a real world second, not in
     the simulation.
     '''
     
     self.velocity_for_maximal_motion_blur = 10
     '''Velocity in which the scratch wheel will get maximal motion blur.'''
     
     self.velocity_time_sampling_minimum = 0.07
     '''The minimum interval over which we can measure the gear's velocity.'''
     
     self.was_playing_before_drag = None
     '''Flag saying if playback was active before user grabbed the gear.'''
         
     self.motion_blur_update_timer = cute_timer.CuteTimer(self)
     '''
     Timer to use for updating the motion blur bitmap.
     
     The motion blur bitmap must get updated periodically as long as its last
     value was non-zero, even if the user doesn't touch anything. This is
     because we don't want to have a situtation where the user dragged fast,
     got a high motion blur, left the scratch wheel, and then the wheel is
     frozen with a high motion blur.
     '''
     
     self.Bind(wx.EVT_TIMER,
               self.on_motion_blur_update_timer,
               self.motion_blur_update_timer)
     
     
     self.recalculation_flag = False
     '''Flag saying whether the scratch wheel needs to recalculate.'''
     
     self.needs_recalculation_emitter = \
         self.gui_project.emitter_system.make_emitter(
             inputs=(
                 self.gui_project.pseudoclock_modified_emitter,
                 self.gui_project.active_node_changed_or_modified_emitter
                 # todo: needed?
             ),
             outputs=(
                 FlagRaiser(self, 'recalculation_flag',
                            function=self._recalculate),
                 # todo: There was originally delay=0.03 here, but it made 
                 # things too sluggish so I removed it. Will this cause a
                 # problem?
             ),
             name='needs_recalculation',
         )
     
     
     self.needs_recalculation_emitter.emit()
Exemplo n.º 4
0
    def on_mouse_event(self, e):
        '''EVT_MOUSE_EVENTS handler.'''
        # todo: possibly do momentum, like in old shockwave carouselle.
        # todo: right click should give context menu with 'Sensitivity...' and
        # 'Disable'
        # todo: make check: if left up and has capture, release capture

        self.Refresh()
        
        (w, h) = self.GetClientSize()
        (x, y) = e.GetPositionTuple()
        (rx, ry) = (x/w, y/h)
        
        if e.LeftDown():
            self.angle_while_dragging = self.grabbed_angle = self._expanded_pos_to_angle(rx)
            self.d_angle_while_dragging = 0
            self.desired_clock_while_dragging = self.grabbed_pseudoclock = \
                self.gui_project.pseudoclock
            self.was_playing_before_drag = self.gui_project.is_playing
            self.gui_project.stop_playing()
            self.being_dragged = True
            
            self.SetCursor(cursor_collection.get_closed_grab())
            # SetCursor must be before CaptureMouse because of wxPython/GTK
            # weirdness
            self.CaptureMouse()
            
            return
        
        if e.LeftIsDown():
            if not self.HasCapture():
                return
            self.angle_while_dragging = self._expanded_pos_to_angle(rx)
            self.d_angle_while_dragging = (self.angle_while_dragging - self.grabbed_angle)
            
            desired_pseudoclock = self.grabbed_pseudoclock + \
                (self.d_angle_while_dragging / self.clock_factor)
            
            self.gui_project.set_pseudoclock(desired_pseudoclock)
            
            if self.gui_project.pseudoclock != desired_pseudoclock:
                # Means we got an edge node
                
                edge_clock = self.gui_project.active_node.state.clock
                direction = cmp(self.gui_project.pseudoclock,
                                desired_pseudoclock)
                # direction that we bring back the cursor to if it goes too far
                d_clock = (edge_clock - self.grabbed_pseudoclock)
                d_angle = d_clock * self.clock_factor
                edge_angle = self.grabbed_angle + d_angle
                edge_rx = self._expanded_angle_to_pos(edge_angle)
                edge_x = edge_rx * w
                is_going_over = \
                    (edge_x - x > 0) if direction == 1 else (edge_x - x < 0)
                if is_going_over:
                    self.WarpPointer(edge_x, y)
            
                
        if e.LeftUp(): #or e.Leaving():
            # todo: make sure that when leaving entire app, things don't get
            # f****d
            if self.HasCapture():
                self.ReleaseMouse()
            # SetCursor must be after ReleaseMouse because of wxPython/GTK
            # weirdness
            self.SetCursor(cursor_collection.get_open_grab())
            self.being_dragged = False
            self.grabbed_angle = None
            self.grabbed_pseudoclock = None
            self.angle_while_dragging = None
            self.d_angle_while_dragging = None
            self.desired_clock_while_dragging = None
            
            if self.was_playing_before_drag:
                self.gui_project.start_playing()
                
            self.gui_project.round_pseudoclock_to_active_node()
                
            self.was_playing_before_drag = None
Exemplo n.º 5
0
 def __init__(self, parent, gui_project, *args, **kwargs):
     
     if 'style' in kwargs:
         kwargs['style'] |= wx.SUNKEN_BORDER
     else:
         kwargs['style'] = wx.SUNKEN_BORDER
         
     wx.Panel.__init__(self, parent, *args, **kwargs)
     
     self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
     
     self.Bind(wx.EVT_PAINT, self.on_paint)
     self.Bind(wx.EVT_SIZE, self.on_size)
     self.Bind(wx.EVT_MOUSE_EVENTS, self.on_mouse_event)
     self.Unbind(wx.EVT_ERASE_BACKGROUND) # Good or bad?
     
     self.SetCursor(cursor_collection.get_open_grab())
     
     self.gui_project = gui_project
     '''The gui project that this scratch wheel is attached to.'''
     
     assert isinstance(self.gui_project, garlicsim_wx.GuiProject)
     
     self.current_frame_number = -1
     '''Serial number of the frame that is currently drawn.'''
     # Set to -1 to make sure first drawing won't f**k up
     
     self.current_blur_alpha = 0.
     '''The current level of motion blur. Between 0 and 1.'''
     
     self.current_bitmap = None
     '''Current bitmap of the wheel.'''
     
     self.image_size = images.get_image_size()
     '''The size of the gear image.'''
     
     self.clock_factor = 0.05 # todo: maybe rename
     '''
     Factor for converting from simulations seconds to radians in the gear.
     '''
     
     self.being_dragged = False
     '''Flag that says whether the gear is currently being dragged.'''
     
     self.grabbed_angle = None
     '''The angle that the user grabbed when starting to drag.'''
     
     self.grabbed_pseudoclock = None
     '''The pseudoclock that the user grabbed when starting to drag.'''
     
     self.angle_while_dragging = None
     
     self.d_angle_while_dragging = None
     
     self.desired_clock_while_dragging = None
             
     self.last_tracked_time_and_angle = (0, 0)
     '''A tuple of (time, angle) that was recorded for velocity tracking.'''
     
     self.current_velocity_estimate = 0
     '''
     The current estimate of the gear's velocity.
     
     The units are radian per second, and that's a real world second, not in
     the simulation.
     '''
     
     self.velocity_for_maximal_motion_blur = 10
     '''Velocity in which the scratch wheel will get maximal motion blur.'''
     
     self.velocity_time_sampling_minimum = 0.07
     '''Minimum interval over which we can measure the gear's velocity.'''
     
     self.was_playing_before_drag = None
     '''Flag saying if playback was active before user grabbed the gear.'''
         
     self.motion_blur_update_timer = cute_timer.CuteTimer(self)
     '''
     Timer to use for updating the motion blur bitmap.
     
     The motion blur bitmap must get updated periodically as long as its
     last value was non-zero, even if the user doesn't touch anything. This
     is because we don't want to have a situtation where the user dragged
     fast, got a high motion blur, left the scratch wheel, and then the
     wheel is frozen with a high motion blur.
     '''
     
     self.Bind(wx.EVT_TIMER,
               self.on_motion_blur_update_timer,
               self.motion_blur_update_timer)
     
     
     self.recalculation_flag = False
     '''Flag saying whether the scratch wheel needs to recalculate.'''
     
     self.needs_recalculation_emitter = \
         self.gui_project.emitter_system.make_emitter(
             inputs=(
                 self.gui_project.pseudoclock_modified_emitter,
                 self.gui_project.active_node_changed_or_modified_emitter
                 # todo: needed?
             ),
             outputs=(
                 FlagRaiser(self, 'recalculation_flag',
                            function=self._recalculate),
                 # todo: There was originally delay=0.03 here, but it made 
                 # things too sluggish so I removed it. Will this cause a
                 # problem?
             ),
             name='needs_recalculation',
         )
     
     
     self.needs_recalculation_emitter.emit()
Exemplo n.º 6
0
    def on_mouse_event(self, e):
        '''EVT_MOUSE_EVENTS handler.'''
        # todo: possibly do momentum, like in old shockwave carouselle.
        # todo: right click should give context menu with 'Sensitivity...' and
        # 'Disable'
        # todo: make check: if left up and has capture, release capture

        
        # If the gui project has no active path, we can't navigate on it at
        # all:
        if self.gui_project.path is None:
            return
        
        self.Refresh()
        
        (w, h) = self.GetClientSize()
        (x, y) = e.GetPositionTuple()
        (rx, ry) = (x/w, y/h)
        
        if e.LeftDown():
            self.angle_while_dragging = self.grabbed_angle = \
                self._expanded_pos_to_angle(rx)
            self.d_angle_while_dragging = 0
            self.desired_clock_while_dragging = self.grabbed_pseudoclock = \
                self.gui_project.pseudoclock
            self.was_playing_before_drag = self.gui_project.is_playing
            self.gui_project.stop_playing()
            self.being_dragged = True
            
            self.SetCursor(cursor_collection.get_closed_grab())
            # SetCursor must be before CaptureMouse because of wxPython/GTK
            # weirdness
            self.CaptureMouse()
            
            return
        
        if e.LeftIsDown():
            if not self.HasCapture():
                return
            self.angle_while_dragging = self._expanded_pos_to_angle(rx)
            self.d_angle_while_dragging = \
                (self.angle_while_dragging - self.grabbed_angle)
            
            desired_pseudoclock = self.grabbed_pseudoclock + \
                (self.d_angle_while_dragging / self.clock_factor)
            
            self.gui_project.set_pseudoclock(desired_pseudoclock)
            
            if self.gui_project.pseudoclock != desired_pseudoclock:
                # Means we got an edge node
                
                edge_clock = self.gui_project.active_node.state.clock
                direction = cmp(self.gui_project.pseudoclock,
                                desired_pseudoclock)
                # direction that we bring back the cursor to if it goes too far
                d_clock = (edge_clock - self.grabbed_pseudoclock)
                d_angle = d_clock * self.clock_factor
                edge_angle = self.grabbed_angle + d_angle
                edge_rx = self._expanded_angle_to_pos(edge_angle)
                edge_x = edge_rx * w
                is_going_over = \
                    (edge_x - x > 0) if direction == 1 else (edge_x - x < 0)
                if is_going_over:
                    self.WarpPointer(edge_x, y)
            
                
        if e.LeftUp(): #or e.Leaving():
            # todo: make sure that when leaving entire app, things don't get
            # f****d
            if self.HasCapture():
                self.ReleaseMouse()
            # SetCursor must be after ReleaseMouse because of wxPython/GTK
            # weirdness
            self.SetCursor(cursor_collection.get_open_grab())
            self.being_dragged = False
            self.grabbed_angle = None
            self.grabbed_pseudoclock = None
            self.angle_while_dragging = None
            self.d_angle_while_dragging = None
            self.desired_clock_while_dragging = None
            
            if self.was_playing_before_drag:
                self.gui_project.start_playing()
                
            self.gui_project.round_pseudoclock_to_active_node()
                
            self.was_playing_before_drag = None
Exemplo n.º 7
0
    def __init__(self, parent, getter, setter, *args, **kwargs):
        """
        Construct the knob.
        
        `getter` is the getter function used to get the value of the variable.
        `setter` is the setter function used to set the value of the variable.
        
        Note that you can't give a size argument to knob, it is always created
        with a size of (29, 29).
        """

        assert "size" not in kwargs
        kwargs["size"] = (29, 29)

        assert callable(setter) and callable(getter)
        self.value_getter, self.value_setter = getter, setter

        wx.Panel.__init__(self, parent, *args, **kwargs)

        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)

        self.original_bitmap = wx.BitmapFromImage(
            wx.ImageFromStream(pkg_resources.resource_stream(images_package, "knob.png"), wx.BITMAP_TYPE_ANY)
        )

        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.Bind(wx.EVT_SIZE, self.on_size)
        self.Bind(wx.EVT_MOUSE_EVENTS, self.on_mouse)
        # self.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)

        self.SetCursor(cursor_collection.get_open_grab())

        self._knob_house_brush = wx.Brush(wx.Colour(0, 0, 0))
        """Brush used to paint the circle around the knob."""

        self.current_angle = 0
        """The current angle of the knob."""

        self.current_ratio = 0
        """The current ratio of the knob."""

        self.sensitivity = 25
        """
        The knob's sensitivity.
        
        Higher values will cause faster changes in value when turning the knob.
        """

        self.angle_resolution = math.pi / 180
        """The minimal change in angle that will warrant a repaint."""

        self.snap_points = []
        """An ordered list of snap points, specified by value."""

        self.base_drag_radius = 50
        """
        The base drag radius, in pixels.
        
        This number is the basis for calculating the height of the area in which
        the user can play with the mouse to turn the knob. Beyond that area the
        knob will be turned all the way to one side, and any movement farther
        will have no effect.
        
        If there are no snap points, the total height of that area will be `2 *
        self.base_drag_radius`.
        """

        self.snap_point_drag_well = 20
        """
        The height of a snap point's drag well, in pixels.
        
        This is the height of the area on the screen in which, when the user
        drags to it, the knob will have the value of the snap point.
        
        The bigger this is, the harder the snap point "traps" the mouse.
        """

        self.being_dragged = False
        """Flag saying whether the knob is currently being dragged."""

        self.snap_map = None
        """
        The current snap map used by the knob.
        
        See documentation of SnapMap for more info.
        """

        self.needs_recalculation_flag = True
        """Flag saying whether the knob needs to be recalculated."""

        self._recalculate()
Exemplo n.º 8
0
    def __init__(self, parent, getter, setter, *args, **kwargs):
        '''
        Construct the knob.
        
        `getter` is the getter function used to get the value of the variable.
        `setter` is the setter function used to set the value of the variable.
        
        Note that you can't give a size argument to knob, it is always created
        with a size of (29, 29).
        '''

        assert 'size' not in kwargs
        kwargs['size'] = (29, 29)

        assert callable(setter) and callable(getter)
        self.value_getter, self.value_setter = getter, setter

        wx.Panel.__init__(self, parent, *args, **kwargs)

        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)

        self.original_bitmap = wx.BitmapFromImage(
            wx.ImageFromStream(
                pkg_resources.resource_stream(images_package, 'knob.png'),
                wx.BITMAP_TYPE_ANY))

        self.Bind(wx.EVT_PAINT, self.on_paint)
        self.Bind(wx.EVT_SIZE, self.on_size)
        self.Bind(wx.EVT_MOUSE_EVENTS, self.on_mouse)
        # self.Bind(wx.EVT_ERASE_BACKGROUND, self.on_erase)

        self.SetCursor(cursor_collection.get_open_grab())

        self._knob_house_brush = wx.Brush(wx.Colour(0, 0, 0))
        '''Brush used to paint the circle around the knob.'''

        self.current_angle = 0
        '''The current angle of the knob.'''

        self.current_ratio = 0
        '''The current ratio of the knob.'''

        self.sensitivity = 25
        '''
        The knob's sensitivity.
        
        Higher values will cause faster changes in value when turning the knob.
        '''

        self.angle_resolution = math.pi / 180
        '''The minimal change in angle that will warrant a repaint.'''

        self.snap_points = []
        '''An ordered list of snap points, specified by value.'''

        self.base_drag_radius = 50
        '''
        The base drag radius, in pixels.
        
        This number is the basis for calculating the height of the area in which
        the user can play with the mouse to turn the knob. Beyond that area the
        knob will be turned all the way to one side, and any movement farther
        will have no effect.
        
        If there are no snap points, the total height of that area will be `2 *
        self.base_drag_radius`.
        '''

        self.snap_point_drag_well = 20
        '''
        The height of a snap point's drag well, in pixels.
        
        This is the height of the area on the screen in which, when the user
        drags to it, the knob will have the value of the snap point.
        
        The bigger this is, the harder the snap point "traps" the mouse.
        '''

        self.being_dragged = False
        '''Flag saying whether the knob is currently being dragged.'''

        self.snap_map = None
        '''
        The current snap map used by the knob.
        
        See documentation of SnapMap for more info.
        '''

        self.needs_recalculation_flag = True
        '''Flag saying whether the knob needs to be recalculated.'''

        self._recalculate()