# coding: UTF8 # Copyright 2009 Thomas Jourdan # # 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 3 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 ka_controller import ka_task import cairo import ka_debug class KandidIncoming(object): """ inv: 0 <= len(self.incoming_protozoans) <= self._capacity inv: 0 <= len(self.incoming_surface_cache) <= self._capacity inv: 0 <= len(self.incoming_surface_cache) <= len(self.incoming_protozoans) inv: self._capacity > 0 """ ids = 0 def __init__(self, capacity, widget_tree): """ pre: capacity > 0 pre: widget_tree is not None """ self._capacity = capacity self._widget_tree = widget_tree self.incoming_id = [] self.incoming_protozoans = {} self.incoming_surface_cache = {} self._inbox_widget = self._widget_tree.get_widget('incomingBox') self._update_incomming_gui() def autoconnect_events(self): """Create a dictionary to connect events.""" events = { } for cell_index in range(self._capacity): key = 'on_incomingarea_#_expose'.replace('#', str(cell_index)) events[key] = self.on_incomingarea_expose self._widget_tree.signal_autoconnect(events) def at_index(self, index): iid = self.incoming_id[index] if index < len(self.incoming_id) \ else -1 protozoon = self.incoming_protozoans[iid] \ if self.incoming_protozoans.has_key(iid) \ else None return protozoon, iid def append_protozoon(self, incoming_protozoon): """ Append incoming protozoon and manage capacity. pre: incoming_protozoon is not None """ ka_debug.info('incoming: append protozoon') while len(self.incoming_protozoans) >= self._capacity: iid = self.incoming_id[0] del self.incoming_id[0] del self.incoming_protozoans[iid] if self.incoming_surface_cache.has_key(iid): del self.incoming_surface_cache[iid] KandidIncoming.ids += 1 self.incoming_id.append(KandidIncoming.ids) self.incoming_protozoans[KandidIncoming.ids] = incoming_protozoon index = len(self.incoming_id) - 1 widget = self._widget_tree.get_widget('incomingarea_' + str(index)) task = ka_task.GeneratorTask(self.task_render, self.on_image_completed) task.start(incoming_protozoon, KandidIncoming.ids, widget.allocation.width, widget.allocation.height) ka_debug.info('incoming: start_calculation %ux%u, iid %u for %s' % (widget.allocation.width, widget.allocation.height, KandidIncoming.ids, widget.name)) def accept_protozoon(self, index): """ Move protozoon from incoming list to image population. pre: 0 <= index < self._capacity """ protozoon, iid = self.at_index(index) if protozoon is not None: ka_debug.info('incoming: accept incoming protozoon %u' % iid) del self.incoming_id[index] del self.incoming_protozoans[iid] if self.incoming_surface_cache.has_key(iid): del self.incoming_surface_cache[iid] self._update_incomming_gui() return protozoon def decline_protozoon(self, index): """ Remove protozoon from incoming list pre: 0 <= index < self._capacity """ if index < len(self.incoming_protozoans): ka_debug.info('incoming: decline incoming protozoon %u' % index) iid = self.incoming_id[index] del self.incoming_id[index] del self.incoming_protozoans[iid] if self.incoming_surface_cache.has_key(iid): del self.incoming_surface_cache[iid] self._update_incomming_gui() def task_render(self, *args, **kwargs): """Draw protozoon to surface cache. pre: len(args) == 4 """ protozoon, iid, width, height = \ args[0], args[1], args[2], args[3] ka_debug.info('incoming: task_render entry: ' + str(iid)) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) ctx = cairo.Context(surface) protozoon.render(ctx, width, height) if self.incoming_protozoans.has_key(iid): self.incoming_surface_cache[iid] = surface ka_debug.info('incoming: task_render exit: ' + str(iid)) #!! ka_task.GeneratorTask.leave() return iid def on_image_completed(self, *args): """Rendering task has finished""" ka_debug.info('incoming: on_image_completed: ' + str(args[0])) self._update_incomming_gui() def on_incomingarea_expose(self, widget, dummy): """ Repaint image of a single protozoon inside incoming area. pre: widget is not None """ ka_debug.info('incoming: on_incomingarea_expose: ' + widget.name) self.draw(ka_controller.name_to_index(widget.name), \ ka_controller.create_context(widget), \ widget.allocation.width, widget.allocation.height) def draw(self, index, ctx, width, height): """ Repaint one protozoon image inside incoming area. pre: 0 <= index < self._capacity pre: ctx is not None pre: width > 0 pre: height > 0 """ iid = -1 if index < len(self.incoming_id): iid = self.incoming_id[index] if self.incoming_surface_cache.has_key(iid): # draw protozoon to screen ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.set_source_surface(self.incoming_surface_cache[iid]) ctx.paint() else: ctx.set_source_rgba(0.65, 0.65, 0.65, 0.0) ctx.rectangle(0.0, 0.0, width, height) ctx.fill() def _update_incomming_gui(self): for index in range(self._capacity): self._widget_tree.get_widget('incomingbutton_' + str(index)). \ set_sensitive(len(self.incoming_id) > index) self._inbox_widget.queue_draw()