Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu@sugarlabs.org>2009-01-30 16:44:15 (GMT)
committer Tomeu Vizoso <tomeu@sugarlabs.org>2009-01-30 16:44:15 (GMT)
commit9841c37d1cd57f1c31812931c2a4361f86a324b8 (patch)
tree0c5e2fd76c80895e8953443c355b312a4c2b8e6f
parent7b58cdb6300d54357afecf2316c174f6d2559309 (diff)
Better position connections and only update the model once the item has been dropped
-rw-r--r--thoughtview.py5
-rw-r--r--view.py108
2 files changed, 81 insertions, 32 deletions
diff --git a/thoughtview.py b/thoughtview.py
index a079476..eeae9e8 100644
--- a/thoughtview.py
+++ b/thoughtview.py
@@ -25,6 +25,7 @@ from sugar.graphics import style
from gaphas.examples import Box, Text
from gaphas.connector import Handle
+from gaphas.geometry import Rectangle
class ThoughtView(Box):
@@ -105,3 +106,7 @@ class ThoughtView(Box):
self.new_thought_handle.y = 20
return updated
+ def get_rectangle(self):
+ x, y = self.get_position()
+ return Rectangle(x, y, self.width, self.height)
+
diff --git a/view.py b/view.py
index 05d4c72..029f3da 100644
--- a/view.py
+++ b/view.py
@@ -19,8 +19,8 @@ from gettext import gettext as _
import gobject
import gtk
-from gaphas import GtkView, Canvas, state, Line
-from gaphas.tool import HandleTool, DefaultTool, ConnectHandleTool
+from gaphas import GtkView, Canvas, Line, geometry
+from gaphas import tool
# We'd rather not depend on sugar in this class
from sugar.graphics import style
@@ -40,24 +40,16 @@ class MindMapView(GtkView):
self.canvas = Canvas()
- tool = DefaultTool()
- tool.prepend(NewThoughtTool())
- self.tool = tool
+ self.tool = tool.ToolChain(). \
+ append(NewThoughtTool()). \
+ append(tool.HoverTool()). \
+ append(ItemTool()). \
+ append(tool.TextEditTool()). \
+ append(tool.RubberbandTool())
if model is not None:
self.model = model
- state.observers.add(self.__state_changed_cb)
-
- def __state_changed_cb(self, event):
- func, args, dict_ = event
- if len(args) > 1 and isinstance(args[1], ThoughtView):
- thought_view = args[1]
- x, y = thought_view.get_position()
- row = self.model.find_by_id(thought_view.id)
- if row[2] != x or row[3] != y:
- self.model.set(row.iter, 2, x, 3, y)
-
def set_model(self, new_model):
logging.debug('set_model %r' % new_model)
if self._model == new_model:
@@ -90,12 +82,48 @@ class MindMapView(GtkView):
model = property(get_model, set_model)
+ def _calculate_ports(self, child_view, parent_view):
+ child_rect = child_view.get_rectangle()
+ parent_rect = parent_view.get_rectangle()
+
+ point_in_child = self._get_closest_intersection(child_rect, parent_rect)
+ point_in_parent = self._get_closest_intersection(parent_rect, child_rect)
+
+ return point_in_child, point_in_parent
+
+ def _get_closest_intersection(self, rect1, rect2):
+ center1 = rect1.x + rect1.width / 2, rect1.y + rect1.height / 2
+ center2 = rect2.x + rect2.width / 2, rect2.y + rect2.height / 2
+
+ return self._intersection_rect_line(rect1, (center1, center2))
+
+ def _intersection_rect_line(self, rect, line):
+ top_edge = (rect.x, rect.y), (rect.x + rect.width, rect.y)
+ left_edge = (rect.x, rect.y), (rect.x, rect.y + rect.height)
+ bottom_edge = (rect.x, rect.y + rect.height), \
+ (rect.x + rect.width, rect.y + rect.height)
+ right_edge = (rect.x + rect.width, rect.y + rect.height), \
+ (rect.x + rect.width, rect.y)
+
+ for edge in (top_edge, left_edge, bottom_edge, right_edge):
+ point = geometry.intersect_line_line(line[0], line[1],
+ edge[0], edge[1])
+ if point is not None:
+ return point
+
+ raise ValueError('Rect %r and line %r dont intersect!' % (rect, line,))
+
def _connect_items(self, parent_view, thought_view):
line = Line()
self.canvas.add(line)
- handle_tool = ConnectHandleTool()
- handle_tool.connect(self, line, line.handles()[0], parent_view.get_position())
- handle_tool.connect(self, line, line.opposite(line.handles()[0]), thought_view.get_position())
+
+ handle_tool = tool.ConnectHandleTool()
+
+ start, end = self._calculate_ports(thought_view, parent_view)
+
+ line_handle = line.handles()[0]
+ handle_tool.connect(self, line, line_handle, start)
+ handle_tool.connect(self, line, line.opposite(line_handle), end)
def __row_changed_cb(self, model, path, iter):
row = model[iter]
@@ -113,11 +141,9 @@ class MindMapView(GtkView):
else:
thought_view.name = row[1]
thought_view.set_position(row[2], row[3])
- thought_view.x = row[2]
- thought_view.y = row[3]
thought_view.color = row[4]
- self.canvas.request_update(thought_view)
+ self.canvas.request_update(thought_view)
def __row_deleted_cb(self, model, path):
logging.debug('__row_deleted_cb %r' % path)
@@ -132,23 +158,23 @@ class MindMapView(GtkView):
return item
return None
-class NewThoughtTool(HandleTool):
+class NewThoughtTool(tool.HandleTool):
def __init__(self):
- HandleTool.__init__(self)
+ tool.HandleTool.__init__(self)
self._new_connection = None
self._parent_thought = None
def grab_handle(self, item, handle):
logging.debug('NewThoughtTool.grab_handle %r %r' % (item, handle))
- HandleTool.grab_handle(self, item, handle)
+ tool.HandleTool.grab_handle(self, item, handle)
def ungrab_handle(self):
logging.debug('NewThoughtTool.ungrab_handle')
- HandleTool.ungrab_handle(self)
+ tool.HandleTool.ungrab_handle(self)
def on_button_release(self, context, event):
- logging.debug('NewThoughtTool.ungrab_handle')
+ logging.debug('NewThoughtTool.on_button_release')
if self._new_connection is not None:
context.view.canvas.remove(self._new_connection)
@@ -157,7 +183,7 @@ class NewThoughtTool(HandleTool):
context.view.model.create_new_thought(x=event.x, y=event.y,
parent_id=self._parent_thought.id)
- HandleTool.on_button_release(self, context, event)
+ tool.HandleTool.on_button_release(self, context, event)
def move(self, view, item, handle, pos):
#logging.debug('NewThoughtTool.move')
@@ -181,17 +207,35 @@ class NewThoughtTool(HandleTool):
view.canvas.request_update(self._new_connection)
#logging.debug('moved line end to %r %r' % (end_handle.x, end_handle.y))
else:
- HandleTool.move(self, view, item, handle, pos)
+ tool.HandleTool.move(self, view, item, handle, pos)
def glue(self, view, item, handle, vpos):
#logging.debug('NewThoughtTool.glue')
- HandleTool.glue(self, view, item, handle, vpos)
+ tool.HandleTool.glue(self, view, item, handle, vpos)
def connect(self, view, item, handle, vpos):
logging.debug('NewThoughtTool.connect')
- HandleTool.connect(self, view, item, handle, vpos)
+ tool.HandleTool.connect(self, view, item, handle, vpos)
def disconnect(self, view, item, handle):
logging.debug('NewThoughtTool.disconnect')
- HandleTool.disconnect(self, view, item, handle)
+ tool.HandleTool.disconnect(self, view, item, handle)
+
+class ItemTool(tool.ItemTool):
+
+ def __init__(self):
+ tool.ItemTool.__init__(self)
+
+ def on_button_release(self, context, event):
+ logging.debug('ItemTool.on_button_release')
+
+ for item in self._movable_items:
+ if not isinstance(item, ThoughtView):
+ continue
+ x, y = item.get_position()
+ row = context.view.model.find_by_id(item.id)
+ if row[2] != x or row[3] != y:
+ context.view.model.set(row.iter, 2, x, 3, y)
+
+ tool.ItemTool.on_button_release(self, context, event)