add color picker
It wraps the upstream color picker, that is designed for DBus access. There is a shortcut and a menu button.
This commit is contained in:
parent
9977a037ec
commit
af694382c8
75
area.js
75
area.js
|
|
@ -29,6 +29,7 @@ const GObject = imports.gi.GObject;
|
|||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const System = imports.system;
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ var Tools = Object.assign({
|
|||
}, Shapes, Manipulations);
|
||||
Object.defineProperty(Tools, 'getNameOf', { enumerable: false });
|
||||
|
||||
const getClutterColorFromString = function(string, fallback) {
|
||||
const getColorFromString = function(string, fallback) {
|
||||
let [success, color] = Clutter.Color.from_string(string);
|
||||
color.toString = () => string;
|
||||
if (success)
|
||||
|
|
@ -70,10 +71,14 @@ const getClutterColorFromString = function(string, fallback) {
|
|||
|
||||
log(`${Me.metadata.uuid}: "${string}" color cannot be parsed.`);
|
||||
color = Clutter.Color.get_static(Clutter.StaticColor[fallback.toUpperCase()]);
|
||||
color.toString = () => fallback.slice(0, 1).toUpperCase() + fallback.slice(1);
|
||||
color.toString = () => fallback;
|
||||
return color;
|
||||
};
|
||||
|
||||
const getColorFromRGB = function(red, green, blue) {
|
||||
return getColorFromString(`rgb(${red},${green},${blue})`, 'White');
|
||||
};
|
||||
|
||||
// DrawingArea is the widget in which we draw, thanks to Cairo.
|
||||
// It creates and manages a DrawingElement for each "brushstroke".
|
||||
// It handles pointer/mouse/(touch?) events and some keyboard events.
|
||||
|
|
@ -152,7 +157,7 @@ var DrawingArea = new Lang.Class({
|
|||
|
||||
set currentPalette(palette) {
|
||||
this._currentPalette = palette;
|
||||
this.colors = palette[1].map(colorString => getClutterColorFromString(colorString, 'white'));
|
||||
this.colors = palette[1].map(colorString => getColorFromString(colorString, 'White'));
|
||||
if (!this.colors[0])
|
||||
this.colors.push(Clutter.Color.get_static(Clutter.StaticColor.WHITE));
|
||||
},
|
||||
|
|
@ -254,9 +259,9 @@ var DrawingArea = new Lang.Class({
|
|||
this.squareAreaSize = Me.drawingSettings.get_uint('square-area-size');
|
||||
}
|
||||
|
||||
this.areaBackgroundColor = getClutterColorFromString(Me.drawingSettings.get_string('background-color'), 'black');
|
||||
this.areaBackgroundColor = getColorFromString(Me.drawingSettings.get_string('background-color'), 'Black');
|
||||
|
||||
this.gridColor = getClutterColorFromString(Me.drawingSettings.get_string('grid-color'), 'gray');
|
||||
this.gridColor = getColorFromString(Me.drawingSettings.get_string('grid-color'), 'Gray');
|
||||
if (Me.drawingSettings.get_boolean('grid-line-auto')) {
|
||||
this.gridLineSpacing = Math.round(this.monitor.width / (5 * GRID_TILES_HORIZONTAL_NUMBER));
|
||||
this.gridLineWidth = this.gridLineSpacing / 20;
|
||||
|
|
@ -1032,6 +1037,62 @@ var DrawingArea = new Lang.Class({
|
|||
});
|
||||
},
|
||||
|
||||
_onColorPicked: function(color) {
|
||||
let { red, green, blue } = color;
|
||||
this.currentColor = getColorFromRGB(red, green, blue);
|
||||
if (this.currentElement) {
|
||||
this.currentElement.color = this.currentColor;
|
||||
this._redisplay();
|
||||
}
|
||||
this.emit('show-osd', Files.Icons.COLOR, String(this.currentColor), this.currentColor.to_string().slice(0, 7), -1, false);
|
||||
this.initPointerCursor();
|
||||
},
|
||||
|
||||
pickColor: function() {
|
||||
if (!Screenshot.PickPixel)
|
||||
// GS 3.28-
|
||||
return;
|
||||
|
||||
// Translators: It is displayed in an OSD notification to ask the user to start picking, so it should use the imperative mood.
|
||||
this.emit('show-osd', Files.Icons.COLOR_PICKER, pgettext("osd-notification", "Pick a color"), "", -1, false);
|
||||
|
||||
try {
|
||||
let screenshot = new Shell.Screenshot();
|
||||
let pickPixel = new Screenshot.PickPixel(screenshot);
|
||||
|
||||
if (pickPixel.pickAsync) {
|
||||
pickPixel.pickAsync().then(result => {
|
||||
if (result instanceof Clutter.Color) {
|
||||
// GS 3.38+
|
||||
this._onColorPicked(result);
|
||||
} else {
|
||||
// GS 3.36
|
||||
let graphenePoint = result;
|
||||
screenshot.pick_color(graphenePoint.x, graphenePoint.y, (o, res) => {
|
||||
let [, color] = screenshot.pick_color_finish(res);
|
||||
this._onColorPicked(color);
|
||||
});
|
||||
}
|
||||
}).catch(() => this.initPointerCursor());
|
||||
} else {
|
||||
// GS 3.34-
|
||||
pickPixel.show();
|
||||
pickPixel.connect('finished', (pickPixel, coords) => {
|
||||
if (coords)
|
||||
screenshot.pick_color(...coords, (o, res) => {
|
||||
let [, color] = screenshot.pick_color_finish(res);
|
||||
this._onColorPicked(color);
|
||||
});
|
||||
else
|
||||
this.initPointerCursor();
|
||||
});
|
||||
}
|
||||
} catch(e) {
|
||||
log(`${Me.metadata.uuid}: color picker failed: ${e.message}`);
|
||||
this.initPointerCursor();
|
||||
}
|
||||
},
|
||||
|
||||
toggleHelp: function() {
|
||||
if (this.helper.visible) {
|
||||
this.helper.hideHelp();
|
||||
|
|
@ -1120,7 +1181,7 @@ var DrawingArea = new Lang.Class({
|
|||
|
||||
elements.push(...JSON.parse(json.contents).map(object => {
|
||||
if (object.color)
|
||||
object.color = getClutterColorFromString(object.color, 'white');
|
||||
object.color = getColorFromString(object.color, 'White');
|
||||
if (object.font && typeof object.font == 'string')
|
||||
object.font = Pango.FontDescription.from_string(object.font);
|
||||
if (object.image)
|
||||
|
|
@ -1227,7 +1288,7 @@ var DrawingArea = new Lang.Class({
|
|||
|
||||
this.elements.push(...JSON.parse(json.contents).map(object => {
|
||||
if (object.color)
|
||||
object.color = getClutterColorFromString(object.color, 'white');
|
||||
object.color = getColorFromString(object.color, 'White');
|
||||
if (object.font && typeof object.font == 'string')
|
||||
object.font = Pango.FontDescription.from_string(object.font);
|
||||
if (object.image)
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ const AreaManager = new Lang.Class({
|
|||
'save-as-json': this.activeArea.saveAsJson.bind(this.activeArea, true, null),
|
||||
'open-previous-json': this.activeArea.loadPreviousJson.bind(this.activeArea),
|
||||
'open-next-json': this.activeArea.loadNextJson.bind(this.activeArea),
|
||||
'pick-color': this.activeArea.pickColor.bind(this.activeArea),
|
||||
'toggle-background': this.activeArea.toggleBackground.bind(this.activeArea),
|
||||
'toggle-grid': this.activeArea.toggleGrid.bind(this.activeArea),
|
||||
'toggle-square-area': this.activeArea.toggleSquareArea.bind(this.activeArea),
|
||||
|
|
|
|||
1
files.js
1
files.js
|
|
@ -41,6 +41,7 @@ const ICON_NAMES = [
|
|||
'tool-ellipse', 'tool-line', 'tool-mirror', 'tool-move', 'tool-none', 'tool-polygon', 'tool-polyline', 'tool-rectangle', 'tool-resize',
|
||||
];
|
||||
const ThemedIconNames = {
|
||||
COLOR_PICKER: 'color-select-symbolic',
|
||||
ENTER: 'applications-graphics', LEAVE: 'application-exit',
|
||||
GRAB: 'input-touchpad', UNGRAB: 'touchpad-disabled',
|
||||
OPEN: 'document-open', SAVE: 'document-save',
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: Draw On Your Screen\n"
|
||||
"Report-Msgid-Bugs-To: https://framagit.org/abakkk/DrawOnYourScreen/issues\n"
|
||||
"POT-Creation-Date: 2020-09-18 11:37+0200\n"
|
||||
"POT-Creation-Date: 2020-09-19 15:32+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
|
@ -47,6 +47,11 @@ msgstr ""
|
|||
msgid "Type your text and press <i>%s</i>"
|
||||
msgstr ""
|
||||
|
||||
#. Translators: It is displayed in an OSD notification to ask the user to start picking, so it should use the imperative mood.
|
||||
msgctxt "osd-notification"
|
||||
msgid "Pick a color"
|
||||
msgstr ""
|
||||
|
||||
#. Translators: "released" as the opposite of "grabbed"
|
||||
msgid "Keyboard and pointer released"
|
||||
msgstr ""
|
||||
|
|
@ -284,6 +289,10 @@ msgstr ""
|
|||
msgid "Color"
|
||||
msgstr ""
|
||||
|
||||
#. Translators: It is displayed in a menu button tooltip or as a shortcut action description, so it should NOT use the imperative mood.
|
||||
msgid "Pick a color"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add to images"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
11
menu.js
11
menu.js
|
|
@ -483,6 +483,17 @@ var DrawingMenu = new Lang.Class({
|
|||
item.icon.set_gicon(icon);
|
||||
item.icon.set_style(`color:${this.area.currentColor.to_string().slice(0, 7)};`);
|
||||
|
||||
if (GS_VERSION >= '3.30') {
|
||||
let colorPickerCallback = () => {
|
||||
this.close();
|
||||
this.area.pickColor();
|
||||
};
|
||||
// Translators: It is displayed in a menu button tooltip or as a shortcut action description, so it should NOT use the imperative mood.
|
||||
let colorPickerButton = new ActionButton(_("Pick a color"), Files.Icons.COLOR_PICKER, colorPickerCallback, null, true);
|
||||
let index = getActor(item).get_children().length - 1;
|
||||
getActor(item).insert_child_at_index(colorPickerButton, index);
|
||||
}
|
||||
|
||||
item.menu.itemActivated = item.menu.close;
|
||||
|
||||
this._populateColorSubMenu();
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -164,6 +164,10 @@
|
|||
<default>["<Primary>v"]</default>
|
||||
<summary>Add images from the clipboard</summary>
|
||||
</key>
|
||||
<key type="as" name="pick-color">
|
||||
<default><![CDATA[['<Primary>KP_0','<Primary>0']]]></default>
|
||||
<summary>Pick a color</summary>
|
||||
</key>
|
||||
<key type="as" name="redo">
|
||||
<default>["<Primary><Shift>z"]</default>
|
||||
<summary>Redo last brushstroke</summary>
|
||||
|
|
|
|||
11
shortcuts.js
11
shortcuts.js
|
|
@ -46,7 +46,7 @@ var INTERNAL_KEYBINDINGS = [
|
|||
['undo', 'redo', 'delete-last-element', 'smooth-last-element'],
|
||||
['select-none-shape', 'select-line-shape', 'select-ellipse-shape', 'select-rectangle-shape', 'select-polygon-shape', 'select-polyline-shape',
|
||||
'select-text-shape', 'select-image-shape', 'select-move-tool', 'select-resize-tool', 'select-mirror-tool'],
|
||||
['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse'],
|
||||
['switch-fill', 'switch-fill-rule', 'switch-color-palette', 'switch-color-palette-reverse', 'pick-color'],
|
||||
['increment-line-width', 'increment-line-width-more', 'decrement-line-width', 'decrement-line-width-more',
|
||||
'switch-linejoin', 'switch-linecap', 'switch-dash'],
|
||||
['switch-font-family', 'switch-font-family-reverse', 'switch-font-weight', 'switch-font-style', 'switch-text-alignment'],
|
||||
|
|
@ -55,6 +55,15 @@ var INTERNAL_KEYBINDINGS = [
|
|||
['open-next-json', 'open-previous-json', 'save-as-json', 'export-to-svg', 'open-preferences', 'toggle-help'],
|
||||
];
|
||||
|
||||
if (GS_VERSION < '3.30') {
|
||||
// Remove 'pick-color' keybinding.
|
||||
INTERNAL_KEYBINDINGS.forEach(settingKeys => {
|
||||
let index = settingKeys.indexOf('pick-color');
|
||||
if (index != -1)
|
||||
settingKeys.splice(index, 1);
|
||||
});
|
||||
}
|
||||
|
||||
if (GS_VERSION < '3.36') {
|
||||
// Remove 'open-preferences' keybinding.
|
||||
INTERNAL_KEYBINDINGS.forEach(settingKeys => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue