/* * Copyright 2019 Abakkk * Copyright 2024 Dave Prowse * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * 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 . * * SPDX-FileCopyrightText: 2019 Abakkk * SPDX-License-Identifier: GPL-3.0-or-later * SPDX-FileContributor: Modified by Dave Prowse */ /* jslint esversion: 6 (2019) */ /* eslint version: 9.16 (2024) */ /* exported DrawingHelper */ import Clutter from 'gi://Clutter'; import St from 'gi://St'; import GObject from 'gi://GObject'; import * as Shortcuts from './shortcuts.js'; import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js'; import { CURATED_UUID as UUID } from './utils.js'; import { SHELL_MAJOR_VERSION } from './utils.js'; import GLib from 'gi://GLib'; const HELPER_ANIMATION_TIME = 0.25; // DrawingHelper provides the "help osd" (Ctrl + F1) // It uses the same texts as in prefs //TODO: Review this class later export const DrawingHelper = GObject.registerClass({ GTypeName: `${UUID}-DrawingHelper`, }, class DrawingHelper extends St.ScrollView { _init(extension, params, monitor) { params.style_class = 'osd-window draw-on-gnome-helper'; super._init(params); this._extension = extension; this.monitor = monitor; this.hide(); this.settingsHandler = this._extension.settings.connect('changed', this._onSettingsChanged.bind(this)); this.internalShortcutsettingsHandler = this._extension.internalShortcutSettings.connect('changed', this._onSettingsChanged.bind(this)); this.connect('destroy', () => { this._extension.settings.disconnect(this.settingsHandler); this._extension.internalShortcutSettings.disconnect(this.internalShortcutsettingsHandler); }); } _onSettingsChanged(settings, key) { if (key == 'toggle-help') this._updateHelpKeyLabel(); if (this.vbox) { this.vbox.destroy(); delete this.vbox; } } _updateHelpKeyLabel() { try { this._helpKeyLabel = this._extension.internalShortcutSettings.get_strv('toggle-help')[0]; } catch(e) { logError(e); this._helpKeyLabel = " "; } } get helpKeyLabel() { if (!this._helpKeyLabel) this._updateHelpKeyLabel(); return GLib.markup_escape_text(this._helpKeyLabel, -1); } _populate() { this.vbox = new St.BoxLayout({ vertical: true }); this.add_child(this.vbox); this.vbox.add_child(new St.Label({ text: _("Global") })); Shortcuts.GLOBAL_KEYBINDINGS.forEach((settingKeys) => { this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' })); if (!this._extension.settings.get_strv(settingKeys)[0]) return; let hbox = new St.BoxLayout({ vertical: false }); let shortcut = this._extension.settings.get_strv(settingKeys)[0]; // Convert modifier keys shortcut = shortcut.replace(//g, 'Ctrl+') .replace(//g, 'Shift+') .replace(//g, 'Alt+') .replace(//g, 'Super+') // Remove KP_ prefix (numpad keys) .replace(/KP_/g, '') // Convert symbol names to actual symbols .replace(/equal/g, '=') .replace(/Multiply/g, '*') .replace(/Divide/g, '/') .replace(/Add/g, '+') .replace(/Subtract/g, '-') .replace(/period/g, '.') .replace(/comma/g, ',') .replace(/slash/g, '/') .replace(/minus/g, '-') .replace(/plus/g, '+') .replace(/asterisk/g, '*') // Uppercase single letters after + or at start .replace(/\+([a-z])$/g, (match, letter) => '+' + letter.toUpperCase()) .replace(/^([a-z])$/g, (match, letter) => letter.toUpperCase()); shortcut = GLib.markup_escape_text(shortcut, -1); hbox.add_child(new St.Label({ text: this._extension.settings.settings_schema.get_key(settingKeys).get_summary() })); let label = new St.Label({ text: "" + shortcut + "", x_expand: true }) label.get_clutter_text().set_use_markup(true); hbox.add_child(label); this.vbox.add_child(hbox); }); this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' })); this.vbox.add_child(new St.Label({ text: _("Internal") })); // Shortcuts.OTHERS.forEach((pairs, index) => { // if (index) // this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' })); // pairs.forEach(pair => { // let [action, shortcut] = pair; // let hbox = new St.BoxLayout({ vertical: false }); // hbox.add_child(new St.Label({ text: action })); // hbox.add_child(new St.Label({ text: shortcut, x_expand: true }).get_clutter_text().set_use_markup(true)); // hbox.get_children()[0]); // this.vbox.add_child(hbox); // }); // }); // this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' })); Shortcuts.INTERNAL_KEYBINDINGS.forEach((settingKeys) => { this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' })); if (!this._extension.internalShortcutSettings.get_strv(settingKeys)[0]) return; let hbox = new St.BoxLayout({ vertical: false }); let shortcut = this._extension.internalShortcutSettings.get_strv(settingKeys)[0]; // Convert modifier keys shortcut = shortcut.replace(//g, 'Ctrl+') .replace(//g, 'Shift+') .replace(//g, 'Alt+') .replace(//g, 'Super+') // Remove KP_ prefix (numpad keys) .replace(/KP_/g, '') // Convert symbol names to actual symbols .replace(/equal/g, '=') .replace(/Multiply/g, '*') .replace(/Divide/g, '/') .replace(/Add/g, '+') .replace(/Subtract/g, '-') .replace(/period/g, '.') .replace(/comma/g, ',') .replace(/slash/g, '/') .replace(/minus/g, '-') .replace(/plus/g, '+') .replace(/asterisk/g, '*') // Uppercase single letters after + or at start .replace(/\+([a-z])$/g, (match, letter) => '+' + letter.toUpperCase()) .replace(/^([a-z])$/g, (match, letter) => letter.toUpperCase()); shortcut = GLib.markup_escape_text(shortcut, -1); hbox.add_child(new St.Label({ text: this._extension.internalShortcutSettings.settings_schema.get_key(settingKeys).get_summary() })); let label = new St.Label({ text: "" + shortcut + "", x_expand: true }) label.get_clutter_text().set_use_markup(true); hbox.add_child(label); this.vbox.add_child(hbox); }); } showHelp() { if (!this.vbox) this._populate(); this.opacity = 0; this.show(); let maxHeight = this.monitor.height * 3 / 4; this.set_height(Math.min(this.height, maxHeight)); this.set_position(Math.floor(this.monitor.width / 2 - this.width / 2), Math.floor(this.monitor.height / 2 - this.height / 2)); // St.PolicyType: GS 3.32+ if (this.height == maxHeight) this.vscrollbar_policy = St.PolicyType ? St.PolicyType.ALWAYS : 1; else this.vscrollbar_policy = St.PolicyType ? St.PolicyType.NEVER : 0; this.remove_all_transitions(); this.ease({ opacity: 255, duration: HELPER_ANIMATION_TIME * 1000, mode: Clutter.AnimationMode.EASE_OUT_QUAD }); } hideHelp() { this.remove_all_transitions(); this.ease({ opacity: 0, duration: HELPER_ANIMATION_TIME * 1000, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => this.hide() }); } });