Exemplo n.º 1
0
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
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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)