diff --git a/data/theme/gnome-shell-sass/widgets/_quick-settings.scss b/data/theme/gnome-shell-sass/widgets/_quick-settings.scss index f1f2eb235..664f24ca8 100644 --- a/data/theme/gnome-shell-sass/widgets/_quick-settings.scss +++ b/data/theme/gnome-shell-sass/widgets/_quick-settings.scss @@ -39,6 +39,19 @@ } } +.quick-slider { + padding: $base_padding; + + .slider-bin { + &:focus {@include button(focus);} + min-height: 16px; // slider size + padding: $base_padding; + border-radius: 99px; + } + .quick-toggle-icon { icon-size: $base_icon_size; } + .icon-button { background-color: transparent; } +} + .quick-toggle-menu { @include card(); padding: 1.5 * $base_padding; diff --git a/js/ui/quickSettings.js b/js/ui/quickSettings.js index ecffc9879..889833a73 100644 --- a/js/ui/quickSettings.js +++ b/js/ui/quickSettings.js @@ -1,8 +1,9 @@ -/* exported QuickToggle, QuickMenuToggle, QuickSettingsMenu, SystemIndicator */ +/* exported QuickToggle, QuickMenuToggle, QuickSlider, QuickSettingsMenu, SystemIndicator */ const {Atk, Clutter, Gio, GLib, GObject, Graphene, Pango, St} = imports.gi; const Main = imports.ui.main; const PopupMenu = imports.ui.popupMenu; +const {Slider} = imports.ui.slider; const {PopupAnimation} = imports.ui.boxpointer; @@ -131,6 +132,88 @@ var QuickMenuToggle = GObject.registerClass({ } }); +var QuickSlider = GObject.registerClass({ + Properties: { + 'icon-name': GObject.ParamSpec.override('icon-name', St.Button), + 'gicon': GObject.ParamSpec.object('gicon', '', '', + GObject.ParamFlags.READWRITE, + Gio.Icon), + 'menu-enabled': GObject.ParamSpec.boolean( + 'menu-enabled', '', '', + GObject.ParamFlags.READWRITE, + false), + }, +}, class QuickSlider extends QuickSettingsItem { + _init(params) { + super._init({ + style_class: 'quick-slider', + ...params, + can_focus: false, + reactive: false, + hasMenu: true, + }); + + const box = new St.BoxLayout(); + this.set_child(box); + + const iconProps = {}; + if (this.gicon) + iconProps['gicon'] = this.gicon; + if (this.iconName) + iconProps['icon-name'] = this.iconName; + + this._icon = new St.Icon({ + style_class: 'quick-toggle-icon', + ...iconProps, + }); + box.add_child(this._icon); + + // bindings are in the "wrong" direction, so we + // pick up StIcon's linking of the two properties + this._icon.bind_property('icon-name', + this, 'icon-name', + GObject.BindingFlags.SYNC_CREATE | + GObject.BindingFlags.BIDIRECTIONAL); + this._icon.bind_property('gicon', + this, 'gicon', + GObject.BindingFlags.SYNC_CREATE | + GObject.BindingFlags.BIDIRECTIONAL); + + this.slider = new Slider(0); + + // for focus indication + const sliderBin = new St.Bin({ + style_class: 'slider-bin', + child: this.slider, + reactive: true, + can_focus: true, + x_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); + box.add_child(sliderBin); + + sliderBin.connect('event', (bin, event) => this.slider.event(event, false)); + + this._menuButton = new St.Button({ + child: new St.Icon({icon_name: 'go-next-symbolic'}), + style_class: 'icon-button', + can_focus: true, + x_expand: false, + y_expand: true, + }); + box.add_child(this._menuButton); + + this.bind_property('menu-enabled', + this._menuButton, 'visible', + GObject.BindingFlags.SYNC_CREATE); + this._menuButton.connect('clicked', () => this.menu.open()); + this.slider.connect('popup-menu', () => { + if (this.menuEnabled) + this.menu.open(); + }); + } +}); + class QuickToggleMenu extends PopupMenu.PopupMenuBase { constructor(sourceActor) { super(sourceActor, 'quick-toggle-menu');