Qball's Weblog

GMPC Keybinding highlights

Tags gmpc 

This is something I saw a long time ago in microsoft office and I recently discovered that unity does something similar for its dock. So today in the train I wrote a small widget that can do this in GTK. It turned out not to be 100% trivial.

What you want todo is draw something ‘on top’ off an existing widget, preferable without modifying that widget. In the end I made the following solution:

You have a special container class (GmpcWidgetsOverlay), you pack the widget  that should have the highlight in this widget. This container overrides the expose event, first calls the widget that is contained, then optinally draws the highlight on top. (this seems to work very well.)

So now in GMPC if you press ALT key, on the play buttons and status icons you get a small box with the key you should hit to activate it. It aint perfect yet, but so far it works:

 

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using Gtk;
using FixGtk;
 
namespace Gmpc
{
	namespace Tools
	{
		public class BindingOverlayNotify : GLib.Object, FixGtk.Buildable
		{
			private Gdk.ModifierType keys = ;
			public string name {get; set; default="";}
			// Buildable stuff
			public void set_name(string name)
			{
				this.name= name;
			}
			public unowned string get_name()
			{
				return this.name;
			}
			public void key_pressed(Gdk.ModifierType key)
			{
				keys |= key;
				state_changed(keys);
			}
			public void key_released(Gdk.ModifierType key)
			{
 
				keys &= ~key;
				state_changed(keys);
			}
 
			public signal void state_changed(Gdk.ModifierType cur_state);
		}
 
	}
	namespace Widgets
	{
		public class Overlay : Gtk.EventBox, Gtk.Buildable
		{
			public Gdk.ModifierType modifier {get; set; default = Gdk.ModifierType.MOD1_MASK;}
			public bool show_overlay {get; set; default = false;}
			public string overlay_text {get; set; default= "left"; }
			construct{
				this.set_app_paintable(true);
			}
			private Tools.BindingOverlayNotify notifier = null;
			public Tools.BindingOverlayNotify binding_overlay_notifier {
				get{
					return notifier;
				}
				set {
					if(notifier != null) {
						notifier.state_changed.disconnect(key_changed);
					}
					notifier = value;
					notifier.state_changed.connect(key_changed);
				}
			}
 
			private void key_changed(Gdk.ModifierType cur_state)
			{
				if((cur_state) == modifier) {
					show_overlay = true;
				}else{
					show_overlay = false;
				}
				this.queue_draw();
			}
 
			public Overlay()
			{
			}
 
			public override bool expose_event(Gdk.EventExpose event)
			{
				// Draw the child of this box.
				var w = (this as Gtk.Bin).get_child();
				w.expose_event(event);
				// 
				if(show_overlay)
				{
					var ct = Gdk.cairo_create(window);
					int pw,ph;
					var l = this.create_pango_layout(overlay_text);
					Gtk.Allocation cell_area = this.allocation;
					l.get_pixel_size(out pw, out ph);
 
					ct.set_source_rgb(0.8,,);
//					Gdk.cairo_set_source_color(ct, this.style.bg[Gtk.StateType.SELECTED]);
					ct.rectangle(1, cell_area.height/2-ph/2-0.5, pw+4, ph);
					ct.fill_preserve();
					Gdk.cairo_set_source_color(ct, this.style.text[Gtk.StateType.SELECTED]);
					ct.stroke();
 
					ct.move_to(3, cell_area.height/2-ph/2-1.5);
					Gdk.cairo_set_source_color(ct,this.style.fg[Gtk.StateType.SELECTED]);
					Pango.cairo_show_layout(ct, l);
					ct.stroke();
				}
				return false;
			}
 
		}
	}
}

As you can see in the above code I needed to make a quick hack in vala to fix the Gtk.Buildable bindings. (replace abstract with virtual) with this fix, you can use this widget from GtkBuilder.
There is also a notification object (also usable from gtkbuilder) that notifies the widgets off the key press.

As I said it aint done, but seems to be nice allready.