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
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
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()
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
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()
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
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()
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()