Allow renaming decks and inputs

This commit is contained in:
asonix 2021-05-06 00:07:07 -05:00
parent 225a8dd2d0
commit 585f5a79ba
10 changed files with 545 additions and 171 deletions

View file

@ -12,6 +12,8 @@ app_files = files(
'src/Data/SwitchScene.vala',
'src/Dialogs/EditCommandDialog.vala',
'src/Dialogs/NewCommandDialog.vala',
'src/Dialogs/EditDeckDialog.vala',
'src/Views/CommandsView.vala',
'src/Views/ConfigCommand.vala',
'src/Views/DeckStack.vala',
'src/Views/DeckView.vala',
@ -33,6 +35,7 @@ executable(
dependency('gdk-3.0'),
dependency('gee-0.8'),
dependency('gio-2.0'),
dependency('glib-2.0'),
dependency('granite'),
dependency('gtk+-3.0'),
dependency('json-glib-1.0'),

View file

@ -14,6 +14,11 @@ public struct Streamdeck.CommandInfo {
public string command;
}
public struct InputName {
public uint8 key;
public string name;
}
public class Streamdeck.Daemon : Object {
[DBus (name = "dog.asonix.git.asonix.Streamdeck")]
private interface StreamdeckBackend : Object {
@ -29,6 +34,10 @@ public class Streamdeck.Daemon : Object {
public async abstract ReadInput[] read_input () throws GLib.Error;
public async abstract void set_input (string serial_number, uint8 key, string command) throws GLib.Error;
public async abstract void unset_input (string serial_number, uint8 key) throws GLib.Error;
public async abstract void set_input_name (string serial_number, uint8 key, string name) throws GLib.Error;
public async abstract InputName[] get_input_names (string serial_number) throws GLib.Error;
public async abstract void set_deck_name (string serial_number, string name) throws GLib.Error;
public async abstract string get_deck_name (string serial_number) throws GLib.Error;
}
private static Daemon? _instance;
@ -48,6 +57,8 @@ public class Streamdeck.Daemon : Object {
private DeckInfo[] decks;
private string[] scenes;
private Gee.HashMap<string, Gee.ArrayList<CommandInfo?>> commands = new Gee.HashMap<string, Gee.ArrayList<CommandInfo?>> ();
private Gee.HashMap<string, Gee.HashMap<uint8, string>> input_names = new Gee.HashMap<string, Gee.HashMap<uint8, string>> ();
private Gee.HashMap<string, string> deck_names = new Gee.HashMap<string, string> ();
public signal void dbus_connection_signal ();
public signal void obs_state_signal (string state);
@ -55,27 +66,21 @@ public class Streamdeck.Daemon : Object {
public signal void on_decks_added (DeckInfo[] decks);
public signal void on_decks_removed (DeckInfo[] decks);
public signal void scenes_signal (string[] scenes);
public signal void commands_signal (string serial_number, CommandInfo[] commands);
public signal void commands_signal (string serial_number, Gee.ArrayList<CommandInfo?> commands);
public signal void key_press_signal (ReadInput key_press);
public signal void input_name_signal (string serial_number, uint8 key, string name);
public signal void deck_name_signal (string serial_number, string name);
construct {
dbus_connection_signal.connect ((_obj) => {
get_state.begin ((_obj, res) => {
try {
var state = get_state.end (res);
obs_state_signal (state);
} catch (Error e) {
print ("Get state error: %s\n", e.message);
}
});
do_load_state ();
do_load_decks ();
load_decks.begin ((_obj, res) => {
try {
var new_decks = load_decks.end (res);
decks_signal (new_decks);
} catch (Error e) {
print ("Get decks error: %s\n", e.message);
}
GLib.Timeout.add_seconds_full (GLib.Priority.DEFAULT, 3, () => {
do_load_state ();
do_load_decks ();
return true;
});
});
@ -100,6 +105,7 @@ public class Streamdeck.Daemon : Object {
foreach (DeckInfo deck_info in new_decks) {
update_command_cache (deck_info.serial_number);
update_name_cache (deck_info.serial_number);
}
});
@ -108,15 +114,7 @@ public class Streamdeck.Daemon : Object {
});
commands_signal.connect ((_obj, serial_number, new_commands) => {
var array_list = new Gee.ArrayList<CommandInfo?> ((a, b) => {
return a.key == b.key && a.command == b.command;
});
foreach (CommandInfo info in new_commands) {
array_list.add (info);
}
commands.set (serial_number, array_list);
commands.set (serial_number, new_commands);
});
Bus.get_proxy.begin<StreamdeckBackend> (
@ -156,6 +154,30 @@ public class Streamdeck.Daemon : Object {
return commands.get (serial_number);
}
public string? get_deck_name (string serial_number) {
return deck_names.get (serial_number);
}
public string? get_input_name (string serial_number, uint8 key) {
var hm = input_names.get (serial_number);
if (hm != null) {
return hm.get (key);
}
return null;
}
public async void set_deck_name (string serial_number, string name) throws GLib.Error {
disconnected_err ();
yield backend_object.set_deck_name (serial_number, name);
}
public async void set_input_name (string serial_number, uint8 key, string name) throws GLib.Error {
disconnected_err ();
yield backend_object.set_input_name (serial_number, key, name);
}
public async void add_command (string serial_number, uint8 key, string command) throws GLib.Error {
disconnected_err ();
@ -207,19 +229,66 @@ public class Streamdeck.Daemon : Object {
load_commands.begin (serial_number, (_obj, res) => {
try {
var new_commands = load_commands.end (res);
commands_signal (serial_number, new_commands);
var array_list = new Gee.ArrayList<CommandInfo?> ((a, b) => {
return a.key == b.key && a.command == b.command;
});
foreach (CommandInfo info in new_commands) {
array_list.add (info);
}
commands_signal (serial_number, array_list);
} catch (Error e) {
print ("Command fetch error: %s\n", e.message);
}
});
}
public void update_name_cache (string serial_number) {
load_deck_name.begin (serial_number, (_obj, res) => {
try {
var deck_name = load_deck_name.end (res);
deck_names.set(serial_number, deck_name);
deck_name_signal (serial_number, deck_name);
} catch {
// do nothing, this is fine
}
});
load_input_names.begin (serial_number, (_obj, res) => {
try {
var names = load_input_names.end (res);
foreach (InputName name in names) {
if (!input_names.has_key (serial_number)) {
input_names.set (serial_number, new Gee.HashMap<uint8, string> ());
}
var hm = input_names.get (serial_number);
hm.set (name.key, name.name);
input_name_signal (serial_number, name.key, name.name);
}
} catch (Error e) {
print ("Name fetch error: %s\n", e.message);
}
});
}
private async string[] load_scenes () throws GLib.Error {
disconnected_err ();
return yield backend_object.get_scenes ();
}
private void do_load_decks () {
load_decks.begin ((_obj, res) => {
try {
var new_decks = load_decks.end (res);
decks_signal (new_decks);
} catch (Error e) {
print ("Get decks error: %s\n", e.message);
}
});
}
private async DeckInfo[] load_decks () throws GLib.Error {
disconnected_err ();
@ -232,6 +301,18 @@ public class Streamdeck.Daemon : Object {
return yield backend_object.get_commands (serial_number);
}
private async string load_deck_name (string serial_number) throws GLib.Error {
disconnected_err ();
return yield backend_object.get_deck_name (serial_number);
}
private async InputName[] load_input_names (string serial_number) throws GLib.Error {
disconnected_err ();
return yield backend_object.get_input_names (serial_number);
}
private async void on_state_change (string state) throws GLib.Error {
if (obs_state == state) {
return;
@ -247,7 +328,18 @@ public class Streamdeck.Daemon : Object {
}
}
private async string get_state () throws GLib.Error {
private void do_load_state () {
load_state.begin ((_obj, res) => {
try {
var state = load_state.end (res);
obs_state_signal (state);
} catch (Error e) {
print ("Get state error: %s\n", e.message);
}
});
}
private async string load_state () throws GLib.Error {
disconnected_err ();
return yield backend_object.get_state ();

View file

@ -1,9 +1,9 @@
namespace Streamdeck.Dialogs {
public class EditCommandDialog : Granite.Dialog {
public EditCommandDialog (string serial_number, Data.Command initial_command) {
public EditCommandDialog (string serial_number, string? command_name, Data.Command initial_command) {
var disconnected_page = new Widgets.DisconnectedPage ();
var command_page = new Views.ConfigCommand.from_existing (serial_number, initial_command);
var command_page = new Views.ConfigCommand.from_existing (serial_number, command_name, initial_command);
var stack = new Gtk.Stack ();
stack.add_named (disconnected_page, "disconnected");
@ -24,6 +24,15 @@ namespace Streamdeck.Dialogs {
} else {
stack.set_visible_child_name ("command");
}
response.connect ((response_id) => {
if (response_id == Gtk.ResponseType.REJECT) {
unowned var app = (MainWindow) transient_for;
app.to_obs ();
}
destroy ();
});
}
}
}

View file

@ -0,0 +1,49 @@
namespace Streamdeck.Dialogs {
public class EditDeckDialog : Granite.Dialog {
private string previous_name;
private string serial_number;
private Gtk.Entry entry;
public EditDeckDialog (string serial_number, string deck_name) {
this.serial_number = serial_number;
this.previous_name = deck_name;
var label = new Gtk.Label (_("Edit Deck Name"));
entry = new Gtk.Entry ();
entry.valign = Gtk.Align.CENTER;
entry.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL);
entry.text = deck_name;
var grid = new Gtk.Grid ();
grid.column_spacing = 12;
grid.row_spacing = 12;
grid.halign = Gtk.Align.CENTER;
grid.margin = 24;
grid.attach (label, 0, 0);
grid.attach (entry, 1, 0, 3);
get_content_area ().add (grid);
entry.changed.connect (handle_entry_change);
add_button ("Close", Gtk.ResponseType.CLOSE);
show_all ();
}
private void handle_entry_change () {
if (previous_name != entry.text) {
previous_name = entry.text;
Daemon.instance.set_deck_name.begin (serial_number, entry.text, (_obj, res) => {
try {
Daemon.instance.set_deck_name.end (res);
Daemon.instance.update_name_cache (serial_number);
} catch {
// do nothing
}
});
}
}
}
}

View file

@ -0,0 +1,86 @@
namespace Streamdeck.Views {
public class CommandsView : Gtk.Grid {
private string serial_number;
private string device_name;
private Gtk.Label label;
private Widgets.CommandList list;
private Dialogs.EditDeckDialog? edit_deck_dialog;
public signal void key_press (ReadInput key_info);
public signal void name_change (string name);
public signal void input_name_change (uint8 key, string name);
public signal void command_list (Gee.ArrayList<CommandInfo?> commands);
public CommandsView (DeckInfo info) {
serial_number = info.serial_number;
device_name = info.device_name;
orientation = Gtk.Orientation.VERTICAL;
list = new Widgets.CommandList (info);
list.expand = true;
label = new Gtk.Label (device_name);
label.get_style_context ().add_class (Granite.STYLE_CLASS_H1_LABEL);
label.halign = Gtk.Align.START;
var edit_button = new Gtk.Button.from_icon_name (
"document-edit",
Gtk.IconSize.BUTTON
);
edit_button.tooltip_text = _("Rename");
edit_button.halign = Gtk.Align.END;
edit_button.valign = Gtk.Align.CENTER;
edit_button.expand = true;
var top_grid = new Gtk.Grid ();
top_grid.attach (label, 0, 0);
top_grid.attach (edit_button, 1, 0);
attach (top_grid, 0, 0);
attach (list, 0, 1, 1, 4);
show_all ();
key_press.connect ((info) => {
list.key_press (info);
});
name_change.connect (handle_name_change);
input_name_change.connect ((key, name) => {
list.input_name_change (key, name);
});
command_list.connect ((commands) => {
list.command_list (commands);
});
edit_button.clicked.connect (handle_edit_click);
}
private void handle_name_change (string name) {
device_name = name;
label.label = name;
}
private void handle_edit_click () {
if (edit_deck_dialog == null) {
edit_deck_dialog = new Dialogs.EditDeckDialog (
serial_number,
device_name
);
edit_deck_dialog.transient_for = (Gtk.Window) get_toplevel ();
edit_deck_dialog.show_all ();
edit_deck_dialog.response.connect ((_response_id) => {
edit_deck_dialog.destroy ();
});
edit_deck_dialog.destroy.connect (() => {
edit_deck_dialog = null;
});
}
edit_deck_dialog.present ();
}
}
}

View file

@ -4,8 +4,10 @@ namespace Streamdeck.Views {
private Widgets.ScenesComboBox scenes_combobox;
private Widgets.CommandComboBox command_combobox;
private string serial_number;
private string? command_name;
private uint8? key;
private Data.Command? command;
private Gtk.Entry name_entry;
public signal void changed (Data.Command command);
@ -18,9 +20,14 @@ namespace Streamdeck.Views {
scenes_combobox.select_first ();
}
public ConfigCommand.from_existing (string serial_number, Data.Command command) {
public ConfigCommand.from_existing (string serial_number, string? name, Data.Command command) {
this.serial_number = serial_number;
this.key = command.get_command_key ();
if (name == null) {
this.command_name = "%d".printf (this.key);
} else {
this.command_name = name;
}
this.command = command;
build ();
@ -65,40 +72,42 @@ namespace Streamdeck.Views {
command_stack.add_named (new Gtk.Label ("..."), "Empty");
command_stack.add_named (switch_scene_grid, "SwitchScene");
var name_label = new Gtk.Label (_("Name:"));
name_entry = new Gtk.Entry ();
name_entry.valign = Gtk.Align.CENTER;
name_entry.get_style_context ().add_class (Granite.STYLE_CLASS_H3_LABEL);
if (command_name != null) {
name_entry.text = command_name;
} else if (key != null) {
command_name = "%d".printf (key);
name_entry.text = command_name;
}
column_spacing = 12;
row_spacing = 12;
halign = Gtk.Align.CENTER;
margin = 24;
attach (command_title, 0, 0, 3);
attach (command_label, 0, 1);
attach (command_combobox, 1, 1);
attach (command_stack, 2, 1);
attach (name_label, 0, 1);
attach (name_entry, 1, 1, 2);
attach (command_label, 0, 2);
attach (command_combobox, 1, 2);
attach (command_stack, 2, 2);
show_all ();
changed.connect ((_obj, cmd) => {
Daemon.instance.add_command.begin (
serial_number,
cmd.get_command_key (),
cmd.to_json (),
(obj, res) => {
try {
Daemon.instance.add_command.end (res);
Daemon.instance.update_command_cache (serial_number);
} catch (Error e) {
print ("Error saving command %s\n", e.message);
}
}
);
});
changed.connect (handle_change);
name_entry.changed.connect (handle_name_change);
scenes_combobox.selected.connect (handle_scene_change);
command_combobox.selected.connect (handle_type_change);
}
public void set_key (uint8 key) {
this.key = key;
if (command_name == null) {
command_name = "%d".printf (key);
}
var type = command_combobox.get_selected_type ();
@ -107,6 +116,41 @@ namespace Streamdeck.Views {
}
}
private void handle_change (Data.Command cmd) {
Daemon.instance.add_command.begin (
serial_number,
cmd.get_command_key (),
cmd.to_json (),
(obj, res) => {
try {
Daemon.instance.add_command.end (res);
Daemon.instance.update_command_cache (serial_number);
} catch (Error e) {
print ("Error saving command %s\n", e.message);
}
}
);
}
private void handle_name_change () {
if (command_name != name_entry.text && key != null) {
command_name = name_entry.text;
Daemon.instance.set_input_name.begin (
serial_number,
key,
name_entry.text,
(_obj, res) => {
try {
Daemon.instance.set_input_name.end (res);
Daemon.instance.update_name_cache (serial_number);
} catch {
// do nothing
}
}
);
}
}
private void handle_type_change (Data.CommandType type) {
switch (type) {
case Data.CommandType.SWITCH_SCENE:

View file

@ -4,6 +4,11 @@ namespace Streamdeck.Views {
add_named (new Widgets.EmptyConfigPane (), "empty-state");
show_all();
Daemon.instance.key_press_signal.connect (handle_key_press);
Daemon.instance.commands_signal.connect (handle_commands);
Daemon.instance.deck_name_signal.connect (handle_name_change);
Daemon.instance.input_name_signal.connect (handle_input_name_change);
}
public void select_deck (string serial_number) {
@ -17,7 +22,7 @@ namespace Streamdeck.Views {
return;
}
var pane = new Widgets.CommandList (deck_info);
var pane = new Views.CommandsView (deck_info);
add_named (pane, deck_info.serial_number);
}
@ -27,5 +32,45 @@ namespace Streamdeck.Views {
remove (child);
}
}
private void handle_key_press (ReadInput key_info) {
var child = get_visible_child ();
if (child == null) {
return;
}
unowned var list = (Views.CommandsView) child;
list.key_press (key_info);
}
private void handle_name_change (string serial_number, string name) {
var child = get_child_by_name (serial_number);
if (child == null) {
return;
}
unowned var list = (Views.CommandsView) child;
list.name_change (name);
}
private void handle_input_name_change (string serial_number, uint8 key, string name) {
var child = get_child_by_name (serial_number);
if (child == null) {
return;
}
unowned var list = (Views.CommandsView) child;
list.input_name_change (key, name);
}
private void handle_commands (string serial_number, Gee.ArrayList<CommandInfo?> commands) {
var child = get_child_by_name (serial_number);
if (child == null) {
return;
}
unowned var list = (Views.CommandsView) child;
list.command_list (commands);
}
}
}

View file

@ -1,12 +1,16 @@
namespace Streamdeck.Widgets {
public class CommandList : Gtk.Frame {
private DeckInfo info;
private string serial_number;
private Gtk.ListBox list_box;
private Dialogs.NewCommandDialog? new_command_dialog;
private Gee.HashMap<uint8, CommandRow> row_map = new Gee.HashMap<uint8, CommandRow> ();
public signal void key_press (ReadInput key_info);
public signal void input_name_change (uint8 key, string name);
public signal void command_list (Gee.ArrayList<CommandInfo?> commands);
public CommandList(DeckInfo info) {
this.info = info;
this.serial_number = info.serial_number;
var alert = new Granite.Widgets.AlertView (
_("No commands registered"),
@ -42,29 +46,15 @@ namespace Streamdeck.Widgets {
scrolled.expand = true;
scrolled.add (list_box);
Daemon.instance.key_press_signal.connect ((_obj, key_info) => {
key_press.connect ((_obj, key_info) => {
if (new_command_dialog != null) {
new_command_dialog.key_press (key_info);
}
});
var commands = Daemon.instance.get_commands (info.serial_number);
var commands = Daemon.instance.get_commands (serial_number);
if (commands != null) {
foreach (CommandInfo cmd_info in commands) {
var command = Data.Command.parse (cmd_info.key, cmd_info.command);
if (command != null) {
var existing = row_map.get (cmd_info.key);
if (existing != null) {
list_box.remove (existing);
}
var row = new CommandRow (info.serial_number, command);
row_map.set (cmd_info.key, row);
list_box.add (row);
}
}
handle_command_list (commands);
}
var grid = new Gtk.Grid ();
@ -74,71 +64,85 @@ namespace Streamdeck.Widgets {
add (grid);
remove_button.clicked.connect (() => {
var row = list_box.get_selected_row ();
if (row == null) {
return;
}
unowned var command_row = (CommandRow) row;
var key = command_row.get_key ();
Daemon.instance.remove_command.begin (info.serial_number, key, (_obj, res) => {
try {
Daemon.instance.remove_command.end (res);
Daemon.instance.update_command_cache (info.serial_number);
row_map.unset (key);
list_box.remove (row);
} catch (Error e) {
print ("Error removing command: %s\n", e.message);
}
});
});
add_button.clicked.connect (() => {
if (new_command_dialog == null) {
new_command_dialog = new Dialogs.NewCommandDialog (info.serial_number);
new_command_dialog.transient_for = (Gtk.Window) get_toplevel ();
new_command_dialog.show_all ();
new_command_dialog.response.connect ((response_id) => {
if (response_id == Gtk.ResponseType.REJECT) {
unowned var app = (MainWindow) get_toplevel ();
app.to_obs ();
}
new_command_dialog.destroy ();
});
new_command_dialog.destroy.connect (() => {
new_command_dialog = null;
});
}
new_command_dialog.present ();
});
Daemon.instance.commands_signal.connect ((_obj, serial_number, commands) => {
if (serial_number == info.serial_number) {
foreach (CommandInfo cmd_info in commands) {
var command = Data.Command.parse (cmd_info.key, cmd_info.command);
if (command != null) {
var existing = row_map.get (cmd_info.key);
if (existing != null) {
list_box.remove (existing);
}
var row = new CommandRow (serial_number, command);
row_map.set (cmd_info.key, row);
list_box.add (row);
}
}
}
});
remove_button.clicked.connect (handle_remove_click);
add_button.clicked.connect (handle_add_click);
command_list.connect (handle_command_list);
input_name_change.connect (handle_input_name_change);
show_all ();
}
private void handle_remove_click () {
var row = list_box.get_selected_row ();
if (row == null) {
return;
}
unowned var command_row = (CommandRow) row;
var key = command_row.get_key ();
Daemon.instance.remove_command.begin (serial_number, key, (_obj, res) => {
try {
Daemon.instance.remove_command.end (res);
Daemon.instance.update_command_cache (serial_number);
row_map.unset (key);
list_box.remove (row);
} catch (Error e) {
print ("Error removing command: %s\n", e.message);
}
});
}
private void handle_add_click () {
if (new_command_dialog == null) {
new_command_dialog = new Dialogs.NewCommandDialog (serial_number);
new_command_dialog.transient_for = (Gtk.Window) get_toplevel ();
new_command_dialog.show_all ();
new_command_dialog.response.connect ((response_id) => {
if (response_id == Gtk.ResponseType.REJECT) {
unowned var app = (MainWindow) get_toplevel ();
app.to_obs ();
}
new_command_dialog.destroy ();
});
new_command_dialog.destroy.connect (() => {
new_command_dialog = null;
});
}
new_command_dialog.present ();
}
private void handle_command_list (Gee.ArrayList<CommandInfo?> commands) {
foreach (CommandInfo cmd_info in commands) {
var command = Data.Command.parse (cmd_info.key, cmd_info.command);
if (command != null) {
var existing = row_map.get (cmd_info.key);
if (existing != null) {
list_box.remove (existing);
}
var name = Daemon.instance.get_input_name (serial_number, cmd_info.key);
var row = new CommandRow (serial_number, name, command);
row_map.set (cmd_info.key, row);
list_box.add (row);
}
}
}
private void handle_input_name_change (uint8 key, string name) {
var row = row_map.get (key);
if (row == null) {
return;
}
unowned var command_row = (CommandRow) row;
command_row.name_change (name);
}
}
}

View file

@ -1,22 +1,31 @@
namespace Streamdeck.Widgets {
public class CommandRow : Gtk.ListBoxRow {
private string serial_number;
private string? command_name;
private Data.Command command;
private Dialogs.EditCommandDialog? edit_dialog;
private Gtk.Label row_key;
public CommandRow (string serial_number, Data.Command command) {
public signal void name_change (string name);
public CommandRow (string serial_number, string? command_name, Data.Command command) {
this.serial_number = serial_number;
this.command_name = command_name;
this.command = command;
var key = command.get_command_key ();
var row_key = new Gtk.Label (@"$(key)");
row_key = new Gtk.Label ("%d".printf (key));
if (command_name != null) {
row_key.label = command_name;
}
row_key.halign = Gtk.Align.START;
row_key.valign = Gtk.Align.START;
row_key.valign = Gtk.Align.CENTER;
row_key.expand = true;
row_key.show_all ();
var row_command = new Gtk.Label (null);
row_command.halign = Gtk.Align.START;
row_command.valign = Gtk.Align.START;
row_command.valign = Gtk.Align.CENTER;
row_command.show_all ();
var row_grid = new Gtk.Grid ();
@ -43,30 +52,8 @@ namespace Streamdeck.Widgets {
);
row_edit.tooltip_text = _("Edit");
row_edit.halign = Gtk.Align.END;
row_edit.valign = Gtk.Align.END;
row_edit.valign = Gtk.Align.CENTER;
row_edit.expand = true;
row_edit.clicked.connect (() => {
if (edit_dialog == null) {
edit_dialog = new Dialogs.EditCommandDialog (serial_number, command);
edit_dialog.transient_for = (Gtk.Window) get_toplevel ();
edit_dialog.show_all ();
edit_dialog.response.connect ((response_id) => {
if (response_id == Gtk.ResponseType.REJECT) {
unowned var app = (MainWindow) get_toplevel ();
app.to_obs ();
}
edit_dialog.destroy ();
});
edit_dialog.destroy.connect (() => {
edit_dialog = null;
});
}
edit_dialog.present ();
});
row_grid.add (row_edit);
@ -75,22 +62,45 @@ namespace Streamdeck.Widgets {
add (row_grid);
show_all ();
row_edit.clicked.connect (handle_edit_click);
name_change.connect (handle_name_change);
}
public uint8 get_key () {
return command.get_command_key ();
}
private void handle_edit_click () {
if (edit_dialog == null) {
edit_dialog = new Dialogs.EditCommandDialog (serial_number, command_name, command);
edit_dialog.transient_for = (Gtk.Window) get_toplevel ();
edit_dialog.show_all ();
edit_dialog.destroy.connect (() => {
edit_dialog = null;
});
}
edit_dialog.present ();
}
private void handle_name_change (string name) {
command_name = name;
row_key.label = name;
}
private void switch_scene_ui (Gtk.Grid row_grid) {
unowned var switch_scene = (Data.SwitchScene) command;
var to = new Gtk.Label (_("to"));
to.halign = Gtk.Align.START;
to.valign = Gtk.Align.START;
to.valign = Gtk.Align.CENTER;
to.show_all ();
var scene_name = new Gtk.Label (switch_scene.scene_name);
scene_name.halign = Gtk.Align.START;
scene_name.valign = Gtk.Align.START;
scene_name.valign = Gtk.Align.CENTER;
scene_name.show_all ();
row_grid.add (to);

View file

@ -27,12 +27,6 @@ namespace Streamdeck.Widgets {
list_box.set_header_func (update_headers);
list_box.row_selected.connect ((row) => {
row.activate ();
unowned var item = (DeckItem) row;
deck_stack.select_deck (item.serial_number);
});
var scroll = new Gtk.ScrolledWindow (null, null);
scroll.hscrollbar_policy = Gtk.PolicyType.NEVER;
scroll.expand = true;
@ -41,13 +35,34 @@ namespace Streamdeck.Widgets {
add (scroll);
show_all ();
list_box.row_selected.connect ((row) => {
if (row == null) {
return;
}
row.activate ();
unowned var item = (DeckItem) row;
deck_stack.select_deck (item.serial_number);
});
Daemon.instance.deck_name_signal.connect (handle_deck_name);
}
public void add_deck (DeckInfo deck_info) {
var already_present = false;
foreach (Gtk.Widget child in list_box.get_children ()) {
var deck_item = (DeckItem) child;
var name = Daemon.instance.get_deck_name (deck_info.serial_number);
if (name != null) {
deck_info.device_name = name;
}
foreach (unowned Gtk.Widget child in list_box.get_children ()) {
if (child == null) {
continue;
}
unowned var deck_item = (DeckItem) child;
already_present = already_present
|| deck_item.serial_number == deck_info.serial_number;
@ -69,8 +84,12 @@ namespace Streamdeck.Widgets {
}
public void remove_deck (DeckInfo deck_info) {
foreach (Gtk.Widget child in list_box.get_children ()) {
var deck_item = (DeckItem) child;
foreach (unowned Gtk.Widget child in list_box.get_children ()) {
if (child == null) {
continue;
}
unowned var deck_item = (DeckItem) child;
if (deck_item.serial_number == deck_info.serial_number) {
deck_stack.remove_deck (deck_info);
@ -83,6 +102,19 @@ namespace Streamdeck.Widgets {
show_all ();
}
private void handle_deck_name (string serial_number, string name) {
foreach (unowned Gtk.Widget row in list_box.get_children ()) {
if (row == null) {
continue;
}
unowned var item = (DeckItem) row;
if (item.serial_number == serial_number) {
item.device_name = name;
}
}
}
private void update_headers (Gtk.ListBoxRow row, Gtk.ListBoxRow? before = null) {
if (before != null) {
row.set_header (null);