Source code for cadbiom_gui.gt_gui.chart_view

## Filename    : chart_view.py
## Author(s)   : Michel Le Borgne
## Created     : 4/3/2010
## Revision    :
## Source      :
##
## Copyright 2009 - 2010 - 2020 IRISA/IRSET
##
## This library 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.1 of the License, or
## any later version.
##
## This library 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.  The software and
## documentation provided hereunder is on an "as is" basis, and IRISA has
## no obligations to provide maintenance, support, updates, enhancements
## or modifications.
## In no event shall IRISA be liable to any party for direct, indirect,
## special, incidental or consequential damages, including lost profits,
## arising out of the use of this software and its documentation, even if
## IRISA have been advised of the possibility of such damage.  See
## the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this library; if not, write to the Free Software Foundation,
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## The original code contained here was initially developed by:
##
##     Michel Le Borgne.
##     IRISA
##     Symbiose team
##     IRISA  Campus de Beaulieu
##     35042 RENNES Cedex, FRANCE
##
##
## Contributor(s): Geoffroy Andrieux, Nolwenn Le Meur
##
"""
Main views for the Cadbiom gui

Classes available and inheritance hierarchy:

    gtk.DrawingArea:
        :class:`ChartView`: Used by the graph editor window/page of charter
            :class:`NavView`: overview widget

    gtk.Frame:
        :class:`ChartPage`: Graph editor window/page of charter
"""
import gtk


[docs]class ChartView(gtk.DrawingArea): """Class for the main drawing window of charter .. note:: Also instanciated by the overview widget. .. note:: DrawingArea can capture key-press-events: - add gtk.gdk.KEY_PRESS_MASK mask to event - be sure that the DrawingArea has the focus by using grab_focus() on mouse events. .. TODO:: Optimize events handling: - on_motion_notify: Mouse over the widget, causing multiple calls to find_element() of the top node. - on_expose_event: When the window is covered/partially covered; all the pixmap is redrawn. """ def __init__(self, width, height, drawing_style, controler, model): """ @param width, height: int - size of the view @param drawing_style: a Drawing style associated with the pattern @param controler: the controller as in the MVC pattern NavControler or ChartControler objects @param model: a ChartModel """ gtk.DrawingArea.__init__(self) self.controler = controler controler.set_view(self) self.model = model # attach as model observer model.attach(self) # signals self.add_events( gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk._2BUTTON_PRESS | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK ) # Get the focus self.set_flags(gtk.HAS_FOCUS | gtk.CAN_FOCUS) self.grab_focus() self.connect("expose-event", self.on_expose_event) self.connect("configure_event", self.on_configure_event) # controlled events self.connect("button_press_event", self.on_button_press) self.connect("button_release_event", controler.on_button_release) self.connect("motion_notify_event", controler.on_motion_notify) # drawing stuffs drawing_style.view = self self.drawing_style = drawing_style controler.drawing_style = drawing_style self.draw_width = width # drawing window self.min_width = width self.draw_height = height self.min_height = height self.set_size_request(width, height) self.stylepango = self.create_pango_layout("") self.pixmap = None # cannot be initialized before self.window creation self.page = None self.zoom_count = 0
[docs] def on_button_press(self, *args): """On button_press event set the focus on the current widget, then redirect the event to the controller. We need this in order to test some keyboard shortcuts in the controller. is_focus(): Determines if the widget is the focus widget within its toplevel. (This does not mean that the has-focus property is necessarily set; has-focus will only be set if the toplevel widget additionally has the global input focus.) """ self.grab_focus() self.controler.on_button_press(*args)
[docs] def on_expose_event(self, widget, event): """ Redisplay drawing after cover and exposure of the window """ self.pixmap.draw_rectangle( self.get_style().white_gc, True, 0, 0, self.draw_width, self.draw_height ) # draw the full model from its top node in the pixmap self.model.draw(self) # expose the drawing self.window.draw_drawable(self.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, 0, 0, 0, 0, self.draw_width, self.draw_height) if self.page: self.page.notify(widget) return True
[docs] def on_configure_event(self, widget, event): """ Initialisation and change in size """ # adjust to visible window xor, yor, width, height = widget.get_allocation() self.draw_width = max(width, self.min_width) self.draw_height = max(height, self.min_height) # set pixmap if necesssary if not self.pixmap: self.pixmap = gtk.gdk.Pixmap(self.window, self.draw_width, self.draw_height) # adjust the pixmap to size size = self.pixmap.get_size() if size[0] != self.draw_width or size[1] != self.draw_height: self.set_size_request(self.draw_width, self.draw_height) self.pixmap = gtk.gdk.Pixmap(self.window, self.draw_width, self.draw_height) return True
[docs] def update(self): """Display a new drawing of the model Notified by the model when changes have been made (move/delete/add item) Or by the ChartControler when a transition/node is selected. """ # update only visible views if not self.window: return # resize if virtual drawing window size changed size = self.pixmap.get_size() if size[0] != self.draw_width or size[1] != self.draw_height: self.set_size_request(self.draw_width, self.draw_height) self.pixmap = gtk.gdk.Pixmap(self.window, self.draw_width, self.draw_height) self.pixmap.draw_rectangle( self.get_style().white_gc, True, 0, 0, self.draw_width, self.draw_height ) # draw in the pixmap self.model.draw(self) # expose the drawing self.window.draw_drawable(self.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, 0, 0, 0, 0, self.draw_width, self.draw_height)
[docs] def zoom_minus(self): """ Zoom out function """ if self.zoom_count < -10: return self.min_height = int(self.min_height * 0.9) self.draw_height = self.min_height self.min_width = int(self.min_width * 0.9) self.draw_width = self.min_width self.update() if self.page: self.page.notify(None) self.zoom_count = self.zoom_count - 1
[docs] def zoom_plus(self): """ Zoom in function """ if self.zoom_count > 15: return self.min_height = int(self.min_height * 1.1) self.draw_height = self.min_height self.min_width = int(self.min_width * 1.1) self.draw_width = self.min_width self.update() if self.page: self.page.notify(None) self.zoom_count += 1
[docs]class ChartPage(gtk.Frame): """ A simple graph editor for pages: a graph area wrapped in a scroll window """ def __init__(self, width, height, drst, controler, model): """ """ gtk.Frame.__init__(self) # for observers self.__observer_list = [] # chart view and model self.draw = ChartView(width, height, drst, controler, model) self.draw.page = self # wrap in a scroll window scr_w = gtk.ScrolledWindow() self.scr_w = scr_w self.vadj = scr_w.get_vadjustment() self.hadj = scr_w.get_hadjustment() self.hadj_h_id = self.hadj.connect("value_changed", self.notify) self.vadj_h_id = self.vadj.connect("value_changed", self.notify) self.allow_adj = True scr_w.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS) viewport = gtk.Viewport() scr_w.add(viewport) viewport.add(self.draw) self.add(scr_w) self.show_all() # observer pattern methods
[docs] def attach(self, obs): """ standard in observer pattern """ if not obs in self.__observer_list: self.__observer_list.append(obs)
[docs] def detach(self, obs): """ standard in observer pattern """ self.__observer_list.remove(obs)
[docs] def notify(self, widget): """ used when the viewport is moved from inside (hbar and vbar) """ if self.allow_adj: x_pos = float(self.hadj.value) / self.draw.draw_width y_pos = float(self.vadj.value) / self.draw.draw_height width = self.hadj.page_size / self.draw.draw_width height = self.vadj.page_size / self.draw.draw_height for obs in self.__observer_list: obs.scroll_update(x_pos, y_pos, width, height)
# signal call back
[docs] def update(self, dxx, dyy): """ Used when the viewport is moved from outside (navigator) """ d_hadj = dxx * self.draw.draw_width d_vadj = dyy * self.draw.draw_height self.allow_adj = False self.hadj.value = int(self.hadj.value + d_hadj) self.vadj.value = int(self.vadj.value + d_vadj) self.scr_w.set_hadjustment(self.hadj) self.scr_w.set_vadjustment(self.vadj) self.allow_adj = True self.notify(None)