Blame plugins/colorpicker/colorpicker.py

Packit 6978fb
# -*- coding: utf-8 -*-
Packit 6978fb
#  Color picker plugin
Packit 6978fb
#  This file is part of gedit-plugins
Packit 6978fb
#
Packit 6978fb
#  Copyright (C) 2006 Jesse van den Kieboom
Packit 6978fb
#  Copyright (C) 2012 Ignacio Casal Quinteiro
Packit 6978fb
#
Packit 6978fb
#  This program is free software; you can redistribute it and/or modify
Packit 6978fb
#  it under the terms of the GNU General Public License as published by
Packit 6978fb
#  the Free Software Foundation; either version 2 of the License, or
Packit 6978fb
#  (at your option) any later version.
Packit 6978fb
#
Packit 6978fb
#  This program is distributed in the hope that it will be useful,
Packit 6978fb
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6978fb
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6978fb
#  GNU General Public License for more details.
Packit 6978fb
#
Packit 6978fb
#  You should have received a copy of the GNU General Public License
Packit 6978fb
#  along with this program; if not, write to the Free Software
Packit 6978fb
#  Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit 6978fb
#  Boston, MA 02110-1301, USA.
Packit 6978fb
Packit 6978fb
import gi
Packit 6978fb
gi.require_version('Gtk', '3.0')
Packit 6978fb
gi.require_version('Gedit', '3.0')
Packit 6978fb
from gi.repository import GObject, Gio, Gtk, Gdk, Gedit
Packit 6978fb
import re
Packit 6978fb
from gpdefs import *
Packit 6978fb
Packit 6978fb
try:
Packit 6978fb
    import gettext
Packit 6978fb
    gettext.bindtextdomain('gedit-plugins')
Packit 6978fb
    gettext.textdomain('gedit-plugins')
Packit 6978fb
    _ = gettext.gettext
Packit 6978fb
except:
Packit 6978fb
    _ = lambda s: s
Packit 6978fb
Packit 6978fb
Packit 6978fb
class ColorHelper:
Packit 6978fb
Packit 6978fb
    def scale_color_component(self, component):
Packit 6978fb
        return min(max(int(round(component * 255.)), 0), 255)
Packit 6978fb
Packit 6978fb
    def skip_hex(self, buf, iter, next_char):
Packit 6978fb
        while True:
Packit 6978fb
            char = iter.get_char()
Packit 6978fb
Packit 6978fb
            if not char:
Packit 6978fb
                return
Packit 6978fb
Packit 6978fb
            if char.lower() not in \
Packit 6978fb
                    ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
Packit 6978fb
                     'a', 'b', 'c', 'd', 'e', 'f'):
Packit 6978fb
                return
Packit 6978fb
Packit 6978fb
            if not next_char(iter):
Packit 6978fb
                return
Packit 6978fb
Packit 6978fb
    def get_rgba_position(self, buf, use_bounds):
Packit 6978fb
        bounds = buf.get_selection_bounds()
Packit 6978fb
        if bounds == ():
Packit 6978fb
            if use_bounds:
Packit 6978fb
                return None
Packit 6978fb
Packit 6978fb
            # No selection, find color in the current cursor position
Packit 6978fb
            start = buf.get_iter_at_mark(buf.get_insert())
Packit 6978fb
Packit 6978fb
            end = start.copy()
Packit 6978fb
            start.backward_char()
Packit 6978fb
Packit 6978fb
            self.skip_hex(buf, start, lambda iter: iter.backward_char())
Packit 6978fb
            self.skip_hex(buf, end, lambda iter: iter.forward_char())
Packit 6978fb
        else:
Packit 6978fb
            start, end = bounds
Packit 6978fb
Packit 6978fb
        text = buf.get_text(start, end, False)
Packit 6978fb
Packit 6978fb
        if not re.match('#?[0-9a-zA-Z]+', text):
Packit 6978fb
            return None
Packit 6978fb
Packit 6978fb
        if text[0] != '#':
Packit 6978fb
            start.backward_char()
Packit 6978fb
Packit 6978fb
            if start.get_char() != '#':
Packit 6978fb
                return None
Packit 6978fb
Packit 6978fb
        return start, end
Packit 6978fb
Packit 6978fb
    def insert_color(self, view, text):
Packit 6978fb
        if not view or not view.get_editable():
Packit 6978fb
            return
Packit 6978fb
Packit 6978fb
        doc = view.get_buffer()
Packit 6978fb
Packit 6978fb
        if not doc:
Packit 6978fb
            return
Packit 6978fb
Packit 6978fb
        doc.begin_user_action()
Packit 6978fb
Packit 6978fb
        # Get the color
Packit 6978fb
        bounds = self.get_rgba_position(doc, False)
Packit 6978fb
Packit 6978fb
        if not bounds:
Packit 6978fb
            doc.delete_selection(False, True)
Packit 6978fb
        else:
Packit 6978fb
            doc.delete(bounds[0], bounds[1])
Packit 6978fb
Packit 6978fb
        doc.insert_at_cursor('#' + text)
Packit 6978fb
Packit 6978fb
        doc.end_user_action()
Packit 6978fb
Packit 6978fb
    def get_current_color(self, doc, use_bounds):
Packit 6978fb
        if not doc:
Packit 6978fb
            return None
Packit 6978fb
Packit 6978fb
        bounds = self.get_rgba_position(doc, use_bounds)
Packit 6978fb
Packit 6978fb
        if bounds:
Packit 6978fb
            return doc.get_text(bounds[0], bounds[1], False)
Packit 6978fb
        else:
Packit 6978fb
            return None
Packit 6978fb
Packit 6978fb
Packit 6978fb
class ColorPickerAppActivatable(GObject.Object, Gedit.AppActivatable):
Packit 6978fb
Packit 6978fb
    app = GObject.Property(type=Gedit.App)
Packit 6978fb
Packit 6978fb
    def __init__(self):
Packit 6978fb
        GObject.Object.__init__(self)
Packit 6978fb
Packit 6978fb
    def do_activate(self):
Packit 6978fb
        self.menu_ext = self.extend_menu("tools-section")
Packit 6978fb
        item = Gio.MenuItem.new(_("Pick _Color…"), "win.colorpicker")
Packit 6978fb
        self.menu_ext.prepend_menu_item(item)
Packit 6978fb
Packit 6978fb
    def do_deactivate(self):
Packit 6978fb
        self.menu_ext = None
Packit 6978fb
Packit 6978fb
Packit 6978fb
class ColorPickerWindowActivatable(GObject.Object, Gedit.WindowActivatable):
Packit 6978fb
Packit 6978fb
    window = GObject.Property(type=Gedit.Window)
Packit 6978fb
Packit 6978fb
    def __init__(self):
Packit 6978fb
        GObject.Object.__init__(self)
Packit 6978fb
        self._dialog = None
Packit 6978fb
        self._color_helper = ColorHelper()
Packit 6978fb
Packit 6978fb
    def do_activate(self):
Packit 6978fb
        action = Gio.SimpleAction(name="colorpicker")
Packit 6978fb
        action.connect('activate', lambda a, p: self.on_color_picker_activate())
Packit 6978fb
        self.window.add_action(action)
Packit 6978fb
        self._update()
Packit 6978fb
Packit 6978fb
    def do_deactivate(self):
Packit 6978fb
        self.window.remove_action("colorpicker")
Packit 6978fb
Packit 6978fb
    def do_update_state(self):
Packit 6978fb
        self._update()
Packit 6978fb
Packit 6978fb
    def _update(self):
Packit 6978fb
        tab = self.window.get_active_tab()
Packit 6978fb
        self.window.lookup_action("colorpicker").set_enabled(tab is not None)
Packit 6978fb
Packit 6978fb
        if not tab and self._dialog and \
Packit 6978fb
                self._dialog.get_transient_for() == self.window:
Packit 6978fb
            self._dialog.response(Gtk.ResponseType.CLOSE)
Packit 6978fb
Packit 6978fb
    # Signal handlers
Packit 6978fb
Packit 6978fb
    def on_color_picker_activate(self):
Packit 6978fb
        if not self._dialog:
Packit 6978fb
            self._dialog = Gtk.ColorChooserDialog.new(_('Pick Color'), self.window)
Packit 6978fb
            self._dialog.connect_after('response', self.on_dialog_response)
Packit 6978fb
Packit 6978fb
        rgba_str = self._color_helper.get_current_color(self.window.get_active_document(), False)
Packit 6978fb
Packit 6978fb
        if rgba_str:
Packit 6978fb
            rgba = Gdk.RGBA()
Packit 6978fb
            parsed = rgba.parse(rgba_str)
Packit 6978fb
Packit 6978fb
            if parsed:
Packit 6978fb
                self._dialog.set_rgba(rgba)
Packit 6978fb
Packit 6978fb
        self._dialog.present()
Packit 6978fb
Packit 6978fb
    def on_dialog_response(self, dialog, response):
Packit 6978fb
        if response == Gtk.ResponseType.OK:
Packit 6978fb
            rgba = dialog.get_rgba()
Packit 6978fb
Packit 6978fb
            self._color_helper.insert_color(self.window.get_active_view(),
Packit 6978fb
                                            "%02x%02x%02x" % (self._color_helper.scale_color_component(rgba.red),
Packit 6978fb
                                                              self._color_helper.scale_color_component(rgba.green),
Packit 6978fb
                                                              self._color_helper.scale_color_component(rgba.blue)))
Packit 6978fb
        else:
Packit 6978fb
            self._dialog.destroy()
Packit 6978fb
            self._dialog = None
Packit 6978fb
Packit 6978fb
Packit 6978fb
class ColorPickerViewActivatable(GObject.Object, Gedit.ViewActivatable):
Packit 6978fb
Packit 6978fb
    view = GObject.Property(type=Gedit.View)
Packit 6978fb
Packit 6978fb
    def __init__(self):
Packit 6978fb
        GObject.Object.__init__(self)
Packit 6978fb
        self._rgba_str = None
Packit 6978fb
        self._color_button = None
Packit 6978fb
        self._color_helper = ColorHelper()
Packit 6978fb
Packit 6978fb
    def do_activate(self):
Packit 6978fb
Packit 6978fb
        buf = self.view.get_buffer()
Packit 6978fb
        buf.connect_after('mark-set', self.on_buffer_mark_set)
Packit 6978fb
Packit 6978fb
    def do_deactivate(self):
Packit 6978fb
        if self._color_button is not None:
Packit 6978fb
            self._color_button.destroy()
Packit 6978fb
            self._color_button = None
Packit 6978fb
Packit 6978fb
    def on_buffer_mark_set(self, buf, location, mark):
Packit 6978fb
Packit 6978fb
        if not buf.get_has_selection():
Packit 6978fb
            if self._color_button:
Packit 6978fb
                self._color_button.destroy()
Packit 6978fb
                self._color_button = None
Packit 6978fb
            return
Packit 6978fb
Packit 6978fb
        if mark != buf.get_insert() and mark != buf.get_selection_bound():
Packit 6978fb
            return
Packit 6978fb
Packit 6978fb
        rgba_str = self._color_helper.get_current_color(self.view.get_buffer(), True)
Packit 6978fb
        if rgba_str is not None and rgba_str != self._rgba_str and self._color_button is not None:
Packit 6978fb
            rgba = Gdk.RGBA()
Packit 6978fb
            parsed = rgba.parse(rgba_str)
Packit 6978fb
            if parsed:
Packit 6978fb
                self._rgba_str = rgba_str
Packit 6978fb
                self._color_button.set_rgba(rgba)
Packit 6978fb
        elif rgba_str is not None and self._color_button is None:
Packit 6978fb
            rgba = Gdk.RGBA()
Packit 6978fb
            parsed = rgba.parse(rgba_str)
Packit 6978fb
            if parsed:
Packit 6978fb
                self._rgba_str = rgba_str
Packit 6978fb
Packit 6978fb
                bounds = buf.get_selection_bounds()
Packit 6978fb
                if bounds != ():
Packit 6978fb
                    self._color_button = Gtk.ColorButton.new_with_rgba(rgba)
Packit 6978fb
                    self._color_button.set_halign(Gtk.Align.START)
Packit 6978fb
                    self._color_button.set_valign(Gtk.Align.START)
Packit 6978fb
                    self._color_button.show()
Packit 6978fb
                    self._color_button.connect('color-set', self.on_color_set)
Packit 6978fb
Packit 6978fb
                    start, end = bounds
Packit 6978fb
                    location = self.view.get_iter_location(start)
Packit 6978fb
                    min_width, nat_width = self._color_button.get_preferred_width()
Packit 6978fb
                    min_height, nat_height = self._color_button.get_preferred_height()
Packit 6978fb
                    x = location.x
Packit 6978fb
                    if location.y - nat_height > 0:
Packit 6978fb
                        y = location.y - nat_height
Packit 6978fb
                    else:
Packit 6978fb
                        y = location.y + location.height
Packit 6978fb
Packit 6978fb
                    self.view.add_child_in_window(self._color_button, Gtk.TextWindowType.TEXT, x, y)
Packit 6978fb
        elif not rgba_str and self._color_button is not None:
Packit 6978fb
            self._color_button.destroy()
Packit 6978fb
            self._color_button = None
Packit 6978fb
Packit 6978fb
    def on_color_set(self, color_button):
Packit 6978fb
        rgba = color_button.get_rgba()
Packit 6978fb
Packit 6978fb
        self._color_helper.insert_color(self.view,
Packit 6978fb
                                        "%02x%02x%02x" % (self._color_helper.scale_color_component(rgba.red),
Packit 6978fb
                                                          self._color_helper.scale_color_component(rgba.green),
Packit 6978fb
                                                          self._color_helper.scale_color_component(rgba.blue)))
Packit 6978fb
Packit 6978fb
# ex:ts=4:et: