Package conduit :: Package gtkui :: Module Canvas
[hide private]

Source Code for Module conduit.gtkui.Canvas

   1  """ 
   2  Manages adding, removing, resizing and drawing the canvas 
   3   
   4  The Canvas is the main area in Conduit, the area to which DataProviders are  
   5  dragged onto. 
   6   
   7  Copyright: John Stowers, 2006 
   8  License: GPLv2 
   9  """ 
  10  import cairo 
  11  import goocanvas 
  12  import gtk 
  13  import pango 
  14  from gettext import gettext as _ 
  15   
  16  import logging 
  17  log = logging.getLogger("gtkui.Canvas") 
  18   
  19  import conduit.utils as Utils 
  20  import conduit.Conduit as Conduit 
  21  import conduit.gtkui.Tree 
  22  import conduit.gtkui.Util as GtkUtil 
  23  import conduit.gtkui.Hints as Hints 
  24   
  25  log.info("Module Information: %s" % Utils.get_module_information(goocanvas, "pygoocanvas_version")) 
  26   
27 -class _StyleMixin:
28
29 - def _get_colors_and_state(self, styleName, stateName):
30 style = self.get_gtk_style() 31 if style: 32 colors = getattr(style, styleName.lower(), None) 33 state = getattr(gtk, "STATE_%s" % stateName.upper(), None) 34 else: 35 colors = None 36 state = None 37 38 return colors,state
39
40 - def get_gtk_style(self):
41 """ 42 @returns: The gtk.Style for the widget 43 """ 44 #not that clean, we can be mixed into the 45 #canvas, or a canvas item 46 try: 47 return self.get_canvas().style 48 except AttributeError: 49 try: 50 return self.style 51 except AttributeError: 52 return None
53
54 - def get_style_color_rgb(self, styleName, stateName):
55 colors,state = self._get_colors_and_state(styleName, stateName) 56 if colors != None and state != None: 57 return GtkUtil.gdk2rgb(colors[state]) 58 else: 59 return GtkUtil.gdk2rgb(GtkUtil.str2gdk("red"))
60
61 - def get_style_color_rgba(self, styleName, stateName, a=1):
62 colors,state = self._get_colors_and_state(styleName, stateName) 63 if colors != None and state != None: 64 return GtkUtil.gdk2rgba(colors[state], a) 65 else: 66 return GtkUtil.gdk2rgba(GtkUtil.str2gdk("red"), a)
67
68 - def get_style_color_int_rgb(self, styleName, stateName):
69 colors,state = self._get_colors_and_state(styleName, stateName) 70 if colors != None and state != None: 71 return GtkUtil.gdk2intrgb(colors[state]) 72 else: 73 return GtkUtil.gdk2intrgb(GtkUtil.str2gdk("red"))
74
75 - def get_style_color_int_rgba(self, styleName, stateName, a=1):
76 colors,state = self._get_colors_and_state(styleName, stateName) 77 if colors != None and state != None: 78 return GtkUtil.gdk2intrgba(colors[state], int(a*255)) 79 else: 80 return GtkUtil.gdk2intrgba(GtkUtil.str2gdk("red"), int(a*255))
81
82 -class _CanvasItem(goocanvas.Group, _StyleMixin):
83 84 #attributes common to Conduit and Dataprovider items 85 RECTANGLE_RADIUS = 4.0 86
87 - def __init__(self, parent, model):
88 #FIXME: If parent is None in base constructor then goocanvas segfaults 89 #this means a ref to items may be kept so this may leak... 90 goocanvas.Group.__init__(self, parent=parent) 91 self.model = model 92 93 #this little piece of magic re-applies style properties to the 94 #widgets, when the users theme changes 95 canv = self.get_canvas() 96 if canv: 97 canv.connect("style-set", self._automatic_style_updater)
98
99 - def _automatic_style_updater(self, *args):
100 if not self.get_gtk_style(): 101 #while in the midst of changing theme, the style is sometimes 102 #None, but dont worry, we will get called again 103 return 104 for attr in self.get_styled_item_names(): 105 item = getattr(self, attr, None) 106 if item: 107 item.set_properties( 108 **self.get_style_properties(attr) 109 )
110
111 - def get_height(self):
112 b = self.get_bounds() 113 return b.y2-b.y1
114
115 - def get_width(self):
116 b = self.get_bounds() 117 return b.x2-b.x1
118
119 - def get_top(self):
120 b = self.get_bounds() 121 return b.y1
122
123 - def get_bottom(self):
124 b = self.get_bounds() 125 return b.y2
126
127 - def get_left(self):
128 b = self.get_bounds() 129 return b.x1
130
131 - def get_right(self):
132 b = self.get_bounds() 133 return b.x2
134
135 - def get_styled_item_names(self):
136 raise NotImplementedError
137
138 - def get_style_properties(self, specifier):
139 raise NotImplementedError
140
141 -class Canvas(goocanvas.Canvas, _StyleMixin):
142 """ 143 This class manages many objects 144 """ 145 DND_TARGETS = [ 146 ('conduit/element-name', 0, 0) 147 ] 148 149 WELCOME_MESSAGE = _("Drag a Data Provider here to continue")
150 - def __init__(self, parentWindow, typeConverter, syncManager, dataproviderMenu, conduitMenu, msg):
151 """ 152 Draws an empty canvas of the appropriate size 153 """ 154 #setup the canvas 155 goocanvas.Canvas.__init__(self) 156 self.set_bounds(0, 0, 157 conduit.GLOBALS.settings.get("gui_initial_canvas_width"), 158 conduit.GLOBALS.settings.get("gui_initial_canvas_height") 159 ) 160 self.set_size_request( 161 conduit.GLOBALS.settings.get("gui_initial_canvas_width"), 162 conduit.GLOBALS.settings.get("gui_initial_canvas_height") 163 ) 164 self.root = self.get_root_item() 165 166 self.sync_manager = syncManager 167 self.typeConverter = typeConverter 168 self.parentWindow = parentWindow 169 self.msg = msg 170 171 self._setup_popup_menus(dataproviderMenu, conduitMenu) 172 173 #set up DND from the treeview 174 self.drag_dest_set( gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, 175 self.DND_TARGETS, 176 gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_LINK) 177 self.connect('drag-motion', self.on_drag_motion) 178 self.connect('size-allocate', self._canvas_resized) 179 180 #track theme chages for canvas background 181 self.connect('realize', self._update_for_theme) 182 #We need a flag becuase otherwise we recurse forever. 183 #It appears that setting background_color_rgb in the 184 #sync-set handler causes sync-set to be emitted again, and again... 185 self._changing_style = False 186 self.connect("style-set", self._update_for_theme) 187 188 #keeps a reference to the currently selected (most recently clicked) 189 #canvas items 190 self.selectedConduitItem = None 191 self.selectedDataproviderItem = None 192 193 #model is a SyncSet, not set till later because it is loaded from xml 194 self.model = None 195 196 #Show a friendly welcome message on the canvas the first time the 197 #application is launched 198 self.welcome = None 199 self._maybe_show_welcome()
200
201 - def _do_hint(self, msgarea, respid):
202 if respid == Hints.BLANK_CANVAS: 203 new = conduit.GLOBALS.moduleManager.get_module_wrapper_with_instance("FolderTwoWay") 204 self.