~desrt/libvalmynd/master

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
namespace Valmynd {
	namespace Gtk {
		class Binding {
			static Quark binding_quark;

			unowned global::Gtk.MenuShell shell;
			ActionGroup actions;
			ulong handler_id;
			Model model;

			void changed (Model model, int position, int removed, int added) {
				// remove existing items
				var children = shell.get_children ();
				var list = children.nth (position).copy ();
				unowned List<global::Gtk.Widget> link = list;

				for (var i = 0; i < removed; i++) {
					shell.remove (link.data);
					link = link.next;
				}

				// add new items
				for (var i = position; i < position + added; i++) {
					var item = model.get_item (i);
					var mi = create_item (item, actions);

					unowned string action;
					if (item.get_attribute ("action", "&s", out action)) {
						mi.set_data ("valmynd-action", action);
						mi.activate.connect (item_activate);
					}

					shell.insert (mi, -1);
				}
			}

			void item_activate (global::Gtk.MenuItem item) {
				var name = item.get_data<string> ("valmynd-action");
				actions.activate_action (name, null);
			}

			~Binding () {
				SignalHandler.disconnect (model, handler_id);
			}

			internal Binding (global::Gtk.MenuShell shell, Model model, ActionGroup actions) {
				if (binding_quark == 0) {
					binding_quark = Quark.from_string ("--valmynd-menu-model");
				}

				this.shell = shell;
				this.model = model;
				this.actions = actions;

				this.handler_id = model.items_changed.connect (changed);

				// start by clearing out the shell
				foreach (var child in shell.get_children ()) {
					shell.remove (child);
				}

				// now add a menu item for each one in the model
				changed (model, 0, 0, model.get_n_items ());

				shell.set_qdata<Binding> (binding_quark, this);
			}
		}

		public global::Gtk.MenuBar create_menubar (Valmynd.Model model, ActionGroup actions) {
			var menubar = new global::Gtk.MenuBar ();

			new Binding (menubar, flatten (model, false), actions);
			menubar.show ();

			return menubar;
		}

		public global::Gtk.Menu create_menu (Valmynd.Model model, ActionGroup actions) {
			var menu = new global::Gtk.Menu ();

			new Binding (menu, flatten (model, true), actions);
			menu.show ();

			return menu;
		}

		public global::Gtk.MenuItem create_item (Valmynd.ModelItem item, ActionGroup actions) {
			switch (item.get_type ()) {
			case MenuItemType.ITEM:
				var mi = new global::Gtk.MenuItem.with_label (item.get_label ());
				mi.show ();

				return mi;

			case MenuItemType.SUBMENU:
				var mi = new global::Gtk.MenuItem.with_label (item.get_label ());
				var child = item.get_link ("menu");

				if (child != null) {
					mi.set_submenu (create_menu (child, actions));
				}

				mi.show ();

				return mi;

			case MenuItemType.SECTION:
				assert_not_reached ();

			case MenuItemType.SEPARATOR:
				var mi = new global::Gtk.SeparatorMenuItem ();
				mi.show ();
				return mi;

			case MenuItemType.OTHER:
				var module = Valmynd.Gtk.Module.request (item.get_type_name ());

				if (module != null) {
					return module.create_item (item, actions);
				} else {
					return new global::Gtk.MenuItem.with_label ("unable to create item type: " + item.get_type_name ());
				}
			}

			return new global::Gtk.MenuItem ();
		}
	}
}