Ejemplo n.º 1
0
def rect_orthogonal(rect, point):
    '''
  Ortho of rect given a point is:
  outward pointing vector orthogonal to side nearest point.
  Point can be inside, outside, or on the rect.
  
  Implementation: four combinations of left and right of diagonals.
  That is, divide rect into quadrants by its two diagonals.
  Each quadrant has an orthogonal.
  '''
    point_vect = vector.Vector(point.x, point.y)
    corner = [x for x in rect]

    # translate points into coordinate systems of diagonals
    point1 = point_vect - corner[0]
    point2 = point_vect - corner[3]

    if magnitude_to_line(corner[0], corner[2], point1) < 0:
        # right of first diagonal
        if magnitude_to_line(corner[3], corner[1], point2) < 0:
            # right of second diagonal
            # FIXME this is for aligned rect
            # return orthogonal to bottom side
            return vector.Vector(0, 1)
        else:
            return vector.Vector(-1, 0)
    else:
        if magnitude_to_line(corner[3], corner[1], point2) < 0:
            return vector.Vector(1, 0)
        else:
            return vector.Vector(0, -1)
Ejemplo n.º 2
0
def decide_stopped(event):
    '''
  Decide whether pointer is more or less stationary,
  given pointer movement event.
  A state machine.
  '''
    global state, previous_event, pointer_timer

    # Copy the event.  event.copy() does not seem to work.
    event_copy = Event(event.x, event.y, event.time)

    if state is None:  # First motion after a reset
        state = "moving"
        # !!! a copy.  Seems like gtk might be deallocating the original?
        previous_event = event_copy
        return

    assert previous_event is not None
    move = vector.Vector(event.x, event.y)
    previous_point = vector.Vector(previous_event.x, previous_event.y)
    motion_vector = move - previous_point
    distance = motion_vector.length()
    elapsed = event.time - previous_event.time

    previous_event = event_copy

    if elapsed <= 0:
        # event.time rolled over, wait for another mouse move.
        # Or, mouse moving so fast the event.time is the same,
        # avoid division by zero.
        return
    speed = distance / elapsed
    # print distance, elapsed, speed

    if state is "moving":
        if speed <= config.GUI_MOVING_SLOWING_THRESHOLD:
            state = "slowed"
            pointer_timer.start(
                config.GUI_MOVING_POPUP_TIME,
                timeout_cb)  # after a delay, go to stopped state
        # else moved fast
    elif state is "slowed":
        if speed > config.GUI_MOVING_SLOWING_THRESHOLD:
            state = "moving"
            pointer_timer.cancel()
        # else same state  still slow motion
    elif state is "stopped":
        if speed <= config.GUI_MOVING_SLOWING_THRESHOLD:
            # slow motion from stopped, try pick if user is making small adjustment
            # if it is acceleration, hope nothing to pick
            if stopped_callback(move):
                state = None
            # else, probably acceleration but don't change state
        else:  # fast motion again
            state = "moving"
    else:  # Null state, the starting state.
        state = "moving"
    return state
Ejemplo n.º 3
0
 def __iter__(self):
     ''' 
 Iteration on Bounds returns the corner points. 
 !!! Don't mutate the bounds while iterating.
 '''
     return itertools.islice([
         vector.Vector(self.x, self.y),
         vector.Vector(self.x + self.width, self.y),
         vector.Vector(self.x + self.width, self.y + self.height),
         vector.Vector(self.x, self.y + self.height)
     ], None)
Ejemplo n.º 4
0
 def position_selection(self):
   '''
   Translate and scale the text selection.
   Self is morph transformer of IB.
   '''
   # Get position of IB relative to TextMorph origin.
   ## position = self.text_glyph.insertion_position()
   position = vector.Vector(0.1,0.1)
   self.translation = position
   # !!!  scale and translation is some fraction of the TextMorph unit?
   self.scale = vector.Vector(0.1,0.1)
   self.derive_transform() # !!! If change specs, derive
Ejemplo n.º 5
0
    def __init__(self):
        drawable.Drawable.__init__(self)

        # My transform.
        # Default to identity transform.
        self.transform = cairo.Matrix()  # assert identity transform

        # Retained transform: saved cumulative transform from walking hierarchy.
        self.retained_transform = cairo.Matrix(
        )  # Identity transform is benign

        # Specs for self.transform: identity transform
        self.translation = vector.Vector(0, 0)
        self.scale = vector.Vector(1.0, 1.0)
        self.rotation = 0.0
Ejemplo n.º 6
0
    def motion_notify_event_cb(self, widget, event):
        '''
    Pointer move event from GUI toolkit.
    
    !!! Overrides default motion callback for GuiControl.
    Does not check for in bounds, that is done by desktop window manager.
    
    At this juncture, the document is NOT the operand, so no need to feedback.
    Alternatively, we could show handles on the window frame, etc.
    
    Event compression on mouse events not needed: ne = gdk.event_peek(), ne.free() 
    never seems to return any events.
    '''
        self.pointer_DCS = vector.Vector(event.x,
                                         event.y)  # save for later key events
        # print "Motion", self.pointer_DCS

        if gui.manager.drop.dropmgr.is_drag():
            # TODO find probe suitable targets
            gui.manager.drop.dropmgr.continued(event, self)
        else:
            # pointer manager decides if stopped and callbacks pick_cb
            gui.manager.pointer.decide_stopped(event)
        # End the chain of emission for signal, enabling pyusecase to intercept.
        widget.stop_emission('motion-notify-event')
        return False
Ejemplo n.º 7
0
 def continued(self, event, target):
     '''
 Some control received mouse motion while is_drag.
 Tell source (EG to ghost its action.)
 '''
     self.source_control.continue_drag(event, self._get_offset(event),
                                       self._get_increment(event))
     self.current_point = vector.Vector(event.x, event.y)
Ejemplo n.º 8
0
def circle_orthogonal(center, point):
    '''
  Ortho of circle is: vector from center to point.
  The point can be inside or outside the circle.
  Orthogonal to the center is the (0,0) null vector, causes problem?
  '''
    point_vect = vector.Vector(point.x, point.y)
    orthog = point_vect - center
    return orthog.normal()
Ejemplo n.º 9
0
    def set_dimensions(self, dimensions):
        '''
    Set the translation and scale (not rotation) of an object.
    For testing: ordinarily, transforms are set by user actions using other methods.
    !!! Not view altering
    '''
        # Zero width or height later yields cairo error non-invertible matrix
        assert dimensions.width > 0
        assert dimensions.height > 0

        # Should be a non-empty morph (a Composite)
        assert len(self) > 0

        self.translation = vector.Vector(dimensions.x, dimensions.y)
        self.scale = vector.Vector(dimensions.width / 1.0,
                                   dimensions.height / 1.0)
        self.derive_transform()
        return self.transform  # debug
Ejemplo n.º 10
0
 def new_layout_spec(self, event):
     '''
 Layout spec for traditional menu: 
   vector is downward (positive y ward)
   opening item is 0 (the topmost item)
   benchmark is at event (under the opening item.)
   FIXME benchmark is UL of first item
 '''
     ## menu_vect = vector.Vector(0, 1.0)
     menu_vect = vector.UNIT_X_AXIS.copy()
     # Translate menu group so opens with opening item centered on event
     # FIXME compute a proper offset to center the opening item
     benchmark = vector.Vector(event.x, event.y)
     benchmark += vector.Vector(-10, -10)
     self.layout_spec = layout.LayoutSpec(event,
                                          benchmark,
                                          menu_vect,
                                          opening_item=0)
Ejemplo n.º 11
0
    def __init__(self):
        self.model = morph.morph.Morph()
        ''' root of modeling tree of user's objects'''

        self.bounding_box = gui.boundingbox.BoundingBox()
        ''' Singleton controls.  Ghosts, not directly controllable by user '''
        # TODO this is being appended to transformed_c...

        # TODO this is obsolete? and should be a morph?
        self.transformed_controls = composite.Composite()
        ''' Semi-permanent GUI controls widgets e.g. text selections that are attached to transformed morphs, thus also need to be transformed.
    '''

        self.widgets = []
        ''' Untransformed. Ephemeral GUI controls widgets '''

        # TODO move this to transformer
        # !!! Set the topmost transform to scale by PENSOOL.SCALE
        translation = vector.Vector(0.0, 0.0)
        scale = vector.Vector(config.PENSOOL_UNIT, config.PENSOOL_UNIT)
        self.model.set_transform(translation, scale, 0.0)
Ejemplo n.º 12
0
    def device_to_user(self, x, y):
        '''
    Transform coordinates from device DCS to user UCS.

    From cairo docs:
    context.device_to_user() returns tuple (float, float)
    Transform a coordinate from device space to user space 
    by multiplying the given point by the inverse of the current transformation matrix (CTM).
    '''
        context = self.user_context()
        ### context.set_matrix(self.matrix)
        return vector.Vector(*context.device_to_user(x, y))
Ejemplo n.º 13
0
 def move_by_drag_handle(self, offset, increment):
     '''
 Establish my dimensions (set transform) 
 according to drag op
 of handle
 by offset
 '''
     # FIXME depends on which handle
     # FIXME more complicated
     # This is all in x-axis aligned coordinate system
     assert isinstance(self, Morph)
     drag_vector = self.device_to_local(increment)
     # insure old vector is along x-axis, length given by scale
     old_vector = vector.Vector(self.scale.x, 0)
     new_vector = old_vector + drag_vector
     length = new_vector.length()
     new_scale = vector.Vector(length, length)
     print self.scale, new_scale
     self.set_transform(self.translation, new_scale,
                        self.rotation + new_vector.angle())
     self.derive_transform()
Ejemplo n.º 14
0
 def center_at(self, point):
     '''
 ??? This only works for controls,
 where the scale is equivalent to pixels in DCS.
 
 Currently, there is no user command to center a graphical morph.
 '''
     delta_x = self.scale.x / 2
     delta_y = self.scale.y / 2
     self.translation = vector.Vector(point.x - delta_x, point.y - delta_y)
     self.derive_transform()
     """
Ejemplo n.º 15
0
 def get_orthogonal(self, point):
     '''
 Return unit orthogonal to drawn self at this point on self.
 Assert point is in DCS and is on self.
 Note drawn self means in the DCS.
 Note the orthogonal does NOT necessarily pass through the point.
 TODO return one of two directional orthogonal vectors,
 the one that is in the direction of the mouse trail (not the point.)
 
 For a line, point is immaterial.
 The point is on (or near) the line and so some ortho to the line
 MUST hit the point (the point can't be on the extension
 of a finite line.)
 
 For a line, there are two orthogonals to a point.
 This is a somewhat arbitray one for now.
 '''
     x, y = self.parent.retained_transform.transform_point(0, 0)
     point1 = vector.Vector(x, y)
     x, y = self.parent.retained_transform.transform_point(1.0, 0)
     point2 = vector.Vector(x, y)
     return orthogonal.line_orthogonal(point1, point2)
Ejemplo n.º 16
0
 def picking_func(self, point):
     # Fresh context since can be called outside a walk of model hierarchy
     context = config.viewport.user_context()
     if self.parent:  # None if in background ctl
         context.set_matrix(transform.copy(self.parent.retained_transform))
     # !!! No style put to context, but insure black ink? TODO
     self.put_path_to(context)  # recursive, with transforms
     # Transform point from DCS to UCS since Cairo in_foo() functions want UCS
     pointUCS = vector.Vector(*context.device_to_user(point.x, point.y))
     # print self, pointUCS
     value = func(self, context, pointUCS)
     print "picking_func returning", value
     return value
Ejemplo n.º 17
0
 def begin(self, event, controlee, control):
     '''
 Enter dragging state.
 Remember event and source controlee and control.
 
 !!! Event already in user coords.
 '''
     assert (controlee is not None)
     assert (self.source is None)  # Not begin before
     self.start_point = vector.Vector(event.x, event.y)
     self.current_point = self.start_point.copy()
     self.source = controlee
     self.draggee = controlee  # Defaults to same as source
     self.source_control = control
Ejemplo n.º 18
0
 def device_to_local(self, point):
     '''
 Get local coordinates (group GCS) of DCS point.
 Uses parent retained transform: only works if previously model traversed and transforms derived.
 Will not work for the model (the top.)
 '''
     if self.parent:
         group_transform = cairo.Matrix() * self.parent.retained_transform
     else:
         # At the top, self is model.  Model's transform (viewing) transforms device to local.
         group_transform = cairo.Matrix() * self.transform
     group_transform.invert()
     # print group_transform
     return vector.Vector(
         *group_transform.transform_point(point.x, point.y))
Ejemplo n.º 19
0
 def _prepare_for_picking(self, point):
     ''' 
 Prepare a context for picking.
 Fresh context since can be called outside a walk of model hierarchy.
 Assert parent is ???
 '''
     #
     context = config.viewport.user_context()
     if self.parent:  # None if in background ctl
         context.set_matrix(transform.copy(self.parent.retained_transform))
     # !!! No style put to context, but insure black ink? TODO
     self.put_path_to(context)  # recursive, with transforms
     # Transform point from DCS to UCS since Cairo in_foo() functions want UCS
     pointUCS = vector.Vector(*context.device_to_user(point.x, point.y))
     return context, pointUCS
Ejemplo n.º 20
0
    def set_by_drag(self, start_coords, event):
        '''
    Establish my dimensions (set transform) 
    according to drag op from start_coords to event.
    My glyph is a unitary thing (unit scale, translation.)
    Set my transform within my parent group's coordinate system (GCS).
    '''
        # assert start_coords and event in device DCS
        # Transform to GCS (Local)
        start_point = self.device_to_local(start_coords)
        event_point = self.device_to_local(event)
        drag_vector_UCS = event_point - start_point

        # Scale both axis by vector length
        drag_length_UCS = drag_vector_UCS.length()
        scale = vector.Vector(drag_length_UCS, drag_length_UCS)

        # print "start", start_coords, "new", start_point, drag_length_UCS
        self.set_transform(start_point, scale, drag_vector_UCS.angle())
Ejemplo n.º 21
0
    def motion_notify_event_cb(self, widget, event):
        '''
    Fundamental mouse interaction with controls:
      Exit if not mouse still inside.
      Move the control to follow the mouse.
      Continue dragging.
      
    !!! Note this is overridden by the bkgd manager.
    '''

        # Seems to be a race between deactivation of controls and motion events
        if self is not gui.manager.control.control_manager.get_active_control(
        ):
            print "Discarding motion event.", self, gui.manager.control.control_manager.get_active_control(
            )
            return False

        # !!! Note events and control dimensions are in device coords
        if self.is_in_control_area(event):
            # Remember the last pointer position (not use gtk.get_pointer())
            self.pointer_DCS = vector.Vector(event.x, event.y)
            # print "Inside", event.x, " ", event.y
            if gui.manager.drop.dropmgr.is_drag():  ### self.is_dragging:
                # Drop manager knows which control is in charge (source or target.)
                gui.manager.drop.dropmgr.continued(event, target=self)
            else:
                self.mouse_move(event)
        else:
            '''
      Note the control continues to exist, with state (eg about drag.)
      It might not be visible.
      Another control will take focus.
      '''
            self._reset_state()
            self.mouse_exit(event)  # Filtered event to subclasses
        return False
Ejemplo n.º 22
0
 def center_of(self):
     '''
 Return a point (an integer pixel) of center.
 TODO does this need to be floating point?
 '''
     return vector.Vector(self.x + self.width / 2, self.y + self.height / 2)
Ejemplo n.º 23
0
  
  An action on a handle translates into an action on the morph it handles.
  E.G. dragging the handle on the end of a line drags one end of the line.
  def set_by_drag(
  '''
    def __init__(self):
        PointMorph.__init__(self)
        # Set pen width broader than ordinary
        # TODO this should be dynamic, depend on current morph
        self.style.pen_width = 3


# class HandleSet(Morph) a set of HandlePoints

# A line morph has set of handles on end points
line_handles = Morph()
line_handles.append(HandlePoint())  # First handle at 0,0 end of unit line
# Second handle at 1,0 end of line
point = HandlePoint()
point.set_translation(vector.Vector(1, 0))
line_handles.append(point)

# A circle morph has handle at center.
# TODO temporarily a line
from math import pi as PI
circle_handles = Morph()
aline = LineMorph()
aline.rotation = PI / 4.0
aline.derive_transform()
circle_handles.append(aline)
Ejemplo n.º 24
0
 def set_origin(self, event):
     ''' Set translation '''
     # FIXME floats?  CS conversions?
     self.translation = vector.Vector(event.x, event.y)
     self.derive_transform()
Ejemplo n.º 25
0
 def _get_offset(self, event):
     # Calculate offset drag end to drag begin
     offset = vector.Vector(event.x, event.y)
     offset -= self.start_point
     return offset
Ejemplo n.º 26
0
 def _get_increment(self, event):
     # Calculate incremental offset previous event to this event
     offset = vector.Vector(event.x, event.y)
     offset -= self.current_point
     return offset
Ejemplo n.º 27
0
 def get_drawn_origin(self):
     ''' Return device coords of origin where drawn.'''
     return vector.Vector(self.bounds.x, self.bounds.y)