diff --git a/src/Command.vala b/src/Command.vala index 9b7f7ab..57d4c93 100644 --- a/src/Command.vala +++ b/src/Command.vala @@ -28,6 +28,45 @@ namespace Plotinus { } public abstract void execute(); + + public virtual bool is_active() { + return false; + } + + public virtual Gtk.ButtonRole get_check_type() { + return Gtk.ButtonRole.NORMAL; + } + + [DBus(visible=false)] + public virtual bool set_image(Gtk.CellRendererPixbuf cell) { + return false; + } + + protected bool set_image_from_widget(Gtk.CellRendererPixbuf cell, Gtk.Widget? widget) { + if(widget == null || !(widget is Gtk.Image)) + return false; + + var image = widget as Gtk.Image; + + cell.stock_size = Gtk.IconSize.MENU; + + switch(image.get_storage_type()) { + case Gtk.ImageType.PIXBUF: + cell.pixbuf = image.pixbuf; + return true; + case Gtk.ImageType.ICON_NAME: + cell.icon_name = image.icon_name; + return true; + case Gtk.ImageType.GICON: + cell.gicon = image.gicon; + return true; + case Gtk.ImageType.STOCK: + cell.stock_id = image.stock; + return true; + default: + return false; + } + } } class SignalCommand : Command { @@ -45,16 +84,48 @@ namespace Plotinus { class ActionCommand : Command { private Action action; private Variant? parameter; + private Variant? icon; - public ActionCommand(string[] path, string label, string[] accelerators, Action action, Variant? parameter) { + public ActionCommand(string[] path, string label, string[] accelerators, Action action, Variant? parameter, Variant? icon) { base(path, label, accelerators); this.action = action; this.parameter = parameter; + this.icon = icon; } public override void execute() { action.activate(parameter); } + + public override bool is_active() { + switch(get_check_type()) { + case Gtk.ButtonRole.RADIO: + return parameter.equal(action.get_state()); + case Gtk.ButtonRole.CHECK: + return action.get_state().get_boolean(); + default: + return false; + } + } + + public override Gtk.ButtonRole get_check_type() { + if(parameter != null && action.get_state() != null) + return Gtk.ButtonRole.RADIO; + + if(action.get_state_type() != null && VariantType.BOOLEAN.equal(action.get_state_type())) + return Gtk.ButtonRole.CHECK; + + return Gtk.ButtonRole.NORMAL; + } + + public override bool set_image(Gtk.CellRendererPixbuf cell) { + if(this.icon == null) + return base.set_image(cell); + + var icon = Icon.deserialize(this.icon); + cell.gicon = icon; + return true; + } } class MenuItemCommand : Command { @@ -68,6 +139,36 @@ namespace Plotinus { public override void execute() { menu_item.activate(); } + + public override bool is_active() { + if(get_check_type() != Gtk.ButtonRole.NORMAL) + return (menu_item as Gtk.CheckMenuItem).active; + + return false; + } + public override Gtk.ButtonRole get_check_type() { + if(menu_item is Gtk.CheckMenuItem) { + var checkable = menu_item as Gtk.CheckMenuItem; + if((menu_item is Gtk.RadioMenuItem) || checkable.draw_as_radio) + return Gtk.ButtonRole.RADIO; + + return Gtk.ButtonRole.CHECK; + } + + return Gtk.ButtonRole.NORMAL; + } + + public override bool set_image(Gtk.CellRendererPixbuf cell) { + if(!(menu_item is Gtk.ImageMenuItem)) + return base.set_image(cell); + + var image_menu_item = menu_item as Gtk.ImageMenuItem; + if(!(image_menu_item.always_show_image || Gtk.Settings.get_default().gtk_menu_images)) + return base.set_image(cell); + + var widget = image_menu_item.get_image(); + return base.set_image_from_widget(cell, widget); + } } class ButtonCommand : Command { @@ -81,6 +182,27 @@ namespace Plotinus { public override void execute() { button.clicked(); } + + public override bool is_active() { + if(get_check_type() != Gtk.ButtonRole.NORMAL) + return (button as Gtk.CheckButton).active; + + return false; + } + + public override Gtk.ButtonRole get_check_type() { + if(button is Gtk.RadioButton) + return Gtk.ButtonRole.RADIO; + + if(button is Gtk.CheckButton) + return Gtk.ButtonRole.CHECK; + + return Gtk.ButtonRole.NORMAL; + } + + public override bool set_image(Gtk.CellRendererPixbuf cell) { + return base.set_image_from_widget(cell, button.get_image()); + } } } diff --git a/src/CommandExtractor.vala b/src/CommandExtractor.vala index ba2d5d3..fbbbcdc 100644 --- a/src/CommandExtractor.vala +++ b/src/CommandExtractor.vala @@ -72,11 +72,19 @@ class Plotinus.CommandExtractor : Object { var action_value = menu_model.get_item_attribute_value(i, Menu.ATTRIBUTE_ACTION, VariantType.STRING); var action_name = (action_value != null) ? action_value.get_string() : null; var action = (action_name != null) ? get_action(action_name) : null; + var icon = menu_model.get_item_attribute_value(i, Menu.ATTRIBUTE_ICON, null); + + if(icon == null) { + var verb = menu_model.get_item_attribute_value(i, "verb-icon", VariantType.STRING); + if(verb != null) { + icon = (Icon.new_for_string(verb.get_string())).serialize(); + } + } if (label != null && label != "" && action != null && action.enabled) { var accelerators = (application != null) ? application.get_accels_for_action(action_name) : new string[0]; var target = menu_model.get_item_attribute_value(i, Menu.ATTRIBUTE_TARGET, null); - commands += new ActionCommand(path, label, accelerators, action, target); + commands += new ActionCommand(path, label, accelerators, action, target, icon); } var link_iterator = menu_model.iterate_item_links(i); diff --git a/src/CommandList.vala b/src/CommandList.vala index b192f93..10d0834 100644 --- a/src/CommandList.vala +++ b/src/CommandList.vala @@ -32,6 +32,30 @@ class Plotinus.CommandList : Gtk.TreeView { } } + private class IconColumn : Gtk.TreeViewColumn { + public IconColumn() { + var toggle_renderer = new Gtk.CellRendererToggle(); + var pixbuf_renderer = new Gtk.CellRendererPixbuf(); + + pack_start(toggle_renderer, false); + pack_start(pixbuf_renderer, false); + + set_cell_data_func(toggle_renderer, (cell_layout, cell, tree_model, tree_iter) => { + var toggle = (cell as Gtk.CellRendererToggle); + var command = get_iter_command(tree_model, tree_iter); + toggle.visible = command.get_check_type() != Gtk.ButtonRole.NORMAL; + toggle.radio = command.get_check_type() == Gtk.ButtonRole.RADIO; + toggle.active = command.is_active(); + }); + + set_cell_data_func(pixbuf_renderer, (cell_layout, cell, tree_model, tree_iter) => { + var pixbuf = (cell as Gtk.CellRendererPixbuf); + var command = get_iter_command(tree_model, tree_iter); + pixbuf.visible = command.set_image(pixbuf); + }); + } + } + private const string COLUMN_PADDING = " "; private string filter = ""; @@ -70,17 +94,17 @@ class Plotinus.CommandList : Gtk.TreeView { text_color.alpha = 0.4; append_column(new ListColumn((command) => { return COLUMN_PADDING + - highlight_words(string.joinv(" \u25B6 ", command.path), filter_words) + - COLUMN_PADDING; + highlight_words(string.joinv(" \u25B6 ", command.path), filter_words); }, true, text_color)); + append_column(new IconColumn()); + append_column(new ListColumn((command) => { return highlight_words(command.label, filter_words); }, false, null, 1.4)); append_column(new ListColumn((command) => { - return COLUMN_PADDING + - Markup.escape_text(string.joinv(", ", map_string(command.accelerators, format_accelerator))) + + return Markup.escape_text(string.joinv(", ", map_string(command.accelerators, format_accelerator))) + COLUMN_PADDING; }, true, selection_color)); });