Merge lp:~meese/slingshot/fix-1294917 into lp:~elementary-pantheon/slingshot/trunk
- fix-1294917
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Cody Garver | ||||
Approved revision: | 456 | ||||
Merged at revision: | 467 | ||||
Proposed branch: | lp:~meese/slingshot/fix-1294917 | ||||
Merge into: | lp:~elementary-pantheon/slingshot/trunk | ||||
Diff against target: |
490 lines (+332/-10) 7 files modified
CMakeLists.txt (+1/-0) src/Backend/App.vala (+97/-1) src/SlingshotView.vala (+21/-4) src/Widgets/AppEntry.vala (+40/-2) src/Widgets/CategoryView.vala (+1/-2) src/Widgets/PopoverMenu.vala (+169/-0) src/Widgets/Switcher.vala (+3/-1) |
||||
To merge this branch: | bzr merge lp:~meese/slingshot/fix-1294917 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cody Garver (community) | Approve | ||
Danielle Foré | ux | Approve | |
elementary Pantheon team | code | Pending | |
Review via email: mp+233304@code.launchpad.net |
Commit message
adds a popover context menu used for showing quicklist items on right click (lp:1294917)
Description of the change
Adds a popover menu widget that avoids the focus issues of using a normal context menu. Used to show launcher quicklist items on right clicking an app.
Cody Garver (codygarver) wrote : | # |
meese (meese) wrote : | # |
fixed
Danielle Foré (danrabbit) wrote : | # |
Works completely as intended for me. Style issues were mine and have been fixed in trunk.
Cody Garver (codygarver) wrote : | # |
All good aside from the background under the popover
Djax (parnold-x) wrote : | # |
@meese
to fix the 1px shrink of the popover on hover over the longest entry you could solve it like this:
add @ PopOverMenu.vala:75
button.
// fix width because there is a issue with resizing on hover
return false;
});
Danielle Foré (danrabbit) wrote : | # |
Djax, that shouldn't happen anymore. There was a theme bug that was causing it.
Cody Garver (codygarver) wrote : | # |
Needs trunk merged in and conflicts resolved
meese (meese) wrote : | # |
done
Rico Tzschichholz (ricotz) wrote : | # |
@messe: while copy&paste from plank, it would have been nice to mention this!
(Sharing code by linking against libplank is also an option if this is reasonable.)
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2014-10-14 17:02:40 +0000 | |||
3 | +++ CMakeLists.txt 2014-10-17 01:18:18 +0000 | |||
4 | @@ -83,6 +83,7 @@ | |||
5 | 83 | src/Widgets/SearchItem.vala | 83 | src/Widgets/SearchItem.vala |
6 | 84 | src/Widgets/Sidebar.vala | 84 | src/Widgets/Sidebar.vala |
7 | 85 | src/Widgets/CategoryView.vala | 85 | src/Widgets/CategoryView.vala |
8 | 86 | src/Widgets/PopoverMenu.vala | ||
9 | 86 | PACKAGES | 87 | PACKAGES |
10 | 87 | ${CORE_DEPS} | 88 | ${CORE_DEPS} |
11 | 88 | ${UI_DEPS} | 89 | ${UI_DEPS} |
12 | 89 | 90 | ||
13 | === modified file 'src/Backend/App.vala' | |||
14 | --- src/Backend/App.vala 2014-10-15 22:16:39 +0000 | |||
15 | +++ src/Backend/App.vala 2014-10-17 01:18:18 +0000 | |||
16 | @@ -47,7 +47,10 @@ | |||
17 | 47 | 47 | ||
18 | 48 | public Synapse.Match? match { get; private set; default = null; } | 48 | public Synapse.Match? match { get; private set; default = null; } |
19 | 49 | public Synapse.Match? target { get; private set; default = null; } | 49 | public Synapse.Match? target { get; private set; default = null; } |
21 | 50 | 50 | public Gee.ArrayList<string> actions { get; private set; default = null; } | |
22 | 51 | public Gee.HashMap<string, string> actions_map { get; private set; default = null; } | ||
23 | 52 | public Gdk.Pixbuf? quicklist_icon { get; private set; default = null; } | ||
24 | 53 | |||
25 | 51 | public signal void icon_changed (); | 54 | public signal void icon_changed (); |
26 | 52 | public signal void launched (App app); | 55 | public signal void launched (App app); |
27 | 53 | 56 | ||
28 | @@ -57,6 +60,18 @@ | |||
29 | 57 | 60 | ||
30 | 58 | private LoadableIcon loadable_icon = null; | 61 | private LoadableIcon loadable_icon = null; |
31 | 59 | 62 | ||
32 | 63 | // for FDO Desktop Actions | ||
33 | 64 | // see http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#extra-actions | ||
34 | 65 | private const string DESKTOP_ACTION_KEY = "Actions"; | ||
35 | 66 | private const string DESKTOP_ACTION_GROUP_NAME = "Desktop Action %s"; | ||
36 | 67 | // for the Unity static quicklists | ||
37 | 68 | // see https://wiki.edubuntu.org/Unity/LauncherAPI#Static_Quicklist_entries | ||
38 | 69 | private const string UNITY_QUICKLISTS_KEY = "X-Ayatana-Desktop-Shortcuts"; | ||
39 | 70 | private const string UNITY_QUICKLISTS_SHORTCUT_GROUP_NAME = "%s Shortcut Group"; | ||
40 | 71 | private const string UNITY_QUICKLISTS_TARGET_KEY = "TargetEnvironment"; | ||
41 | 72 | private const string UNITY_QUICKLISTS_TARGET_VALUE = "Unity"; | ||
42 | 73 | private const string[] SUPPORTED_GETTEXT_DOMAINS_KEYS = {"X-Ubuntu-Gettext-Domain", "X-GNOME-Gettext-Domain"}; | ||
43 | 74 | |||
44 | 60 | public App (GMenu.TreeEntry entry) { | 75 | public App (GMenu.TreeEntry entry) { |
45 | 61 | app_type = AppType.APP; | 76 | app_type = AppType.APP; |
46 | 62 | 77 | ||
47 | @@ -280,4 +295,85 @@ | |||
48 | 280 | return true; | 295 | return true; |
49 | 281 | } | 296 | } |
50 | 282 | 297 | ||
51 | 298 | public void init_actions () throws KeyFileError { | ||
52 | 299 | actions = new Gee.ArrayList<string> (); | ||
53 | 300 | actions_map = new Gee.HashMap<string, string> (); | ||
54 | 301 | quicklist_icon = load_icon (16); | ||
55 | 302 | |||
56 | 303 | // get FDO Desktop Actions | ||
57 | 304 | // see http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#extra-actions | ||
58 | 305 | // get the Unity static quicklists | ||
59 | 306 | // see https://wiki.edubuntu.org/Unity/LauncherAPI#Static Quicklist entries | ||
60 | 307 | KeyFile file; | ||
61 | 308 | try { | ||
62 | 309 | file = new KeyFile (); | ||
63 | 310 | file.load_from_file (desktop_path, 0); | ||
64 | 311 | } catch (Error e) { | ||
65 | 312 | critical ("%s: %s", desktop_path, e.message); | ||
66 | 313 | } | ||
67 | 314 | |||
68 | 315 | string? textdomain = null; | ||
69 | 316 | foreach (var domain_key in SUPPORTED_GETTEXT_DOMAINS_KEYS) | ||
70 | 317 | if (file.has_key (KeyFileDesktop.GROUP, domain_key)) { | ||
71 | 318 | textdomain = file.get_string (KeyFileDesktop.GROUP, domain_key); | ||
72 | 319 | break; | ||
73 | 320 | } | ||
74 | 321 | if (actions != null && actions_map != null) { | ||
75 | 322 | actions.clear (); | ||
76 | 323 | actions_map.clear (); | ||
77 | 324 | string[] keys = {DESKTOP_ACTION_KEY, UNITY_QUICKLISTS_KEY}; | ||
78 | 325 | |||
79 | 326 | foreach (var key in keys) { | ||
80 | 327 | if (!file.has_key (KeyFileDesktop.GROUP, key)) | ||
81 | 328 | continue; | ||
82 | 329 | |||
83 | 330 | foreach (var action in file.get_string_list (KeyFileDesktop.GROUP, key)) { | ||
84 | 331 | var group = DESKTOP_ACTION_GROUP_NAME.printf (action); | ||
85 | 332 | if (!file.has_group (group)) { | ||
86 | 333 | group = UNITY_QUICKLISTS_SHORTCUT_GROUP_NAME.printf (action); | ||
87 | 334 | if (!file.has_group (group)) | ||
88 | 335 | continue; | ||
89 | 336 | } | ||
90 | 337 | |||
91 | 338 | // check for TargetEnvironment | ||
92 | 339 | if (file.has_key (group, UNITY_QUICKLISTS_TARGET_KEY)) { | ||
93 | 340 | var target = file.get_string (group, UNITY_QUICKLISTS_TARGET_KEY); | ||
94 | 341 | if (target != UNITY_QUICKLISTS_TARGET_VALUE) | ||
95 | 342 | continue; | ||
96 | 343 | } | ||
97 | 344 | |||
98 | 345 | // check for OnlyShowIn | ||
99 | 346 | if (file.has_key (group, KeyFileDesktop.KEY_ONLY_SHOW_IN)) { | ||
100 | 347 | var found = false; | ||
101 | 348 | |||
102 | 349 | foreach (var s in file.get_string_list (group, KeyFileDesktop.KEY_ONLY_SHOW_IN)) | ||
103 | 350 | if (s == UNITY_QUICKLISTS_TARGET_VALUE) { | ||
104 | 351 | found = true; | ||
105 | 352 | break; | ||
106 | 353 | } | ||
107 | 354 | |||
108 | 355 | if (!found) | ||
109 | 356 | continue; | ||
110 | 357 | } | ||
111 | 358 | |||
112 | 359 | var action_name = file.get_locale_string (group, KeyFileDesktop.KEY_NAME); | ||
113 | 360 | |||
114 | 361 | var action_icon = ""; | ||
115 | 362 | if (file.has_key (group, KeyFileDesktop.KEY_ICON)) | ||
116 | 363 | action_icon = file.get_locale_string (group, KeyFileDesktop.KEY_ICON); | ||
117 | 364 | |||
118 | 365 | var action_exec = ""; | ||
119 | 366 | if (file.has_key (group, KeyFileDesktop.KEY_EXEC)) | ||
120 | 367 | action_exec = file.get_string (group, KeyFileDesktop.KEY_EXEC); | ||
121 | 368 | |||
122 | 369 | // apply given gettext-domain if available | ||
123 | 370 | if (textdomain != null) | ||
124 | 371 | action_name = GLib.dgettext (textdomain, action_name).dup (); | ||
125 | 372 | |||
126 | 373 | actions.add (action_name); | ||
127 | 374 | actions_map.set (action_name, "%s;;%s".printf (action_exec, action_icon)); | ||
128 | 375 | } | ||
129 | 376 | } | ||
130 | 377 | } | ||
131 | 378 | } | ||
132 | 283 | } | 379 | } |
133 | 284 | \ No newline at end of file | 380 | \ No newline at end of file |
134 | 285 | 381 | ||
135 | === modified file 'src/SlingshotView.vala' (properties changed: +x to -x) | |||
136 | --- src/SlingshotView.vala 2014-10-15 21:57:37 +0000 | |||
137 | +++ src/SlingshotView.vala 2014-10-17 01:18:18 +0000 | |||
138 | @@ -31,6 +31,8 @@ | |||
139 | 31 | public Gtk.Stack stack; | 31 | public Gtk.Stack stack; |
140 | 32 | public Granite.Widgets.ModeButton view_selector; | 32 | public Granite.Widgets.ModeButton view_selector; |
141 | 33 | private Gtk.Revealer view_selector_revealer; | 33 | private Gtk.Revealer view_selector_revealer; |
142 | 34 | // Single popover to use for all of app as context menu | ||
143 | 35 | private Widgets.NofocusPopover context_popover; | ||
144 | 34 | 36 | ||
145 | 35 | // Views | 37 | // Views |
146 | 36 | private Widgets.Grid grid_view; | 38 | private Widgets.Grid grid_view; |
147 | @@ -97,8 +99,9 @@ | |||
148 | 97 | 99 | ||
149 | 98 | height_request = calculate_grid_height () + Pixels.BOTTOM_SPACE; | 100 | height_request = calculate_grid_height () + Pixels.BOTTOM_SPACE; |
150 | 99 | setup_ui (); | 101 | setup_ui (); |
151 | 102 | context_popover = new Widgets.NofocusPopover (this, event_box); | ||
152 | 103 | |||
153 | 100 | connect_signals (); | 104 | connect_signals (); |
154 | 101 | |||
155 | 102 | debug ("Apps loaded"); | 105 | debug ("Apps loaded"); |
156 | 103 | } | 106 | } |
157 | 104 | 107 | ||
158 | @@ -311,6 +314,7 @@ | |||
159 | 311 | 314 | ||
160 | 312 | categories = app_system.get_categories (); | 315 | categories = app_system.get_categories (); |
161 | 313 | apps = app_system.get_apps (); | 316 | apps = app_system.get_apps (); |
162 | 317 | |||
163 | 314 | populate_grid_view (); | 318 | populate_grid_view (); |
164 | 315 | category_view.setup_sidebar (); | 319 | category_view.setup_sidebar (); |
165 | 316 | }); | 320 | }); |
166 | @@ -336,6 +340,19 @@ | |||
167 | 336 | motion_notify_event.connect (hotcorner_trigger); | 340 | motion_notify_event.connect (hotcorner_trigger); |
168 | 337 | } | 341 | } |
169 | 338 | 342 | ||
170 | 343 | public void show_popover_menu (Gtk.Widget menu, Gtk.Widget relative) { | ||
171 | 344 | context_popover = new Widgets.NofocusPopover (this, event_box); | ||
172 | 345 | context_popover.set_relative_to (relative); | ||
173 | 346 | context_popover.add (menu); | ||
174 | 347 | context_popover.show_all (); | ||
175 | 348 | |||
176 | 349 | var entry = relative as Widgets.AppEntry; | ||
177 | 350 | if (entry != null) | ||
178 | 351 | entry.app_launched.connect (() => {context_popover.hide ();}); | ||
179 | 352 | |||
180 | 353 | relative.grab_focus (); | ||
181 | 354 | } | ||
182 | 355 | |||
183 | 339 | private void gala_settings_changed () { | 356 | private void gala_settings_changed () { |
184 | 340 | if (Slingshot.settings.gala_settings.hotcorner_topleft == "open-launcher") { | 357 | if (Slingshot.settings.gala_settings.hotcorner_topleft == "open-launcher") { |
185 | 341 | can_trigger_hotcorner = true; | 358 | can_trigger_hotcorner = true; |
186 | @@ -650,7 +667,7 @@ | |||
187 | 650 | } | 667 | } |
188 | 651 | 668 | ||
189 | 652 | public override bool scroll_event (Gdk.EventScroll event) { | 669 | public override bool scroll_event (Gdk.EventScroll event) { |
191 | 653 | 670 | context_popover.hide (); | |
192 | 654 | switch (event.direction.to_string ()) { | 671 | switch (event.direction.to_string ()) { |
193 | 655 | case "GDK_SCROLL_UP": | 672 | case "GDK_SCROLL_UP": |
194 | 656 | case "GDK_SCROLL_LEFT": | 673 | case "GDK_SCROLL_LEFT": |
195 | @@ -674,7 +691,7 @@ | |||
196 | 674 | } | 691 | } |
197 | 675 | 692 | ||
198 | 676 | public void show_slingshot () { | 693 | public void show_slingshot () { |
200 | 677 | 694 | context_popover.hide (); | |
201 | 678 | search_entry.text = ""; | 695 | search_entry.text = ""; |
202 | 679 | 696 | ||
203 | 680 | reposition (); | 697 | reposition (); |
204 | @@ -768,7 +785,7 @@ | |||
205 | 768 | 785 | ||
206 | 769 | foreach (Backend.App app in app_system.get_apps_by_name ()) { | 786 | foreach (Backend.App app in app_system.get_apps_by_name ()) { |
207 | 770 | 787 | ||
209 | 771 | var app_entry = new Widgets.AppEntry (app); | 788 | var app_entry = new Widgets.AppEntry (app, this); |
210 | 772 | app_entry.app_launched.connect (() => hide ()); | 789 | app_entry.app_launched.connect (() => hide ()); |
211 | 773 | grid_view.append (app_entry); | 790 | grid_view.append (app_entry); |
212 | 774 | app_entry.show_all (); | 791 | app_entry.show_all (); |
213 | 775 | 792 | ||
214 | === modified file 'src/Widgets/AppEntry.vala' (properties changed: +x to -x) | |||
215 | --- src/Widgets/AppEntry.vala 2014-10-15 21:57:37 +0000 | |||
216 | +++ src/Widgets/AppEntry.vala 2014-10-17 01:18:18 +0000 | |||
217 | @@ -32,8 +32,10 @@ | |||
218 | 32 | private bool dragging = false; //prevent launching | 32 | private bool dragging = false; //prevent launching |
219 | 33 | 33 | ||
220 | 34 | private Backend.App application; | 34 | private Backend.App application; |
221 | 35 | private unowned SlingshotView view; | ||
222 | 35 | 36 | ||
224 | 36 | public AppEntry (Backend.App app) { | 37 | public AppEntry (Backend.App app, SlingshotView view) { |
225 | 38 | this.view = view; | ||
226 | 37 | Gtk.TargetEntry dnd = {"text/uri-list", 0, 0}; | 39 | Gtk.TargetEntry dnd = {"text/uri-list", 0, 0}; |
227 | 38 | Gtk.drag_source_set (this, Gdk.ModifierType.BUTTON1_MASK, {dnd}, | 40 | Gtk.drag_source_set (this, Gdk.ModifierType.BUTTON1_MASK, {dnd}, |
228 | 39 | Gdk.DragAction.COPY); | 41 | Gdk.DragAction.COPY); |
229 | @@ -75,7 +77,13 @@ | |||
230 | 75 | 77 | ||
231 | 76 | this.clicked.connect (launch_app); | 78 | this.clicked.connect (launch_app); |
232 | 77 | 79 | ||
234 | 78 | this.button_press_event.connect ((e) => {return e.button == 3;}); | 80 | this.button_release_event.connect ((e) => { |
235 | 81 | if (e.button == Gdk.BUTTON_SECONDARY) { | ||
236 | 82 | show_menu (); | ||
237 | 83 | return true; | ||
238 | 84 | } | ||
239 | 85 | return false; | ||
240 | 86 | }); | ||
241 | 79 | 87 | ||
242 | 80 | this.drag_begin.connect ( (ctx) => { | 88 | this.drag_begin.connect ( (ctx) => { |
243 | 81 | this.dragging = true; | 89 | this.dragging = true; |
244 | @@ -111,4 +119,34 @@ | |||
245 | 111 | application.launch (); | 119 | application.launch (); |
246 | 112 | app_launched (); | 120 | app_launched (); |
247 | 113 | } | 121 | } |
248 | 122 | |||
249 | 123 | private void show_menu () { | ||
250 | 124 | // Display the apps static quicklist items in a popover menu | ||
251 | 125 | if (application.actions == null) { | ||
252 | 126 | try { | ||
253 | 127 | application.init_actions (); | ||
254 | 128 | } catch (KeyFileError e) { | ||
255 | 129 | critical ("%s: %s", desktop_path, e.message); | ||
256 | 130 | } | ||
257 | 131 | } | ||
258 | 132 | |||
259 | 133 | var menu = new PopoverMenu (); | ||
260 | 134 | foreach (var action in application.actions) { | ||
261 | 135 | var values = application.actions_map.get (action).split (";;"); | ||
262 | 136 | var menuitem = new Widgets.PopoverMenuItem (action, application.quicklist_icon); | ||
263 | 137 | menu.add_menu_item (menuitem); | ||
264 | 138 | menuitem.activated.connect (() => { | ||
265 | 139 | try { | ||
266 | 140 | AppInfo.create_from_commandline (values[0], null, AppInfoCreateFlags.NONE).launch (null, null); | ||
267 | 141 | app_launched (); | ||
268 | 142 | } catch (Error e) { | ||
269 | 143 | critical ("%s: %s", desktop_path, e.message); | ||
270 | 144 | } | ||
271 | 145 | }); | ||
272 | 146 | } | ||
273 | 147 | |||
274 | 148 | if (menu.get_size () > 0) | ||
275 | 149 | view.show_popover_menu (menu, this); | ||
276 | 150 | } | ||
277 | 151 | |||
278 | 114 | } | 152 | } |
279 | 115 | \ No newline at end of file | 153 | \ No newline at end of file |
280 | 116 | 154 | ||
281 | === modified file 'src/Widgets/CategoryView.vala' | |||
282 | --- src/Widgets/CategoryView.vala 2014-10-15 21:44:44 +0000 | |||
283 | +++ src/Widgets/CategoryView.vala 2014-10-17 01:18:18 +0000 | |||
284 | @@ -96,8 +96,7 @@ | |||
285 | 96 | } | 96 | } |
286 | 97 | 97 | ||
287 | 98 | private void add_app (Backend.App app) { | 98 | private void add_app (Backend.App app) { |
290 | 99 | 99 | var app_entry = new AppEntry (app, view); | |
289 | 100 | var app_entry = new AppEntry (app); | ||
291 | 101 | app_entry.app_launched.connect (() => view.hide ()); | 100 | app_entry.app_launched.connect (() => view.hide ()); |
292 | 102 | app_view.append (app_entry); | 101 | app_view.append (app_entry); |
293 | 103 | app_view.show_all (); | 102 | app_view.show_all (); |
294 | 104 | 103 | ||
295 | === added file 'src/Widgets/PopoverMenu.vala' | |||
296 | --- src/Widgets/PopoverMenu.vala 1970-01-01 00:00:00 +0000 | |||
297 | +++ src/Widgets/PopoverMenu.vala 2014-10-17 01:18:18 +0000 | |||
298 | @@ -0,0 +1,169 @@ | |||
299 | 1 | // -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- | ||
300 | 2 | // | ||
301 | 3 | // Copyright (C) 2011-2012 Giulio Collura | ||
302 | 4 | // Copyright (C) 2014 Maddie May <madelynn@madelynnmay.com> | ||
303 | 5 | // | ||
304 | 6 | // This program is free software: you can redistribute it and/or modify | ||
305 | 7 | // it under the terms of the GNU General Public License as published by | ||
306 | 8 | // the Free Software Foundation, either version 3 of the License, or | ||
307 | 9 | // (at your option) any later version. | ||
308 | 10 | // | ||
309 | 11 | // This program is distributed in the hope that it will be useful, | ||
310 | 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
311 | 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
312 | 14 | // GNU General Public License for more details. | ||
313 | 15 | // | ||
314 | 16 | // You should have received a copy of the GNU General Public License | ||
315 | 17 | // along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
316 | 18 | // | ||
317 | 19 | |||
318 | 20 | // A menu to be used inside of popovers for when a normal context | ||
319 | 21 | // menu can't be used | ||
320 | 22 | namespace Slingshot.Widgets { | ||
321 | 23 | |||
322 | 24 | public class PopoverMenu : Gtk.Grid { | ||
323 | 25 | private int line_count = 0; | ||
324 | 26 | private Gee.ArrayList<PopoverMenuItem> items = new Gee.ArrayList<PopoverMenuItem> (); | ||
325 | 27 | |||
326 | 28 | public PopoverMenu () { | ||
327 | 29 | row_homogeneous = true; | ||
328 | 30 | column_homogeneous = true; | ||
329 | 31 | } | ||
330 | 32 | |||
331 | 33 | public void add_menu_item (PopoverMenuItem item) { | ||
332 | 34 | line_count++; | ||
333 | 35 | this.items.add (item); | ||
334 | 36 | this.attach (item.child, 0, line_count, 1 , 1); | ||
335 | 37 | } | ||
336 | 38 | |||
337 | 39 | public int get_size () { | ||
338 | 40 | return items.size; | ||
339 | 41 | } | ||
340 | 42 | } | ||
341 | 43 | |||
342 | 44 | public class PopoverMenuItem : Object { | ||
343 | 45 | public Gtk.Widget child = null; | ||
344 | 46 | public signal void activated (); | ||
345 | 47 | |||
346 | 48 | public PopoverMenuItem (string label, Gdk.Pixbuf? icon) { | ||
347 | 49 | var button = new Gtk.Button (); | ||
348 | 50 | button.get_style_context ().add_class (Gtk.STYLE_CLASS_MENUITEM); | ||
349 | 51 | |||
350 | 52 | var grid = new Gtk.Grid (); | ||
351 | 53 | if (icon != null) { | ||
352 | 54 | var image = new Gtk.Image.from_pixbuf (icon); | ||
353 | 55 | image.margin_left = 2; | ||
354 | 56 | image.margin_right = 2; | ||
355 | 57 | image.halign = Gtk.Align.START; | ||
356 | 58 | grid.attach (image, 0, 0, 1, 1); | ||
357 | 59 | } else { | ||
358 | 60 | var space_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); | ||
359 | 61 | space_box.set_size_request (16, 16); | ||
360 | 62 | grid.attach (space_box, 0, 0, 1, 1); | ||
361 | 63 | } | ||
362 | 64 | |||
363 | 65 | var label_widget = new Gtk.Label.with_mnemonic (label); | ||
364 | 66 | label_widget.margin_right = 16; | ||
365 | 67 | label_widget.justify = Gtk.Justification.LEFT; | ||
366 | 68 | label_widget.set_alignment (0, 0); | ||
367 | 69 | grid.attach (label_widget, 1, 0, 1, 1); | ||
368 | 70 | |||
369 | 71 | button.add (grid); | ||
370 | 72 | button.relief = Gtk.ReliefStyle.NONE; | ||
371 | 73 | button.clicked.connect (on_activate); | ||
372 | 74 | child = button; | ||
373 | 75 | } | ||
374 | 76 | |||
375 | 77 | private void on_activate () { | ||
376 | 78 | activated (); | ||
377 | 79 | } | ||
378 | 80 | } | ||
379 | 81 | |||
380 | 82 | // A popover that doesn't grab focus | ||
381 | 83 | public class NofocusPopover : Gtk.Popover { | ||
382 | 84 | private Gtk.Container parent_container; | ||
383 | 85 | private unowned SlingshotView view; | ||
384 | 86 | |||
385 | 87 | private const string POPOVER_STYLESHEET = """ | ||
386 | 88 | .popover, | ||
387 | 89 | .popover.osd, | ||
388 | 90 | GtkPopover { | ||
389 | 91 | border-radius: 0px; | ||
390 | 92 | margin: 0px; | ||
391 | 93 | text-shadow: none; | ||
392 | 94 | } | ||
393 | 95 | """; | ||
394 | 96 | |||
395 | 97 | public NofocusPopover (SlingshotView view, Gtk.Container parent) { | ||
396 | 98 | this.view = view; | ||
397 | 99 | this.parent_container = parent; | ||
398 | 100 | connect_popover_signals (parent); | ||
399 | 101 | modal = false; | ||
400 | 102 | parent.button_release_event.connect (hide_popover_menu); | ||
401 | 103 | parent.button_press_event.connect (hide_popover_menu); | ||
402 | 104 | get_style_context ().add_class (Gtk.STYLE_CLASS_MENU); | ||
403 | 105 | Granite.Widgets.Utils.set_theming_for_screen (get_screen (), POPOVER_STYLESHEET, | ||
404 | 106 | Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); | ||
405 | 107 | } | ||
406 | 108 | |||
407 | 109 | public void connect_popover_signals (Gtk.Container parent) { | ||
408 | 110 | foreach (Gtk.Widget child in parent.get_children ()) { | ||
409 | 111 | if (child is Gtk.Container) { | ||
410 | 112 | Gtk.Container container = child as Gtk.Container; | ||
411 | 113 | connect_popover_signals (container); | ||
412 | 114 | } | ||
413 | 115 | |||
414 | 116 | if (child is Widgets.Switcher) { | ||
415 | 117 | var switcher = child as Widgets.Switcher; | ||
416 | 118 | switcher.on_stack_changed.connect (switched); | ||
417 | 119 | } | ||
418 | 120 | |||
419 | 121 | child.button_release_event.connect (hide_popover_menu); | ||
420 | 122 | child.button_press_event.connect (hide_popover_menu); | ||
421 | 123 | } | ||
422 | 124 | } | ||
423 | 125 | |||
424 | 126 | private void disconnect_popover_signals (Gtk.Container parent) { | ||
425 | 127 | foreach (Gtk.Widget child in parent.get_children ()) { | ||
426 | 128 | if (child is Gtk.Container) { | ||
427 | 129 | Gtk.Container container = child as Gtk.Container; | ||
428 | 130 | disconnect_popover_signals (container); | ||
429 | 131 | } | ||
430 | 132 | |||
431 | 133 | if (child is Widgets.Switcher) { | ||
432 | 134 | var switcher = child as Widgets.Switcher; | ||
433 | 135 | switcher.on_stack_changed.disconnect (switched); | ||
434 | 136 | } | ||
435 | 137 | |||
436 | 138 | child.button_release_event.disconnect (hide_popover_menu); | ||
437 | 139 | child.button_press_event.disconnect (hide_popover_menu); | ||
438 | 140 | } | ||
439 | 141 | } | ||
440 | 142 | |||
441 | 143 | public void switched () { | ||
442 | 144 | this.hide (); | ||
443 | 145 | } | ||
444 | 146 | |||
445 | 147 | public bool hide_popover_menu (Gdk.EventButton event) { | ||
446 | 148 | if (this.visible) { | ||
447 | 149 | view.set_focus (null); | ||
448 | 150 | view.search_entry.grab_focus (); | ||
449 | 151 | |||
450 | 152 | this.hide (); | ||
451 | 153 | // Block here to replicate context menu behavior | ||
452 | 154 | return true; | ||
453 | 155 | } | ||
454 | 156 | // Visible can be false but the popover still thinks it's up | ||
455 | 157 | // and will show when it's view is switched back to | ||
456 | 158 | // in that case don't block forwarding but make sure it is | ||
457 | 159 | // really hidden | ||
458 | 160 | this.hide (); | ||
459 | 161 | return false; | ||
460 | 162 | } | ||
461 | 163 | |||
462 | 164 | ~NofocusPopover () { | ||
463 | 165 | disconnect_popover_signals (parent_container); | ||
464 | 166 | } | ||
465 | 167 | } | ||
466 | 168 | |||
467 | 169 | } // End namespace | ||
468 | 0 | \ No newline at end of file | 170 | \ No newline at end of file |
469 | 1 | 171 | ||
470 | === modified file 'src/Widgets/Switcher.vala' | |||
471 | --- src/Widgets/Switcher.vala 2014-05-26 06:26:17 +0000 | |||
472 | +++ src/Widgets/Switcher.vala 2014-10-17 01:18:18 +0000 | |||
473 | @@ -27,7 +27,8 @@ | |||
474 | 27 | 27 | ||
475 | 28 | private Gtk.Stack stack; | 28 | private Gtk.Stack stack; |
476 | 29 | private Gee.HashMap<Gtk.Widget, Gtk.ToggleButton> buttons; | 29 | private Gee.HashMap<Gtk.Widget, Gtk.ToggleButton> buttons; |
478 | 30 | 30 | public signal void on_stack_changed (); | |
479 | 31 | |||
480 | 31 | public Switcher () { | 32 | public Switcher () { |
481 | 32 | orientation = Gtk.Orientation.HORIZONTAL; | 33 | orientation = Gtk.Orientation.HORIZONTAL; |
482 | 33 | spacing = 2; | 34 | spacing = 2; |
483 | @@ -86,6 +87,7 @@ | |||
484 | 86 | 87 | ||
485 | 87 | private void on_button_clicked (Gtk.Widget widget) { | 88 | private void on_button_clicked (Gtk.Widget widget) { |
486 | 88 | stack.set_visible_child (widget); | 89 | stack.set_visible_child (widget); |
487 | 90 | on_stack_changed (); | ||
488 | 89 | } | 91 | } |
489 | 90 | 92 | ||
490 | 91 | private void populate_switcher () { | 93 | private void populate_switcher () { |
Has merge conflicts