Codebase list lightdm-gtk-greeter-settings / debian/1.2.2-4 lightdm_gtk_greeter_settings / IconEntry.py
debian/1.2.2-4

Tree @debian/1.2.2-4 (Download .tar.gz)

IconEntry.py @debian/1.2.2-4raw · history · blame

# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
#   LightDM GTK Greeter Settings
#   Copyright (C) 2015 Andrew P. <pan.pav.7c5@gmail.com>
#
#   This program is free software: you can redistribute it and/or modify it
#   under the terms of the GNU General Public License version 3, as published
#   by the Free Software Foundation.
#
#   This program is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranties of
#   MERCHANTABILITY, SATISFACTORY QUALITY, 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 os

from gi.repository import Gtk

from lightdm_gtk_greeter_settings.IconChooserDialog import IconChooserDialog
from lightdm_gtk_greeter_settings.OptionEntry import BaseEntry
from lightdm_gtk_greeter_settings.helpers import (
    C_,
    get_data_path,
    set_image_from_path,
    SimpleEnum)


__all__ = ['IconEntry']


class IconEntry(BaseEntry):

    class Item(SimpleEnum):
        priority = 0
        # (value, just_label) => (label, tooltip)
        update = None
        # (old_value) => str or None
        ask = None
        # Associated menu item
        menuitem = None

    def __init__(self, widgets):
        super().__init__(widgets)
        self._value = None
        self._image = widgets['image']
        self._button = widgets['button']
        self._button.props.popup = Gtk.Menu()
        self._icon_dialog = None
        self._path_dialog = None
        self._current_item = None

        self._add_controlled_by_state_widget(self._button)

        self._items = []
        for priority, (update, ask) in self._get_items():
            item = self.Item(priority=priority, update=update, ask=ask)
            item.menuitem = Gtk.MenuItem()
            item.menuitem.props.visible = True
            item.menuitem.props.label = item.update(None, True)[0]
            item.menuitem.connect('activate', self._on_item_clicked, item)
            self._button.props.popup.append(item.menuitem)
            self._items.append(item)

        self._items.sort(key=lambda i: i.priority)

    def _get_value(self):
        return self._value

    def _set_value(self, value):
        applied_item = None
        tooltip = None
        for item in self._items:
            if applied_item:
                label, __ = item.update(None, True)
            else:
                label, tooltip = item.update(value, False)
                if tooltip:
                    applied_item = item
            item.menuitem.get_child().set_markup(label)

        if not applied_item:
            tooltip = C_('option-entry|icon', 'Unrecognized value: {value}').format(value=value)
        self._button.set_tooltip_markup(tooltip)

        self._value = value
        self._current_item = applied_item

        self._emit_changed()

    def _get_items(self):
        return ((0, (self._update_icon, self._ask_icon)),
                (100, (self._update_image, self._ask_image)))

    def _on_item_clicked(self, menuitem, item):
        value = item.ask(self._value if item == self._current_item else None)
        if value is not None:
            self._set_value(value)

    def _update_icon(self, value, just_label=False):
        if just_label or value is None or not value.startswith('#'):
            return C_('option-entry|icon', 'Select icon name...'), None
        name = value[1:]
        label = C_('option-entry|icon', '<b>Icon: {icon}</b>').format(icon=name)
        tooltip = label
        self._image.set_from_icon_name(name, Gtk.IconSize.DIALOG)
        return label, tooltip

    def _ask_icon(self, oldvalue):
        if not self._icon_dialog:
            self._icon_dialog = IconChooserDialog()
            self._icon_dialog.props.transient_for = self._image.get_toplevel()
        if oldvalue:
            self._icon_dialog.select_icon(oldvalue[1:])

        value = None
        if self._icon_dialog.run() == Gtk.ResponseType.OK:
            value = '#' + self._icon_dialog.get_selected_icon()
        self._icon_dialog.hide()
        return value

    def _update_image(self, value, just_label=False):
        if just_label or value is None:
            return C_('option-entry|icon', 'Select file...'), None

        if set_image_from_path(self._image, value):
            label = C_('option-entry|icon', '<b>File: {path}</b>')
        else:
            label = C_('option-entry|icon', '<b>File: {path}</b> (failed to load)')

        return (label.format(path=os.path.basename(value)),
                label.format(path=value))

    def _ask_image(self, oldvalue):
        if not self._path_dialog:
            builder = Gtk.Builder()
            builder.add_from_file(get_data_path('ImageChooserDialog.ui'))

            self._path_dialog = builder.get_object('dialog')
            self._path_dialog.props.transient_for = self._image.get_toplevel()
            self._path_dialog.connect('update-preview', self._on_update_path_preview)

            preview_size = self._image.props.pixel_size
            preview = self._path_dialog.props.preview_widget
            preview.props.pixel_size = preview_size
            preview.set_size_request(preview_size, preview_size)

        if oldvalue is not None:
            self._path_dialog.select_filename(self._value)

        value = None
        if self._path_dialog.run() == Gtk.ResponseType.OK:
            value = self._path_dialog.get_filename()
        self._path_dialog.hide()
        return value

    def _on_update_path_preview(self, chooser):
        set_image_from_path(chooser.props.preview_widget, chooser.get_filename())