Пример #1
0
class FlowItem(SimItem):

  def __init__(self, flow_from=None, name=None, start=None, end=None, 
               dragging=True, focus=True, line_width=9, **kwargs):
    super(FlowItem, self).__init__(**kwargs)

    self.__needs_resize_calc = True
    self.dragging = dragging
    self.active_color = [0, 0, 0]
    self.__old_name = ""
    self.arrow_size = 20
    self.named = True

    if flow_from:
      start_coord = flow_from.abs_center()  
      self.x1 = start_coord[0]
      self.y1 = start_coord[1]

      self.x2 = start_coord[0]
      self.y2 = start_coord[1]

      # keep track of where we're coming from, even if its a cloud.
      self.flow_from = flow_from

      #now make sure we update our endpoints when the targets move
      self.__start_cb = self.flow_from.connect("item_moved_event", 
                                               self.update_point)
    else:
      if not start or not end:
        logging.error("flow_from and start or end undefined!")
        return
      
      self.x1, self.y1 = start
      self.x2, self.y2 = end
      self.flow_from = None

    self.flow_to = None
    self._new = True
    # this will be the variable created in the simulator
    self.var = None
    self.line_width = line_width

    if name is not None:
      self._display_name = TextInfo(name, 
                                    placeholder_text=False)
    else:
      self._display_name = TextInfo("(new flow)", 
                                    placeholder_text=True)

    if focus:
      self.get_canvas().grab_focus(self)
      self.get_canvas().grab_highlight(self)


  def remove(self):
    # get rid of clouds
    if self.flow_from:
      self.flow_from.disconnect(self.__start_cb)
      if type(self.flow_from) is CloudItem:
        self.get_canvas().remove_item(self.flow_from)

    if self.flow_to:
      self.flow_to.disconnect(self.__end_cb)
      if type(self.flow_to) is CloudItem:
        self.get_canvas().remove_item(self.flow_to)
    
    super(FlowItem, self).remove()


  def center(self):
    return (int(self.x1 + (self.x2 - self.x1)/2), 
            int(self.y1 + (self.y2 - self.y1)/2))


  def abs_center(self):
    center = self.center()
    transform = self.get_transform()
    x0, y0 = 0, 0
    if transform is not None:
      xx, yx, xy, yy, x0, y0 = self.get_transform()
    return (x0 + center[0], y0 + center[1])


  def edge_point(self, end_point):
    center_x, center_y = self.abs_center()
    
    line_angle = math.atan2((end_point[1] - center_y), 
                            (end_point[0] - center_x))
    if line_angle < 0: line_angle = 2*math.pi + line_angle
    
    
    radius = self.icon_size/2
 
    center_x = center_x + radius * math.cos(line_angle)
    center_y = center_y + radius * math.sin(line_angle)
    
    return (center_x, center_y)


  def do_simple_create_path(self, cr):
    self.ensure_size(cr)

    # define the bounding path here.
    cr.rectangle(self.bounds_x1, self.bounds_y1,
                 self.bounds_x2, self.bounds_y2)


  def ensure_size(self, cr):
    if self.__needs_resize_calc:
      self.bounds_x1 = float(min(self.x1, self.x2) - self.line_width)
      self.bounds_y1 = float(min(self.y1, self.y2) - self.line_width)
      self.bounds_x2 = float(max(self.x1, self.x2) + self.line_width)
      self.bounds_y2 = float(max(self.y1, self.y2) + self.line_width)

      b_w = self.bounds_x2 - self.bounds_x1
      b_h = self.bounds_y2 - self.bounds_y1
      b_cx = self.bounds_x1 + b_w/2.0
      b_cy = self.bounds_y1 + b_h/2.0

      self._display_name.update_extents(cr)
      t_w = self._display_name.width

      bottom_extent = b_cy + self.padding + self.icon_size/2 \
                      + self._display_name.height

      self.bounds_x1 = float(min(self.bounds_x1, b_cx - t_w/2.0))
      self.bounds_y1 = float(min(self.bounds_y1, b_cy - self.icon_size/2 \
                                                 - self.padding))
      self.bounds_x2 = float(max(self.bounds_x2, b_cx + t_w/2.0))
      self.bounds_y2 = float(max(self.bounds_y2, bottom_extent))

      #self._display_name.update_extents(cr)
      self.__needs_resize_calc = False
      self.force_redraw()


  def do_simple_paint(self, cr, bounds):

    cr.save()
    self.ensure_size(cr)

    cr.set_line_cap(cairo.LINE_CAP_ROUND)

    cr.move_to(self.x1, self.y1)
    
    angle = math.atan2(self.y2-self.y1, self.x2-self.x1)
    end_x = self.x2 - math.cos(angle) * self.arrow_size
    end_y = self.y2 - math.sin(angle) * self.arrow_size
    
    cr.line_to(end_x, end_y)
    cr.set_line_width(self.line_width)
    cr.set_source_rgb(self.active_color[0], \
                      self.active_color[1], \
                      self.active_color[2])
    cr.stroke()

    # draw arrow
    cr.move_to(self.x2, self.y2)
    # 10/pi is 20 degrees to either side of the line
    cr.line_to(self.x2 - math.cos(angle+20.0/180*pi) * self.arrow_size,
               self.y2 - math.sin(angle+20.0/180*pi) * self.arrow_size)
    cr.curve_to(end_x, end_y, end_x, end_y,
                self.x2 - math.cos(angle-20.0/180*pi) * self.arrow_size,
                self.y2 - math.sin(angle-20.0/180*pi) * self.arrow_size)
    cr.close_path()
    cr.set_line_width(self.line_width/1.5)
    cr.set_line_join(cairo.LINE_JOIN_ROUND)
    cr.stroke_preserve()
    cr.set_source_rgb(1, 1, 1)
    cr.fill()
    
    cr.move_to(self.x1, self.y1)
    cr.line_to((self.x2 + end_x)/2, (self.y2 + end_y)/2)
    cr.set_line_width(self.line_width/3)
    cr.set_source_rgb(1, 1, 1)
    cr.stroke()
    
    # print flow name
    if not self._new:
      center = self.center()
      cr.move_to(center[0] + self.icon_size/2.0, center[1])
      cr.arc(center[0], center[1], self.icon_size/2, 0, 2*math.pi)
      cr.close_path()
      cr.fill_preserve()
      cr.set_source_rgb(self.active_color[0], \
                        self.active_color[1], \
                        self.active_color[2]) 
      cr.stroke()

      self._display_name.update_extents(cr)
      y_offset = center[1] + self.padding + self._display_name.height/2.0 \
                 + self.icon_size/2
      cr.translate(center[0], y_offset)

      # white background for text
      cr.rectangle(-self._display_name.text_width/2.0, 
                   -self._display_name.height/2.0,
                   self._display_name.text_width, 
                   self._display_name.height)
      cr.set_source_rgba(1, 1, 1, .8)
      cr.fill()

      cr.set_source_rgb(self.active_color[0], \
                        self.active_color[1], \
                        self.active_color[2]) 
      self._display_name.show_text(cr)
    
    cr.restore()


  def set_flow_from(self, flow_from):

    if self.flow_from:
      self.flow_from.disconnect(self.__start_cb)
      if type(self.flow_from) is CloudItem:
        self.get_canvas().remove_item(self.flow_from)

    self.flow_from = flow_from
    self.x1, self.y1 = self.flow_from.abs_center()
    self._new = False

    #now make sure we update our endpoints when the targets move
    self.__start_cb = self.flow_from.connect("item_moved_event", 
                                             self.update_point)

    self.__needs_resize_calc = True
    self.force_redraw()
    

  def set_flow_to(self, flow_to):

    if self.flow_to:
      self.flow_to.disconnect(self.__end_cb)
      if type(self.flow_to) is CloudItem:
        self.get_canvas().remove_item(self.flow_to)

    self.flow_to = flow_to
    self.x2, self.y2 = self.flow_to.edge_point((self.x1, self.y2))
    self.x1, self.y1 = self.flow_from.edge_point((self.x2, self.y2))
    self._new = False

    #now make sure we update our endpoints when the targets move
    self.__end_cb = self.flow_to.connect("item_moved_event", 
                                         self.update_point)

    self.dragging = False
    self.__needs_resize_calc = True
    self.force_redraw()


  def update_point(self, item, target):
    self.x1, self.y1 = self.flow_from.abs_center()
    
    self.x2, self.y2 = self.flow_to.edge_point((self.x1, self.y1))

    self.x1, self.y1 = self.flow_from.edge_point((self.x2, self.y2))

    self.__needs_resize_calc = True
    self.emit("item_moved_event", self)
    self.force_redraw()


  def xml_representation(self):
    xml_string = '\
    <flow>\n\
      <name>%s</name>\n\
      <x1>%d</x1>\n\
      <y1>%d</y1>\n\
      <x2>%d</x2>\n\
      <y2>%d</y2>\n\
      <start>%s</start>\n\
      <end>%s</end>\n\
    </flow>\n' % (self.name(), self.x1, self.y1, 
                  self.x2, self.y2, 
                  self.flow_from.name(), self.flow_to.name())

    return xml_string


  def name(self):
    return self._display_name.string


  def do_simple_is_item_at(self, x, y, cr, is_pointer_event):
    self.ensure_size(cr)

    b_w = self.bounds_x2 - self.bounds_x1
    b_h = self.bounds_y2 - self.bounds_y1
    b_cx = self.bounds_x1 + b_w/2.0
    b_cy = self.bounds_y1 + b_h/2.0

    self._display_name.update_extents(cr)
    t_w = self._display_name.width

    bottom_extent = b_cy + self.padding + self.icon_size/2 \
                    + self._display_name.height

    if ((x < b_cx - t_w/2.0) or (x > b_cx + t_w/2.0)) or \
       ((y < b_cy - self.icon_size/2 - self.padding) or (y > bottom_extent)):
      return False
    else:    
      return True


  def on_key_press(self, item, target, event):
    # don't allow input while we're creating the flow.
    if self._new:
      return False

    key_name = gtk.gdk.keyval_name(event.keyval)

    if key_name in self.enter_key:
      self.emit("highlight_out_event", self)
    elif key_name in self.delete_key:
      self._display_name.backspace()
    elif key_name in self.escape_key:
      print("escape key!")
    else:
      # add key to name buffer
      self._display_name.add(event.string)

    self.__needs_resize_calc = True
    self.force_redraw()

    # return true to stop propogation
    return True


  def on_button_press(self, item, target, event):
    canvas = self.get_canvas()

    if canvas.override:
      # if we're in the process of drawing a line, just 
      # propogate the signal.
      return False

    canvas.grab_focus(item)
    logging.debug("**before grab")
    canvas.grab_highlight(self)
    logging.debug("**after grab")

    if event.button is 1:
      pass
    elif event.button is 3:
      edit_equation(self.var)
      canvas.drop_highlight()
    else:
      print "unsupported button: %d" % event.button
    return True


  def on_button_release(self, item, target, event):
      pass


  def on_motion_notify (self, item, target, event):
    if self.dragging is True:
      self.x2 = event.x
      self.y2 = event.y
      self.__needs_resize_calc = True
      self.force_redraw()
      return True
    return False


  def on_focus_in(self, item, target, event):
    return False


  def on_focus_out(self, item, target, event):
    return False


  def on_highlight_in(self, item, target):
    self.active_color = [1, .6, .2]
    self.force_redraw()

    #logging.debug("h_in : (%s)" % self.name())

    self.__old_name = self.name()
    if self.name() == "(new flow)":
      self.__old_name = ""

    return False
Пример #2
0
class VariableItem(SimItem):
    def __init__(self, x, y, width=200, height=80, name=None, focus=True, line_width=3.5, **kwargs):
        super(VariableItem, self).__init__(**kwargs)
        self.x = int(x - width / 2)
        self.y = int(y - height / 2)
        self.width = width
        self.height = height
        self.__needs_resize_calc = True
        self.dragging = False
        self.active_color = [0, 0, 0]
        self.__old_name = ""
        self.named = True

        self._new = True
        # this will be the variable created in the simulator
        self.var = None

        self.line_width = line_width

        text_width = self.width - self.padding * 2 - self.icon_size

        if name is not None:
            self._display_name = TextInfo(name, wrap_width=text_width, align=pango.ALIGN_LEFT, placeholder_text=False)
        else:
            self._display_name = TextInfo(
                "(enter name)", wrap_width=text_width, align=pango.ALIGN_LEFT, placeholder_text=True
            )

        if focus:
            self.get_canvas().grab_focus(self)
            self.get_canvas().grab_highlight(self)

    def do_simple_create_path(self, cr):
        self.ensure_size(cr)

        # define the bounding path here.
        cr.rectangle(
            self.x - self.line_width / 2.0,
            self.y - self.line_width / 2.0,
            self.width + self.line_width / 2.0,
            self.height + self.line_width / 2.0,
        )

    def center(self):
        return (int(self.x + self.width / 2), int(self.y + self.height / 2))

    def abs_center(self):
        center = self.center()
        transform = self.get_transform()
        x0, y0 = 0, 0
        if transform is not None:
            xx, yx, xy, yy, x0, y0 = self.get_transform()
        return (x0 + self.x + self.icon_size / 2.0, y0 + center[1])

    def edge_point(self, end_point):
        center_x, center_y = self.abs_center()

        line_angle = math.atan2((end_point[1] - center_y), (end_point[0] - center_x))
        if line_angle < 0:
            line_angle = 2 * math.pi + line_angle

        radius = self.icon_size / 2

        center_x = center_x + radius * math.cos(line_angle)
        center_y = center_y + radius * math.sin(line_angle)

        return (center_x, center_y)

    def ensure_size(self, cr):
        if self.__needs_resize_calc:
            self._display_name.update_extents(cr)

            old_center_x = self.x + self.width / 2.0
            old_center_y = self.y + self.height / 2.0
            self.height = max(self.icon_size, self._display_name.height) + 2 * self.padding
            self.x = old_center_x - self.width / 2.0
            self.y = old_center_y - self.height / 2.0

            self.bounds_x1 = self.x - self.line_width / 2.0
            self.bounds_y1 = self.y - self.line_width / 2.0
            self.bounds_x2 = self.x + self.width + self.line_width + 2 * self.padding
            self.bounds_y2 = self.y + self.height + self.line_width + 2 * self.padding

            self.__needs_resize_calc = False
            self.force_redraw()

    def do_simple_paint(self, cr, bounds):

        cr.save()

        # keep track of the transformation matrix, so we can save
        # the right coordinates
        matrix = cr.get_matrix()

        self.ensure_size(cr)

        self.type_icon(cr)

        center = self.center()
        cr.translate(int(center[0] + self.icon_size / 2 + self.padding), center[1])

        # white background for text
        cr.rectangle(
            -self._display_name.width / 2.0,
            -self._display_name.height / 2.0,
            self._display_name.text_width,
            self._display_name.height,
        )
        cr.set_source_rgba(1, 1, 1, 0.8)
        cr.fill()

        cr.set_source_rgb(self.active_color[0], self.active_color[1], self.active_color[2])

        self._display_name.show_text(cr)

        cr.restore()

    def type_icon(self, cr):
        cr.move_to(self.x + self.icon_size, self.y + 0.5 * self.height)
        cr.arc(self.x + 0.5 * self.icon_size, self.y + 0.5 * self.height, self.icon_size / 2, 0, 2 * math.pi)
        cr.close_path()
        cr.set_source_rgb(1, 1, 1)
        cr.fill_preserve()
        cr.set_line_width(self.line_width)
        cr.set_source_rgb(self.active_color[0], self.active_color[1], self.active_color[2])
        cr.stroke()

    def xml_representation(self):
        # get the center of the widget, so that we get the correct
        # behavior when it loads.  also, add the cairo transformation
        # matrix offset.
        x_center = self.bounds_x1 + self.width / 2
        y_center = self.bounds_y1 + self.height / 2

        xml_string = (
            "\
    <var>\n\
      <name>%s</name>\n\
      <x>%d</x>\n\
      <y>%d</y>\n\
      <width>%f</width>\n\
      <height>%f</height>\n\
    </var>\n"
            % (self._display_name.string, x_center, y_center, self.width, self.height)
        )

        return xml_string

    def name(self):
        return self._display_name.string

    def on_key_press(self, item, target, event):
        key_name = gtk.gdk.keyval_name(event.keyval)

        if key_name in self.enter_key:
            self.emit("highlight_out_event", self)
        elif key_name in self.delete_key:
            self._display_name.backspace()
        elif key_name in self.escape_key:
            print ("escape key!")
        else:
            # add key to name buffer
            self._display_name.add(event.string)

        self.__needs_resize_calc = True
        self.force_redraw()

        # return true to stop propogation
        return True

    def on_button_press(self, item, target, event):
        canvas = self.get_canvas()

        if canvas.override:
            # if we're in the process of drawing a line, just
            # propogate the signal.  first fix the coordinates
            canvas = self.get_canvas()
            event.x, event.y = canvas.convert_from_item_space(self, event.x, event.y)
            return False

        canvas.grab_focus(item)
        logging.debug("**before grab")
        canvas.grab_highlight(self)
        logging.debug("**after grab")

        if event.button is 1:
            self.drag_x = event.x
            self.drag_y = event.y

            fleur = gtk.gdk.Cursor(gtk.gdk.FLEUR)
            canvas = item.get_canvas()
            canvas.pointer_grab(item, gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK, fleur, event.time)
            self.dragging = True
        elif event.button is 3:
            edit_equation(self.var, self.get_influences())
            canvas.drop_highlight()
        else:
            print "unsupported button: %d" % event.button

        return True

    def on_button_release(self, item, target, event):
        if event.button is 1:
            canvas = item.get_canvas()
            canvas.pointer_ungrab(item, event.time)
            self.dragging = False

    def on_motion_notify(self, item, target, event):
        if (self.dragging == True) and (event.state & gtk.gdk.BUTTON1_MASK):
            new_x = event.x
            new_y = event.y
            item.translate(new_x - self.drag_x, new_y - self.drag_y)
            self.emit("item_moved_event", self)
            return True
        canvas = self.get_canvas()
        event.x, event.y = canvas.convert_from_item_space(self, event.x, event.y)
        return False

    def on_focus_in(self, item, target, event):
        return False

    def on_focus_out(self, item, target, event):
        return False

    def on_highlight_in(self, item, target):
        self.active_color = [1, 0.6, 0.2]
        self.force_redraw()

        logging.debug("h_in : '%s'" % self.name())

        self.__old_name = self.name()

        return False
Пример #3
0
class StockItem(SimItem):

  def __init__(self, x, y, width=140, height=80, name=None,
               focus=True, line_width=3.5, **kwargs):
    super(StockItem, self).__init__(**kwargs)

    self._new = True
    # this will be the variable created in the simulator
    self.var = None

    self.x = int(x - width/2)
    self.y = int(y - height/2)
    self.width = width
    self.height = height
    self.dragging = False

    self.active_color = [0, 0, 0]
    self.line_width = line_width
    self.__old_name = ""
    self.named = True

    # keep track of inflows and outflows, for use in engine
    self.inflows = []
    self.outflows = []

    text_width = self.width - self.padding*2

    if name is not None:
      self._display_name = TextInfo(name, wrap_width=text_width, 
                                    placeholder_text=False)
    else:
      self._display_name = TextInfo("(enter name)", wrap_width=text_width, 
                                    placeholder_text=True)

    self.__needs_resize_calc = True

    if focus:
      self.get_canvas().grab_focus(self)
      self.get_canvas().grab_highlight(self)


  def do_simple_create_path(self, cr):
    self.ensure_size(cr)

    # define the bounding path here.
    cr.rectangle(self.x - self.line_width/2.0, 
                 self.y - self.line_width/2.0,
                 self.width + self.line_width/2.0, 
                 self.height + self.line_width/2.0)


  def center(self):
    return (int(self.x + self.width/2), int(self.y + self.height/2))


  def abs_center(self):
    center = self.center()
    transform = self.get_transform()
    x0, y0 = 0, 0
    if transform is not None:
      xx, yx, xy, yy, x0, y0 = transform
    return (x0 + center[0], y0 + center[1])


  def edge_point(self, end_point):
    center_x, center_y = self.abs_center()
    
    line_angle = math.atan2((end_point[1] - center_y), 
                            (end_point[0] - center_x))
    if line_angle < 0: line_angle = 2*math.pi + line_angle
    
    # should always be between 0 and .5*pi
    ref_angle = math.atan2(float(self.height),float(self.width))
    
    width = self.width/2
    height = self.height/2
    
    if line_angle < ref_angle or line_angle > 2*math.pi - ref_angle:
      center_x = center_x + width
      center_y = center_y + width * math.tan(line_angle)
    elif line_angle > math.pi - ref_angle and line_angle < math.pi + ref_angle:
      center_x = center_x - width
      center_y = center_y - width * math.tan(line_angle)
    
    if line_angle >= ref_angle and line_angle <= math.pi - ref_angle:
      center_x = center_x - height * math.tan(line_angle - math.pi/2)
      center_y = center_y + height
    elif line_angle >= math.pi + ref_angle and \
         line_angle <= 2*math.pi - ref_angle:
      center_x = center_x + height * math.tan(line_angle - math.pi/2)
      center_y = center_y - height
    
    #logging.debug("line: %5.1f, ref %5.1f" % (math.degrees(line_angle), 
    #                                          math.degrees(ref_angle)))
    
    return (center_x, center_y)


  def ensure_size(self, cr):
    if self.__needs_resize_calc:
      self._display_name.update_extents(cr)

      old_center_x = self.x + self.width/2.0
      old_center_y = self.y + self.height/2.0
      self.height = max(self.height, \
                        self._display_name.height + 2*self.padding)
      self.x = old_center_x - self.width/2.0
      self.y = old_center_y - self.height/2.0
      
      self.bounds_x1 = self.x - self.line_width/2.0 
      self.bounds_y1 = self.y - self.line_width/2.0
      self.bounds_x2 = self.x + self.width + self.line_width/2.0 
      self.bounds_y2 = self.y + self.height + self.line_width/2.0

      self.__needs_resize_calc = False
      self.force_redraw()


  def do_simple_paint(self, cr, bounds):

    cr.save()
    self.ensure_size(cr)
    cr.rectangle(self.x, self.y, self.width, self.height)
    cr.set_source_rgb (1, 1, 1)
    cr.fill_preserve()
    cr.set_line_width(self.line_width)
    cr.set_source_rgb(self.active_color[0], \
                      self.active_color[1], \
                      self.active_color[2])
    cr.stroke()

    # translate so that our coordinate system is in the widget
    
    center = self.center()
    cr.translate(center[0], center[1])
    self._display_name.show_text(cr)

    cr.restore()


  def xml_representation(self):
    # get the center of the widget, so that we get the correct 
    # behavior when it loads.  also, add the cairo transformation
    # matrix offset.
    x_center = self.bounds_x1 + self.width/2.0
    y_center = self.bounds_y1 + self.height/2.0

    xml_string = '\
    <stock>\n\
      <name>%s</name>\n\
      <x>%d</x>\n\
      <y>%d</y>\n\
      <width>%f</width>\n\
      <height>%f</height>\n\
    </stock>\n' % (self._display_name.string, x_center, y_center, 
                   self.width, self.height)

    return xml_string


  def name(self):
    return self._display_name.string


  def on_key_press(self, item, target, event):
    key_name = gtk.gdk.keyval_name(event.keyval)

    if key_name in self.enter_key:
      self.emit("highlight_out_event", self)
    elif key_name in self.delete_key:
      self._display_name.backspace()
    elif key_name in self.escape_key:
      print("escape key!")
    else:
      # add key to name buffer
      self._display_name.add(event.string)

    self.__needs_resize_calc = True
    self.force_redraw()

    # return true to stop propogation
    return True


  def on_button_press(self, item, target, event):
    canvas = self.get_canvas()

    if canvas.override:
      # if we're in the process of drawing a line, just 
      # propogate the signal.  first fix the coordinates
      canvas = self.get_canvas()
      event.x, event.y = canvas.convert_from_item_space(self, 
                                                        event.x, event.y)
      return False

    canvas.grab_focus(item)
    logging.debug("**before grab")
    canvas.grab_highlight(self)
    logging.debug("**after grab")

    if event.button is 1:
      self.drag_x = event.x
      self.drag_y = event.y

      fleur = gtk.gdk.Cursor(gtk.gdk.FLEUR)
      canvas = item.get_canvas()
      canvas.pointer_grab(item,
                          gtk.gdk.POINTER_MOTION_MASK 
                           | gtk.gdk.BUTTON_RELEASE_MASK,
                          fleur, event.time)
      self.dragging = True
    elif event.button is 3:
      edit_equation(self.var)
      canvas.drop_highlight()
    else:
      print "unsupported button: %d" % event.button

    return True


  def on_button_release(self, item, target, event):
    if event.button is 1:
      canvas = item.get_canvas()
      canvas.pointer_ungrab(item, event.time)
      self.dragging = False


  def on_motion_notify (self, item, target, event):
    if (self.dragging == True) and (event.state & gtk.gdk.BUTTON1_MASK):
      new_x = event.x
      new_y = event.y
      item.translate(new_x - self.drag_x, new_y - self.drag_y)
      self.emit("item_moved_event", self)
      return True
    canvas = self.get_canvas()
    event.x, event.y = canvas.convert_from_item_space(self, event.x, event.y)
    return False


  def on_focus_in(self, item, target, event):
    return False


  def on_focus_out(self, item, target, event):
    return False


  def on_highlight_in(self, item, target):
    self.active_color = [1, .6, .2]
    self.force_redraw()

    self.__old_name = self.name()

    return False
Пример #4
0
class VariableItem(SimItem):
    def __init__(self,
                 x,
                 y,
                 width=200,
                 height=80,
                 name=None,
                 focus=True,
                 line_width=3.5,
                 **kwargs):
        super(VariableItem, self).__init__(**kwargs)
        self.x = int(x - width / 2)
        self.y = int(y - height / 2)
        self.width = width
        self.height = height
        self.__needs_resize_calc = True
        self.dragging = False
        self.active_color = [0, 0, 0]
        self.__old_name = ""
        self.named = True

        self._new = True
        # this will be the variable created in the simulator
        self.var = None

        self.line_width = line_width

        text_width = self.width - self.padding * 2 - self.icon_size

        if name is not None:
            self._display_name = TextInfo(name,
                                          wrap_width=text_width,
                                          align=pango.ALIGN_LEFT,
                                          placeholder_text=False)
        else:
            self._display_name = TextInfo("(enter name)",
                                          wrap_width=text_width,
                                          align=pango.ALIGN_LEFT,
                                          placeholder_text=True)

        if focus:
            self.get_canvas().grab_focus(self)
            self.get_canvas().grab_highlight(self)

    def do_simple_create_path(self, cr):
        self.ensure_size(cr)

        # define the bounding path here.
        cr.rectangle(self.x - self.line_width / 2.0,
                     self.y - self.line_width / 2.0,
                     self.width + self.line_width / 2.0,
                     self.height + self.line_width / 2.0)

    def center(self):
        return (int(self.x + self.width / 2), int(self.y + self.height / 2))

    def abs_center(self):
        center = self.center()
        transform = self.get_transform()
        x0, y0 = 0, 0
        if transform is not None:
            xx, yx, xy, yy, x0, y0 = self.get_transform()
        return (x0 + self.x + self.icon_size / 2.0, y0 + center[1])

    def edge_point(self, end_point):
        center_x, center_y = self.abs_center()

        line_angle = math.atan2((end_point[1] - center_y),
                                (end_point[0] - center_x))
        if line_angle < 0: line_angle = 2 * math.pi + line_angle

        radius = self.icon_size / 2

        center_x = center_x + radius * math.cos(line_angle)
        center_y = center_y + radius * math.sin(line_angle)

        return (center_x, center_y)

    def ensure_size(self, cr):
        if self.__needs_resize_calc:
            self._display_name.update_extents(cr)

            old_center_x = self.x + self.width / 2.0
            old_center_y = self.y + self.height / 2.0
            self.height = max(self.icon_size, self._display_name.height) \
                          + 2*self.padding
            self.x = old_center_x - self.width / 2.0
            self.y = old_center_y - self.height / 2.0

            self.bounds_x1 = self.x - self.line_width / 2.0
            self.bounds_y1 = self.y - self.line_width / 2.0
            self.bounds_x2 = self.x + self.width + self.line_width \
                             + 2*self.padding
            self.bounds_y2 = self.y + self.height + self.line_width \
                             + 2*self.padding

            self.__needs_resize_calc = False
            self.force_redraw()

    def do_simple_paint(self, cr, bounds):

        cr.save()

        # keep track of the transformation matrix, so we can save
        # the right coordinates
        matrix = cr.get_matrix()

        self.ensure_size(cr)

        self.type_icon(cr)

        center = self.center()
        cr.translate(int(center[0] + self.icon_size / 2 + self.padding),
                     center[1])

        # white background for text
        cr.rectangle(-self._display_name.width / 2.0,
                     -self._display_name.height / 2.0,
                     self._display_name.text_width, self._display_name.height)
        cr.set_source_rgba(1, 1, 1, .8)
        cr.fill()

        cr.set_source_rgb(self.active_color[0], \
                          self.active_color[1], \
                          self.active_color[2])

        self._display_name.show_text(cr)

        cr.restore()

    def type_icon(self, cr):
        cr.move_to(self.x + self.icon_size, self.y + .5 * self.height)
        cr.arc(self.x + .5 * self.icon_size, self.y + .5 * self.height,
               self.icon_size / 2, 0, 2 * math.pi)
        cr.close_path()
        cr.set_source_rgb(1, 1, 1)
        cr.fill_preserve()
        cr.set_line_width(self.line_width)
        cr.set_source_rgb(self.active_color[0], \
                          self.active_color[1], \
                          self.active_color[2])
        cr.stroke()

    def xml_representation(self):
        # get the center of the widget, so that we get the correct
        # behavior when it loads.  also, add the cairo transformation
        # matrix offset.
        x_center = self.bounds_x1 + self.width / 2
        y_center = self.bounds_y1 + self.height / 2

        xml_string = '\
    <var>\n\
      <name>%s</name>\n\
      <x>%d</x>\n\
      <y>%d</y>\n\
      <width>%f</width>\n\
      <height>%f</height>\n\
    </var>\n' % (self._display_name.string, x_center, y_center, self.width,
                 self.height)

        return xml_string

    def name(self):
        return self._display_name.string

    def on_key_press(self, item, target, event):
        key_name = gtk.gdk.keyval_name(event.keyval)

        if key_name in self.enter_key:
            self.emit("highlight_out_event", self)
        elif key_name in self.delete_key:
            self._display_name.backspace()
        elif key_name in self.escape_key:
            print("escape key!")
        else:
            # add key to name buffer
            self._display_name.add(event.string)

        self.__needs_resize_calc = True
        self.force_redraw()

        # return true to stop propogation
        return True

    def on_button_press(self, item, target, event):
        canvas = self.get_canvas()

        if canvas.override:
            # if we're in the process of drawing a line, just
            # propogate the signal.  first fix the coordinates
            canvas = self.get_canvas()
            event.x, event.y = canvas.convert_from_item_space(
                self, event.x, event.y)
            return False

        canvas.grab_focus(item)
        logging.debug("**before grab")
        canvas.grab_highlight(self)
        logging.debug("**after grab")

        if event.button is 1:
            self.drag_x = event.x
            self.drag_y = event.y

            fleur = gtk.gdk.Cursor(gtk.gdk.FLEUR)
            canvas = item.get_canvas()
            canvas.pointer_grab(
                item, gtk.gdk.POINTER_MOTION_MASK
                | gtk.gdk.BUTTON_RELEASE_MASK, fleur, event.time)
            self.dragging = True
        elif event.button is 3:
            edit_equation(self.var, self.get_influences())
            canvas.drop_highlight()
        else:
            print "unsupported button: %d" % event.button

        return True

    def on_button_release(self, item, target, event):
        if event.button is 1:
            canvas = item.get_canvas()
            canvas.pointer_ungrab(item, event.time)
            self.dragging = False

    def on_motion_notify(self, item, target, event):
        if (self.dragging == True) and (event.state & gtk.gdk.BUTTON1_MASK):
            new_x = event.x
            new_y = event.y
            item.translate(new_x - self.drag_x, new_y - self.drag_y)
            self.emit("item_moved_event", self)
            return True
        canvas = self.get_canvas()
        event.x, event.y = canvas.convert_from_item_space(
            self, event.x, event.y)
        return False

    def on_focus_in(self, item, target, event):
        return False

    def on_focus_out(self, item, target, event):
        return False

    def on_highlight_in(self, item, target):
        self.active_color = [1, .6, .2]
        self.force_redraw()

        logging.debug("h_in : '%s'" % self.name())

        self.__old_name = self.name()

        return False