Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TheDrawingAreaEventBox.py
diff options
context:
space:
mode:
Diffstat (limited to 'TheDrawingAreaEventBox.py')
-rwxr-xr-xTheDrawingAreaEventBox.py268
1 files changed, 268 insertions, 0 deletions
diff --git a/TheDrawingAreaEventBox.py b/TheDrawingAreaEventBox.py
new file mode 100755
index 0000000..630483a
--- /dev/null
+++ b/TheDrawingAreaEventBox.py
@@ -0,0 +1,268 @@
+# TheDrawingAreaEventBox.py Manages the drawing component
+#
+# Copyright (C) 2011 Laurent BERNABE
+#
+# This program is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General
+# Public License as published by the Free Software
+# Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will
+# be useful, but WITHOUT ANY WARRANTY; without even
+# the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public
+# License for more details.
+#
+# You should have received a copy of the GNU General
+# Public License along with this program; if not, write
+# to the Free Software Foundation, Inc., 51 Franklin
+# St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import cairo
+import gobject
+
+class TheDrawingAreaEventBox(gtk.EventBox):
+ '''
+ A gtk.EventBox wrapping the DrawingArea (or canvas) of the application
+ We use an EventBox in order to pass events to the contained DrawingArea
+ '''
+ __DARK_GREEN = (27.0/255.0, 103.0/255.0,46.0/255.0)
+ __WHITE = (1.0, 1.0, 1.0)
+
+
+ def __init__(self):
+ '''
+ Simple constructor without argument
+ '''
+ gtk.EventBox.__init__(self)
+ self.__setFields()
+ self.__setConnections()
+
+ def __setFields(self):
+ '''
+ Gives values to fields
+ '''
+ self.__drawingArea = gtk.DrawingArea()
+ self.add(self.__drawingArea)
+ self.__figures = []
+ self.__lineThickness = 1
+ # number of steps (for the figures overall) currently drawn
+ # only used in reading mode (which is the starting mode)
+ self.__drawn_steps = -1
+ # __overall_maximum_steps stores the steps of all the figures
+ # only used in reading mode (which is the starting mode)
+ self.__overall_maximum_steps = -1
+ # __current_maximum_steps stores the maximum steps the updater thread
+ # is allowing to draw. In each cycle of the updater thread, this value
+ # is incremented, giving this impression of a tape reading
+ # only used in reading mode (which is the starting mode)
+ self.__current_maximum_steps = -1
+ # the updater delay in milliseconds
+ # => at which intervals, in reading mode,
+ # the redraws should be done
+ self.__updater_delay_milliseconds = -1
+ self.__mousePressed = False
+ self.__readingMode = False
+
+ def __setConnections(self):
+ '''
+ Define the events connections
+ '''
+ self.__drawingArea.connect("expose-event", self.__paintSurface)
+ self.connect("motion-notify-event", self.__manageMouseMovedEvent)
+ self.connect("button-press-event", self.__manageButtonPressedEvent)
+ self.connect("button-release-event", self.__manageButtonReleasedEvent)
+
+ def setRecordingMode(self, line_thickness):
+ '''
+ Switch drawing area management to recording mode
+ => setRecordingMode(line_thickness)
+ where line_thickness is an integer
+ '''
+ self.__readingMode = False
+ self.__figures = []
+ self.__drawingArea.queue_draw()
+ self.__startNewFigure()
+ self.__setLineThickness(line_thickness)
+
+ def setReadingMode(self, intervals_between_steps_milliseconds):
+ '''
+ Switch drawing area management to reading mode
+ => intervals_between_steps argument is an integer saying delays
+ in millisecond between steps
+ => setReadingMode(intervals_between_steps_milliseconds)
+ => intervals_between_steps_milliseconds : integer
+ '''
+ self.__updater_delay_milliseconds = intervals_between_steps_milliseconds
+ self.__drawn_steps = 0
+ self.__current_maximum_steps = 0
+ self.__computeOverallMaximumSteps()
+ self.__drawingArea.queue_draw()
+ self.__readingMode = True
+ self.__regularlyUpdatePaintForReadingMode()
+
+
+ def __setLineThickness(self, line_thickness):
+ '''
+ Sets lines thickness. Only integers greater than 0 will be taken
+ in consideration.
+ => __setLineThickness(line_thickness)
+ where line_thickness is an integer
+ '''
+ if isinstance(line_thickness, int) and line_thickness > 0:
+ self.__lineThickness = line_thickness
+
+ def __paintSurface(self, widget, event):
+ '''
+ Paint the whole drawing area
+ => __paintSurface(widget, event)
+ '''
+ cairoContext = self.__drawingArea.window.cairo_create()
+ self.__drawBackground(cairoContext)
+ self.__drawFigures(cairoContext)
+ return True
+
+ def __drawBackground(self, cairoContext):
+ '''
+ Paints the background
+ => __drawBackground(cairoContext)
+ where cairoContext is a cairo context of the DrawingArea
+ '''
+ cairoContext.set_source_rgb(*TheDrawingAreaEventBox.__DARK_GREEN)
+ cairoContext.rectangle( 0,0, *(self.window.get_size()) )
+ cairoContext.fill()
+
+ def __drawFigures(self, cairoContext):
+ '''
+ Draws the figures
+ => __drawFigures(cairoContext)
+ where cairoContext is a cairo context of the DrawingArea
+ '''
+ cairoContext.set_source_rgb(*TheDrawingAreaEventBox.__WHITE)
+ cairoContext.set_line_width(self.__lineThickness)
+ cairoContext.set_line_join(cairo.LINE_JOIN_ROUND)
+ cairoContext.set_line_cap(cairo.LINE_CAP_ROUND)
+ if self.__readingMode:
+ self.__drawn_steps = 0
+ for current_figure in self.__figures:
+ if len(current_figure) > 0 :
+ startPoint = current_figure[0]
+ cairoContext.move_to(*startPoint)
+ if self.__readingMode:
+ self.__drawn_steps += 1
+ for pointIndex in range(1, len(current_figure)):
+ if self.__readingMode and self.__drawn_steps >= self.__current_maximum_steps :
+ cairoContext.stroke()
+ return
+ endPoint = current_figure[pointIndex]
+ cairoContext.line_to(*endPoint)
+ startPoint = endPoint
+ if self.__readingMode :
+ self.__drawn_steps += 1
+ cairoContext.stroke()
+
+ def __startNewFigure(self):
+ '''
+ Starts a new figure
+ '''
+ self.__figures += [[]]
+
+ def __addPointToCurrentFigure(self, pointTuple):
+ '''
+ Adds a point to the current figure
+ ==> __addPointToCurrentFigure(pointTuple)
+ where pointTuple is a tuple of the point coordinates
+ '''
+ self.__figures[len(self.__figures)-1] += [pointTuple]
+
+ def __computeOverallMaximumSteps(self):
+ '''
+ Computes the number of steps of all the Figures to draw
+ '''
+ self.__overall_maximum_steps = 0
+ for current_figure in self.__figures :
+ self.__overall_maximum_steps += len(current_figure)
+
+ def __manageMouseMovedEvent(self, widget, event):
+ '''
+ Manage mouse move event
+ => __manageMouseMovedEvent(widget, event)
+ '''
+ if self.__mousePressed:
+ self.__addPointToCurrentFigure((event.x, event.y))
+ self.__drawingArea.queue_draw() # repaint the drawing area
+ return True # we don't need further handling for this event
+
+ def __manageButtonPressedEvent(self, widget, event):
+ '''
+ Manage button pressed event
+ => __manageButtonPressedEvent(widget, event)
+ '''
+ self.__startNewFigure()
+ self.__mousePressed = True
+ return True # we don't need further handling for this event
+
+ def __manageButtonReleasedEvent(self, widget, event):
+ '''
+ Manage button released event
+ => __manageButtonReleasedEvent(widget, event)
+ '''
+ self.__mousePressed = False
+ return True # we don't need further handling for this event
+
+ def __regularlyUpdatePaintForReadingMode(self):
+ '''
+ Increases the current maximum drawn steps and repaint all, at
+ regular delays. (For reading mode)
+ => __regularlyUpdatePaintForReadingMode(regular_delay_milliseconds)
+ regular_delay_milliseconds : integer
+ '''
+ if self.__readingMode:
+ self.__current_maximum_steps += 1
+ self.__drawingArea.queue_draw()
+ if self.__current_maximum_steps < self.__overall_maximum_steps :
+ gobject.timeout_add(
+ self.__updater_delay_milliseconds,
+ self.__regularlyUpdatePaintForReadingMode
+ )
+
+ def saveFiguresInTextFile(self, text_file):
+ '''
+ Save the points in a file opened with function 'open' in write mode.
+ Be careful !!! Do not pass a file opened in binary mode !!!
+ And also, remember to close the file after this method call !!!
+ => saveFiguresInTextFile(text_file)
+ '''
+ for current_figure in self.__figures :
+ if current_figure:
+ text_file.write("New\n")
+ for point_coordinates in current_figure:
+ if point_coordinates:
+ text_file.write("%d#%d " % point_coordinates)
+ text_file.write("\n")
+
+ def readFiguresFromTextFile(self, text_file):
+ '''
+ Read the points from a file opened with function 'open' in read mode.
+ Be careful !!! Do not pass a filed opened in a binary mode !!!
+ And also, remember to close the file after this method call !!!
+ => readFiguresFromTextFile(text_file)
+ '''
+ new_figures_array = []
+ for current_line in text_file.readlines():
+ if current_line != "New" :
+ new_figure = []
+ for current_point_string in current_line.split(' '):
+ if current_point_string:
+ current_point_string_parts = current_point_string.split('#')
+ new_figure.append((int(current_point_string_parts[0]),
+ int(current_point_string_parts[1])))
+ if new_figure:
+ new_figures_array.append(new_figure)
+ self.__figures = new_figures_array
+ self.__drawingArea.queue_draw()
+ \ No newline at end of file