2019-03-05 08:36:59 -03:00
/* jslint esversion: 6 */
2020-08-31 06:05:33 -03:00
/* exported DrawingMenu */
2019-03-05 08:36:59 -03:00
/ *
* Copyright 2019 Abakkk
*
2019-12-28 09:25:41 -03:00
* This file is part of DrawOnYourScreen , a drawing extension for GNOME Shell .
2019-03-05 08:36:59 -03:00
* https : //framagit.org/abakkk/DrawOnYourScreen
*
* 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 2 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 < http : //www.gnu.org/licenses/>.
* /
const Clutter = imports . gi . Clutter ;
2019-03-29 12:35:18 -03:00
const Gio = imports . gi . Gio ;
2019-03-05 08:36:59 -03:00
const GLib = imports . gi . GLib ;
2019-03-26 18:28:24 -03:00
const GObject = imports . gi . GObject ;
2019-03-05 08:36:59 -03:00
const Gtk = imports . gi . Gtk ;
const Lang = imports . lang ;
const St = imports . gi . St ;
2019-03-26 18:28:24 -03:00
const BoxPointer = imports . ui . boxpointer ;
2019-10-11 04:22:37 -03:00
const Config = imports . misc . config ;
2019-03-26 18:28:24 -03:00
const Main = imports . ui . main ;
const PopupMenu = imports . ui . popupMenu ;
const Slider = imports . ui . slider ;
2019-03-05 08:36:59 -03:00
const ExtensionUtils = imports . misc . extensionUtils ;
2020-01-05 11:44:51 -03:00
const Me = ExtensionUtils . getCurrentExtension ( ) ;
2020-07-04 03:42:45 -03:00
const Area = Me . imports . area ;
2020-07-04 03:35:59 -03:00
const Elements = Me . imports . elements ;
2020-08-04 21:00:20 -03:00
const Files = Me . imports . files ;
2020-01-06 11:29:01 -03:00
const _ = imports . gettext . domain ( Me . metadata [ 'gettext-domain' ] ) . gettext ;
2019-03-05 08:36:59 -03:00
2019-10-11 04:22:37 -03:00
const GS _VERSION = Config . PACKAGE _VERSION ;
2020-06-08 15:50:23 -03:00
const ICON _DIR = Me . dir . get _child ( 'data' ) . get _child ( 'icons' ) ;
2020-07-11 15:41:04 -03:00
const SMOOTH _ICON _PATH = ICON _DIR . get _child ( 'smooth-symbolic.svg' ) . get _path ( ) ;
2020-08-31 04:43:00 -03:00
const PALETTE _ICON _PATH = ICON _DIR . get _child ( 'palette-symbolic.svg' ) . get _path ( ) ;
2020-06-27 06:42:53 -03:00
const COLOR _ICON _PATH = ICON _DIR . get _child ( 'color-symbolic.svg' ) . get _path ( ) ;
2020-06-08 15:50:23 -03:00
const FILL _ICON _PATH = ICON _DIR . get _child ( 'fill-symbolic.svg' ) . get _path ( ) ;
const STROKE _ICON _PATH = ICON _DIR . get _child ( 'stroke-symbolic.svg' ) . get _path ( ) ;
const LINEJOIN _ICON _PATH = ICON _DIR . get _child ( 'linejoin-symbolic.svg' ) . get _path ( ) ;
const LINECAP _ICON _PATH = ICON _DIR . get _child ( 'linecap-symbolic.svg' ) . get _path ( ) ;
const FILLRULE _NONZERO _ICON _PATH = ICON _DIR . get _child ( 'fillrule-nonzero-symbolic.svg' ) . get _path ( ) ;
const FILLRULE _EVENODD _ICON _PATH = ICON _DIR . get _child ( 'fillrule-evenodd-symbolic.svg' ) . get _path ( ) ;
const DASHED _LINE _ICON _PATH = ICON _DIR . get _child ( 'dashed-line-symbolic.svg' ) . get _path ( ) ;
const FULL _LINE _ICON _PATH = ICON _DIR . get _child ( 'full-line-symbolic.svg' ) . get _path ( ) ;
2019-03-26 18:28:24 -03:00
2020-08-05 18:30:25 -03:00
// 150 labels with font-family style take ~15Mo
const FONT _FAMILY _STYLE = true ;
2020-08-31 06:05:33 -03:00
// use 'login-dialog-message-warning' class in order to get GS theme warning color (default: #f57900)
const WARNING _COLOR _STYLE _CLASS _NAME = 'login-dialog-message-warning' ;
2020-08-05 18:30:25 -03:00
2020-03-02 12:32:50 -03:00
const getActor = function ( object ) {
2020-01-01 21:38:57 -03:00
return GS _VERSION < '3.33.0' ? object . actor : object ;
2020-03-02 12:32:50 -03:00
} ;
2020-01-01 21:38:57 -03:00
2020-07-03 17:51:23 -03:00
var DrawingMenu = new Lang . Class ( {
2019-03-26 18:28:24 -03:00
Name : 'DrawOnYourScreenDrawingMenu' ,
2019-12-29 11:26:20 -03:00
_init : function ( area , monitor ) {
2019-03-26 18:28:24 -03:00
this . area = area ;
let side = Clutter . get _default _text _direction ( ) == Clutter . TextDirection . RTL ? St . Side . RIGHT : St . Side . LEFT ;
this . menu = new PopupMenu . PopupMenu ( Main . layoutManager . dummyCursor , 0.25 , side ) ;
2019-10-11 04:22:37 -03:00
this . menuManager = new PopupMenu . PopupMenuManager ( GS _VERSION < '3.33.0' ? { actor : this . area } : this . area ) ;
2019-03-26 18:28:24 -03:00
this . menuManager . addMenu ( this . menu ) ;
Main . layoutManager . uiGroup . add _actor ( this . menu . actor ) ;
this . menu . actor . add _style _class _name ( 'background-menu draw-on-your-screen-menu' ) ;
2019-12-29 11:26:20 -03:00
this . menu . actor . set _style ( 'max-height:' + monitor . height + 'px;' ) ;
2019-03-26 18:28:24 -03:00
this . menu . actor . hide ( ) ;
2020-06-05 17:45:11 -03:00
this . hasSeparators = monitor . height >= 750 ;
2019-03-26 18:28:24 -03:00
// do not close the menu on item activated
this . menu . itemActivated = ( ) => { } ;
this . menu . connect ( 'open-state-changed' , this . _onMenuOpenStateChanged . bind ( this ) ) ;
2019-03-29 12:35:18 -03:00
2020-01-05 08:36:42 -03:00
// Case where the menu is closed (escape key) while the save entry clutter_text is active:
// St.Entry clutter_text set the DEFAULT cursor on leave event with a delay and
// overrides the cursor set by area.updatePointerCursor().
// In order to update drawing cursor on menu closed, we need to leave the saveEntry before closing menu.
// Since escape key press event can't be captured easily, the job is done in the menu close function.
let menuCloseFunc = this . menu . close ;
this . menu . close = ( animate ) => {
2020-02-09 12:43:21 -03:00
if ( this . saveDrawingSubMenu && this . saveDrawingSubMenu . isOpen )
2020-01-05 08:36:42 -03:00
this . saveDrawingSubMenu . close ( ) ;
menuCloseFunc . bind ( this . menu ) ( animate ) ;
} ;
2020-08-31 04:43:00 -03:00
this . paletteIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( PALETTE _ICON _PATH ) } ) ;
2020-06-27 06:42:53 -03:00
this . colorIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( COLOR _ICON _PATH ) } ) ;
2020-07-11 15:41:04 -03:00
this . smoothIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( SMOOTH _ICON _PATH ) } ) ;
2019-03-29 12:35:18 -03:00
this . strokeIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( STROKE _ICON _PATH ) } ) ;
this . fillIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( FILL _ICON _PATH ) } ) ;
2020-06-08 15:50:23 -03:00
this . fillRuleNonzeroIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( FILLRULE _NONZERO _ICON _PATH ) } ) ;
this . fillRuleEvenoddIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( FILLRULE _EVENODD _ICON _PATH ) } ) ;
2019-03-29 12:35:18 -03:00
this . linejoinIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( LINEJOIN _ICON _PATH ) } ) ;
this . linecapIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( LINECAP _ICON _PATH ) } ) ;
this . fullLineIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( FULL _LINE _ICON _PATH ) } ) ;
this . dashedLineIcon = new Gio . FileIcon ( { file : Gio . File . new _for _path ( DASHED _LINE _ICON _PATH ) } ) ;
2019-03-26 18:28:24 -03:00
} ,
2019-03-27 10:23:34 -03:00
disable : function ( ) {
this . menuManager . removeMenu ( this . menu ) ;
Main . layoutManager . uiGroup . remove _actor ( this . menu . actor ) ;
2020-06-22 09:38:42 -03:00
this . menu . destroy ( ) ;
2019-03-27 10:23:34 -03:00
} ,
2019-03-26 18:28:24 -03:00
_onMenuOpenStateChanged : function ( menu , open ) {
2019-11-27 02:04:37 -03:00
if ( open ) {
this . area . setPointerCursor ( 'DEFAULT' ) ;
} else {
this . area . updatePointerCursor ( ) ;
2019-03-26 18:28:24 -03:00
// actionMode has changed, set previous actionMode in order to keep internal shortcuts working
2020-06-25 06:41:15 -03:00
this . area . updateActionMode ( ) ;
2020-01-05 08:36:42 -03:00
this . area . grab _key _focus ( ) ;
2019-11-27 02:04:37 -03:00
}
2019-03-26 18:28:24 -03:00
} ,
2019-03-27 10:23:34 -03:00
popup : function ( ) {
if ( this . menu . isOpen ) {
this . close ( ) ;
} else {
this . open ( ) ;
this . menu . actor . navigate _focus ( null , Gtk . DirectionType . TAB _FORWARD , false ) ;
}
} ,
2019-03-26 18:28:24 -03:00
open : function ( x , y ) {
2019-03-27 10:23:34 -03:00
if ( this . menu . isOpen )
return ;
if ( x === undefined || y === undefined )
[ x , y ] = [ this . area . monitor . x + this . area . monitor . width / 2 , this . area . monitor . y + this . area . monitor . height / 2 ] ;
2019-03-26 18:28:24 -03:00
this . _redisplay ( ) ;
Main . layoutManager . setDummyCursorGeometry ( x , y , 0 , 0 ) ;
let monitor = this . area . monitor ;
this . menu . _arrowAlignment = ( y - monitor . y ) / monitor . height ;
this . menu . open ( BoxPointer . PopupAnimation . NONE ) ;
this . menuManager . ignoreRelease ( ) ;
} ,
2019-03-27 10:23:34 -03:00
close : function ( ) {
if ( this . menu . isOpen )
this . menu . close ( ) ;
} ,
2019-03-26 18:28:24 -03:00
_redisplay : function ( ) {
this . menu . removeAll ( ) ;
2020-07-13 07:53:01 -03:00
this . actionButtons = [ ] ;
2020-07-11 15:41:04 -03:00
let groupItem = new PopupMenu . PopupBaseMenuItem ( { reactive : false , can _focus : false , style _class : "draw-on-your-screen-menu-group-item" } ) ;
2020-08-07 19:27:41 -03:00
getActor ( groupItem ) . add _child ( this . _createActionButton ( _ ( "Undo" ) , this . area . undo . bind ( this . area ) , 'edit-undo-symbolic' ) ) ;
getActor ( groupItem ) . add _child ( this . _createActionButton ( _ ( "Redo" ) , this . area . redo . bind ( this . area ) , 'edit-redo-symbolic' ) ) ;
getActor ( groupItem ) . add _child ( this . _createActionButton ( _ ( "Erase" ) , this . area . deleteLastElement . bind ( this . area ) , 'edit-clear-all-symbolic' ) ) ;
getActor ( groupItem ) . add _child ( this . _createActionButton ( _ ( "Smooth" ) , this . area . smoothLastElement . bind ( this . area ) , this . smoothIcon ) ) ;
2020-07-11 15:41:04 -03:00
this . menu . addMenuItem ( groupItem ) ;
this . _addSeparator ( this . menu , true ) ;
2019-03-26 18:28:24 -03:00
2020-07-04 03:42:45 -03:00
this . _addSubMenuItem ( this . menu , 'document-edit-symbolic' , Area . ToolNames , this . area , 'currentTool' , this . _updateSectionVisibility . bind ( this ) ) ;
2020-08-31 04:43:00 -03:00
this . paletteItem = this . _addPaletteSubMenuItem ( this . menu ) ;
2020-07-13 07:53:01 -03:00
this . colorItem = this . _addColorSubMenuItem ( this . menu ) ;
2020-06-08 15:50:23 -03:00
this . fillItem = this . _addSwitchItem ( this . menu , _ ( "Fill" ) , this . strokeIcon , this . fillIcon , this . area , 'fill' , this . _updateSectionVisibility . bind ( this ) ) ;
this . fillSection = new PopupMenu . PopupMenuSection ( ) ;
2020-06-27 08:40:34 -03:00
this . fillSection . itemActivated = ( ) => { } ;
this . fillRuleItem = this . _addSwitchItem ( this . fillSection , _ ( "Evenodd" ) , this . fillRuleNonzeroIcon , this . fillRuleEvenoddIcon , this . area , 'currentEvenodd' ) ;
2020-06-08 15:50:23 -03:00
this . menu . addMenuItem ( this . fillSection ) ;
2019-03-27 18:11:51 -03:00
this . _addSeparator ( this . menu ) ;
2019-03-26 18:28:24 -03:00
2019-03-27 18:11:51 -03:00
let lineSection = new PopupMenu . PopupMenuSection ( ) ;
this . _addSliderItem ( lineSection , this . area , 'currentLineWidth' ) ;
2020-07-04 03:35:59 -03:00
this . _addSubMenuItem ( lineSection , this . linejoinIcon , Elements . LineJoinNames , this . area , 'currentLineJoin' ) ;
this . _addSubMenuItem ( lineSection , this . linecapIcon , Elements . LineCapNames , this . area , 'currentLineCap' ) ;
2019-03-29 12:35:18 -03:00
this . _addSwitchItem ( lineSection , _ ( "Dashed" ) , this . fullLineIcon , this . dashedLineIcon , this . area , 'dashedLine' ) ;
2019-03-27 18:11:51 -03:00
this . _addSeparator ( lineSection ) ;
this . menu . addMenuItem ( lineSection ) ;
2019-03-28 11:26:10 -03:00
lineSection . itemActivated = ( ) => { } ;
2019-03-27 18:11:51 -03:00
this . lineSection = lineSection ;
2019-03-26 18:28:24 -03:00
2019-03-27 18:11:51 -03:00
let fontSection = new PopupMenu . PopupMenuSection ( ) ;
2020-08-05 18:30:25 -03:00
this . _addFontFamilySubMenuItem ( fontSection , 'font-x-generic-symbolic' ) ;
2020-07-04 03:35:59 -03:00
this . _addSubMenuItem ( fontSection , 'format-text-bold-symbolic' , Elements . FontWeightNames , this . area , 'currentFontWeight' ) ;
this . _addSubMenuItem ( fontSection , 'format-text-italic-symbolic' , Elements . FontStyleNames , this . area , 'currentFontStyle' ) ;
2020-06-27 10:10:01 -03:00
this . _addSwitchItem ( fontSection , _ ( "Right aligned" ) , 'format-justify-left-symbolic' , 'format-justify-right-symbolic' , this . area , 'currentTextRightAligned' ) ;
2019-03-27 18:11:51 -03:00
this . _addSeparator ( fontSection ) ;
this . menu . addMenuItem ( fontSection ) ;
2020-06-27 10:10:01 -03:00
fontSection . itemActivated = ( ) => { } ;
2019-03-27 18:11:51 -03:00
this . fontSection = fontSection ;
2019-03-26 18:28:24 -03:00
2020-07-30 06:13:23 -03:00
let imageSection = new PopupMenu . PopupMenuSection ( ) ;
let images = this . area . getImages ( ) ;
if ( images . length ) {
if ( this . area . currentImage > images . length - 1 )
this . area . currentImage = images . length - 1 ;
this . _addSubMenuItem ( imageSection , null , images , this . area , 'currentImage' ) ;
}
this . _addSeparator ( imageSection ) ;
this . menu . addMenuItem ( imageSection ) ;
imageSection . itemActivated = ( ) => { } ;
this . imageSection = imageSection ;
2020-08-31 08:05:41 -03:00
let areaManager = Me . stateObj . areaManager ;
this . _addSimpleSwitchItem ( this . menu , _ ( "Hide panel and dock" ) , areaManager . hiddenList ? true : false , areaManager . togglePanelAndDockOpacity . bind ( areaManager ) ) ;
2020-06-08 15:50:23 -03:00
this . _addSimpleSwitchItem ( this . menu , _ ( "Add a drawing background" ) , this . area . hasBackground , this . area . toggleBackground . bind ( this . area ) ) ;
this . _addSimpleSwitchItem ( this . menu , _ ( "Add a grid overlay" ) , this . area . hasGrid , this . area . toggleGrid . bind ( this . area ) ) ;
this . _addSimpleSwitchItem ( this . menu , _ ( "Square drawing area" ) , this . area . isSquareArea , this . area . toggleSquareArea . bind ( this . area ) ) ;
2019-03-27 18:11:51 -03:00
this . _addSeparator ( this . menu ) ;
2019-03-26 18:28:24 -03:00
2020-01-03 20:16:20 -03:00
this . _addDrawingNameItem ( this . menu ) ;
this . _addOpenDrawingSubMenuItem ( this . menu ) ;
this . _addSaveDrawingSubMenuItem ( this . menu ) ;
this . menu . addAction ( _ ( "Save drawing as a SVG file" ) , this . area . saveAsSvg . bind ( this . area ) , 'image-x-generic-symbolic' ) ;
2020-08-31 08:05:41 -03:00
this . menu . addAction ( _ ( "Open preferences" ) , areaManager . openPreferences . bind ( areaManager ) , 'document-page-setup-symbolic' ) ;
2020-03-02 12:42:46 -03:00
this . menu . addAction ( _ ( "Show help" ) , ( ) => { this . close ( ) ; this . area . toggleHelp ( ) ; } , 'preferences-desktop-keyboard-shortcuts-symbolic' ) ;
2019-03-27 18:11:51 -03:00
2020-07-13 07:53:01 -03:00
this . _updateActionSensitivity ( ) ;
2020-06-08 15:50:23 -03:00
this . _updateSectionVisibility ( ) ;
2019-03-27 18:11:51 -03:00
} ,
2020-07-11 15:41:04 -03:00
// from system.js (GS 3.34-)
_createActionButton : function ( accessibleName , callback , icon ) {
2020-07-13 07:53:01 -03:00
let button = new St . Button ( { track _hover : true ,
2020-07-11 15:41:04 -03:00
x _align : Clutter . ActorAlign . CENTER ,
accessible _name : accessibleName ,
2020-07-13 07:53:01 -03:00
// use 'popup-menu' and 'popup-menu-item' style classes to provide theme colors
style _class : 'system-menu-action popup-menu-item popup-menu' } ) ;
2020-07-11 15:41:04 -03:00
button . child = new St . Icon ( typeof icon == 'string' ? { icon _name : icon } : { gicon : icon } ) ;
2020-07-13 07:53:01 -03:00
button . connect ( 'clicked' , ( ) => {
callback ( ) ;
this . _updateActionSensitivity ( ) ;
} ) ;
button . bind _property ( 'reactive' , button , 'can_focus' , GObject . BindingFlags . DEFAULT ) ;
this . actionButtons . push ( button ) ;
2020-07-11 15:41:04 -03:00
return new St . Bin ( { child : button , x _expand : true } ) ;
} ,
2020-07-13 07:53:01 -03:00
_updateActionSensitivity : function ( ) {
let [ undoButton , redoButton , eraseButton , smoothButton ] = this . actionButtons ;
undoButton . reactive = this . area . elements . length > 0 ;
redoButton . reactive = this . area . undoneElements . length > 0 ;
eraseButton . reactive = this . area . elements . length > 0 ;
smoothButton . reactive = this . area . elements . length > 0 && this . area . elements [ this . area . elements . length - 1 ] . shape == Area . Tools . NONE ;
} ,
2020-06-08 15:50:23 -03:00
_updateSectionVisibility : function ( ) {
2020-07-30 06:13:23 -03:00
let [ isText , isImage ] = [ this . area . currentTool == Area . Tools . TEXT , this . area . currentTool == Area . Tools . IMAGE ] ;
this . lineSection . actor . visible = ! isText && ! isImage ;
this . fontSection . actor . visible = isText ;
this . imageSection . actor . visible = isImage ;
this . colorItem . setSensitive ( ! isImage ) ;
2020-08-31 04:43:00 -03:00
this . paletteItem . setSensitive ( ! isImage ) ;
2020-07-30 06:13:23 -03:00
this . fillItem . setSensitive ( ! isText && ! isImage ) ;
this . fillSection . setSensitive ( ! isText && ! isImage ) ;
2020-06-08 15:50:23 -03:00
if ( this . area . fill )
this . fillSection . actor . show ( ) ;
else
this . fillSection . actor . hide ( ) ;
} ,
_addSwitchItem : function ( menu , label , iconFalse , iconTrue , target , targetProperty , onToggled ) {
2019-03-26 18:28:24 -03:00
let item = new PopupMenu . PopupSwitchMenuItem ( label , target [ targetProperty ] ) ;
2019-03-29 18:57:22 -03:00
item . icon = new St . Icon ( { style _class : 'popup-menu-icon' } ) ;
2020-01-01 21:38:57 -03:00
getActor ( item ) . insert _child _at _index ( item . icon , 1 ) ;
2020-06-27 10:10:01 -03:00
let icon = target [ targetProperty ] ? iconTrue : iconFalse ;
if ( icon && icon instanceof GObject . Object && GObject . type _is _a ( icon , Gio . Icon ) )
item . icon . set _gicon ( icon ) ;
else if ( icon )
item . icon . set _icon _name ( icon ) ;
2019-03-26 18:28:24 -03:00
item . connect ( 'toggled' , ( item , state ) => {
target [ targetProperty ] = state ;
2020-06-27 10:10:01 -03:00
let icon = target [ targetProperty ] ? iconTrue : iconFalse ;
if ( icon && icon instanceof GObject . Object && GObject . type _is _a ( icon , Gio . Icon ) )
item . icon . set _gicon ( icon ) ;
else if ( icon )
item . icon . set _icon _name ( icon ) ;
2020-06-08 15:50:23 -03:00
if ( onToggled )
onToggled ( ) ;
2019-03-26 18:28:24 -03:00
} ) ;
2019-03-27 18:11:51 -03:00
menu . addMenuItem ( item ) ;
2019-03-29 12:35:18 -03:00
return item ;
2019-03-26 18:28:24 -03:00
} ,
2020-06-08 15:50:23 -03:00
_addSimpleSwitchItem : function ( menu , label , active , onToggled ) {
2019-03-26 18:28:24 -03:00
let item = new PopupMenu . PopupSwitchMenuItem ( label , active ) ;
item . connect ( 'toggled' , onToggled ) ;
2019-03-27 18:11:51 -03:00
menu . addMenuItem ( item ) ;
2019-03-26 18:28:24 -03:00
} ,
2019-03-27 18:11:51 -03:00
_addSliderItem : function ( menu , target , targetProperty ) {
2019-03-26 18:28:24 -03:00
let item = new PopupMenu . PopupBaseMenuItem ( { activate : false } ) ;
2020-06-20 06:17:56 -03:00
let label = new St . Label ( { text : _ ( "%d px" ) . format ( target [ targetProperty ] ) , style _class : 'draw-on-your-screen-menu-slider-label' } ) ;
2019-03-26 18:28:24 -03:00
let slider = new Slider . Slider ( target [ targetProperty ] / 50 ) ;
2019-10-11 04:22:37 -03:00
if ( GS _VERSION < '3.33.0' ) {
slider . connect ( 'value-changed' , ( slider , value , property ) => {
2019-10-11 08:26:08 -03:00
target [ targetProperty ] = Math . max ( Math . round ( value * 50 ) , 0 ) ;
2019-10-11 04:22:37 -03:00
label . set _text ( target [ targetProperty ] + " px" ) ;
2019-10-11 08:26:08 -03:00
if ( target [ targetProperty ] === 0 )
2020-08-31 06:05:33 -03:00
label . add _style _class _name ( WARNING _COLOR _STYLE _CLASS _NAME ) ;
2019-10-11 08:26:08 -03:00
else
2020-08-31 06:05:33 -03:00
label . remove _style _class _name ( WARNING _COLOR _STYLE _CLASS _NAME ) ;
2019-10-11 04:22:37 -03:00
} ) ;
} else {
slider . connect ( 'notify::value' , ( ) => {
2019-10-11 08:26:08 -03:00
target [ targetProperty ] = Math . max ( Math . round ( slider . value * 50 ) , 0 ) ;
2019-10-11 04:22:37 -03:00
label . set _text ( target [ targetProperty ] + " px" ) ;
2019-10-11 08:26:08 -03:00
if ( target [ targetProperty ] === 0 )
2020-08-31 06:05:33 -03:00
label . add _style _class _name ( WARNING _COLOR _STYLE _CLASS _NAME ) ;
2019-10-11 08:26:08 -03:00
else
2020-08-31 06:05:33 -03:00
label . remove _style _class _name ( WARNING _COLOR _STYLE _CLASS _NAME ) ;
2019-10-11 04:22:37 -03:00
} ) ;
}
2019-03-26 18:28:24 -03:00
2020-03-10 20:09:21 -03:00
getActor ( slider ) . x _expand = true ;
getActor ( item ) . add _child ( getActor ( slider ) ) ;
getActor ( item ) . add _child ( label ) ;
if ( slider . onKeyPressEvent )
getActor ( item ) . connect ( 'key-press-event' , slider . onKeyPressEvent . bind ( slider ) ) ;
2019-03-27 18:11:51 -03:00
menu . addMenuItem ( item ) ;
2019-03-26 18:28:24 -03:00
} ,
2019-03-27 18:11:51 -03:00
_addSubMenuItem : function ( menu , icon , obj , target , targetProperty , callback ) {
2020-07-30 06:13:23 -03:00
if ( targetProperty == 'currentImage' )
icon = obj [ target [ targetProperty ] ] . gicon ;
let item = new PopupMenu . PopupSubMenuMenuItem ( _ ( String ( obj [ target [ targetProperty ] ] ) ) , icon ? true : false ) ;
2019-03-29 12:35:18 -03:00
if ( icon && icon instanceof GObject . Object && GObject . type _is _a ( icon , Gio . Icon ) )
2019-03-26 18:28:24 -03:00
item . icon . set _gicon ( icon ) ;
else if ( icon )
item . icon . set _icon _name ( icon ) ;
item . menu . itemActivated = ( ) => {
item . menu . close ( ) ;
} ;
2020-06-22 07:16:17 -03:00
GLib . idle _add ( GLib . PRIORITY _DEFAULT _IDLE , ( ) => {
2019-03-26 18:28:24 -03:00
for ( let i in obj ) {
2019-03-29 18:31:13 -03:00
let text ;
2020-08-05 18:30:25 -03:00
if ( targetProperty == 'currentFontWeight' )
2020-06-26 07:19:53 -03:00
text = ` <span font_weight=" ${ i } "> ${ _ ( obj [ i ] ) } </span> ` ;
2019-03-29 18:31:13 -03:00
else if ( targetProperty == 'currentFontStyle' )
text = ` <span font_style=" ${ obj [ i ] . toLowerCase ( ) } "> ${ _ ( obj [ i ] ) } </span> ` ;
else
2020-07-30 06:13:23 -03:00
text = _ ( String ( obj [ i ] ) ) ;
2019-03-29 18:31:13 -03:00
2020-06-15 17:13:03 -03:00
let iCaptured = Number ( i ) ;
2019-03-29 18:31:13 -03:00
let subItem = item . menu . addAction ( text , ( ) => {
2020-07-30 06:13:23 -03:00
item . label . set _text ( _ ( String ( obj [ iCaptured ] ) ) ) ;
2019-11-29 14:43:42 -03:00
target [ targetProperty ] = iCaptured ;
2020-07-30 06:13:23 -03:00
if ( targetProperty == 'currentImage' )
item . icon . set _gicon ( obj [ iCaptured ] . gicon ) ;
2019-03-27 18:11:51 -03:00
if ( callback )
callback ( ) ;
2019-03-26 18:28:24 -03:00
} ) ;
2019-03-29 18:31:13 -03:00
subItem . label . get _clutter _text ( ) . set _use _markup ( true ) ;
2020-08-06 17:10:12 -03:00
getActor ( subItem ) . connect ( 'key-focus-in' , updateSubMenuAdjustment ) ;
2020-06-07 13:57:11 -03:00
2020-06-13 08:53:52 -03:00
// change the display order of tools
2020-07-04 03:42:45 -03:00
if ( obj == Area . ToolNames && i == Area . Tools . POLYGON )
2020-06-07 13:57:11 -03:00
item . menu . moveMenuItem ( subItem , 4 ) ;
2020-07-04 03:42:45 -03:00
else if ( obj == Area . ToolNames && i == Area . Tools . POLYLINE )
2020-06-07 15:05:30 -03:00
item . menu . moveMenuItem ( subItem , 5 ) ;
2019-03-26 18:28:24 -03:00
}
return GLib . SOURCE _REMOVE ;
} ) ;
2019-03-27 18:11:51 -03:00
menu . addMenuItem ( item ) ;
2019-03-26 18:28:24 -03:00
} ,
2020-08-31 04:43:00 -03:00
_addPaletteSubMenuItem : function ( menu ) {
let text = _ ( this . area . currentPalette [ 0 ] || "Palette" ) ;
let item = new PopupMenu . PopupSubMenuMenuItem ( text , true ) ;
item . icon . set _gicon ( this . paletteIcon ) ;
item . menu . itemActivated = ( ) => {
item . menu . close ( ) ;
} ;
GLib . idle _add ( GLib . PRIORITY _DEFAULT _IDLE , ( ) => {
this . area . palettes . forEach ( palette => {
let [ name , colors ] = palette ;
if ( ! colors [ 0 ] )
return ;
let subItem = item . menu . addAction ( _ ( name || "Palette" ) , ( ) => {
item . label . set _text ( _ ( name || "Palette" ) ) ;
this . area . currentPalette = palette ;
this . _populateColorSubMenu ( ) ;
} ) ;
getActor ( subItem ) . connect ( 'key-focus-in' , updateSubMenuAdjustment ) ;
} ) ;
return GLib . SOURCE _REMOVE ;
} ) ;
menu . addMenuItem ( item ) ;
return item ;
} ,
2019-03-27 18:11:51 -03:00
_addColorSubMenuItem : function ( menu ) {
2019-03-26 18:28:24 -03:00
let item = new PopupMenu . PopupSubMenuMenuItem ( _ ( "Color" ) , true ) ;
2020-08-31 04:43:00 -03:00
this . colorSubMenu = item . menu ;
2020-06-27 06:42:53 -03:00
item . icon . set _gicon ( this . colorIcon ) ;
2019-03-26 18:28:24 -03:00
item . icon . set _style ( ` color: ${ this . area . currentColor . to _string ( ) . slice ( 0 , 7 ) } ; ` ) ;
item . menu . itemActivated = ( ) => {
item . menu . close ( ) ;
} ;
2020-08-31 04:43:00 -03:00
this . _populateColorSubMenu ( ) ;
menu . addMenuItem ( item ) ;
return item ;
} ,
_populateColorSubMenu : function ( ) {
this . colorSubMenu . removeAll ( ) ;
2020-06-22 07:16:17 -03:00
GLib . idle _add ( GLib . PRIORITY _DEFAULT _IDLE , ( ) => {
2020-08-31 04:43:00 -03:00
this . area . colors . forEach ( color => {
let text = color . string || color . to _string ( ) ;
let subItem = this . colorSubMenu . addAction ( text , ( ) => {
this . area . currentColor = color ;
this . colorItem . icon . set _style ( ` color: ${ color . to _string ( ) . slice ( 0 , 7 ) } ; ` ) ;
2019-03-26 18:28:24 -03:00
} ) ;
2020-06-01 14:28:06 -03:00
// Foreground color markup is not displayed since 3.36, use style instead but the transparency is lost.
2020-08-31 04:43:00 -03:00
subItem . label . set _style ( ` color: ${ color . to _string ( ) . slice ( 0 , 7 ) } ; ` ) ;
getActor ( subItem ) . connect ( 'key-focus-in' , updateSubMenuAdjustment ) ;
} ) ;
2019-03-26 18:28:24 -03:00
return GLib . SOURCE _REMOVE ;
} ) ;
} ,
2020-08-05 18:30:25 -03:00
_addFontFamilySubMenuItem : function ( menu , icon ) {
let item = new PopupMenu . PopupSubMenuMenuItem ( this . area . currentFontFamily , true ) ;
item . icon . set _icon _name ( icon ) ;
item . menu . itemActivated = ( ) => {
item . menu . close ( ) ;
} ;
item . menu . openOld = item . menu . open ;
item . menu . open = ( animate ) => {
if ( ! item . menu . isOpen && item . menu . isEmpty ( ) ) {
this . area . fontFamilies . forEach ( family => {
let subItem = item . menu . addAction ( _ ( family ) , ( ) => {
item . label . set _text ( _ ( family ) ) ;
this . area . currentFontFamily = family ;
} ) ;
if ( FONT _FAMILY _STYLE )
subItem . label . set _style ( ` font-family: ${ family } ` ) ;
2020-08-06 17:10:12 -03:00
getActor ( subItem ) . connect ( 'key-focus-in' , updateSubMenuAdjustment ) ;
2020-08-05 18:30:25 -03:00
} ) ;
}
item . menu . openOld ( ) ;
} ;
menu . addMenuItem ( item ) ;
} ,
2020-01-03 20:16:20 -03:00
_addDrawingNameItem : function ( menu ) {
this . drawingNameMenuItem = new PopupMenu . PopupMenuItem ( '' , { reactive : false , activate : false } ) ;
this . drawingNameMenuItem . setSensitive ( false ) ;
menu . addMenuItem ( this . drawingNameMenuItem ) ;
this . _updateDrawingNameMenuItem ( ) ;
} ,
_updateDrawingNameMenuItem : function ( ) {
getActor ( this . drawingNameMenuItem ) . visible = this . area . jsonName ? true : false ;
if ( this . area . jsonName ) {
2020-01-04 08:50:43 -03:00
let prefix = this . area . drawingContentsHasChanged ? "* " : "" ;
this . drawingNameMenuItem . label . set _text ( ` <i> ${ prefix } ${ this . area . jsonName } </i> ` ) ;
2020-01-03 20:16:20 -03:00
this . drawingNameMenuItem . label . get _clutter _text ( ) . set _use _markup ( true ) ;
}
} ,
_addOpenDrawingSubMenuItem : function ( menu ) {
let item = new PopupMenu . PopupSubMenuMenuItem ( _ ( "Open drawing" ) , true ) ;
this . openDrawingSubMenuItem = item ;
this . openDrawingSubMenu = item . menu ;
2020-08-05 18:30:25 -03:00
item . setSensitive ( Boolean ( Files . getJsons ( ) . length ) ) ;
2020-01-03 20:16:20 -03:00
item . icon . set _icon _name ( 'document-open-symbolic' ) ;
item . menu . itemActivated = ( ) => {
item . menu . close ( ) ;
} ;
2020-06-22 09:38:42 -03:00
item . menu . openOld = item . menu . open ;
item . menu . open = ( animate ) => {
if ( ! item . menu . isOpen )
this . _populateOpenDrawingSubMenu ( ) ;
item . menu . openOld ( ) ;
2020-06-25 06:41:15 -03:00
} ;
2020-06-22 09:38:42 -03:00
2020-01-03 20:16:20 -03:00
menu . addMenuItem ( item ) ;
} ,
_populateOpenDrawingSubMenu : function ( ) {
this . openDrawingSubMenu . removeAll ( ) ;
2020-08-04 21:00:20 -03:00
let jsons = Files . getJsons ( ) ;
jsons . forEach ( json => {
2020-08-06 17:10:12 -03:00
let subItem = this . openDrawingSubMenu . addAction ( ` <i> ${ String ( json ) } </i> ` , ( ) => {
2020-08-04 21:00:20 -03:00
this . area . loadJson ( json . name ) ;
2020-01-03 20:16:20 -03:00
this . _updateDrawingNameMenuItem ( ) ;
this . _updateSaveDrawingSubMenuItemSensitivity ( ) ;
} ) ;
2020-08-06 17:10:12 -03:00
subItem . label . get _clutter _text ( ) . set _use _markup ( true ) ;
getActor ( subItem ) . connect ( 'key-focus-in' , updateSubMenuAdjustment ) ;
2020-01-03 20:16:20 -03:00
let expander = new St . Bin ( {
style _class : 'popup-menu-item-expander' ,
x _expand : true ,
} ) ;
2020-08-06 17:10:12 -03:00
getActor ( subItem ) . add _child ( expander ) ;
2020-01-03 20:16:20 -03:00
let deleteButton = new St . Button ( { style _class : 'draw-on-your-screen-menu-delete-button' ,
child : new St . Icon ( { icon _name : 'edit-delete-symbolic' ,
style _class : 'popup-menu-icon' ,
x _align : Clutter . ActorAlign . END } ) } ) ;
2020-08-06 17:10:12 -03:00
getActor ( subItem ) . add _child ( deleteButton ) ;
2020-01-03 20:16:20 -03:00
deleteButton . connect ( 'clicked' , ( ) => {
2020-08-04 21:00:20 -03:00
json . delete ( ) ;
2020-08-06 17:10:12 -03:00
subItem . destroy ( ) ;
2020-08-04 21:49:52 -03:00
this . openDrawingSubMenuItem . setSensitive ( ! this . openDrawingSubMenu . isEmpty ( ) ) ;
2020-01-03 20:16:20 -03:00
} ) ;
} ) ;
this . openDrawingSubMenuItem . setSensitive ( ! this . openDrawingSubMenu . isEmpty ( ) ) ;
} ,
_addSaveDrawingSubMenuItem : function ( menu ) {
let item = new PopupMenu . PopupSubMenuMenuItem ( _ ( "Save drawing" ) , true ) ;
this . saveDrawingSubMenuItem = item ;
this . _updateSaveDrawingSubMenuItemSensitivity ( ) ;
this . saveDrawingSubMenu = item . menu ;
item . icon . set _icon _name ( 'document-save-symbolic' ) ;
item . menu . itemActivated = ( ) => {
item . menu . close ( ) ;
} ;
2020-06-22 09:38:42 -03:00
item . menu . openOld = item . menu . open ;
item . menu . open = ( animate ) => {
if ( ! item . menu . isOpen )
this . _populateSaveDrawingSubMenu ( ) ;
item . menu . openOld ( ) ;
2020-06-25 06:41:15 -03:00
} ;
2020-01-03 20:16:20 -03:00
menu . addMenuItem ( item ) ;
} ,
_updateSaveDrawingSubMenuItemSensitivity : function ( ) {
this . saveDrawingSubMenuItem . setSensitive ( this . area . elements . length > 0 ) ;
} ,
2020-08-04 21:49:52 -03:00
_onDrawingSaved ( ) {
this . _updateDrawingNameMenuItem ( ) ;
this . openDrawingSubMenuItem . setSensitive ( true ) ;
} ,
2020-01-03 20:16:20 -03:00
_populateSaveDrawingSubMenu : function ( ) {
2020-06-22 09:38:42 -03:00
this . saveDrawingSubMenu . removeAll ( ) ;
2020-08-04 21:00:20 -03:00
let saveEntry = new DrawingMenuEntry ( { initialTextGetter : Files . getDateString ,
2020-01-03 20:16:20 -03:00
entryActivateCallback : ( text ) => {
2020-08-04 21:49:52 -03:00
this . area . saveAsJsonWithName ( text , this . _onDrawingSaved . bind ( this ) ) ;
2020-01-03 20:16:20 -03:00
this . saveDrawingSubMenu . toggle ( ) ;
} ,
2020-01-10 08:32:28 -03:00
invalidStrings : [ Me . metadata [ 'persistent-file-name' ] , '/' ] ,
2020-01-03 20:16:20 -03:00
primaryIconName : 'insert-text' } ) ;
2020-06-22 09:38:42 -03:00
this . saveDrawingSubMenu . addMenuItem ( saveEntry . item ) ;
2020-01-03 20:16:20 -03:00
} ,
2020-07-11 15:41:04 -03:00
_addSeparator : function ( menu , thin ) {
2020-06-05 17:45:11 -03:00
if ( this . hasSeparators ) {
let separatorItem = new PopupMenu . PopupSeparatorMenuItem ( ' ' ) ;
getActor ( separatorItem ) . add _style _class _name ( 'draw-on-your-screen-menu-separator-item' ) ;
2020-07-11 15:41:04 -03:00
if ( thin )
getActor ( separatorItem ) . add _style _class _name ( 'draw-on-your-screen-menu-thin-separator-item' ) ;
2020-06-05 17:45:11 -03:00
menu . addMenuItem ( separatorItem ) ;
}
2019-03-26 18:28:24 -03:00
}
} ) ;
2020-08-06 17:10:12 -03:00
// based on ApplicationsButton.scrollToButton , https://gitlab.gnome.org/GNOME/gnome-shell-extensions/blob/master/extensions/apps-menu/extension.js
const updateSubMenuAdjustment = function ( itemActor ) {
let scrollView = itemActor . get _parent ( ) . get _parent ( ) ;
let adjustment = scrollView . get _vscroll _bar ( ) . get _adjustment ( ) ;
let scrollViewAlloc = scrollView . get _allocation _box ( ) ;
let currentScrollValue = adjustment . get _value ( ) ;
let height = scrollViewAlloc . y2 - scrollViewAlloc . y1 ;
let itemActorAlloc = itemActor . get _allocation _box ( ) ;
let newScrollValue = currentScrollValue ;
if ( currentScrollValue > itemActorAlloc . y1 - 10 )
newScrollValue = itemActorAlloc . y1 - 10 ;
if ( height + currentScrollValue < itemActorAlloc . y2 + 10 )
newScrollValue = itemActorAlloc . y2 - height + 10 ;
if ( newScrollValue != currentScrollValue )
adjustment . set _value ( newScrollValue ) ;
} ;
2020-01-03 20:16:20 -03:00
// based on searchItem.js, https://github.com/leonardo-bartoli/gnome-shell-extension-Recents
2020-03-02 12:32:50 -03:00
const DrawingMenuEntry = new Lang . Class ( {
2020-01-03 20:16:20 -03:00
Name : 'DrawOnYourScreenDrawingMenuEntry' ,
2020-03-02 12:32:50 -03:00
_init : function ( params ) {
2020-01-03 20:16:20 -03:00
this . params = params ;
this . item = new PopupMenu . PopupBaseMenuItem ( { style _class : 'draw-on-your-screen-menu-entry-item' ,
activate : false ,
reactive : true ,
can _focus : false } ) ;
this . itemActor = GS _VERSION < '3.33.0' ? this . item . actor : this . item ;
this . entry = new St . Entry ( {
style _class : 'search-entry draw-on-your-screen-menu-entry' ,
track _hover : true ,
reactive : true ,
2020-03-10 20:09:21 -03:00
can _focus : true ,
x _expand : true
2020-01-03 20:16:20 -03:00
} ) ;
this . entry . set _primary _icon ( new St . Icon ( { style _class : 'search-entry-icon' ,
icon _name : this . params . primaryIconName } ) ) ;
this . entry . clutter _text . connect ( 'text-changed' , this . _onTextChanged . bind ( this ) ) ;
this . entry . clutter _text . connect ( 'activate' , this . _onTextActivated . bind ( this ) ) ;
this . clearIcon = new St . Icon ( {
style _class : 'search-entry-icon' ,
icon _name : 'edit-clear-symbolic'
} ) ;
this . entry . connect ( 'secondary-icon-clicked' , this . _reset . bind ( this ) ) ;
2020-03-10 20:09:21 -03:00
getActor ( this . item ) . add _child ( this . entry ) ;
2020-01-03 20:16:20 -03:00
getActor ( this . item ) . connect ( 'notify::mapped' , ( actor ) => {
if ( actor . mapped ) {
this . entry . set _text ( this . params . initialTextGetter ( ) ) ;
this . entry . clutter _text . grab _key _focus ( ) ;
}
} ) ;
} ,
_setError : function ( hasError ) {
if ( hasError )
this . entry . add _style _class _name ( 'draw-on-your-screen-menu-entry-error' ) ;
else
this . entry . remove _style _class _name ( 'draw-on-your-screen-menu-entry-error' ) ;
} ,
_reset : function ( ) {
this . entry . text = '' ;
this . entry . clutter _text . set _cursor _visible ( true ) ;
this . entry . clutter _text . set _selection ( 0 , 0 ) ;
this . _setError ( false ) ;
} ,
_onTextActivated : function ( clutterText ) {
let text = clutterText . get _text ( ) ;
if ( text . length == 0 )
return ;
if ( this . _getIsInvalid ( ) )
return ;
this . _reset ( ) ;
this . params . entryActivateCallback ( text ) ;
} ,
_onTextChanged : function ( clutterText ) {
let text = clutterText . get _text ( ) ;
this . entry . set _secondary _icon ( text . length ? this . clearIcon : null ) ;
if ( text . length )
this . _setError ( this . _getIsInvalid ( ) ) ;
} ,
_getIsInvalid : function ( ) {
for ( let i = 0 ; i < this . params . invalidStrings . length ; i ++ ) {
if ( this . entry . text . indexOf ( this . params . invalidStrings [ i ] ) != - 1 )
return true ;
}
return false ;
}
} ) ;