class HistorietaActivity(activity.Activity): _EXPORT_FORMATS = [['image/png', _('Save as Image'), _('PNG'), ""]] def __init__(self, handle): activity.Activity.__init__(self, handle) self.set_title('FotoToon') self._max_participants = 1 self.page = None toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_toolbar = activity_button.page toolbar_box.toolbar.insert(activity_button, 0) edit_toolbar_btn = ToolbarButton() edit_toolbar = Gtk.Toolbar() edit_toolbar_btn.props.page = edit_toolbar edit_toolbar_btn.props.icon_name = 'toolbar-edit' edit_toolbar_btn.label = _('Edit') toolbar_box.toolbar.insert(edit_toolbar_btn, -1) view_toolbar_btn = ToolbarButton() view_toolbar = Gtk.Toolbar() view_toolbar_btn.props.page = view_toolbar view_toolbar_btn.props.icon_name = 'toolbar-view' view_toolbar_btn.label = _('View') toolbar_box.toolbar.insert(view_toolbar_btn, -1) slideview_btn = ToggleToolButton('slideshow') slideview_btn.set_tooltip(_('Slideshow')) slideview_btn.set_active(False) slideview_btn.connect('clicked', self._switch_view_mode, False) view_toolbar.insert(slideview_btn, -1) slideview_btn.show() slideview_timings_btn = ToggleToolButton('slideshow-stopwatch') slideview_timings_btn.set_tooltip(_('Slideshow with Timings')) slideview_timings_btn.set_active(False) slideview_timings_btn.connect('clicked', self._switch_view_mode, True) view_toolbar.insert(slideview_timings_btn, -1) slideview_timings_btn.show() time_button = ToolButton('stopwatch') time_button.set_tooltip(_('Set Image Duration in Slideshow (Seconds)')) view_toolbar.insert(time_button, -1) time_button.show() self._time_spin = Gtk.SpinButton.new_with_range(MIN_TIME, MAX_TIME, 1) self._time_spin.connect('value-changed', self.__time_spin_changed_cb) self._time_spin.props.value = DEFAULT_TIME self._time_spin.props.update_policy = \ Gtk.SpinButtonUpdatePolicy.IF_VALID palette = time_button.get_palette() palette.connect('popup', self.__time_button_popup_cb) time_button.connect( 'clicked', lambda *args: palette.popup(immediate=True, state=Palette.SECONDARY)) alignment = Gtk.Alignment() alignment.set_padding(style.DEFAULT_PADDING, style.DEFAULT_PADDING, style.DEFAULT_PADDING, style.DEFAULT_PADDING) alignment.add(self._time_spin) self._time_spin.show() palette.set_content(alignment) alignment.show() fullscreen_btn = ToolButton('view-fullscreen') fullscreen_btn.set_tooltip(_('Fullscreen')) fullscreen_btn.props.accelerator = '<Alt>Return' fullscreen_btn.connect('clicked', lambda w: self.fullscreen()) view_toolbar.insert(fullscreen_btn, -1) fullscreen_btn.show() self.set_toolbar_box(toolbar_box) toolbar = toolbar_box.toolbar self.page = Page() self.globes_manager = GlobesManager(toolbar, edit_toolbar, self) # fonts self._text_button = ToolbarButton() self._text_button.props.page = TextToolbar(self.page) self._text_button.props.icon_name = 'format-text-size' self._text_button.props.label = _('Text') self._toolbar_box.toolbar.insert(self._text_button, -1) reorder_img_btn = ToolButton('thumbs-view') reorder_img_btn.set_icon_name('thumbs-view') reorder_img_btn.set_tooltip(_('Change image order')) reorder_img_btn.connect('clicked', self.__image_order_cb) edit_toolbar.insert(reorder_img_btn, -1) reorder_img_btn.show() bgchange = ToolButton(icon_name='contract-coordinates') bgchange.set_tooltip(_('Edit background image')) bgchange.connect('clicked', self.__bgchange_clicked_cb) edit_toolbar.insert(bgchange, -1) bgchange.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) stop = StopButton(self) toolbar_box.toolbar.insert(stop, -1) toolbar_box.show_all() # add export button separator_2 = Gtk.SeparatorToolItem() separator_2.show() activity_toolbar.insert(separator_2, -1) self.bt_save_as_image = ToolButton() self.bt_save_as_image.props.icon_name = 'save-as-image' self.bt_save_as_image.connect('clicked', self.write_image) self.bt_save_as_image.set_tooltip(_('Save as Image')) activity_toolbar.insert(self.bt_save_as_image, -1) self.bt_save_as_image.show() save_as_pdf = ToolButton() save_as_pdf.props.icon_name = 'save-as-pdf' save_as_pdf.connect('clicked', self._save_as_pdf) save_as_pdf.set_tooltip(_('Save as a Book (PDF)')) activity_toolbar.insert(save_as_pdf, -1) save_as_pdf.show() save_as_ogg = ToolButton() save_as_ogg.props.icon_name = 'save-as-ogg' save_as_ogg.connect('clicked', self.__save_as_ogg_cb) save_as_ogg.set_tooltip(_('Save as a Movie (OGG)')) activity_toolbar.insert(save_as_ogg, -1) Gst.init(None) if Gst.version_string() != 'GStreamer 1.0.10': save_as_ogg.show() activity_button.page.title.connect("focus-in-event", self.on_title) scrolled = Gtk.ScrolledWindow() # scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS) scrolled.add_with_viewport(self.page) scrolled.set_kinetic_scrolling(False) scrolled.show_all() self._slideview = SlideView(self) self._slideview.show_all() self._notebook = Gtk.Notebook() self._notebook.set_show_tabs(False) self._notebook.append_page(scrolled, None) self._notebook.append_page(self._slideview, None) self._notebook.show_all() if self._jobject.file_path is None or self._jobject.file_path == '': empty_widget = EmptyWidget() empty_widget.connect('choose-image', self.__add_image) self.set_canvas(empty_widget) else: self.set_canvas(self._notebook) self.show() self.metadata['mime_type'] = 'application/x-fototoon-activity' self.page.empty_page = handle.object_id is None self._key_press_signal_id = None def __add_image(self, button): self.set_canvas(self._notebook) self.globes_manager.add_image() def on_title(self, widget, event): # unselect the active globe when editting the title logging.debug('Editing the title') if self.page.get_active_box() is not None: box = self.page.get_active_box() self.page.set_active_box(None) box.glob_press = False box.set_globo_activo(None) box.redraw() logging.debug('After edit the title') def write_file(self, file_path): if len(self.page.boxs) == 1: return self._commit_all_changes() persistence = persistencia.Persistence() persistence.write(file_path, self.page) def _commit_all_changes(self): # be sure all the changes are commited active_globe = self.page.get_globo_activo() if active_globe is not None: active_globe.set_selected(False) def read_file(self, file_path): persistence = persistencia.Persistence() persistence.read(file_path, self.page) def _get_image_size(self): image_height, image_width = 0, 0 posi = 0 for box in self.page.boxs: if posi > 0: reng = (posi + 1) // 2 column = (posi + 1) - (reng * 2) if column == 0: image_height = image_height + box.height else: image_width = box.width image_height = image_height + box.height # hide the cursor for globe in box.globos: globe.set_selected(False) posi = posi + 1 return image_width, image_height def write_image(self, button): self._commit_all_changes() # calculate image size image_width, image_height = self._get_image_size() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, image_width + 1, image_height + 1) ctx = cairo.Context(surface) ctx.set_source_rgb(1, 1, 1) ctx.rectangle(0, 0, image_width + 1, image_height + 1) ctx.fill() posi = 0 y_posi = 0 for box in self.page.boxs: if posi > 0: try: reng = (posi + 1) // 2 column = (posi + 1) - (reng * 2) ctx.rectangle(column * box.width, y_posi, (column + 1) * box.width, y_posi + box.height) ctx.set_source_rgb(0, 0, 0) ctx.stroke() ctx.translate(column * box.width, y_posi) box.draw_in_context(ctx) ctx.translate(column * box.width * -1, y_posi * -1) if column == 1: y_posi = y_posi + box.height except: pass else: box.draw_in_context(ctx) y_posi = box.height posi = posi + 1 temp_file_name = os.path.join(self.get_activity_root(), 'instance', 'tmp-%i.png' % time.time()) surface.write_to_png(temp_file_name) self.dl_jobject = datastore.create() self.dl_jobject.metadata['progress'] = '0' self.dl_jobject.metadata['keep'] = '0' self.dl_jobject.metadata['buddies'] = '' self.dl_jobject.metadata['icon-color'] = \ profile.get_color().to_string() self.dl_jobject.metadata['mime_type'] = 'image/png' self.dl_jobject.metadata['title'] = \ self._jobject.metadata['title'] + " as image" self.dl_jobject.metadata['description'] = "" self.dl_jobject.metadata['progress'] = '100' self.dl_jobject.file_path = temp_file_name self.dl_jobject.metadata['preview'] = \ self._get_preview_image(temp_file_name) datastore.write(self.dl_jobject, transfer_ownership=True) self._object_id = self.dl_jobject.object_id self._show_journal_alert(_('Success'), _('A image was created in the Journal')) def __image_order_cb(self, button): reorderwin = ReorderView(self) reorderwin.show_all() def __bgchange_clicked_cb(self, button): editorwin = ImageEditorView(self.page.get_active_box()) editorwin.show_all() def _save_as_pdf(self, widget): self._commit_all_changes() file_name = os.path.join(activity.get_activity_root(), 'instance', 'tmp-%i.pdf' % time.time()) file_obj = open(file_name, 'wb') page_width = self.page.boxs[1].width page_height = self.page.boxs[1].height surface = cairo.PDFSurface(file_obj, page_width, page_height) context = cairo.Context(surface) for box in self.page.boxs[0:]: context.save() if box.width != page_width: # for the first box, scale and center scale = float(page_width) / float(box.width) top_margin = (page_height - box.height) // 2 context.translate(0, top_margin) context.scale(scale, scale) box.draw_in_context(context) context.show_page() context.restore() surface.finish() file_obj.close() jobject = datastore.create() jobject.metadata['icon-color'] = \ profile.get_color().to_string() jobject.metadata['mime_type'] = 'application/pdf' jobject.metadata['title'] = \ self.metadata['title'] + " as book" jobject.file_path = file_name # jobject.metadata['preview'] = \ # self._get_preview_image(file_name) datastore.write(jobject, transfer_ownership=True) self._object_id = jobject.object_id self._show_journal_alert(_('Success'), _('A PDF was created in the Journal')) def __save_as_ogg_cb(self, button): self._commit_all_changes() directory = tempfile.mkdtemp() output_path = os.path.join(directory, 'output.ogv') first_box = self.page.boxs[1] width = first_box.width height = first_box.height framerate = first_box.slideshow_duration if len(self.page.boxs) > 2: for box in self.page.boxs[1:]: framerate = gcd(framerate, box.slideshow_duration) framerate = int(framerate) i = 0 for box in self.page.boxs[1:]: surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) context = cairo.Context(surface) context.set_source_rgb(1.0, 1.0, 1.0) context.paint() box.draw_in_context(context) for __ in range(int(box.slideshow_duration // framerate)): path = os.path.join(directory, '{}.png'.format(i)) surface.write_to_png(path) i += 1 pipeline_string = VIDEO_PIPELINE.format( os.path.join(directory, '%d.png'), framerate, output_path) pipeline = Gst.parse_launch(pipeline_string) pipeline.set_state(Gst.State.PLAYING) pipeline.get_bus().timed_pop_filtered( Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) pipeline.set_state(Gst.State.NULL) jobject = datastore.create() jobject.metadata['icon-color'] = profile.get_color().to_string() jobject.metadata['mime_type'] = 'video/ogg' jobject.metadata['title'] = \ _('{} as a movie').format(self.metadata['title']) jobject.file_path = output_path datastore.write(jobject, transfer_ownership=True) self._object_id = jobject.object_id self._show_journal_alert(_('Success'), _('A movie was saved in the Journal')) shutil.rmtree(directory) def _show_journal_alert(self, title, msg): _stop_alert = Alert() _stop_alert.props.title = title _stop_alert.props.msg = msg _stop_alert.add_button(Gtk.ResponseType.APPLY, _('Show in Journal'), Icon(icon_name='zoom-activity')) _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), Icon(icon_name='dialog-ok')) # Remove other alerts for alert in self._alerts: self.remove_alert(alert) self.add_alert(_stop_alert) _stop_alert.connect('response', self.__stop_response_cb) _stop_alert.show_all() def __stop_response_cb(self, alert, response_id): if response_id is Gtk.ResponseType.APPLY: activity.show_object_in_journal(self._object_id) self.remove_alert(alert) def _get_preview_image(self, file_name): preview_width, preview_height = style.zoom(300), style.zoom(225) pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_name) width, height = pixbuf.get_width(), pixbuf.get_height() scale = 1 if (width > preview_width) or (height > preview_height): scale_x = preview_width / float(width) scale_y = preview_height / float(height) scale = min(scale_x, scale_y) pixbuf2 = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), preview_width, preview_height) pixbuf2.fill(style.COLOR_WHITE.get_int()) margin_x = int((preview_width - (width * scale)) // 2) margin_y = int((preview_height - (height * scale)) // 2) pixbuf.scale(pixbuf2, margin_x, margin_y, preview_width - (margin_x * 2), preview_height - (margin_y * 2), margin_x, margin_y, scale, scale, GdkPixbuf.InterpType.BILINEAR) succes, preview_data = pixbuf2.save_to_bufferv('png', [], []) return dbus.ByteArray(preview_data) def _switch_view_mode(self, widget, use_timings): if widget.get_active(): self._notebook.set_current_page(1) self._slideview.stop() self._slideview.set_boxes(self.page.boxs) self._slideview.set_current_box(0) self._slideview.start(use_timings) # disable edition mode in the globes for box in self.page.boxs: box.set_globo_activo(None) self._key_press_signal_id = self.connect( 'key_press_event', self._slideview.key_press_cb) else: self._slideview.stop() self._notebook.set_current_page(0) if self._key_press_signal_id is not None: self.disconnect(self._key_press_signal_id) self.globes_manager.set_buttons_sensitive(not widget.get_active()) self._text_button.set_sensitive(not widget.get_active()) def __time_button_popup_cb(self, palette): self._time_spin.props.value = \ self.page.get_active_box().slideshow_duration def __time_spin_changed_cb(self, button): if self.page: self.page.get_active_box().slideshow_duration = \ self._time_spin.props.value
class RulerActivity(activity.Activity): def __init__(self, handle): super(RulerActivity, self).__init__(handle) self.button_dict = {} self.callback_dict = {} self._ready = False font = 'helvetica 12' font_bold = 'helvetica bold 12' # # We need a canvas # self._canvas = MyCanvas() self.set_canvas(self._canvas) self._canvas.show() screen = Gdk.Screen() width = screen.width() height = screen.height() - GRID_CELL_SIZE dpi, self.known_dpi = calc_dpi() self._canvas.set_dpi(dpi) # Create instances of our graphics self._r = show_rulers.ScreenOfRulers(font, font_bold, width, height) self._gcm = show_grids.ScreenGrid_cm(font, font_bold, width, height) self._gmm = show_grids.ScreenGrid_mm(font, font_bold, width, height) self._a90 = show_angles.Angles90(font, font_bold, width, height) self._a360 = show_angles.Angles360(font, font_bold, width, height) self._c = show_checkers.ScreenOfCircles(font, font_bold, width, height) # start with a ruler self._current = self._r self._canvas.add_a_ruler(self._current) # other settings self._grids_mode = "cm" self._angles_mode = "90" # # We need some toolbars # self.max_participants = 1 toolbar_box = ToolbarBox() # Buttons added to the Activity toolbar activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() self.rulers = radio_factory('ruler', toolbar_box.toolbar, self._rulers_cb, tooltip=_('Ruler'), group=None) self.grids = radio_factory('grid-a', toolbar_box.toolbar, self._grids_cb, tooltip=_('Grid'), group=self.rulers) self.angles = radio_factory('angles-90', toolbar_box.toolbar, self._angles_cb, tooltip=_('Angles'), group=self.rulers) self.checker = radio_factory('checker', toolbar_box.toolbar, self._checker_cb, tooltip=_('Checker'), group=self.rulers) self.wrapper = Gtk.ToolItem() self.wrapper2 = Gtk.ToolItem() self.wrapper3 = Gtk.ToolItem() self.custom_unit_entry = Gtk.Entry() self.txt1 = Gtk.Label() self.txt1.set_text(_('1 custom unit equals ')) self.txt2 = Gtk.Label() # TRANS: mm is for Milli Meters self.txt2.set_text(_(' mm.')) self.wrapper.add(self.txt1) self.wrapper2.add(self.custom_unit_entry) self.wrapper3.add(self.txt2) self.wrapper.show_all() self.wrapper2.show_all() self.wrapper3.show_all() separator = Gtk.SeparatorToolItem() separator.props.draw = True separator.set_expand(False) separator.show() toolbar_box.toolbar.insert(separator, -1) custom_units_toolbox = ToolbarBox() custom_units_toolbox.toolbar.insert(self.wrapper, -1) custom_units_toolbox.toolbar.insert(self.wrapper2, -1) custom_units_toolbox.toolbar.insert(self.wrapper3, -1) custom_units_toolbox.show() self.custom_units_button = ToolbarButton(icon_name='view-source', page=custom_units_toolbox) toolbar_box.toolbar.insert(self.custom_units_button, -1) self.custom_unit_entry.connect('changed', self.custom_unit_change_cb) self.custom_units_button.show() if not self.known_dpi: separator = Gtk.SeparatorToolItem() separator.show() toolbar_box.toolbar.insert(separator, -1) dpi = self._canvas.get_dpi() self._dpi_spin_adj = Gtk.Adjustment(dpi, 72, 200, 2, 32, 0) self._dpi_spin = Gtk.SpinButton(self._dpi_spin_adj, 0, 0) self._dpi_spin_id = self._dpi_spin.connect('value-changed', self._dpi_spin_cb) self._dpi_spin.set_numeric(True) self._dpi_spin.show() self.tool_item_dpi = Gtk.ToolItem() self.tool_item_dpi.add(self._dpi_spin) toolbar_box.toolbar.insert(self.tool_item_dpi, -1) self.tool_item_dpi.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) separator.show() toolbar_box.toolbar.insert(separator, -1) # The ever-present Stop Button stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self.show_all() # Restore state if previously saved self._ready = True if 'ruler' in self.metadata and \ self.metadata['ruler'] in self.button_dict: _logger.debug('restoring %s', self.metadata['ruler']) self.button_dict[self.metadata['ruler']].set_active(True) self.callback_dict[self.metadata['ruler']] else: self._rulers_cb() self.rulers.set_active(True) if 'custom_unit' in self.metadata: self.custom_unit_entry.set_text(self.metadata['custom_unit']) else: # set the default self.custom_unit_entry.set_text("25.4") # # Button callbacks # def _rulers_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(True) self._current = self._r self._canvas.add_a_ruler(self._current) _logger.debug('selecting ruler') self.metadata['ruler'] = 'ruler' return False def custom_unit_change_cb(self, widget): try: new = float(widget.get_text()) except ValueError: new = MMPERINCH new = abs(new) if new == 0: new = MMPERINCH if widget.get_text != '': widget.set_text(str(new)) self._canvas.add_a_ruler(self._r) self._r.custom_unit_in_mm = new self._r.draw_custom_ruler(self._r.custom_unit_in_mm) self.metadata['custom_unit'] = str(new) def _grids_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._grids_mode == "cm": self._current = self._gcm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-c") self._grids_mode = "mm" else: self._current = self._gmm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-a") self._grids_mode = "cm" self._canvas.add_a_ruler(self._current) _logger.debug('selecting grids') self.metadata['ruler'] = 'grids' return False def _angles_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._angles_mode == "90": self._current = self._a90 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-360") self._angles_mode = "360" else: self._current = self._a360 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-90") self._angles_mode = "90" self._canvas.add_a_ruler(self._current) _logger.debug('selecting angles') self.metadata['ruler'] = 'angles' return False def _checker_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) self._current = self._c self._canvas.add_a_ruler(self._current) _logger.debug('selecting checker') self.metadata['ruler'] = 'checker' return False def _dpi_spin_cb(self, button): self._canvas.set_dpi(self._dpi_spin.get_value_as_int()) self._canvas.add_a_ruler(self._current) return def write_file(self, file_path): ''' Write the dpi to the Journal ''' dpi = self._canvas.get_dpi() _logger.debug("Write dpi: " + str(dpi)) self.metadata['dpi'] = str(dpi)
class HistorietaActivity(activity.Activity): _EXPORT_FORMATS = [['image/png', _('Save as Image'), _('PNG'), ""]] def __init__(self, handle): activity.Activity.__init__(self, handle) self.set_title('FotoToon') self._max_participants = 1 self.page = None toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) activity_toolbar = activity_button.page toolbar_box.toolbar.insert(activity_button, 0) edit_toolbar_btn = ToolbarButton() edit_toolbar = Gtk.Toolbar() edit_toolbar_btn.props.page = edit_toolbar edit_toolbar_btn.props.icon_name = 'toolbar-edit' edit_toolbar_btn.label = _('Edit') toolbar_box.toolbar.insert(edit_toolbar_btn, -1) view_toolbar_btn = ToolbarButton() view_toolbar = Gtk.Toolbar() view_toolbar_btn.props.page = view_toolbar view_toolbar_btn.props.icon_name = 'toolbar-view' view_toolbar_btn.label = _('View') toolbar_box.toolbar.insert(view_toolbar_btn, -1) slideview_btn = ToggleToolButton('slideshow') slideview_btn.set_tooltip(_('Slideshow')) slideview_btn.set_active(False) slideview_btn.connect('clicked', self._switch_view_mode, False) view_toolbar.insert(slideview_btn, -1) slideview_btn.show() slideview_timings_btn = ToggleToolButton('slideshow-stopwatch') slideview_timings_btn.set_tooltip(_('Slideshow with Timings')) slideview_timings_btn.set_active(False) slideview_timings_btn.connect('clicked', self._switch_view_mode, True) view_toolbar.insert(slideview_timings_btn, -1) slideview_timings_btn.show() time_button = ToolButton('stopwatch') time_button.set_tooltip(_('Set Image Duration in Slideshow (Seconds)')) view_toolbar.insert(time_button, -1) time_button.show() self._time_spin = Gtk.SpinButton.new_with_range(MIN_TIME, MAX_TIME, 1) self._time_spin.connect('value-changed', self.__time_spin_changed_cb) self._time_spin.props.value = DEFAULT_TIME self._time_spin.props.update_policy = \ Gtk.SpinButtonUpdatePolicy.IF_VALID palette = time_button.get_palette() palette.connect('popup', self.__time_button_popup_cb) time_button.connect( 'clicked', lambda *args: palette.popup(immediate=True, state=Palette.SECONDARY)) alignment = Gtk.Alignment() alignment.set_padding(style.DEFAULT_PADDING, style.DEFAULT_PADDING, style.DEFAULT_PADDING, style.DEFAULT_PADDING) alignment.add(self._time_spin) self._time_spin.show() palette.set_content(alignment) alignment.show() fullscreen_btn = ToolButton('view-fullscreen') fullscreen_btn.set_tooltip(_('Fullscreen')) fullscreen_btn.props.accelerator = '<Alt>Return' fullscreen_btn.connect('clicked', lambda w: self.fullscreen()) view_toolbar.insert(fullscreen_btn, -1) fullscreen_btn.show() self.set_toolbar_box(toolbar_box) toolbar = toolbar_box.toolbar self.page = Page() self.globes_manager = GlobesManager(toolbar, edit_toolbar, self) # fonts self._text_button = ToolbarButton() self._text_button.props.page = TextToolbar(self.page) self._text_button.props.icon_name = 'format-text-size' self._text_button.props.label = _('Text') self._toolbar_box.toolbar.insert(self._text_button, -1) reorder_img_btn = ToolButton('thumbs-view') reorder_img_btn.set_icon_name('thumbs-view') reorder_img_btn.set_tooltip(_('Change image order')) reorder_img_btn.connect('clicked', self.__image_order_cb) edit_toolbar.insert(reorder_img_btn, -1) reorder_img_btn.show() bgchange = ToolButton(icon_name='contract-coordinates') bgchange.set_tooltip(_('Edit background image')) bgchange.connect('clicked', self.__bgchange_clicked_cb) edit_toolbar.insert(bgchange, -1) bgchange.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) stop = StopButton(self) toolbar_box.toolbar.insert(stop, -1) toolbar_box.show_all() # add export button separator_2 = Gtk.SeparatorToolItem() separator_2.show() activity_toolbar.insert(separator_2, -1) self.bt_save_as_image = ToolButton() self.bt_save_as_image.props.icon_name = 'save-as-image' self.bt_save_as_image.connect('clicked', self.write_image) self.bt_save_as_image.set_tooltip(_('Save as Image')) activity_toolbar.insert(self.bt_save_as_image, -1) self.bt_save_as_image.show() save_as_pdf = ToolButton() save_as_pdf.props.icon_name = 'save-as-pdf' save_as_pdf.connect('clicked', self._save_as_pdf) save_as_pdf.set_tooltip(_('Save as a Book (PDF)')) activity_toolbar.insert(save_as_pdf, -1) save_as_pdf.show() save_as_ogg = ToolButton() save_as_ogg.props.icon_name = 'save-as-ogg' save_as_ogg.connect('clicked', self.__save_as_ogg_cb) save_as_ogg.set_tooltip(_('Save as a Movie (OGG)')) activity_toolbar.insert(save_as_ogg, -1) save_as_ogg.show() activity_button.page.title.connect("focus-in-event", self.on_title) scrolled = Gtk.ScrolledWindow() # scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS) scrolled.add_with_viewport(self.page) scrolled.set_kinetic_scrolling(False) scrolled.show_all() self._slideview = SlideView(self) self._slideview.show_all() self._notebook = Gtk.Notebook() self._notebook.set_show_tabs(False) self._notebook.append_page(scrolled, None) self._notebook.append_page(self._slideview, None) self._notebook.show_all() if self._jobject.file_path is None or self._jobject.file_path == '': empty_widget = EmptyWidget() empty_widget.connect('choose-image', self.__add_image) self.set_canvas(empty_widget) else: self.set_canvas(self._notebook) self.show() self.metadata['mime_type'] = 'application/x-fototoon-activity' self.page.empty_page = handle.object_id is None self._key_press_signal_id = None def __add_image(self, button): self.set_canvas(self._notebook) self.globes_manager.add_image() def on_title(self, widget, event): # unselect the active globe when editting the title logging.debug('Editing the title') if self.page.get_active_box() is not None: box = self.page.get_active_box() self.page.set_active_box(None) box.glob_press = False box.set_globo_activo(None) box.redraw() logging.debug('After edit the title') def write_file(self, file_path): if len(self.page.boxs) == 1: return self._commit_all_changes() persistence = persistencia.Persistence() persistence.write(file_path, self.page) def _commit_all_changes(self): # be sure all the changes are commited active_globe = self.page.get_globo_activo() if active_globe is not None: active_globe.set_selected(False) def read_file(self, file_path): persistence = persistencia.Persistence() persistence.read(file_path, self.page) def _get_image_size(self): image_height, image_width = 0, 0 posi = 0 for box in self.page.boxs: if posi > 0: try: reng = int((posi + 1) / 2) column = (posi + 1) - (reng * 2) # logging.error("reng %d column %d" % (reng, column)) if column == 0: image_height = image_height + box.height except: pass else: image_width = box.width image_height = image_height + box.height # hide the cursor for globe in box.globos: globe.set_selected(False) posi = posi + 1 return image_width, image_height def write_image(self, button): self._commit_all_changes() # calculate image size image_width, image_height = self._get_image_size() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, image_width + 1, image_height + 1) ctx = cairo.Context(surface) ctx.set_source_rgb(1, 1, 1) ctx.rectangle(0, 0, image_width + 1, image_height + 1) ctx.fill() posi = 0 y_posi = 0 for box in self.page.boxs: if posi > 0: try: reng = int((posi + 1) / 2) column = (posi + 1) - (reng * 2) ctx.rectangle(column * box.width, y_posi, (column + 1) * box.width, y_posi + box.height) ctx.set_source_rgb(0, 0, 0) ctx.stroke() ctx.translate(column * box.width, y_posi) box.draw_in_context(ctx) ctx.translate(column * box.width * - 1, y_posi * - 1) if column == 1: y_posi = y_posi + box.height except: pass else: box.draw_in_context(ctx) y_posi = box.height posi = posi + 1 temp_file_name = os.path.join(self.get_activity_root(), 'instance', 'tmp-%i.png' % time.time()) surface.write_to_png(temp_file_name) self.dl_jobject = datastore.create() self.dl_jobject.metadata['progress'] = '0' self.dl_jobject.metadata['keep'] = '0' self.dl_jobject.metadata['buddies'] = '' self.dl_jobject.metadata['icon-color'] = \ profile.get_color().to_string() self.dl_jobject.metadata['mime_type'] = 'image/png' self.dl_jobject.metadata['title'] = \ self._jobject.metadata['title'] + " as image" self.dl_jobject.metadata['description'] = "" self.dl_jobject.metadata['progress'] = '100' self.dl_jobject.file_path = temp_file_name self.dl_jobject.metadata['preview'] = \ self._get_preview_image(temp_file_name) datastore.write(self.dl_jobject, transfer_ownership=True) self._object_id = self.dl_jobject.object_id self._show_journal_alert(_('Success'), _('A image was created in the Journal')) def __image_order_cb(self, button): reorderwin = ReorderView(self) reorderwin.show_all() def __bgchange_clicked_cb(self, button): editorwin = ImageEditorView(self.page.get_active_box()) editorwin.show_all() def _save_as_pdf(self, widget): self._commit_all_changes() file_name = os.path.join(self.get_activity_root(), 'instance', 'tmp-%i.pdf' % time.time()) file_obj = open(file_name, 'w') page_width = self.page.boxs[1].width page_height = self.page.boxs[1].height surface = cairo.PDFSurface(file_obj, page_width, page_height) context = cairo.Context(surface) for box in self.page.boxs[0:]: context.save() if box.width != page_width: # for the first box, scale and center scale = float(page_width) / float(box.width) top_margin = (page_height - box.height) / 2 context.translate(0, top_margin) context.scale(scale, scale) box.draw_in_context(context) context.show_page() context.restore() surface.finish() file_obj.close() jobject = datastore.create() jobject.metadata['icon-color'] = \ profile.get_color().to_string() jobject.metadata['mime_type'] = 'application/pdf' jobject.metadata['title'] = \ self.metadata['title'] + " as book" jobject.file_path = file_name # jobject.metadata['preview'] = \ # self._get_preview_image(file_name) datastore.write(jobject, transfer_ownership=True) self._object_id = jobject.object_id self._show_journal_alert(_('Success'), _('A PDF was created in the Journal')) def __save_as_ogg_cb(self, button): self._commit_all_changes() directory = tempfile.mkdtemp() output_path = os.path.join(directory, 'output.ogv') first_box = self.page.boxs[1] width = first_box.width height = first_box.height framerate = first_box.slideshow_duration if len(self.page.boxs) > 2: for box in self.page.boxs[1:]: framerate = gcd(framerate, box.slideshow_duration) framerate = int(framerate) i = 0 for box in self.page.boxs[1:]: surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) context = cairo.Context(surface) context.set_source_rgb(1.0, 1.0, 1.0) context.paint() box.draw_in_context(context) for __ in range(int(box.slideshow_duration / framerate)): path = os.path.join(directory, '{}.png'.format(i)) surface.write_to_png(path) i += 1 Gst.init(None) pipeline_string = VIDEO_PIPELINE.format( os.path.join(directory, '%d.png'), framerate, output_path) pipeline = Gst.parse_launch(pipeline_string) pipeline.set_state(Gst.State.PLAYING) pipeline.get_bus().timed_pop_filtered( Gst.CLOCK_TIME_NONE, Gst.MessageType.ERROR | Gst.MessageType.EOS) pipeline.set_state(Gst.State.NULL) jobject = datastore.create() jobject.metadata['icon-color'] = profile.get_color().to_string() jobject.metadata['mime_type'] = 'video/ogg' jobject.metadata['title'] = \ _('{} as a movie').format(self.metadata['title']) jobject.file_path = output_path datastore.write(jobject, transfer_ownership=True) self._object_id = jobject.object_id self._show_journal_alert(_('Success'), _('A movie was saved in the Journal')) shutil.rmtree(directory) def _show_journal_alert(self, title, msg): _stop_alert = Alert() _stop_alert.props.title = title _stop_alert.props.msg = msg _stop_alert.add_button(Gtk.ResponseType.APPLY, _('Show in Journal'), Icon(icon_name='zoom-activity')) _stop_alert.add_button(Gtk.ResponseType.OK, _('Ok'), Icon(icon_name='dialog-ok')) # Remove other alerts for alert in self._alerts: self.remove_alert(alert) self.add_alert(_stop_alert) _stop_alert.connect('response', self.__stop_response_cb) _stop_alert.show_all() def __stop_response_cb(self, alert, response_id): if response_id is Gtk.ResponseType.APPLY: activity.show_object_in_journal(self._object_id) self.remove_alert(alert) def _get_preview_image(self, file_name): preview_width, preview_height = style.zoom(300), style.zoom(225) pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_name) width, height = pixbuf.get_width(), pixbuf.get_height() scale = 1 if (width > preview_width) or (height > preview_height): scale_x = preview_width / float(width) scale_y = preview_height / float(height) scale = min(scale_x, scale_y) pixbuf2 = GdkPixbuf.Pixbuf.new( GdkPixbuf.Colorspace.RGB, pixbuf.get_has_alpha(), pixbuf.get_bits_per_sample(), preview_width, preview_height) pixbuf2.fill(style.COLOR_WHITE.get_int()) margin_x = int((preview_width - (width * scale)) / 2) margin_y = int((preview_height - (height * scale)) / 2) pixbuf.scale(pixbuf2, margin_x, margin_y, preview_width - (margin_x * 2), preview_height - (margin_y * 2), margin_x, margin_y, scale, scale, GdkPixbuf.InterpType.BILINEAR) succes, preview_data = pixbuf2.save_to_bufferv('png', [], []) return dbus.ByteArray(preview_data) def _switch_view_mode(self, widget, use_timings): if widget.get_active(): self._notebook.set_current_page(1) self._slideview.stop() self._slideview.set_boxes(self.page.boxs) self._slideview.set_current_box(0) self._slideview.start(use_timings) # disable edition mode in the globes for box in self.page.boxs: box.set_globo_activo(None) self._key_press_signal_id = self.connect( 'key_press_event', self._slideview.key_press_cb) else: self._slideview.stop() self._notebook.set_current_page(0) if self._key_press_signal_id is not None: self.disconnect(self._key_press_signal_id) self.globes_manager.set_buttons_sensitive(not widget.get_active()) self._text_button.set_sensitive(not widget.get_active()) def __time_button_popup_cb(self, palette): self._time_spin.props.value = \ self.page.get_active_box().slideshow_duration def __time_spin_changed_cb(self, button): if self.page: self.page.get_active_box().slideshow_duration = \ self._time_spin.props.value
class RulerActivity(activity.Activity): def __init__(self, handle): super(RulerActivity, self).__init__(handle) self.button_dict = {} self.callback_dict = {} self._ready = False font = 'helvetica 12' font_bold = 'helvetica bold 12' # # We need a canvas # self._canvas = MyCanvas() self.set_canvas(self._canvas) self._canvas.show() screen = GdkX11.X11Screen() width = screen.width() height = screen.height() - GRID_CELL_SIZE dpi, self.known_dpi = calc_dpi() self._canvas.set_dpi(dpi) # Create instances of our graphics self._r = show_rulers.ScreenOfRulers(font, font_bold, width, height) self._gcm = show_grids.ScreenGrid_cm(font, font_bold, width, height) self._gmm = show_grids.ScreenGrid_mm(font, font_bold, width, height) self._a90 = show_angles.Angles90(font, font_bold, width, height) self._a360 = show_angles.Angles360(font, font_bold, width, height) self._c = show_checkers.ScreenOfCircles(font, font_bold, width, height) # start with a ruler self._current = self._r self._canvas.add_a_ruler(self._current) # other settings self._grids_mode = "cm" self._angles_mode = "90" # # We need some toolbars # self.max_participants = 1 toolbar_box = ToolbarBox() # Buttons added to the Activity toolbar activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.show() self.rulers = radio_factory('ruler', toolbar_box.toolbar, self._rulers_cb, tooltip=_('Ruler'), group=None) self.grids = radio_factory('grid-a', toolbar_box.toolbar, self._grids_cb, tooltip=_('Grid'), group=self.rulers) self.angles = radio_factory('angles-90', toolbar_box.toolbar, self._angles_cb, tooltip=_('Angles'), group=self.rulers) self.checker = radio_factory('checker', toolbar_box.toolbar, self._checker_cb, tooltip=_('Checker'), group=self.rulers) self.wrapper = Gtk.ToolItem() self.wrapper2 = Gtk.ToolItem() self.wrapper3 = Gtk.ToolItem() self.custom_unit_entry = Gtk.Entry() self.txt1 = Gtk.Label() self.txt1.set_text(_('1 custom unit equals ')) self.txt2 = Gtk.Label() # TRANS: mm is for Milli Meters self.txt2.set_text(_(' mm.')) self.wrapper.add(self.txt1) self.wrapper2.add(self.custom_unit_entry) self.wrapper3.add(self.txt2) self.wrapper.show_all() self.wrapper2.show_all() self.wrapper3.show_all() separator = Gtk.SeparatorToolItem() separator.props.draw = True separator.set_expand(False) separator.show() toolbar_box.toolbar.insert(separator, -1) custom_units_toolbox = ToolbarBox() custom_units_toolbox.toolbar.insert(self.wrapper, -1) custom_units_toolbox.toolbar.insert(self.wrapper2, -1) custom_units_toolbox.toolbar.insert(self.wrapper3, -1) custom_units_toolbox.show() self.custom_units_button = ToolbarButton(icon_name='view-source', page=custom_units_toolbox) toolbar_box.toolbar.insert(self.custom_units_button, -1) self.custom_unit_entry.connect('changed', self.custom_unit_change_cb) self.custom_units_button.show() if not self.known_dpi: separator = Gtk.SeparatorToolItem() separator.show() toolbar_box.toolbar.insert(separator, -1) dpi = self._canvas.get_dpi() self._dpi_spin_adj = Gtk.Adjustment(dpi, 72, 200, 2, 32, 0) self._dpi_spin = Gtk.SpinButton(self._dpi_spin_adj, 0, 0) self._dpi_spin_id = self._dpi_spin.connect('value-changed', self._dpi_spin_cb) self._dpi_spin.set_numeric(True) self._dpi_spin.show() self.tool_item_dpi = Gtk.ToolItem() self.tool_item_dpi.add(self._dpi_spin) toolbar_box.toolbar.insert(self.tool_item_dpi, -1) self.tool_item_dpi.show() separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) separator.show() toolbar_box.toolbar.insert(separator, -1) # The ever-present Stop Button stop_button = StopButton(self) stop_button.props.accelerator = '<Ctrl>Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() self.show_all() # Restore state if previously saved self._ready = True if 'ruler' in self.metadata and \ self.metadata['ruler'] in self.button_dict: _logger.debug('restoring %s', self.metadata['ruler']) self.button_dict[self.metadata['ruler']].set_active(True) self.callback_dict[self.metadata['ruler']] else: self._rulers_cb() self.rulers.set_active(True) if 'custom_unit' in self.metadata: self.custom_unit_entry.set_text(str(self.metadata['custom_unit'])) else: # set the default self.custom_unit_entry.set_text("25.4") # # Button callbacks # def _rulers_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(True) self._current = self._r self._canvas.add_a_ruler(self._current) _logger.debug('selecting ruler') self.metadata['ruler'] = 'ruler' return False def custom_unit_change_cb(self, widget): try: new = float(widget.get_text()) except ValueError: new = MMPERINCH new = abs(new) if new == 0: new = MMPERINCH if widget.get_text != '': widget.set_text(str(new)) self._canvas.add_a_ruler(self._r) self._r.custom_unit_in_mm = new self._r.draw_custom_ruler(self._r.custom_unit_in_mm) self.metadata['custom_unit'] = new def _grids_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._grids_mode == "cm": self._current = self._gcm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-c") self._grids_mode = "mm" else: self._current = self._gmm if hasattr(self, 'grids'): self.grids.set_icon_name("grid-a") self._grids_mode = "cm" self._canvas.add_a_ruler(self._current) _logger.debug('selecting grids') self.metadata['ruler'] = 'grids' return False def _angles_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) if self._angles_mode == "90": self._current = self._a90 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-360") self._angles_mode = "360" else: self._current = self._a360 if hasattr(self, 'angles'): self.angles.set_icon_name("angles-90") self._angles_mode = "90" self._canvas.add_a_ruler(self._current) _logger.debug('selecting angles') self.metadata['ruler'] = 'angles' return False def _checker_cb(self, button=None): if self._ready: self.custom_units_button.set_sensitive(False) self.custom_units_button.set_expanded(False) self._current = self._c self._canvas.add_a_ruler(self._current) _logger.debug('selecting checker') self.metadata['ruler'] = 'checker' return False def _dpi_spin_cb(self, button): self._canvas.set_dpi(self._dpi_spin.get_value_as_int()) self._canvas.add_a_ruler(self._current) return def write_file(self, file_path): ''' Write the dpi to the Journal ''' dpi = self._canvas.get_dpi() _logger.debug("Write dpi: " + str(dpi)) self.metadata['dpi'] = str(dpi)