Add toggle button (#304)
* Add toggle button * Toggle button documentation * Fix issues * Add env variable for toggle button * Add state update command for toggle buttons * Fix Uncrustify * Update README
This commit is contained in:
parent
69e92da659
commit
b7631c7de5
27
README.md
27
README.md
|
@ -38,6 +38,7 @@ Table of Contents
|
|||
* [Run](#run)
|
||||
* [Control Center Shortcuts](#control-center-shortcuts)
|
||||
* [Configuring](#configuring)
|
||||
* [Toggle Buttons](#toggle-buttons)
|
||||
* [Notification Inhibition](#notification-inhibition)
|
||||
* [Scripting](#scripting)
|
||||
* [Disable scripting](#disable-scripting)
|
||||
|
@ -242,6 +243,32 @@ to your `~/.config/swaync/` folder to customize without needing root access.
|
|||
**Tip**: running swaync with `GTK_DEBUG=interactive swaync` will open a inspector
|
||||
window that'll allow you to see all of the CSS classes + other information.
|
||||
|
||||
## Toggle Buttons
|
||||
|
||||
To add toggle buttons to your control center you can set the "type" in any acton to "toggle".
|
||||
The toggle button supports different commands depending on the state of the button and
|
||||
an "update_command" to update the state in case of changes from outside swaync. The update_command
|
||||
is called every time the control center is opened/closed.
|
||||
The active toggle button also gains the css-class ".toggle:checked"
|
||||
|
||||
`config.json` example:
|
||||
|
||||
```json
|
||||
{
|
||||
"buttons-gird": { // also works with actions in menubar widget
|
||||
"actions": [
|
||||
{
|
||||
"label": "WiFi",
|
||||
"type": "toggle",
|
||||
"active": true,
|
||||
"command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && nmcli radio wifi on || nmcli radio wifi off'",
|
||||
"update_command": "sh -c '[[ $(nmcli radio wifi) == \"enabled\" ]] && echo true || echo false'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Notification Inhibition
|
||||
|
||||
Notifications can be inhibited through the provided `swaync-client` executable
|
||||
|
|
|
@ -377,6 +377,22 @@ config file to be able to detect config errors
|
|||
type: string ++
|
||||
default: "" ++
|
||||
description: "Command to be executed on click" ++
|
||||
type: ++
|
||||
type: string ++
|
||||
default: "normal" ++
|
||||
description: Type of the button. ++
|
||||
Toggle buttons receive the '.active' css class ++
|
||||
enum: ["normal", "toggle"] ++
|
||||
update-command: ++
|
||||
type: string ++
|
||||
default: "" ++
|
||||
description: "Command to be executed on visibility change of ++
|
||||
cc to update the active state of the toggle button (should ++
|
||||
echo true or false)" ++
|
||||
active: ++
|
||||
type: bool ++
|
||||
default: false ++
|
||||
description: Wether the toggle button is active as default or not ++
|
||||
description: A list of actions containing a label and a command ++
|
||||
description: A button to reveal a dropdown with action-buttons ++
|
||||
buttons#<name>: ++
|
||||
|
@ -402,6 +418,24 @@ config file to be able to detect config errors
|
|||
type: string ++
|
||||
default: "" ++
|
||||
description: "Command to be executed on click" ++
|
||||
type: ++
|
||||
type: string ++
|
||||
default: "normal" ++
|
||||
description: Type of the button ++
|
||||
Toggle buttons receive the '.active' css class and an env ++
|
||||
variable "SWAYNC_TOGGLE_STATE" is set. See example usage in the ++
|
||||
default config.json ++
|
||||
enum: ["normal", "toggle"] ++
|
||||
update-command: ++
|
||||
type: string ++
|
||||
default: "" ++
|
||||
description: "Command to be executed on visibility change of ++
|
||||
cc to update the active state of the toggle button (should ++
|
||||
echo true or false)" ++
|
||||
active: ++
|
||||
type: bool ++
|
||||
default: false ++
|
||||
description: Wether the toggle button is active as default or not ++
|
||||
description: A list of actions containing a label and a command ++
|
||||
description: A list of buttons to be displayed in the menu-button-bar ++
|
||||
*buttons-grid*++
|
||||
|
@ -422,6 +456,18 @@ config file to be able to detect config errors
|
|||
type: string ++
|
||||
default: "" ++
|
||||
description: "Command to be executed on click" ++
|
||||
type: ++
|
||||
type: string ++
|
||||
default: "normal" ++
|
||||
description: Type of the button ++
|
||||
Toggle buttons receive the '.active' css class and an env ++
|
||||
variable "SWAYNC_TOGGLE_STATE" is set. See example usage in the ++
|
||||
default config.json ++
|
||||
enum: ["normal", "toggle"] ++
|
||||
active: ++
|
||||
type: bool ++
|
||||
default: false ++
|
||||
description: Wether the toggle button is active as default or not ++
|
||||
description: A list of actions containing a label and a command ++
|
||||
description: A grid of buttons that execute shell commands ++
|
||||
#START pulse-audio
|
||||
|
|
|
@ -74,6 +74,17 @@
|
|||
"mpris": {
|
||||
"image-size": 96,
|
||||
"image-radius": 12
|
||||
},
|
||||
"buttons-grid": {
|
||||
"actions": [
|
||||
{
|
||||
"label": "直",
|
||||
"type": "toggle",
|
||||
"active": true,
|
||||
"command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && nmcli radio wifi on || nmcli radio wifi off'",
|
||||
"update_command": "sh -c '[[ $(nmcli radio wifi) == \"enabled\" ]] && echo true || echo false'"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,6 +427,22 @@
|
|||
"type": "string",
|
||||
"description": "Command to be executed on click",
|
||||
"default": ""
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Type of the button; toggle buttons receive the .active css class and an env variable 'SWAYNC_TOGGLE_STATE' is set. See example in the default config.json",
|
||||
"default": "normal",
|
||||
"enum": ["normal", "toggle"]
|
||||
},
|
||||
"update-command": {
|
||||
"type": "string",
|
||||
"description": "Command to be executed on visibility change of cc to update the active state of the toggle button (should echo true or false)",
|
||||
"default": ""
|
||||
},
|
||||
"active": {
|
||||
"type": "bool",
|
||||
"description": "Wether the toggle button is active as default or not",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,20 @@ namespace SwayNotificationCenter.Widgets {
|
|||
public unowned SwayncDaemon swaync_daemon;
|
||||
public unowned NotiDaemon noti_daemon;
|
||||
|
||||
public enum ButtonType {
|
||||
TOGGLE,
|
||||
NORMAL;
|
||||
|
||||
public static ButtonType parse (string value) {
|
||||
switch (value) {
|
||||
case "toggle":
|
||||
return ButtonType.TOGGLE;
|
||||
default:
|
||||
return ButtonType.NORMAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected BaseWidget (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
this.suffix = suffix;
|
||||
this.key = widget_name + (suffix.length > 0 ? "#%s".printf (suffix) : "");
|
||||
|
@ -91,14 +105,23 @@ namespace SwayNotificationCenter.Widgets {
|
|||
for (int i = 0; i < actions.get_length (); i++) {
|
||||
string label = actions.get_object_element (i).get_string_member_with_default ("label", "label");
|
||||
string command = actions.get_object_element (i).get_string_member_with_default ("command", "");
|
||||
string t = actions.get_object_element (i).get_string_member_with_default ("type", "normal");
|
||||
ButtonType type = ButtonType.parse (t);
|
||||
string update_command =
|
||||
actions.get_object_element (i).get_string_member_with_default ("update-command", "");
|
||||
bool active = actions.get_object_element (i).get_boolean_member_with_default ("active", false);
|
||||
res[i] = Action () {
|
||||
label = label,
|
||||
command = command
|
||||
command = command,
|
||||
type = type,
|
||||
update_command = update_command,
|
||||
active = active
|
||||
};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
protected async void execute_command (string cmd, string[] env_additions = {}) {
|
||||
string msg = "";
|
||||
yield Functions.execute_command (cmd, env_additions, out msg);
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace SwayNotificationCenter.Widgets {
|
|||
}
|
||||
|
||||
Action[] actions;
|
||||
List<ToggleButton> toggle_buttons;
|
||||
|
||||
public ButtonsGrid (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
base (suffix, swaync_daemon, noti_daemon);
|
||||
|
@ -26,14 +27,29 @@ namespace SwayNotificationCenter.Widgets {
|
|||
|
||||
// add action to container
|
||||
foreach (var act in actions) {
|
||||
Gtk.Button b = new Gtk.Button.with_label (act.label);
|
||||
|
||||
b.clicked.connect (() => execute_command.begin (act.command));
|
||||
|
||||
container.insert (b, -1);
|
||||
switch (act.type) {
|
||||
case ButtonType.TOGGLE:
|
||||
ToggleButton tb = new ToggleButton (act.label, act.command, act.update_command, act.active);
|
||||
container.insert (tb, -1);
|
||||
toggle_buttons.append (tb);
|
||||
break;
|
||||
default:
|
||||
Gtk.Button b = new Gtk.Button.with_label (act.label);
|
||||
b.clicked.connect (() => execute_command.begin (act.command));
|
||||
container.insert (b, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
show_all ();
|
||||
}
|
||||
|
||||
public override void on_cc_visibility_change (bool value) {
|
||||
if (!value) {
|
||||
foreach (var tb in toggle_buttons) {
|
||||
tb.on_update.begin ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@ namespace SwayNotificationCenter.Widgets {
|
|||
public struct Action {
|
||||
string ? label;
|
||||
string ? command;
|
||||
BaseWidget.ButtonType ? type;
|
||||
string ? update_command;
|
||||
bool ? active;
|
||||
}
|
||||
|
||||
public class Menubar : BaseWidget {
|
||||
|
@ -38,6 +41,7 @@ namespace SwayNotificationCenter.Widgets {
|
|||
Gtk.Box topbar_container;
|
||||
|
||||
List<ConfigObject ?> menu_objects;
|
||||
List<ToggleButton> toggle_buttons;
|
||||
|
||||
public Menubar (string suffix, SwayncDaemon swaync_daemon, NotiDaemon noti_daemon) {
|
||||
base (suffix, swaync_daemon, noti_daemon);
|
||||
|
@ -74,11 +78,18 @@ namespace SwayNotificationCenter.Widgets {
|
|||
if (obj.name != null) container.get_style_context ().add_class (obj.name);
|
||||
|
||||
foreach (Action a in obj.actions) {
|
||||
Gtk.Button b = new Gtk.Button.with_label (a.label);
|
||||
|
||||
b.clicked.connect (() => execute_command.begin (a.command));
|
||||
|
||||
container.add (b);
|
||||
switch (a.type) {
|
||||
case ButtonType.TOGGLE:
|
||||
ToggleButton tb = new ToggleButton (a.label, a.command, a.update_command, a.active);
|
||||
container.add (tb);
|
||||
toggle_buttons.append (tb);
|
||||
break;
|
||||
default:
|
||||
Gtk.Button b = new Gtk.Button.with_label (a.label);
|
||||
b.clicked.connect (() => execute_command.begin (a.command));
|
||||
container.add (b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (obj.position) {
|
||||
case Position.LEFT:
|
||||
|
@ -210,6 +221,9 @@ namespace SwayNotificationCenter.Widgets {
|
|||
foreach (var obj in menu_objects) {
|
||||
obj.revealer ?.set_reveal_child (false);
|
||||
}
|
||||
foreach (var tb in toggle_buttons) {
|
||||
tb.on_update.begin ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
namespace SwayNotificationCenter.Widgets {
|
||||
class ToggleButton : Gtk.ToggleButton {
|
||||
|
||||
private string command;
|
||||
private string update_command;
|
||||
|
||||
public ToggleButton (string label, string command, string update_command, bool active) {
|
||||
this.command = command;
|
||||
this.update_command = update_command;
|
||||
this.label = label;
|
||||
|
||||
if (active) {
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
this.toggled.connect (on_toggle);
|
||||
}
|
||||
|
||||
private async void on_toggle () {
|
||||
string msg = "";
|
||||
string[] env_additions = { "SWAYNC_TOGGLE_STATE=" + this.active.to_string () };
|
||||
yield Functions.execute_command (this.command, env_additions, out msg);
|
||||
}
|
||||
|
||||
public async void on_update () {
|
||||
if (update_command == "") return;
|
||||
string msg = "";
|
||||
string[] env_additions = { "SWAYNC_TOGGLE_STATE=" + this.active.to_string () };
|
||||
yield Functions.execute_command (this.update_command, env_additions, out msg);
|
||||
try {
|
||||
// remove trailing whitespaces
|
||||
Regex regex = new Regex ("\\s+$");
|
||||
string res = regex.replace (msg, msg.length, 0, "");
|
||||
if (res.up () == "TRUE") {
|
||||
this.active = true;
|
||||
} else {
|
||||
this.active = false;
|
||||
}
|
||||
} catch (RegexError e) {
|
||||
stderr.printf ("RegexError: %s\n", e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -313,13 +313,38 @@ namespace SwayNotificationCenter {
|
|||
Shell.parse_argv (cmd, out argvp);
|
||||
|
||||
Pid child_pid;
|
||||
Process.spawn_async (
|
||||
int std_input;
|
||||
int std_output;
|
||||
int std_err;
|
||||
Process.spawn_async_with_pipes (
|
||||
"/",
|
||||
argvp,
|
||||
spawn_env,
|
||||
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
|
||||
null,
|
||||
out child_pid);
|
||||
out child_pid,
|
||||
out std_input,
|
||||
out std_output,
|
||||
out std_err);
|
||||
|
||||
// stdout:
|
||||
string res = "";
|
||||
IOChannel output = new IOChannel.unix_new (std_output);
|
||||
output.add_watch (IOCondition.IN | IOCondition.HUP, (channel, condition) => {
|
||||
if (condition == IOCondition.HUP) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
channel.read_line (out res, null, null);
|
||||
return true;
|
||||
} catch (IOChannelError e) {
|
||||
stderr.printf ("stdout: IOChannelError: %s\n", e.message);
|
||||
return false;
|
||||
} catch (ConvertError e) {
|
||||
stderr.printf ("stdout: ConvertError: %s\n", e.message);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Close the child when the spawned process is idling
|
||||
int end_status = 0;
|
||||
|
@ -330,6 +355,7 @@ namespace SwayNotificationCenter {
|
|||
});
|
||||
// Waits until `run_script.callback()` is called above
|
||||
yield;
|
||||
msg = res;
|
||||
return end_status == 0;
|
||||
} catch (Error e) {
|
||||
stderr.printf ("Run_Script Error: %s\n", e.message);
|
||||
|
|
|
@ -26,6 +26,7 @@ widget_sources = [
|
|||
# Helpers
|
||||
'controlCenter/widgets/baseWidget.vala',
|
||||
'controlCenter/widgets/factory.vala',
|
||||
'controlCenter/widgets/shared/toggleButton.vala',
|
||||
# Widget: Title
|
||||
'controlCenter/widgets/title/title.vala',
|
||||
# Widget: Dnd
|
||||
|
|
|
@ -282,8 +282,11 @@
|
|||
border-radius: 12px;
|
||||
}
|
||||
|
||||
/* style given to the active toggle button */
|
||||
.widget-buttons-grid>flowbox>flowboxchild>button.toggle:checked {
|
||||
}
|
||||
|
||||
.widget-buttons-grid>flowbox>flowboxchild>button:hover {
|
||||
background: @noti-bg-hover;
|
||||
}
|
||||
|
||||
/* Menubar widget */
|
||||
|
|
Loading…
Reference in New Issue