[Avida-cvs] [avida-svn] r856 - branches/developers/avida-edward/source/python/AvidaGui2

gerrishj@myxo.css.msu.edu gerrishj at myxo.css.msu.edu
Thu Jul 27 12:41:39 PDT 2006


Author: gerrishj
Date: 2006-07-27 15:41:39 -0400 (Thu, 27 Jul 2006)
New Revision: 856

Modified:
   branches/developers/avida-edward/source/python/AvidaGui2/pyOneOrg_ScopeView.ui
   branches/developers/avida-edward/source/python/AvidaGui2/pyTimeline.py
Log:
Updated timeline to spread out overlapping events.


Modified: branches/developers/avida-edward/source/python/AvidaGui2/pyOneOrg_ScopeView.ui
===================================================================
--- branches/developers/avida-edward/source/python/AvidaGui2/pyOneOrg_ScopeView.ui	2006-07-26 04:51:51 UTC (rev 855)
+++ branches/developers/avida-edward/source/python/AvidaGui2/pyOneOrg_ScopeView.ui	2006-07-27 19:41:39 UTC (rev 856)
@@ -87,7 +87,7 @@
             <property name="minimumSize">
                 <size>
                     <width>0</width>
-                    <height>50</height>
+                    <height>70</height>
                 </size>
             </property>
         </widget>

Modified: branches/developers/avida-edward/source/python/AvidaGui2/pyTimeline.py
===================================================================
--- branches/developers/avida-edward/source/python/AvidaGui2/pyTimeline.py	2006-07-26 04:51:51 UTC (rev 855)
+++ branches/developers/avida-edward/source/python/AvidaGui2/pyTimeline.py	2006-07-27 19:41:39 UTC (rev 856)
@@ -39,6 +39,20 @@
         self.info = info
 #        self.pixmap = QPixmap(filename)
 
+    # Overload comparison operators so we can sort by position in timeline
+    def __eq__(self, other):
+        return (self.filename == other.filename) and \
+            (self.pos == other.pos) and \
+            (self.info == other.info)
+    def __lt__(self, other):
+        return self.pos < other.pos
+    def __le__(self, other):
+        return self.pos <= other.pos
+    def __gt__(self, other):
+        return self.pos > other.pos
+    def __ge__(self, other):
+        return self.pos >= other.pos
+
 class pyTimeline(QwtThermo):
     """pyTimeline is a generic timeline control.
     It is derived from the QwtThermo control.  It offers the ability to plot
@@ -46,34 +60,125 @@
     def __init__(self, *args):
         QwtThermo.__init__(self, *args)
         self.setOrientation(Qt.Horizontal, QwtThermo.Bottom)
-        self.setPipeWidth(16)
-        self.flags = []
+        self.setPipeWidth(32)
+        self.flags = []         # holds the events for this timeline
+        self.clusters = []      # holds event clusters for overlapping events
 
     def addFlag(self, flag):
         "Add new flag to timeline"
         self.flags.append(flag)
+        self.clusters.append([flag])
+        flag.cluster = self.clusters[-1]
+        self.flags.sort()
 #        flag.widget = TimelineFlagWidget(self, flag.pixmap, flag.info)
         flag.widget = TimelineFlagLabel(self, flag.filename, flag.info)
-        self.move_flag(flag)
         if self.maxValue() == 0.0:
+            # Uninitialized range
+            return
+	flag.calc_pos = self.get_flag_pos(flag)
+        flag.adj_pos = flag.calc_pos
+        self.layout_events()
+	self.draw_event(flag)
+        if self.maxValue() == 0.0:
             flag.widget.hide()
         else:
             flag.widget.show()
 
-    def move_flag(self, flag):
-        "Draw the flag in the proper location"
-        if self.maxValue() == 0.0:
-            # Uninitialized range
-            return
+
+    def get_border_width(self):
+        "Get full border width"
+	# default margin size is 10 (QwtThermo docs)
+	return self.borderWidth() + 10
+
+    def get_flag_pos(self, flag):
+	"Calculate where in timeline flag should appear"
         # center widget
 	adj = flag.widget.width() / 2
 	frame = self.frameSize().width() - self.width()
-	# default margin size is 10 (QwtThermo docs)
-	borders = self.borderWidth() + 10
+	borders = self.get_border_width()
 	a = self.width() - frame - (borders * 2)
         mult = a / (self.maxValue() - self.minValue())
-        flag.widget.move((flag.pos * mult) + (frame / 2) + borders - adj, 2)
+	final_pos = (flag.pos * mult) + (frame / 2) + borders - adj
+	return final_pos
 
+    def layout_events(self):
+        """Layout flags so there is no overlapping.
+        We cluster flags together that are overlapping, and then layout the
+        cluster"""
+        last_flag = None
+        redraw = False
+        for flag in self.flags:
+            flag_width = flag.widget.width() / 2
+            if last_flag:
+                if (flag.calc_pos - last_flag.adj_pos) < flag.widget.width() + 2:
+                    # This flag overlaps on the last flag
+                    flag.cluster.remove(flag)
+                    flag.cluster = last_flag.cluster
+                    last_flag.cluster.append(flag)
+                    flag.cluster.sort()
+                    # Clean up empty clusters
+                    self.clusters = [c for c in self.clusters if c]
+                    self.recalc_cluster(flag.cluster)
+                    redraw = True
+                else:
+                    # flag doesn't overlap previous flag
+                    flag.adj_pos = flag.calc_pos
+                    if len(flag.cluster) > 1:
+                        flag.cluster.remove(flag)
+                        if flag.cluster:
+                            self.recalc_cluster(flag.cluster)
+                        # Clean up empty clusters
+                        self.clusters = [c for c in self.clusters if c]
+                        self.clusters.append([flag])
+                        flag.cluster = self.clusters[-1]
+
+            last_flag = flag
+
+        if redraw:
+            self.repaint()
+
+    def recalc_cluster(self, cluster):
+        "Recalculate event cluster location"
+        # Cluster position is the average of the events in the
+        # cluster
+        sum = 0.0
+        widget_sum = 0
+        for flag in cluster:
+            sum += flag.calc_pos
+            widget_sum += flag.widget.width()
+        avg = sum / len(cluster)
+        start = widget_sum / 2
+        start = avg - start + (cluster[0].widget.width() / 2)
+        if start < self.get_border_width() + 1:
+            start = self.get_border_width() + 1
+        for flag in cluster:
+            flag.adj_pos = start
+            start += flag.widget.width()
+
+    def draw_event(self, flag):
+	"Draw both flag and line"
+	self.draw_flag(flag)
+	self.draw_line(flag)
+
+    def draw_flag(self, flag):
+        "Draw the flag in the proper location"
+        flag.widget.move(flag.adj_pos, 2)
+
+    def draw_line(self, flag):
+	"Draw line connecting flag and event in timeline"
+        flag_center = flag.widget.width() / 2
+	flag_bottom = flag.widget.height()
+        painter = QPainter(self)
+        orig = flag.calc_pos + flag_center
+	final = flag.adj_pos + flag_center
+	line_height = self.pipeWidth() - flag_bottom - 6
+	painter.drawLine(orig, self.pipeWidth(), orig,
+                         self.pipeWidth() - 4)
+	painter.drawLine(orig, self.pipeWidth() - 4, final,
+			 self.pipeWidth() - line_height)
+	painter.drawLine(final, self.pipeWidth() - line_height,
+                         final, flag_bottom)
+
     def removeFlag(self, pos):
         "Remove flag from timeline position pos"
         tmp_flag = None
@@ -87,12 +192,13 @@
     def paintEvent(self, event):
         "Paint event handler"
         QwtThermo.paintEvent(self, event)
-        self.draw_flags()
+	# draw the flags
+        self.draw_events()
 
-    def draw_flags(self):
+    def draw_events(self):
         "Draw flags on timeline"
         for flag in self.flags:
-            self.move_flag(flag)
+            self.draw_event(flag)
 
     def setMaxValue(self, value):
         "Set the range max value"
@@ -111,3 +217,10 @@
         for flag in self.flags:
             flag.widget.close(True)
         self.flags = []
+
+    def resizeEvent(self, evt):
+        "Resize event"
+        QwtThermo.resizeEvent(self, evt)
+        for flag in self.flags:
+            flag.calc_pos = self.get_flag_pos(flag)
+        self.layout_events()




More information about the Avida-cvs mailing list