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 hide_thumb(self): xo_buddy = os.path.join(os.path.dirname(__file__), "icons/link.svg") bg_surface = self._read_link_background(xo_buddy) bg_width, bg_height = style.zoom(120), style.zoom(110) pixbuf = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0, bg_width, bg_height) self._img.set_from_pixbuf(pixbuf)
def _get_preview_data(screenshot_surface): screenshot_width = screenshot_surface.get_width() screenshot_height = screenshot_surface.get_height() preview_width, preview_height = style.zoom(300), style.zoom(225) preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, preview_width, preview_height) cr = cairo.Context(preview_surface) scale_w = preview_width * 1.0 / screenshot_width scale_h = preview_height * 1.0 / screenshot_height scale = min(scale_w, scale_h) translate_x = int((preview_width - (screenshot_width * scale)) / 2) translate_y = int((preview_height - (screenshot_height * scale)) / 2) cr.translate(translate_x, translate_y) cr.scale(scale, scale) cr.set_source_rgba(1, 1, 1, 0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() cr.set_source_surface(screenshot_surface) cr.paint() preview_str = StringIO.StringIO() preview_surface.write_to_png(preview_str) return dbus.ByteArray(preview_str.getvalue())
def set_empty_image(self, page, fill='#0000ff', stroke='#4d4c4f'): img = Gtk.Image() bg_width, bg_height = style.zoom(120), style.zoom(110) bg_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, bg_width, bg_height) context = cairo.Context(bg_surface) # draw a rectangle in the background with the selected colors context.set_line_width(style.zoom(10)) context.set_source_rgba(*style.Color(fill).get_rgba()) context.rectangle(0, 0, bg_width, bg_height) context.fill_preserve() context.set_source_rgba(*style.Color(stroke).get_rgba()) context.stroke() # add the page number context.set_font_size(style.zoom(60)) text = str(page) x, y = bg_width / 2, bg_height / 2 xbearing, ybearing, width, height, xadvance, yadvance = \ context.text_extents(text) context.move_to(x - width / 2, y + height / 2) context.show_text(text) context.stroke() pixbuf_bg = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0, bg_width, bg_height) img.set_from_pixbuf(pixbuf_bg) self.set_icon_widget(img) img.show()
def get_preview(self): """Returns an image representing the state of the activity. Generally this is what the user is seeing in this moment. Activities can override this method, which should return a str with the binary content of a png image with a width of 300 and a height of 225 pixels. The method does create a cairo surface similar to that of the canvas' window and draws on that. Then we create a cairo image surface with the desired preview size and scale the canvas surface on that. """ if self.canvas is None or not hasattr(self.canvas, 'get_window'): return None window = self.canvas.get_window() alloc = self.canvas.get_allocation() dummy_cr = Gdk.cairo_create(window) target = dummy_cr.get_target() canvas_width, canvas_height = alloc.width, alloc.height screenshot_surface = target.create_similar(cairo.CONTENT_COLOR, canvas_width, canvas_height) del dummy_cr, target cr = cairo.Context(screenshot_surface) r, g, b, a_ = style.COLOR_PANEL_GREY.get_rgba() cr.set_source_rgb(r, g, b) cr.paint() self.canvas.draw(cr) del cr preview_width, preview_height = style.zoom(300), style.zoom(225) preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, preview_width, preview_height) cr = cairo.Context(preview_surface) scale_w = preview_width * 1.0 / canvas_width scale_h = preview_height * 1.0 / canvas_height scale = min(scale_w, scale_h) translate_x = int((preview_width - (canvas_width * scale)) / 2) translate_y = int((preview_height - (canvas_height * scale)) / 2) cr.translate(translate_x, translate_y) cr.scale(scale, scale) cr.set_source_rgba(1, 1, 1, 0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() cr.set_source_surface(screenshot_surface) cr.paint() preview_str = StringIO.StringIO() preview_surface.write_to_png(preview_str) return preview_str.getvalue()
def __expose_cb(self, widget, cr): rect = self.get_allocation() hmargin = style.zoom(15) x = hmargin y = 0 width = rect.width - _BORDER_DEFAULT * 2. - hmargin * 2 if self.tail is not None: height = rect.height - _BORDER_DEFAULT * 2. - self._radius else: height = rect.height - _BORDER_DEFAULT * 2. cr.move_to(x + self._radius, y) cr.arc(x + width - self._radius, y + self._radius, self._radius, math.pi * 1.5, math.pi * 2) tail_height = style.zoom(5) if self.tail == 'right': cr.arc(x + width - self._radius, y + height - self._radius * 2, self._radius, 0, math.pi * 0.5) cr.line_to(x + width - self._radius, y + height) cr.line_to(x + width - tail_height * self._radius, y + height - self._radius) cr.arc(x + self._radius, y + height - self._radius * 2, self._radius, math.pi * 0.5, math.pi) elif self.tail == 'left': cr.arc(x + width - self._radius, y + height - self._radius * 2, self._radius, 0, math.pi * 0.5) cr.line_to(x + self._radius * tail_height, y + height - self._radius) cr.line_to(x + self._radius, y + height) cr.line_to(x + self._radius, y + height - self._radius) cr.arc(x + self._radius, y + height - self._radius * 2, self._radius, math.pi * 0.5, math.pi) else: cr.arc(x + width - self._radius, y + height - self._radius, self._radius, 0, math.pi * 0.5) cr.arc(x + self._radius, y + height - self._radius, self._radius, math.pi * 0.5, math.pi) cr.arc(x + self._radius, y + self._radius, self._radius, math.pi, math.pi * 1.5) cr.close_path() if self.background_color is not None: r, g, b, __ = self.background_color.get_rgba() cr.set_source_rgb(r, g, b) cr.fill_preserve() if self.border_color is not None: r, g, b, __ = self.border_color.get_rgba() cr.set_source_rgb(r, g, b) cr.set_line_width(_BORDER_DEFAULT) cr.stroke() return False
def create_preview_metadata(self, filename): file_mimetype = mime.get_for_file(filename) if not file_mimetype.startswith('image/'): return '' scaled_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, style.zoom(320), style.zoom(240)) preview_data = [] succes, preview_data = scaled_pixbuf.save_to_bufferv('png', [], []) preview_data = ''.join(preview_data) return preview_data
def get_preview(self): if not hasattr(self.abiword_canvas, 'render_page_to_image'): return activity.Activity.get_preview(self) pixbuf = self.abiword_canvas.render_page_to_image(1) pixbuf = pixbuf.scale_simple(style.zoom(300), style.zoom(225), GdkPixbuf.InterpType.BILINEAR) preview_data = [] def save_func(buf, data): data.append(buf) ##pixbuf.save_to_callback(save_func, 'png', user_data=preview_data) preview_data = ''.join(preview_data) return preview_data
def __init__(self, start_on_age_page): Gtk.VBox.__init__(self) self.set_border_width(style.zoom(30)) self._page = self.PAGE_NAME self._name_page = _NamePage(self) self._color_page = _ColorPage() self._gender_page = _GenderPage() self._age_page = _AgePage(None) self._current_page = None self._next_button = None settings = Gio.Settings('org.sugarlabs.user') default_nick = settings.get_string('default-nick') if default_nick != 'disabled': self._page = self.PAGE_COLOR if default_nick == 'system': pwd_entry = pwd.getpwuid(os.getuid()) default_nick = (pwd_entry.pw_gecos.split(',')[0] or pwd_entry.pw_name) self._name_page.set_name(default_nick) # XXX should also consider whether or not there is a nick nick = settings.get_string('nick') if start_on_age_page and nick: self._page = self.PAGE_AGE self._setup_page()
def __init__(self, primary_text): Palette.__init__(self, primary_text) self._level = 0 self._time = 0 self._status = _STATUS_NOT_PRESENT self._warning_capacity = _settings_get('warning-capacity') self._progress_widget = PaletteMenuBox() self.set_content(self._progress_widget) self._progress_widget.show() inner_box = Gtk.VBox() inner_box.set_spacing(style.DEFAULT_PADDING) self._progress_widget.append_item(inner_box, vertical_padding=0) inner_box.show() self._progress_bar = Gtk.ProgressBar() self._progress_bar.set_size_request( style.zoom(style.GRID_CELL_SIZE * 4), -1) inner_box.pack_start(self._progress_bar, True, True, 0) self._progress_bar.show() self._status_label = Gtk.Label() inner_box.pack_start(self._status_label, True, True, 0) self._status_label.show()
def __init__(self, handle): "The entry point to the Activity" global page activity.Activity.__init__(self, handle) toolbox = widgets.ActivityToolbar(self) toolbox.share.props.visible = False stop_button = StopButton(self) stop_button.show() toolbox.insert(stop_button, -1) self.set_toolbar_box(toolbox) toolbox.show() self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.textview = Gtk.TextView() self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_left_margin(50) self.textview.connect("key_press_event", self.keypress_cb) self.scrolled_window.add(self.textview) self.set_canvas(self.scrolled_window) self.textview.show() self.scrolled_window.show() page = 0 self.textview.grab_focus() self.font_desc = Pango.FontDescription("sans %d" % style.zoom(10)) self.textview.modify_font(self.font_desc)
def update_preview_cb(self, file_chooser, preview): filename = file_chooser.get_preview_filename() try: file_mimetype = mime.get_for_file(filename) if file_mimetype == 'application/x-cbz' or file_mimetype == 'application/zip': fname = self.extract_image(filename) pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(fname, style.zoom(320), style.zoom(240)) preview.set_from_pixbuf(pixbuf) have_preview = True os.remove(fname) else: have_preview = False except: have_preview = False file_chooser.set_preview_widget_active(have_preview) return
def set_image(self, buf, fill='#0000ff', stroke='#4d4c4f'): img = Gtk.Image() str_buf = StringIO.StringIO(buf) thumb_surface = cairo.ImageSurface.create_from_png(str_buf) bg_width, bg_height = style.zoom(120), style.zoom(110) bg_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, bg_width, bg_height) context = cairo.Context(bg_surface) # draw a rectangle in the background with the selected colors context.set_line_width(style.zoom(10)) context.set_source_rgba(*style.Color(fill).get_rgba()) context.rectangle(0, 0, bg_width, bg_height) context.fill_preserve() context.set_source_rgba(*style.Color(stroke).get_rgba()) context.stroke() # add the screenshot dest_x = style.zoom(10) dest_y = style.zoom(20) context.set_source_surface(thumb_surface, dest_x, dest_y) thumb_width, thumb_height = style.zoom(100), style.zoom(80) context.rectangle(dest_x, dest_y, thumb_width, thumb_height) context.fill() pixbuf_bg = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0, bg_width, bg_height) img.set_from_pixbuf(pixbuf_bg) self.set_icon_widget(img) img.show()
def __init__(self): self._palette_invoker = ToolInvoker() Gtk.ToolItem.__init__(self) self._font_label = FontLabel() bt = Gtk.Button('') bt.set_can_focus(False) bt.remove(bt.get_children()[0]) box = Gtk.HBox() bt.add(box) icon = Icon(icon_name='font-text') box.pack_start(icon, False, False, 10) box.pack_start(self._font_label, False, False, 10) self.add(bt) self.show_all() self._font_name = 'Sans' # theme the button, can be removed if add the style to the sugar css if style.zoom(100) == 100: subcell_size = 15 else: subcell_size = 11 radius = 2 * subcell_size theme = "GtkButton {border-radius: %dpx;}" % radius css_provider = Gtk.CssProvider() css_provider.load_from_data(theme) style_context = bt.get_style_context() style_context.add_provider(css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) # init palette self._hide_tooltip_on_click = True self._palette_invoker.attach_tool(self) self._palette_invoker.props.toggle_palette = True self.palette = Palette(_('Select font')) self.palette.set_invoker(self._palette_invoker) # load the fonts in the palette menu self._menu_box = PaletteMenuBox() self.props.palette.set_content(self._menu_box) self._menu_box.show() context = self.get_pango_context() self._init_font_list() tmp_list = [] for family in context.list_families(): name = family.get_name() if name in self._font_white_list: tmp_list.append(name) for name in sorted(tmp_list): self._add_menu(name, self.__font_selected_cb) self._font_label.set_font(self._font_name)
def __init__(self, **kwargs): Gtk.HBox.__init__(self, **kwargs) self._radius = style.zoom(10) self.border = self._BORDER_DEFAULT self.border_color = style.COLOR_BLACK self.background_color = None self.connect("draw", self.__draw_cb) self.connect("size-allocate", self.__size_allocate_cb) self.connect("add", self.__add_cb)
def __init__(self, **kwargs): Gtk.HBox.__init__(self, **kwargs) self._radius = style.zoom(15) self.border_color = style.COLOR_BLACK self.tail = None self.background_color = None self.set_resize_mode(Gtk.ResizeMode.PARENT) self.set_reallocate_redraws(True) self.connect('draw', self.__expose_cb) self.connect('add', self.__add_cb)
def font_zoom(size): """ 21 Returns the proper font size for current Sugar environment NOTE: Use this function only if you are targeting activity for XO with 0.82 Sugar and want non-default font sizes, otherwise just do not mention font sizes in your code """ if hasattr(style, '_XO_DPI'): return style.zoom(size) else: return size
def get_preview(self): if not hasattr(self.abiword_canvas, 'render_page_to_image'): return activity.Activity.get_preview(self) from gi.repository import GdkPixbuf pixbuf = self.abiword_canvas.render_page_to_image(1) pixbuf = pixbuf.scale_simple(style.zoom(300), style.zoom(225), GdkPixbuf.InterpType.BILINEAR) preview_data = [] def save_func(buf, lenght, data): data.append(buf) return True pixbuf.save_to_callbackv(save_func, preview_data, 'png', [], []) preview_data = ''.join(preview_data) return preview_data
def _get_screenshot(self): browser = self._tabbed_view.props.current_browser window = browser.get_window() width, height = window.get_width(), window.get_height() thumb_width, thumb_height = style.zoom(100), style.zoom(80) thumb_surface = Gdk.Window.create_similar_surface( window, cairo.CONTENT_COLOR, thumb_width, thumb_height) cairo_context = cairo.Context(thumb_surface) thumb_scale_w = thumb_width * 1.0 / width thumb_scale_h = thumb_height * 1.0 / height cairo_context.scale(thumb_scale_w, thumb_scale_h) Gdk.cairo_set_source_window(cairo_context, window, 0, 0) cairo_context.paint() thumb_str = StringIO.StringIO() thumb_surface.write_to_png(thumb_str) return thumb_str.getvalue()
def _read_link_background(self, filename): icon_file = open(filename, 'r') data = icon_file.read() icon_file.close() entity = '<!ENTITY fill_color "%s">' % self._fill data = re.sub('<!ENTITY fill_color .*>', entity, data) entity = '<!ENTITY stroke_color "%s">' % self._stroke data = re.sub('<!ENTITY stroke_color .*>', entity, data) link_width, link_height = style.zoom(120), style.zoom(110) link_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, link_width, link_height) link_context = cairo.Context(link_surface) link_scale_w = link_width * 1.0 / 120 link_scale_h = link_height * 1.0 / 110 link_context.scale(link_scale_w, link_scale_h) handler = Rsvg.Handle.new_from_data(data) handler.render_cairo(link_context) return link_surface
def set_image(self, buf): self._img = Gtk.Image() str_buf = StringIO.StringIO(buf) thumb_surface = cairo.ImageSurface.create_from_png(str_buf) xo_buddy = os.path.join(os.path.dirname(__file__), "icons/link.svg") bg_surface = self._read_link_background(xo_buddy) cairo_context = cairo.Context(bg_surface) cairo_context.set_source_surface(thumb_surface, self._dest_x, self._dest_y) thumb_width, thumb_height = style.zoom(100), style.zoom(80) cairo_context.rectangle(self._dest_x, self._dest_y, thumb_width, thumb_height) cairo_context.fill() bg_width, bg_height = style.zoom(120), style.zoom(110) self._pixbuf_bg = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0, bg_width, bg_height) self._img.set_from_pixbuf(self._pixbuf_bg) self.set_icon_widget(self._img) self._img.show()
def __init__(self, default, options): self._palette_invoker = ToolInvoker() Gtk.ToolItem.__init__(self) self._label = Gtk.Label() bt = Gtk.Button('') bt.set_can_focus(False) bt.remove(bt.get_children()[0]) self._box = Gtk.HBox() bt.add(self._box) self._icon = Icon(icon_name='') self._box.pack_start(self._icon, False, False, 5) self._box.pack_end(self._label, False, False, 5) self.add(bt) self.show_all() # theme the button, can be removed if add the style to the sugar css if style.zoom(100) == 100: subcell_size = 15 else: subcell_size = 11 radius = 2 * subcell_size theme = "GtkButton {border-radius: %dpx;}" % radius css_provider = Gtk.CssProvider() css_provider.load_from_data(theme) style_context = bt.get_style_context() style_context.add_provider(css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) # init palette self._hide_tooltip_on_click = True self._palette_invoker.attach_tool(self) self._palette_invoker.props.toggle_palette = True self.palette = Palette(_('Select option')) self.palette.set_invoker(self._palette_invoker) # load the fonts in the palette menu self._menu_box = PaletteMenuBox() self.props.palette.set_content(self._menu_box) self._menu_box.show() for option in options: if option.__class__ is str: self._add_menu(option, activate_cb=self.__option_selected_cb) else: self._add_menu(option[0], icon=option[1], activate_cb=self.__option_selected_cb) self.set_value(default)
def __init__(self, **kwargs): GObject.GObject.__init__(self, **kwargs) self._radius = style.zoom(20) self.border_color = style.Color("#0000FF") self.background_color = style.Color("#FFFF00") self.modify_bg(0, self.background_color.get_gdk_color()) self.set_resize_mode(Gtk.ResizeMode.PARENT) self.connect("draw", self.__draw_cb) self.connect("add", self.__add_cb) close_icon = Icon(icon_name = 'entry-stop') close_icon.props.pixel_size = style.zoom(20) drag_icon = Icon(icon_name = 'hand1') drag_icon.props.pixel_size = style.zoom(20) self.drag_button = Gtk.Button() #self.drag_button.set_icon_widget(drag_icon) self.drag_button.set_image(drag_icon) drag_icon.show() self.drag_button.add_events(Gdk.EventMask.POINTER_MOTION_HINT_MASK | \ Gdk.EventMask.POINTER_MOTION_MASK) self.drag_button.connect("motion_notify_event", self.__motion_notify_cb) self.drag_button.connect("enter_notify_event", self.__enter_notify_cb) self.drag_button.connect("button-press-event", self._button_pressed) self.drag_button.connect("button-release-event", self._button_released) self.close_button = ToolButton(icon_name='entry-stop') self.close_button.set_icon_widget(close_icon) close_icon.show() self.close_button.connect("clicked", self._close_box) self.pack_end(self.close_button, False, False, 0) self.pack_start(self.drag_button, False, False, style.zoom(20))
def _area_draw_cb(self, widget, context): if self._current_box is None: return box = self._boxes[self._current_box] self._area.set_size_request(box.width + 1, box.height + 1) context.move_to(box.width - style.zoom(40), box.height + style.zoom(25)) context.set_font_size(style.zoom(20)) context.show_text('%s/%s' % (self._current_box + 1, str(len(self._boxes)))) if self._current_box == len(self._boxes) - 1: self._next_icon.set_fill_color(style.COLOR_BUTTON_GREY.get_html()) else: self._next_icon.set_fill_color(None) if self._current_box == 0: self._prev_icon.set_fill_color(style.COLOR_BUTTON_GREY.get_html()) else: self._prev_icon.set_fill_color(None) box.draw_in_context(context)
def __init__(self, icon_name, stroke_color=globals.USER_COLOR[0], fill_color=globals.USER_COLOR[1], bg_color=globals.ACTIVITY_BG, pixel_size=82.5): super(ImageButton, self).__init__() self.icon = Icon(icon_name=icon_name, pixel_size=style.zoom(pixel_size), stroke_color=style.Color(stroke_color) .get_svg(), fill_color=style.Color(fill_color).get_svg()) self.set_image(self.icon) self.props.relief = Gtk.ReliefStyle.NONE self.modify_bg(Gtk.StateType.NORMAL, style.Color(bg_color).get_gdk_color())
def __init__(self, intro): _Page.__init__(self) self._intro = intro alignment = Gtk.Alignment.new(0.5, 0.5, 0, 0) self.pack_start(alignment, expand=True, fill=True, padding=0) hbox = Gtk.HBox(spacing=style.DEFAULT_SPACING) alignment.add(hbox) label = Gtk.Label(label=_('Name:')) hbox.pack_start(label, False, True, 0) self._entry = Gtk.Entry() self._entry.connect('notify::text', self._text_changed_cb) self._entry.set_size_request(style.zoom(300), -1) self._entry.set_max_length(45) hbox.pack_start(self._entry, False, True, 0)
def __init__(self, model): list_model = UpdateListModel(model) Gtk.TreeView.__init__(self, list_model) self.set_reorderable(False) self.set_enable_search(False) self.set_headers_visible(False) toggle_renderer = Gtk.CellRendererToggle() toggle_renderer.props.activatable = True toggle_renderer.props.xpad = style.DEFAULT_PADDING toggle_renderer.props.indicator_size = style.zoom(26) toggle_renderer.connect('toggled', self.__toggled_cb) toggle_column = Gtk.TreeViewColumn() toggle_column.pack_start(toggle_renderer, True) toggle_column.add_attribute(toggle_renderer, 'active', UpdateListModel.SELECTED) self.append_column(toggle_column) icon_renderer = CellRendererIcon(self) icon_renderer.props.width = style.STANDARD_ICON_SIZE icon_renderer.props.height = style.STANDARD_ICON_SIZE icon_renderer.props.size = style.STANDARD_ICON_SIZE icon_renderer.props.xpad = style.DEFAULT_PADDING icon_renderer.props.ypad = style.DEFAULT_PADDING icon_renderer.props.stroke_color = style.COLOR_TOOLBAR_GREY.get_svg() icon_renderer.props.fill_color = style.COLOR_TRANSPARENT.get_svg() icon_column = Gtk.TreeViewColumn() icon_column.pack_start(icon_renderer, True) icon_column.add_attribute(icon_renderer, 'file-name', UpdateListModel.ICON_FILE_NAME) self.append_column(icon_column) text_renderer = Gtk.CellRendererText() description_column = Gtk.TreeViewColumn() description_column.pack_start(text_renderer, True) description_column.add_attribute(text_renderer, 'markup', UpdateListModel.DESCRIPTION) self.append_column(description_column)
def __init__(self): Gtk.VBox.__init__(self) self.set_border_width(style.zoom(30)) self._page = self.PAGE_NAME self._name_page = _NamePage(self) self._color_page = _ColorPage() self._current_page = None self._next_button = None settings = Gio.Settings('org.sugarlabs.user') default_nick = settings.get_string('default-nick') if default_nick != 'disabled': self._page = self.PAGE_COLOR if default_nick == 'system': pwd_entry = pwd.getpwuid(os.getuid()) default_nick = (pwd_entry.pw_gecos.split(',')[0] or pwd_entry.pw_name) self._name_page.set_name(default_nick) self._setup_page()
def __init__(self): Gtk.VBox.__init__(self) self.set_border_width(style.zoom(30)) self._page = self.PAGE_NAME self._name_page = _NamePage(self) self._color_page = _ColorPage() self._current_page = None self._next_button = None client = GConf.Client.get_default() default_nick = client.get_string('/desktop/sugar/user/default_nick') if default_nick != 'disabled': self._page = self.PAGE_COLOR if default_nick == 'system': pwd_entry = pwd.getpwuid(os.getuid()) default_nick = (pwd_entry.pw_gecos.split(',')[0] or pwd_entry.pw_name) self._name_page.set_name(default_nick) self._setup_page()
def __init__(self, packages): list_model = PackageListModel(packages) Gtk.TreeView.__init__(self, list_model) self.set_reorderable(False) self.set_enable_search(False) self.set_headers_visible(False) # select select_renderer = Gtk.CellRendererToggle() select_renderer.props.activatable = True select_renderer.props.xpad = style.DEFAULT_PADDING select_renderer.props.indicator_size = style.zoom(26) select_renderer.connect('toggled', self.__toggled_cb) select_column = Gtk.TreeViewColumn() select_column.pack_start(select_renderer, True) select_column.add_attribute(select_renderer, 'active', PackageListModel.SELECTED) self.append_column(select_column) # package package_renderer = Gtk.CellRendererText() package_column = Gtk.TreeViewColumn() package_column.pack_start(package_renderer, True) package_column.add_attribute(package_renderer, 'markup', PackageListModel.PACKAGE) self.append_column(package_column) # version version_renderer = Gtk.CellRendererText() version_column = Gtk.TreeViewColumn() version_column.pack_start(version_renderer, True) version_column.add_attribute(version_renderer, 'markup', PackageListModel.VERSION) self.append_column(version_column)
def _add_columns(self): if self._enable_multi_operations: cell_select = Gtk.CellRendererToggle() cell_select.connect('toggled', self.__cell_select_toggled_cb) cell_select.props.activatable = True cell_select.props.xpad = style.DEFAULT_PADDING cell_select.props.indicator_size = style.zoom(26) column = Gtk.TreeViewColumn() column.props.sizing = Gtk.TreeViewColumnSizing.FIXED column.props.fixed_width = style.GRID_CELL_SIZE column.pack_start(cell_select, True) column.set_cell_data_func(cell_select, self.__select_set_data_cb) self.tree_view.append_column(column) cell_favorite = CellRendererFavorite() cell_favorite.connect('clicked', self._favorite_clicked_cb) cell_favorite.connect_to_scroller(self._scrolling_detector) self._fav_column = Gtk.TreeViewColumn() self._fav_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED self._fav_column.props.fixed_width = cell_favorite.props.width self._fav_column.pack_start(cell_favorite, True) self._fav_column.set_cell_data_func(cell_favorite, self.__favorite_set_data_cb) self.tree_view.append_column(self._fav_column) self.cell_icon = CellRendererActivityIcon() self.cell_icon.connect_to_scroller(self._scrolling_detector) column = Gtk.TreeViewColumn() self.tree_view.icon_activity_column = column column.props.sizing = Gtk.TreeViewColumnSizing.FIXED column.props.fixed_width = self.cell_icon.props.width column.pack_start(self.cell_icon, True) column.add_attribute(self.cell_icon, 'file-name', ListModel.COLUMN_ICON) column.add_attribute(self.cell_icon, 'xo-color', ListModel.COLUMN_ICON_COLOR) self.tree_view.append_column(column) self.icon_activity_column = column self.cell_title = Gtk.CellRendererText() self.cell_title.props.ellipsize = style.ELLIPSIZE_MODE_DEFAULT self.cell_title.props.ellipsize_set = True self._title_column = Gtk.TreeViewColumn() self._title_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED self._title_column.props.expand = True self._title_column.props.clickable = True self._title_column.pack_start(self.cell_title, True) self._title_column.add_attribute(self.cell_title, 'markup', ListModel.COLUMN_TITLE) self.tree_view.append_column(self._title_column) for column_index in [ ListModel.COLUMN_BUDDY_1, ListModel.COLUMN_BUDDY_2, ListModel.COLUMN_BUDDY_3 ]: buddies_column = Gtk.TreeViewColumn() buddies_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED self.tree_view.append_column(buddies_column) cell_icon = CellRendererBuddy(column_index=column_index) buddies_column.pack_start(cell_icon, True) buddies_column.props.fixed_width += cell_icon.props.width buddies_column.add_attribute(cell_icon, 'buddy', column_index) buddies_column.set_cell_data_func(cell_icon, self.__buddies_set_data_cb) self.tree_view.buddies_columns.append(buddies_column) cell_progress = Gtk.CellRendererProgress() cell_progress.props.ypad = style.GRID_CELL_SIZE / 4 buddies_column.pack_start(cell_progress, True) buddies_column.add_attribute(cell_progress, 'value', ListModel.COLUMN_PROGRESS) buddies_column.set_cell_data_func(cell_progress, self.__progress_data_cb) cell_text = Gtk.CellRendererText() cell_text.props.xalign = 1 # Measure the required width for a date in the form of "10 hours, 10 # minutes ago" timestamp = time.time() - 10 * 60 - 10 * 60 * 60 date = util.timestamp_to_elapsed_string(timestamp) date_width = self._get_width_for_string(date) self.sort_column = Gtk.TreeViewColumn() self.sort_column.props.sizing = Gtk.TreeViewColumnSizing.FIXED self.sort_column.props.fixed_width = date_width self.sort_column.set_alignment(1) self.sort_column.props.resizable = True self.sort_column.props.clickable = True self.sort_column.pack_start(cell_text, True) self.sort_column.add_attribute(cell_text, 'text', ListModel.COLUMN_TIMESTAMP) self.tree_view.append_column(self.sort_column)
from gi.repository import Soup from gi.repository import Gio from sugar3.activity.activity import get_bundle_path, get_activity_root from sugar3.graphics import style from sugar3.graphics.icon import Icon from sugar3.graphics.alert import Alert, ConfirmationAlert from widgets import BrowserNotebook from palettes import ContentInvoker from filepicker import FilePicker import globalhistory from pdfviewer import PDFTabPage # Sugar is relative to 100x (XO), the web is relative to 72x (desktop) scale ZOOM_ORIGINAL = style.zoom(100 * 100 / 72) / 100.0 _ZOOM_AMOUNT = 0.1 LIBRARY_PATH = '/usr/share/library-common/index.html' _WEB_SCHEMES = [ 'http', 'https', 'ftp', 'file', 'javascript', 'data', 'about', 'gopher', 'mailto' ] _NON_SEARCH_REGEX = re.compile( ''' (^localhost(\\.[^\s]+)?(:\\d+)?(/.*)?$| ^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]$| ^::[0-9a-f:]*$| # IPv6 literals ^[0-9a-f:]+:[0-9a-f:]*$| # IPv6 literals ^[^\\.\s]+\\.[^\\.\s]+.*$| # foo.bar...
import cairo from gi.repository import GLib from gi.repository import Gdk from gi.repository import GdkPixbuf from gi.repository import Gtk from gi.repository import Pango from gi.repository import PangoCairo from sugar3.util import LRU from sugar3.graphics import style import face import model BORDER_WIDTH = style.zoom(10) class Card(Gtk.EventBox): # Default properties default_props = {} default_props['back'] = { 'fill_color': style.Color('#666666'), 'stroke_color': style.Color('#666666') } default_props['back_text'] = {'text_color': style.Color('#c7c8cc')} default_props['front'] = { 'fill_color': style.Color('#4b4d4a'), 'stroke_color': style.Color('#111111') }
def show_image(self, filename): "display a resized image in a preview" scaled_buf = GdkPixbuf.Pixbuf.new_from_file_at_size( filename, style.zoom(300), style.zoom(225)) self.image.set_from_pixbuf(scaled_buf) self.image.show()
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 DEF_SPACING = 6 DEF_WIDTH = 4 SCREEN_HEIGHT = Gdk.Screen.height() # HACK: This is to calculate the scrollbar width # defined in sugar-artwork gtk-widgets.css.em if style.zoom(1): scrollbar_width = 15 else: scrollbar_width = 11 SCREEN_WIDTH = Gdk.Screen.width() - scrollbar_width - 5 BOX_HEIGHT = 450 THUMB_SIZE = activity.PREVIEW_SIZE class Page(Gtk.VBox): def __init__(self): Gtk.VBox.__init__(self, False, 0) self._internal_box = Gtk.VBox()
class LinkButton(TrayButton, GObject.GObject): __gtype_name__ = 'LinkButton' __gsignals__ = { 'remove_link': (GObject.SignalFlags.RUN_FIRST, None, ([str])), } notes_changed_signal = GObject.Signal( 'notes-changed', arg_types=[str, str]) _dest_x = style.zoom(10) _dest_y = style.zoom(20) def __init__(self, buf, color, title, owner, hash, notes=None): TrayButton.__init__(self) self._fill, self._stroke = color.split(',') self.set_image(buf) self.hash = hash self.notes = notes info = title + '\n' + owner self.setup_rollover_options(info) def get_image_coords(self, relative_to): return self._img.translate_coordinates( relative_to, self._dest_x, self._dest_y) def show_thumb(self): self._img.set_from_pixbuf(self._pixbuf_bg) def hide_thumb(self): xo_buddy = os.path.join(os.path.dirname(__file__), "icons/link.svg") bg_surface = self._read_link_background(xo_buddy) bg_width, bg_height = style.zoom(120), style.zoom(110) pixbuf = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0, bg_width, bg_height) self._img.set_from_pixbuf(pixbuf) def set_image(self, buf): self._img = Gtk.Image() str_buf = io.StringIO(buf) thumb_surface = cairo.ImageSurface.create_from_png(str_buf) xo_buddy = os.path.join(os.path.dirname(__file__), "icons/link.svg") bg_surface = self._read_link_background(xo_buddy) cairo_context = cairo.Context(bg_surface) cairo_context.set_source_surface(thumb_surface, self._dest_x, self._dest_y) thumb_width, thumb_height = style.zoom(100), style.zoom(80) cairo_context.rectangle(self._dest_x, self._dest_y, thumb_width, thumb_height) cairo_context.fill() bg_width, bg_height = style.zoom(120), style.zoom(110) self._pixbuf_bg = Gdk.pixbuf_get_from_surface(bg_surface, 0, 0, bg_width, bg_height) self._img.set_from_pixbuf(self._pixbuf_bg) self.set_icon_widget(self._img) self._img.show() def _read_link_background(self, filename): icon_file = open(filename, 'r') data = icon_file.read() icon_file.close() entity = '<!ENTITY fill_color "%s">' % self._fill data = re.sub('<!ENTITY fill_color .*>', entity, data) entity = '<!ENTITY stroke_color "%s">' % self._stroke data = re.sub('<!ENTITY stroke_color .*>', entity, data) link_width, link_height = style.zoom(120), style.zoom(110) link_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, link_width, link_height) link_context = cairo.Context(link_surface) link_scale_w = link_width * 1.0 / 120 link_scale_h = link_height * 1.0 / 110 link_context.scale(link_scale_w, link_scale_h) handler = Rsvg.Handle.new_from_data(data) handler.render_cairo(link_context) return link_surface def setup_rollover_options(self, info): palette = Palette(info, text_maxlen=50) self.set_palette(palette) box = PaletteMenuBox() palette.set_content(box) box.show() menu_item = PaletteMenuItem(_('Remove'), 'list-remove') menu_item.connect('activate', self.item_remove_cb) box.append_item(menu_item) menu_item.show() separator = PaletteMenuItemSeparator() box.append_item(separator) separator.show() textview = Gtk.TextView() textview.props.height_request = style.GRID_CELL_SIZE * 2 textview.props.width_request = style.GRID_CELL_SIZE * 3 textview.props.hexpand = True textview.props.vexpand = True box.append_item(textview) textview.show() buffer = textview.get_buffer() if self.notes is None: buffer.set_text(_('Take notes on this page')) else: buffer.set_text(self.notes) buffer.connect('changed', self.__buffer_changed_cb) def item_remove_cb(self, widget): self.emit('remove_link', self.hash) def __buffer_changed_cb(self, buffer): start, end = buffer.get_bounds() self.notes = buffer.get_text(start, end, False) self.notes_changed_signal.emit(self.hash, self.notes)
def __init__(self, activity_updater, activity_pane): GObject.GObject.__init__(self) self.activity_updater = activity_updater self.activity_pane = activity_pane # create the TreeView using a filtered treestore self.ftreestore = self.activity_updater.activity_list.filter_new() if not _DEBUG_VIEW_ALL: self.ftreestore.set_visible_column(model.UPDATE_EXISTS) self.treeview = Gtk.TreeView(self.ftreestore) # create some cell renderers. crbool = Gtk.CellRendererToggle() crbool.set_property('activatable', True) crbool.set_property('xpad', style.DEFAULT_PADDING) # indicator size should be themeable, but is not. # if we're in sugar, use the larger indicator size. # otherwise, use the hard-coded GTK default. if self.activity_updater._in_sugar: crbool.set_property('indicator_size', style.zoom(26)) def toggled_cb(crbool, path, self): path = Gtk.TreePath(path) path = self.ftreestore.convert_path_to_child_path(path) self.activity_updater.activity_list.toggle_select(path) self.activity_pane._refresh_update_size() crbool.connect('toggled', toggled_cb, self) cricon = Gtk.CellRendererPixbuf() cricon.set_property('width', style.STANDARD_ICON_SIZE) cricon.set_property('height', style.STANDARD_ICON_SIZE) crtext = Gtk.CellRendererText() crtext.set_property('xpad', style.DEFAULT_PADDING) crtext.set_property('ypad', style.DEFAULT_PADDING) # create the TreeViewColumn to display the data def view_func_maker(propname): def view_func(cell_layout, renderer, m, it, user_data=None): renderer.set_property(propname, not m.get_value(it, model.IS_HEADER)) return view_func hide_func = view_func_maker('visible') insens_func = view_func_maker('sensitive') self.column_install = Gtk.TreeViewColumn('Install', crbool) self.column_install.add_attribute(crbool, 'active', model.UPDATE_SELECTED) self.column_install.set_cell_data_func(crbool, hide_func) self.column = Gtk.TreeViewColumn('Name') self.column.pack_start(cricon, False) self.column.pack_start(crtext, True) self.column.add_attribute(cricon, 'pixbuf', model.ACTIVITY_ICON) self.column.set_resizable(True) self.column.set_cell_data_func(cricon, hide_func) def markup_func(cell_layout, renderer, m, it, user_data): s = '<b>%s</b>' % _e(m.get_value(it, model.DESCRIPTION_BIG)) if m.get_value(it, model.IS_HEADER): s = '<big>%s</big>' % s desc = m.get_value(it, model.DESCRIPTION_SMALL) if desc is not None and desc != '': s += '\n<small>%s</small>' % _e(desc) renderer.set_property('markup', s) insens_func(cell_layout, renderer, m, it) self.column.set_cell_data_func(crtext, markup_func) # add tvcolumn to treeview self.treeview.append_column(self.column_install) self.treeview.append_column(self.column) self.treeview.set_reorderable(False) self.treeview.set_enable_search(False) self.treeview.set_headers_visible(False) self.treeview.set_rules_hint(True) self.treeview.connect('button-press-event', self.show_context_menu) def is_valid_cb(activity_list, __): self.treeview.set_sensitive(activity_list.is_valid()) self.activity_updater.activity_list.connect('notify::is-valid', is_valid_cb) is_valid_cb(self.activity_updater.activity_list, None) # now put this all inside ourself (a Gtk.ScrolledWindow) self.add_with_viewport(self.treeview) self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
class ActivityIcon(CanvasIcon): __gtype_name__ = 'SugarFavoriteActivityIcon' _BORDER_WIDTH = style.zoom(9) _MAX_RESUME_ENTRIES = 5 def __init__(self, activity_info): CanvasIcon.__init__(self, cache=True, file_name=activity_info.get_icon()) self._activity_info = activity_info self._journal_entries = [] self._resume_mode = Gio.Settings('org.sugarlabs.user').get_boolean( 'resume-activity') self.connect_after('activate', self.__button_activate_cb) datastore.updated.connect(self.__datastore_listener_updated_cb) datastore.deleted.connect(self.__datastore_listener_deleted_cb) self._refresh() self._update() def _refresh(self): bundle_id = self._activity_info.get_bundle_id() properties = [ 'uid', 'title', 'icon-color', 'activity', 'activity_id', 'mime_type', 'mountpoint' ] self._get_last_activity_async(bundle_id, properties) def __datastore_listener_updated_cb(self, **kwargs): bundle_id = self._activity_info.get_bundle_id() if kwargs['metadata'].get('activity', '') == bundle_id: self._refresh() def __datastore_listener_deleted_cb(self, **kwargs): for entry in self._journal_entries: if entry['uid'] == kwargs['object_id']: self._refresh() break def _get_last_activity_async(self, bundle_id, properties): query = {'activity': bundle_id} datastore.find(query, sorting=['+timestamp'], limit=self._MAX_RESUME_ENTRIES, properties=properties, reply_handler=self.__get_last_activity_reply_handler_cb, error_handler=self.__get_last_activity_error_handler_cb) def __get_last_activity_reply_handler_cb(self, entries, total_count): # If there's a problem with the DS index, we may get entries not # related to this activity. checked_entries = [] for entry in entries: if entry['activity'] == self.bundle_id: checked_entries.append(entry) self._journal_entries = checked_entries self._update() def __get_last_activity_error_handler_cb(self, error): logging.error('Error retrieving most recent activities: %r', error) def _update(self): self.palette = None if not self._resume_mode or not self._journal_entries: xo_color = XoColor('%s,%s' % (style.COLOR_BUTTON_GREY.get_svg(), style.COLOR_WHITE.get_svg())) else: xo_color = misc.get_icon_color(self._journal_entries[0]) self.props.xo_color = xo_color def create_palette(self): palette = FavoritePalette(self._activity_info, self._journal_entries) palette.connect('activate', self.__palette_activate_cb) palette.connect('entry-activate', self.__palette_entry_activate_cb) self.connect_to_palette_pop_events(palette) return palette def __palette_activate_cb(self, palette): self._activate() def __palette_entry_activate_cb(self, palette, metadata): self._resume(metadata) def do_get_preferred_width(self): width = CanvasIcon.do_get_preferred_width(self)[0] width += ActivityIcon._BORDER_WIDTH * 2 return (width, width) def do_get_preferred_height(self): height = CanvasIcon.do_get_preferred_height(self)[0] height += ActivityIcon._BORDER_WIDTH * 2 return (height, height) def __button_activate_cb(self, icon): self._activate() def _resume(self, journal_entry): if not journal_entry['activity_id']: journal_entry['activity_id'] = activityfactory.create_activity_id() misc.resume(journal_entry, self._activity_info.get_bundle_id()) def _activate(self): if self.palette is not None: self.palette.popdown(immediate=True) if self._resume_mode and self._journal_entries: self._resume(self._journal_entries[0]) else: misc.launch(self._activity_info) def run_activity(self): self._activate() def get_bundle_id(self): return self._activity_info.get_bundle_id() bundle_id = property(get_bundle_id, None) def get_version(self): return self._activity_info.get_activity_version() version = property(get_version, None) def get_activity_name(self): return self._activity_info.get_name() def _get_installation_time(self): return self._activity_info.get_installation_time() installation_time = property(_get_installation_time, None) def _get_fixed_position(self): registry = bundleregistry.get_registry() return registry.get_bundle_position(self.bundle_id, self.version) fixed_position = property(_get_fixed_position, None) def set_resume_mode(self, resume_mode): self._resume_mode = resume_mode self._update()
def __init__(self): Gtk.ToolItem.__init__(self) self._font_sizes = [ 8, 9, 10, 11, 12, 14, 16, 20, 22, 24, 26, 28, 36, 48, 72 ] # theme the buttons, can be removed if add the style to the sugar css # these are the same values used in gtk-widgets.css.em if style.zoom(100) == 100: subcell_size = 15 default_padding = 6 else: subcell_size = 11 default_padding = 4 hbox = Gtk.HBox() vbox = Gtk.VBox() self.add(vbox) # add a vbox to set the padding up and down vbox.pack_start(hbox, True, True, default_padding) self._size_down = Gtk.Button() self._size_down.set_can_focus(False) icon = Icon(icon_name='resize-') self._size_down.set_image(icon) self._size_down.connect('clicked', self.__font_sizes_cb, False) hbox.pack_start(self._size_down, False, False, 5) # TODO: default? self._default_size = 12 self._font_size = self._default_size self._size_label = Gtk.Label(str(self._font_size)) hbox.pack_start(self._size_label, False, False, 10) self._size_up = Gtk.Button() self._size_up.set_can_focus(False) icon = Icon(icon_name='resize+') self._size_up.set_image(icon) self._size_up.connect('clicked', self.__font_sizes_cb, True) hbox.pack_start(self._size_up, False, False, 5) radius = 2 * subcell_size theme_up = "GtkButton {border-radius:0px %dpx %dpx 0px;}" % (radius, radius) css_provider_up = Gtk.CssProvider() css_provider_up.load_from_data(theme_up) style_context = self._size_up.get_style_context() style_context.add_provider(css_provider_up, Gtk.STYLE_PROVIDER_PRIORITY_USER) theme_down = "GtkButton {border-radius: %dpx 0px 0px %dpx;}" % (radius, radius) css_provider_down = Gtk.CssProvider() css_provider_down.load_from_data(theme_down) style_context = self._size_down.get_style_context() style_context.add_provider(css_provider_down, Gtk.STYLE_PROVIDER_PRIORITY_USER) self.show_all()
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. import math from gi.repository import Gtk from gi.repository import Gdk from sugar3.graphics import style _BASE_DISTANCE = style.zoom(25) _CHILDREN_FACTOR = style.zoom(3) class SnowflakeLayout(Gtk.Container): __gtype_name__ = 'SugarSnowflakeLayout' def __init__(self): Gtk.Container.__init__(self) self.set_has_window(False) self._nflakes = 0 self._children = {} def do_realize(self): self.set_realized(True) self.set_window(self.get_parent_window())
def __add_cb(self, child, params): child.set_border_width(style.zoom(5))
# from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GObject from gi.repository import Pango from sugar3.graphics import style import svgcard import os import math import logging CARD_PAD = style.zoom(6) class CardTable(Gtk.EventBox): __gsignals__ = { 'card-flipped': (GObject.SignalFlags.RUN_FIRST, None, [int, GObject.TYPE_PYOBJECT]), 'card-highlighted': (GObject.SignalFlags.RUN_FIRST, None, [int, GObject.TYPE_PYOBJECT]), } def __init__(self): Gtk.EventBox.__init__(self) self.data = None self.cards_data = None
def _create_preview(self): width = style.zoom(320) height = style.zoom(240) box = Gtk.EventBox() box.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color()) if len(self._metadata.get('preview', '')) > 4: if self._metadata['preview'][1:4] == 'PNG': preview_data = self._metadata['preview'] else: # TODO: We are close to be able to drop this. import base64 preview_data = base64.b64decode(self._metadata['preview']) png_file = StringIO.StringIO(preview_data) try: # Load image and scale to dimensions im = Gtk.Image() surface = cairo.ImageSurface.create_from_png(png_file) png_width = surface.get_width() png_height = surface.get_height() preview_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) cr = cairo.Context(preview_surface) scale_w = width * 1.0 / png_width scale_h = height * 1.0 / png_height scale = min(scale_w, scale_h) cr.scale(scale, scale) cr.set_source_rgba(1, 1, 1, 0) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() cr.set_source_surface(surface) cr.paint() pixbuf_bg = Gdk.pixbuf_get_from_surface( preview_surface, 0, 0, width, height) im.set_from_pixbuf(pixbuf_bg) has_preview = True except Exception: logging.exception('Error while loading the preview') has_preview = False else: has_preview = False if has_preview: box.add(im) im.show() else: label = Gtk.Label() label.set_text(_('No preview')) label.set_size_request(width, height) box.add(label) label.show() box.connect_after('button-release-event', self._preview_box_button_release_event_cb) return box
def __init__(self, text, icon_name): Gtk.VBox.__init__(self) self._progress_bar = None self._adjustment = None icon = Icon(pixel_size=style.SMALL_ICON_SIZE) icon.props.icon_name = icon_name icon.props.xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(), style.COLOR_BUTTON_GREY.get_svg())) icon.show() label = Gtk.Label(text) label.show() grid = Gtk.Grid() grid.set_column_spacing(style.DEFAULT_SPACING) grid.attach(icon, 0, 0, 1, 1) grid.attach(label, 1, 0, 1, 1) grid.show() alignment = Gtk.Alignment() alignment.set(0.5, 0, 0, 0) alignment.add(grid) alignment.show() self.add(alignment) alignment = Gtk.Alignment() alignment.set(0.5, 0, 0, 0) alignment.set_padding(0, 0, style.DEFAULT_SPACING, style.DEFAULT_SPACING) self._model = brightness.get_instance() self._model_changed_hid = \ self._model.changed_signal.connect(self.__brightness_changed_cb) # if sugar-backlight-helper finds the device if self._model.get_path(): adjustment = Gtk.Adjustment( value=self._model.get_brightness(), lower=0, upper=self._model.get_max_brightness() + 1, step_incr=self._model.get_step_amount(), page_incr=self._model.get_step_amount(), page_size=self._model.get_step_amount()) self._adjustment = adjustment self._adjustment_timeout_id = None self._adjustment_hid = \ self._adjustment.connect('value-changed', self.__adjusted_cb) hscale = Gtk.HScale() hscale.props.draw_value = False hscale.set_adjustment(adjustment) hscale.set_digits(0) hscale.set_size_request(style.GRID_CELL_SIZE * 4, -1) alignment.add(hscale) hscale.show() else: self._progress_bar = Gtk.ProgressBar() self._progress_bar.set_size_request( style.zoom(style.GRID_CELL_SIZE * 4), -1) alignment.props.top_padding = style.DEFAULT_PADDING alignment.add(self._progress_bar) self._progress_bar.show() alignment.show() self.add(alignment)
import logging import time from gettext import gettext as _ from gi.repository import GObject from gi.repository import Gtk from gi.repository import GLib from gi.repository import GdkPixbuf from sugar3.graphics.icon import Icon from sugar3.graphics import style from jarabelocal.journal import model from iconmodel import IconModel PREVIEW_SIZE = style.zoom(300) / 2, style.zoom(225) / 2 _pixbuf_cache = {} def get_preview_pixbuf(preview_path, width=-1, height=-1): """Retrive a pixbuf with the content of the preview field Keyword arguments: preview_path -- the path to the image to show width -- the pixbuf width, if is not set, the default width will be used height -- the pixbuf width, if is not set, the default height will be used Return: a Pixbuf or None if couldn't create it
def add_text(self, buddy, text, status_message=False): '''Display text on screen, with name and colors. buddy -- buddy object or dict {nick: string, color: string} (The dict is for loading the chat log from the journal, when we don't have the buddy object any more.) text -- string, what the buddy said status_message -- boolean False: show what buddy said True: show what buddy did .----- rb ------------. | +----align-------+ | | | +--message---+ | | | | | nick: | | | | | | text 1 | | | | | | text 2 | | | | | +------------+ | | | +----------------+ | `----------------- +--' \| The color scheme for owner messages is: nick in lighter of stroke and fill colors background in darker of stroke and fill colors text in white The color scheme for buddy messages is: nick in darker of stroke and fill colors background in light gray text in black rb has a tail on the right for owner messages and the left for buddy messages. ''' if not buddy: buddy = self._owner if type(buddy) is dict: # dict required for loading chat log from journal nick = buddy['nick'] color = buddy['color'] else: nick = buddy.props.nick color = buddy.props.color try: color_stroke_html, color_fill_html = color.split(',') except ValueError: color_stroke_html, color_fill_html = ('#000000', '#888888') lighter = lighter_color(color.split(',')) darker = 1 - lighter if len(text) > 3 and text[0:4] == '/me ': me_message = True else: me_message = False if status_message or me_message: text_color = style.COLOR_WHITE nick_color = style.COLOR_WHITE color_fill = style.Color('#808080') highlight_fill = style.COLOR_WHITE tail = None else: highlight_fill = style.COLOR_BUTTON_GREY if is_dark_too_light(color.split(',')[darker]): text_color = style.COLOR_BLACK darker = lighter # use black on lighter of the two colors else: text_color = style.COLOR_WHITE if darker == 0: color_fill = style.Color(color_stroke_html) if is_low_contrast(color.split(',')): nick_color = text_color else: nick_color = style.Color(color_fill_html) else: color_fill = style.Color(color_fill_html) if is_low_contrast(color.split(',')): nick_color = text_color else: nick_color = style.Color(color_stroke_html) if nick == profile.get_nick_name(): tail = 'right' else: tail = 'left' color_stroke = None self._add_log(nick, color, text, status_message) # Check for Right-To-Left languages: if Pango.find_base_dir(nick, -1) == Pango.Direction.RTL: lang_rtl = True else: lang_rtl = False # Check if new message box or add text to previous: new_msg = True if self._last_msg_sender and buddy == self._last_msg_sender: # Add text to previous message if not (me_message or status_message): new_msg = False if not new_msg: message = self._last_msg message.add_text(text) else: rb = RoundBox() rb.background_color = color_fill rb.border_color = color_stroke rb.tail = tail self._rb_list.append(rb) grid_internal = Gtk.Grid() grid_internal.set_row_spacing(0) grid_internal.set_border_width(style.DEFAULT_PADDING) grid_internal.set_size_request( Gdk.Screen.width() - style.GRID_CELL_SIZE, -1) self._grid_list.append(grid_internal) row = 0 if status_message: nick = None elif me_message: text = text[4:] message = TextBox(self, nick_color, text_color, color_fill, highlight_fill, lang_rtl, nick, text) self._message_list.append(message) message.connect('open-on-journal', self.__open_on_journal) self._last_msg_sender = buddy self._last_msg = message grid_internal.attach(message, 0, row, 1, 1) row += 1 align = Gtk.Alignment.new(xalign=0.0, yalign=0.0, xscale=1.0, yscale=1.0) if rb.tail is None: bottom_padding = style.zoom(7) else: bottom_padding = style.zoom(35) align.set_padding(style.zoom(7), bottom_padding, style.zoom(30), style.zoom(30)) align.add(grid_internal) grid_internal.show() rb.pack_start(align, True, True, 0) align.show() self._conversation.attach(rb, 0, self._row_counter, 1, 1) rb.show() self._row_counter += 1 message.show() if status_message: self._last_msg_sender = None self.emit("new-message")
from sugar3.activity.widgets import StopButton from sugar3.datastore import datastore from sugar3.activity import activity from sugar3.graphics.alert import Alert from sugar3.graphics.icon import Icon import tempfile import filepicker import places from browser import Browser from browser import LIBRARY_PATH from pdfviewer import DummyBrowser _MAX_HISTORY_ENTRIES = 15 _SEARCH_ENTRY_MARGIN = style.zoom(14) class _SearchWindow(Gtk.Window): """A search window that can be styled in the theme.""" __gtype_name__ = "BrowseSearchWindow" def __init__(self): Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP) class WebEntry(iconentry.IconEntry): _COL_ADDRESS = 0 _COL_TITLE = 1
def __init__(self, handle): activity.Activity.__init__(self, handle) self.max_participants = 1 self._document = None self._fileserver = None self._object_id = handle.object_id self._toc_model = None self.filehash = None self.connect('key-press-event', self._key_press_event_cb) self.connect('key-release-event', self._key_release_event_cb) _logger.debug('Starting Read...') self._view = None self.dpi = _get_screen_dpi() self._bookmark_view = BookmarkView() self._bookmark_view.connect('bookmark-changed', self._update_bookmark_cb) tray = HTray() self.set_tray(tray, Gtk.PositionType.BOTTOM) toolbar_box = ToolbarBox() self.activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(self.activity_button, 0) self.activity_button.show() self._edit_toolbar = EditToolbar() self._edit_toolbar.undo.props.visible = False self._edit_toolbar.redo.props.visible = False self._edit_toolbar.separator.props.visible = False self._edit_toolbar.copy.set_sensitive(False) self._edit_toolbar.copy.connect('clicked', self._edit_toolbar_copy_cb) self._edit_toolbar.paste.props.visible = False edit_toolbar_button = ToolbarButton(page=self._edit_toolbar, icon_name='toolbar-edit') self._edit_toolbar.show() toolbar_box.toolbar.insert(edit_toolbar_button, -1) edit_toolbar_button.show() self._highlight = self._edit_toolbar.highlight self._highlight_id = self._highlight.connect('clicked', self.__highlight_cb) self._view_toolbar = ViewToolbar() self._view_toolbar.connect('go-fullscreen', self.__view_toolbar_go_fullscreen_cb) self._view_toolbar.connect('toggle-index-show', self.__toogle_navigator_cb) self._view_toolbar.connect('toggle-tray-show', self.__toogle_tray_cb) view_toolbar_button = ToolbarButton(page=self._view_toolbar, icon_name='toolbar-view') self._view_toolbar.show() toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() self._back_button = self._create_back_button() toolbar_box.toolbar.insert(self._back_button, -1) self._back_button.show() self._forward_button = self._create_forward_button() toolbar_box.toolbar.insert(self._forward_button, -1) self._forward_button.show() num_page_item = Gtk.ToolItem() self._num_page_entry = self._create_search() num_page_item.add(self._num_page_entry) self._num_page_entry.show() toolbar_box.toolbar.insert(num_page_item, -1) num_page_item.show() total_page_item = Gtk.ToolItem() self._total_page_label = Gtk.Label() total_page_item.add(self._total_page_label) self._total_page_label.show() self._total_page_label.set_margin_right(5) toolbar_box.toolbar.insert(total_page_item, -1) total_page_item.show() self._bookmarker = ToggleToolButton('emblem-favorite') self._bookmarker_toggle_handler_id = self._bookmarker.connect( 'toggled', self.__bookmarker_toggled_cb) self._bookmarker.show() toolbar_box.toolbar.insert(self._bookmarker, -1) self.speech_toolbar_button = ToolbarButton(icon_name='speak') toolbar_box.toolbar.insert(self.speech_toolbar_button, -1) separator = Gtk.SeparatorToolItem() separator.props.draw = False separator.set_size_request(0, -1) separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() # This is needed to prevent the call of read_file on # canvas map, becuase interact in a bad way with the emptypanel # the program takes responsability of this task. self._read_file_called = True self._vbox = Gtk.VBox() self._vbox.show() overlay = Gtk.Overlay() self._hbox = Gtk.HBox() self._hbox.show() overlay.add(self._hbox) self._bookmark_view.props.halign = Gtk.Align.END self._bookmark_view.props.valign = Gtk.Align.START # HACK: This is to calculate the scrollbar width # defined in sugar-artwork gtk-widgets.css.em if style.zoom(1): scrollbar_width = 15 else: scrollbar_width = 11 self._bookmark_view.props.margin_right = scrollbar_width overlay.add_overlay(self._bookmark_view) overlay.show() self._vbox.pack_start(overlay, True, True, 0) self.set_canvas(self._vbox) self._navigator = self._create_navigator() # Set up for idle suspend self._idle_timer = 0 self._service = None # start with sleep off self._sleep_inhibit = True self.unused_download_tubes = set() self._want_document = True self._download_content_length = 0 self._download_content_type = None # Status of temp file used for write_file: self._tempfile = None self._close_requested = False fname = os.path.join('/etc', 'inhibit-ebook-sleep') if not os.path.exists(fname): try: bus = dbus.SystemBus() proxy = bus.get_object(_HARDWARE_MANAGER_SERVICE, _HARDWARE_MANAGER_OBJECT_PATH) self._service = dbus.Interface(proxy, _HARDWARE_MANAGER_INTERFACE) self._scrolled.props.vadjustment.connect( "value-changed", self._user_action_cb) self._scrolled.props.hadjustment.connect( "value-changed", self._user_action_cb) self.connect("focus-in-event", self._focus_in_event_cb) self.connect("focus-out-event", self._focus_out_event_cb) self.connect("notify::active", self._now_active_cb) _logger.debug('Suspend on idle enabled') except dbus.DBusException: _logger.info( 'Hardware manager service not found, no idle suspend.') else: _logger.debug('Suspend on idle disabled') self.connect("shared", self._shared_cb) h = hash(self._activity_id) self.port = 1024 + (h % 64511) self._progress_alert = None if self._jobject.file_path is not None and \ self._jobject.file_path != '': self.read_file(self._jobject.file_path) elif handle.uri: self._load_document(handle.uri) # TODO: we need trasfer the metadata and uodate # bookmarks and urls elif self.shared_activity: # We're joining if self.get_shared(): # Already joined for some reason, just get the document self._joined_cb(self) else: self._progress_alert = ProgressAlert() self._progress_alert.props.title = _('Please wait') self._progress_alert.props.msg = _('Starting connection...') self.add_alert(self._progress_alert) # Wait for a successful join before trying to get the document self.connect("joined", self._joined_cb) else: # Not joining, not resuming or resuming session without file emptypanel.show(self, 'activity-read', _('No book'), _('Choose something to read'), self._show_journal_object_picker_cb)
def setup(self, activity): self._activity = activity self.__going_fwd = False self.__going_back = True self.textview = Gtk.TextView() self.textview.set_editable(False) self.textview.set_cursor_visible(False) self.textview.set_left_margin(50) self.textview.set_right_margin(50) self.textview.set_justification(Gtk.Justification.FILL) self.textview.set_wrap_mode(Gtk.WrapMode.WORD) self.textview.connect('button-release-event', self._view_buttonrelease_event_cb) self.connect('selection-changed', activity._view_selection_changed_cb) self.textview.set_events(self.textview.get_events() | Gdk.EventMask.TOUCH_MASK) self.textview.connect('event', self.__touch_event_cb) self._sw = Gtk.ScrolledWindow() self._sw.add(self.textview) self._v_vscrollbar = self._sw.get_vscrollbar() self._v_scrollbar_value_changed_cb_id = \ self._v_vscrollbar.connect('value-changed', self._v_scrollbar_value_changed_cb) self._scrollbar = Gtk.VScrollbar() self._scrollbar_change_value_cb_id = \ self._scrollbar.connect('change-value', self._scrollbar_change_value_cb) overlay = Gtk.Overlay() hbox = Gtk.HBox() overlay.add(hbox) hbox.add(self._sw) self._scrollbar.props.halign = Gtk.Align.END self._scrollbar.props.valign = Gtk.Align.FILL overlay.add_overlay(self._scrollbar) overlay.show_all() activity._hbox.pack_start(overlay, True, True, 0) self._font_size = style.zoom(10) self.font_desc = Pango.FontDescription("sans %d" % self._font_size) self.textview.modify_font(self.font_desc) self._zoom = 100 self.font_zoom_relation = self._zoom / self._font_size self._current_page = 0 self.highlight_tag = self.textview.get_buffer().create_tag() self.highlight_tag.set_property('underline', Pango.Underline.SINGLE) self.highlight_tag.set_property('foreground', 'black') self.highlight_tag.set_property('background', 'yellow') # text to speech initialization self.current_word = 0 self.word_tuples = [] self.spoken_word_tag = self.textview.get_buffer().create_tag() self.spoken_word_tag.set_property('weight', Pango.Weight.BOLD) self.normal_tag = self.textview.get_buffer().create_tag() self.normal_tag.set_property('weight', Pango.Weight.NORMAL)
def create_palette(self): self._palette = self.get_child().create_palette() color_palette_hbox = self._palette._picker_hbox self.custom_box = Gtk.VBox() self.vbox_brush_options = Gtk.VBox() # This is where we set restrictions for size: # Initial value, minimum value, maximum value, step adj = Gtk.Adjustment(self.properties['line size'], 1.0, 100.0, 1.0) self.size_scale = Gtk.HScale() self.size_scale.set_adjustment(adj) self.size_scale.set_draw_value(False) self.size_scale.set_size_request(style.zoom(200), -1) self.size_label = Gtk.Label(label=_('Size')) self.size_label.props.halign = Gtk.Align.START self.vbox_brush_options.pack_start(self.size_label, True, True, 0) self.vbox_brush_options.pack_start(self.size_scale, True, True, 0) self.size_scale.connect('value-changed', self._on_value_changed) # Control alpha alpha = self.properties['alpha'] * 100 adj_alpha = Gtk.Adjustment(alpha, 10.0, 100.0, 1.0) self.alpha_scale = Gtk.HScale() self.alpha_scale.set_adjustment(adj_alpha) self.alpha_scale.set_draw_value(False) self.alpha_scale.set_size_request(style.zoom(200), -1) self.alpha_label = Gtk.Label(label=_('Opacity')) self.alpha_label.props.halign = Gtk.Align.START self.vbox_brush_options.pack_start(self.alpha_label, True, True, 0) self.vbox_brush_options.pack_start(self.alpha_scale, True, True, 0) self.alpha_scale.connect('value-changed', self._on_alpha_changed) # User is able to choose Shapes for 'Brush' and 'Eraser' self.shape_box = Gtk.HBox() self.custom_box.pack_start(self.vbox_brush_options, True, True, 0) item1 = RadioToolButton() item1.set_icon_name('tool-shape-ellipse') item2 = RadioToolButton() item2.set_icon_name('tool-shape-rectangle') item2.props.group = item1 if self.properties['line shape'] == 'circle': item1.set_active(True) else: item2.set_active(True) item1.connect('toggled', self._on_toggled, self.properties, 'circle') item2.connect('toggled', self._on_toggled, self.properties, 'square') self.shape_box.pack_start(Gtk.Label(_('Shape')), True, True, 0) self.shape_box.pack_start(item1, True, True, 0) self.shape_box.pack_start(item2, True, True, 0) self.vbox_brush_options.pack_start(self.shape_box, True, True, 0) self.keep_aspect_checkbutton = Gtk.CheckButton(_('Keep aspect')) ratio = self._activity.area.keep_aspect_ratio self.keep_aspect_checkbutton.set_active(ratio) self.keep_aspect_checkbutton.connect( 'toggled', self._keep_aspect_checkbutton_toggled) self.vbox_brush_options.pack_start(self.keep_aspect_checkbutton, True, True, 0) self.custom_separator = Gtk.VSeparator() color_palette_hbox.pack_start(self.custom_separator, True, True, padding=style.DEFAULT_SPACING) color_palette_hbox.pack_start(self.custom_box, True, True, padding=style.DEFAULT_SPACING) color_palette_hbox.show_all() self._update_palette() return self._palette
SCOPE_PRIVATE = 'private' SCOPE_INVITE_ONLY = 'invite' # shouldn't be shown in UI, it's implicit SCOPE_NEIGHBORHOOD = 'public' J_DBUS_SERVICE = 'org.laptop.Journal' J_DBUS_PATH = '/org/laptop/Journal' J_DBUS_INTERFACE = 'org.laptop.Journal' N_BUS_NAME = 'org.freedesktop.Notifications' N_OBJ_PATH = '/org/freedesktop/Notifications' N_IFACE_NAME = 'org.freedesktop.Notifications' CONN_INTERFACE_ACTIVITY_PROPERTIES = 'org.laptop.Telepathy.ActivityProperties' PREVIEW_SIZE = style.zoom(300), style.zoom(225) class _ActivitySession(GObject.GObject): __gsignals__ = { 'quit-requested': (GObject.SignalFlags.RUN_FIRST, None, ([])), 'quit': (GObject.SignalFlags.RUN_FIRST, None, ([])), } def __init__(self): GObject.GObject.__init__(self) self._xsmp_client = SugarExt.ClientXSMP() self._xsmp_client.connect('quit-requested', self.__sm_quit_requested_cb)
from sugar3.activity.widgets import StopButton from sugar3.graphics import style from sugar3.graphics.alert import Alert from sugar3.graphics.alert import NotifyAlert from sugar3.graphics.icon import Icon from sugar3.graphics.animator import Animator, Animation from sugar3 import mime from sugar3.graphics.toolbarbox import ToolbarBox, ToolbarButton from sugar3 import profile from collabwrapper import CollabWrapper from widgets import TitledTray PROFILE_VERSION = 2 THUMB_WIDTH, THUMB_HEIGHT = style.zoom(100), style.zoom(80) _profile_version = 0 _profile_path = os.path.join(activity.get_activity_root(), 'data/gecko') _version_file = os.path.join(_profile_path, 'version') _cookies_db_path = os.path.join(_profile_path, 'cookies.sqlite') if os.path.exists(_version_file): f = open(_version_file) _profile_version = int(f.read()) f.close() if _profile_version < PROFILE_VERSION: if not os.path.exists(_profile_path): os.mkdir(_profile_path)
def __init__(self, value_range, default_value, default_image): Gtk.ToolItem.__init__(self) self._palette_invoker = ToolInvoker() self.palette = None self._values = value_range self._palette_invoker.attach_tool(self) # theme the buttons, can be removed if add the style to the sugar css # these are the same values used in gtk-widgets.css.em if style.zoom(100) == 100: subcell_size = 15 default_padding = 6 else: subcell_size = 11 default_padding = 4 hbox = Gtk.HBox() vbox = Gtk.VBox() self.add(vbox) # add a vbox to set the padding up and down vbox.pack_start(hbox, True, True, default_padding) self._size_down = ToolButton('go-previous-paired') self._palette_invoker.attach_tool(self._size_down) self._size_down.set_can_focus(False) self._size_down.connect('clicked', self.__value_changed_cb, False) hbox.pack_start(self._size_down, False, False, 5) # TODO: default? self._default_value = default_value self._value = self._default_value self.image_wrapper = Gtk.EventBox() self._intensityImage = Gtk.Image() self.image_wrapper.add(self._intensityImage) self.image_wrapper.show() self._intensityImage.set_from_file(default_image) self._intensityImage.show() self._palette_invoker.attach_widget(self.image_wrapper) hbox.pack_start(self.image_wrapper, False, False, 10) self._size_up = ToolButton('go-next-paired') self._palette_invoker.attach_tool(self._size_up) self._size_up.set_can_focus(False) self._size_up.connect('clicked', self.__value_changed_cb, True) hbox.pack_start(self._size_up, False, False, 5) radius = 2 * subcell_size theme_up = "GtkButton {border-radius:0px %dpx %dpx 0px;}" % (radius, radius) css_provider_up = Gtk.CssProvider() css_provider_up.load_from_data(theme_up) style_context = self._size_up.get_style_context() style_context.add_provider(css_provider_up, Gtk.STYLE_PROVIDER_PRIORITY_USER) theme_down = "GtkButton {border-radius: %dpx 0px 0px %dpx;}" % (radius, radius) css_provider_down = Gtk.CssProvider() css_provider_down.load_from_data(theme_down) style_context = self._size_down.get_style_context() style_context.add_provider(css_provider_down, Gtk.STYLE_PROVIDER_PRIORITY_USER) self.show_all()
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GdkPixbuf import shutil from math import ceil from sugar3.activity.activity import get_bundle_path, get_activity_root from sugar3.graphics import style SOUND_SPEAKER = 'images/sounds/speaker.png' SOUND_MUTE = 'images/sounds/mute.png' SOUND_CUSTOM = 'images/sounds/custom.png' LOGO_WIDTH = style.zoom(275) TAPE_COUNT = 11 FRAME_COUNT = 14 DESKTOP_WIDTH = Gdk.Screen.width() DESKTOP_HEIGHT = Gdk.Screen.height() - style.LARGE_ICON_SIZE THUMB_SIZE = style.zoom(min(100, DESKTOP_WIDTH / (TAPE_COUNT + 1))) FRAME_COLS = style.zoom( max(1, ((DESKTOP_WIDTH - LOGO_WIDTH) - min(DESKTOP_HEIGHT - THUMB_SIZE - THUMB_SIZE / 2, DESKTOP_WIDTH - LOGO_WIDTH)) / THUMB_SIZE)) FRAME_ROWS = max((DESKTOP_HEIGHT - THUMB_SIZE * 3) / THUMB_SIZE, int(ceil(float(FRAME_COUNT) / FRAME_COLS)))