|
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:
|