diff options
Diffstat (limited to 'TheDrawingAreaEventBox.py')
-rwxr-xr-x | TheDrawingAreaEventBox.py | 268 |
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 |