Merge lp:~mmcg069/software-center/pathbar-atk into lp:software-center
- pathbar-atk
- Merge into trunk
Proposed by
Matthew McGowan
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~mmcg069/software-center/pathbar-atk |
Merge into: | lp:software-center |
Diff against target: |
4408 lines (+1961/-1978) 12 files modified
softwarecenter/app.py (+3/-2) softwarecenter/view/appview.py (+8/-3) softwarecenter/view/availablepane.py (+123/-78) softwarecenter/view/channelpane.py (+6/-1) softwarecenter/view/installedpane.py (+3/-1) softwarecenter/view/navhistory.py (+147/-88) softwarecenter/view/softwarepane.py (+1/-1) softwarecenter/view/widgets/backforward.py (+140/-132) softwarecenter/view/widgets/pathbar2.py (+0/-1605) softwarecenter/view/widgets/pathbar_common.py (+827/-0) softwarecenter/view/widgets/pathbar_gtk_atk.py (+703/-0) softwarecenter/view/widgets/rgb.py (+0/-67) |
To merge this branch: | bzr merge lp:~mmcg069/software-center/pathbar-atk |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
software-store-developers | Pending | ||
Review via email: mp+22778@code.launchpad.net |
Commit message
Description of the change
most notable:
* Modify PathBar to now use gtk.EventBox's for PathPart's
* Enable atk accessibility support
* Pathbar now provides for keyboard navigation, complete with focus box drawing
* Improve theme coverage
* All features of old PathBar retained in shift to new PathBar design
other:
* Tweak navhistory behaviour to better work with new Pathbar
* Other minor tweaks
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'softwarecenter/app.py' |
2 | --- softwarecenter/app.py 2010-04-01 19:48:40 +0000 |
3 | +++ softwarecenter/app.py 2010-04-04 06:00:32 +0000 |
4 | @@ -214,7 +214,8 @@ |
5 | |
6 | # default focus |
7 | self.available_pane.searchentry.grab_focus() |
8 | - |
9 | + self.window_main.set_size_request(600, 400) |
10 | + |
11 | # restore state |
12 | self.config = get_config() |
13 | self.restore_state() |
14 | @@ -561,7 +562,7 @@ |
15 | def restore_state(self): |
16 | if self.config.has_option("general", "size"): |
17 | (x, y) = self.config.get("general", "size").split(",") |
18 | - self.window_main.resize(int(x), int(y)) |
19 | + self.window_main.set_default_size(int(x), int(y)) |
20 | if (self.config.has_option("general", "maximized") and |
21 | self.config.getboolean("general", "maximized")): |
22 | self.window_main.maximize() |
23 | |
24 | === modified file 'softwarecenter/view/appview.py' |
25 | --- softwarecenter/view/appview.py 2010-04-01 19:48:40 +0000 |
26 | +++ softwarecenter/view/appview.py 2010-04-04 06:00:32 +0000 |
27 | @@ -96,6 +96,7 @@ |
28 | data further. A python function that gets a pkgname |
29 | """ |
30 | gtk.GenericTreeModel.__init__(self) |
31 | + self.search_query = search_query |
32 | self.cache = cache |
33 | self.db = db |
34 | self.icons = icons |
35 | @@ -258,7 +259,7 @@ |
36 | summary = app.pkgname |
37 | if self.db.is_appname_duplicated(appname): |
38 | appname = "%s (%s)" % (appname, app.pkgname) |
39 | - s = "%s\n<small>%s</small>" % ( |
40 | + s = "<b>%s</b>\n<small>%s</small>" % ( |
41 | gobject.markup_escape_text(appname), |
42 | gobject.markup_escape_text(summary)) |
43 | return s |
44 | @@ -900,7 +901,9 @@ |
45 | """ |
46 | (path, column) = self.get_cursor() |
47 | model = self.get_model() |
48 | - action_in_progress = (model[path][AppStore.COL_ACTION_IN_PROGRESS] != -1) |
49 | + action_in_progress = False |
50 | + if path: |
51 | + action_in_progress = (model[path][AppStore.COL_ACTION_IN_PROGRESS] != -1) |
52 | return action_in_progress |
53 | |
54 | def _on_realize(self, widget, tr): |
55 | @@ -948,7 +951,9 @@ |
56 | def _on_cursor_changed(self, view): |
57 | # trigger callback, if we do it here get_selection() returns |
58 | # the previous selected row for some reason |
59 | - gobject.timeout_add(10, self._app_selected_timeout_cb, view) |
60 | + |
61 | + # mvo: can we make this timeout 1? The AppView is much nicer this way... |
62 | + gobject.timeout_add(1, self._app_selected_timeout_cb, view) |
63 | |
64 | def _app_selected_timeout_cb(self, view): |
65 | selection = view.get_selection() |
66 | |
67 | === modified file 'softwarecenter/view/availablepane.py' |
68 | --- softwarecenter/view/availablepane.py 2010-03-05 15:53:27 +0000 |
69 | +++ softwarecenter/view/availablepane.py 2010-04-04 06:00:32 +0000 |
70 | @@ -48,7 +48,7 @@ |
71 | (PAGE_CATEGORY, |
72 | PAGE_APPLIST, |
73 | PAGE_APP_DETAILS) = range(3) |
74 | - |
75 | + |
76 | # define ID values for the various buttons found in the navigation bar |
77 | NAV_BUTTON_ID_CATEGORY = "category" |
78 | NAV_BUTTON_ID_LIST = "list" |
79 | @@ -73,14 +73,14 @@ |
80 | self.connect("app-list-changed", self._on_app_list_changed) |
81 | self.current_app_by_category = {} |
82 | self.current_app_by_subcategory = {} |
83 | + # track navigation history |
84 | + self.nav_history = NavigationHistory(self) |
85 | # UI |
86 | self._build_ui() |
87 | - # track navigation history |
88 | - self.nav_history = NavigationHistory(self) |
89 | |
90 | def _build_ui(self): |
91 | # categories, appview and details into the notebook in the bottom |
92 | - self.cat_view = CategoriesView(self.datadir, APP_INSTALL_PATH, |
93 | + self.cat_view = CategoriesView(self.datadir, APP_INSTALL_PATH, |
94 | self.db, |
95 | self.icons) |
96 | scroll_categories = gtk.ScrolledWindow() |
97 | @@ -88,8 +88,8 @@ |
98 | scroll_categories.add(self.cat_view) |
99 | self.notebook.append_page(scroll_categories, gtk.Label("categories")) |
100 | # sub-categories view |
101 | - self.subcategories_view = CategoriesView(self.datadir, |
102 | - APP_INSTALL_PATH, |
103 | + self.subcategories_view = CategoriesView(self.datadir, |
104 | + APP_INSTALL_PATH, |
105 | self.db, |
106 | self.icons, |
107 | self.cat_view.categories[0]) |
108 | @@ -108,7 +108,7 @@ |
109 | self.top_hbox.pack_start(self.back_forward, expand=False, padding=self.PADDING) |
110 | # nav buttons first in the panel |
111 | self.top_hbox.reorder_child(self.back_forward, 0) |
112 | - # now a vbox for subcategories and applist |
113 | + # now a vbox for subcategories and applist |
114 | apps_vbox = gtk.VPaned() |
115 | apps_vbox.pack1(self.scroll_subcategories, resize=True) |
116 | apps_vbox.pack2(self.scroll_app_list) |
117 | @@ -120,9 +120,10 @@ |
118 | # set status text |
119 | self._update_status_text(len(self.db)) |
120 | # home button |
121 | - self.navigation_bar.add_with_id(_("Get Software"), |
122 | + self.navigation_bar.add_with_id(_("Get Software"), |
123 | self.on_navigation_category, |
124 | self.NAV_BUTTON_ID_CATEGORY, |
125 | + do_callback=True, |
126 | animate=False) |
127 | |
128 | def _get_query(self): |
129 | @@ -137,7 +138,7 @@ |
130 | elif self.apps_category: |
131 | cat_query = self.apps_category.query |
132 | # mix category with the search terms and return query |
133 | - return self.db.get_query_list_from_search_entry(self.apps_search_term, |
134 | + return self.db.get_query_list_from_search_entry(self.apps_search_term, |
135 | cat_query) |
136 | |
137 | def _in_no_display_category(self): |
138 | @@ -150,7 +151,7 @@ |
139 | def _show_hide_subcategories(self): |
140 | # check if have subcategories and are not in a subcategory |
141 | # view - if so, show it |
142 | - if (self.apps_category and |
143 | + if (self.apps_category and |
144 | self.apps_category.subcategories and |
145 | not (self.apps_search_term or self.apps_subcategory)): |
146 | self.scroll_subcategories.show() |
147 | @@ -163,16 +164,16 @@ |
148 | # not hide it |
149 | model = self.app_view.get_model() |
150 | if (model and |
151 | - len(model) == 0 and |
152 | + len(model) == 0 and |
153 | self.apps_category and |
154 | - self.apps_category.subcategories and |
155 | + self.apps_category.subcategories and |
156 | not self.apps_subcategory): |
157 | self.scroll_app_list.hide() |
158 | else: |
159 | self.scroll_app_list.show() |
160 | |
161 | def refresh_apps(self): |
162 | - """refresh the applist after search changes and update the |
163 | + """refresh the applist after search changes and update the |
164 | navigation bar |
165 | """ |
166 | logging.debug("refresh_apps") |
167 | @@ -185,18 +186,28 @@ |
168 | def _refresh_apps_with_apt_cache(self): |
169 | # build query |
170 | query = self._get_query() |
171 | - logging.debug("availablepane query: %s" % query) |
172 | - # *ugh* deactivate the old model because otherwise it keeps |
173 | - # getting progress_changed events and eats CPU time until its |
174 | - # garbage collected |
175 | + |
176 | old_model = self.app_view.get_model() |
177 | if old_model is not None: |
178 | - old_model.active = False |
179 | + # check if new AppStore query == old query. if yes, do nothing |
180 | + if isinstance(old_model, AppStore) and \ |
181 | + str(old_model.search_query) == str(query): |
182 | + # check if we show subcategoriy |
183 | + self._show_hide_applist() |
184 | + self.emit("app-list-changed", len(old_model)) |
185 | + return |
186 | + else: |
187 | + # *ugh* deactivate the old model because otherwise it keeps |
188 | + # getting progress_changed events and eats CPU time until its |
189 | + # garbage collected |
190 | + old_model.active = False |
191 | + |
192 | + logging.debug("availablepane query: %s" % query) |
193 | # create new model and attach it |
194 | new_model = AppStore(self.cache, |
195 | - self.db, |
196 | - self.icons, |
197 | - query, |
198 | + self.db, |
199 | + self.icons, |
200 | + query, |
201 | limit=self.apps_limit, |
202 | sort=self.apps_sorted, |
203 | filter=self.apps_filter) |
204 | @@ -210,15 +221,14 @@ |
205 | """Update the navigation button""" |
206 | if self.apps_category and not self.apps_search_term: |
207 | cat = self.apps_category.name |
208 | - self.navigation_bar.add_with_id(cat, |
209 | + self.navigation_bar.add_with_id(cat, |
210 | self.on_navigation_list, |
211 | - self.NAV_BUTTON_ID_LIST, |
212 | - None) |
213 | + self.NAV_BUTTON_ID_LIST, True) |
214 | + |
215 | elif self.apps_search_term: |
216 | self.navigation_bar.add_with_id(_("Search Results"), |
217 | - self.on_navigation_search, |
218 | - self.NAV_BUTTON_ID_SEARCH, |
219 | - None) |
220 | + self.on_navigation_search, |
221 | + self.NAV_BUTTON_ID_SEARCH, True) |
222 | |
223 | # status text woo |
224 | def get_status_text(self): |
225 | @@ -228,7 +238,7 @@ |
226 | self._in_no_display_category()): |
227 | return "" |
228 | return self._status_text |
229 | - |
230 | + |
231 | def get_current_app(self): |
232 | """return the current active application object""" |
233 | if self.is_category_view_showing(): |
234 | @@ -238,13 +248,13 @@ |
235 | return self.current_app_by_subcategory.get(self.apps_subcategory) |
236 | else: |
237 | return self.current_app_by_category.get(self.apps_category) |
238 | - |
239 | + |
240 | def _on_app_list_changed(self, pane, length): |
241 | """internal helper that keeps the status text up-to-date by |
242 | keeping track of the app-list-changed signals |
243 | """ |
244 | self._update_status_text(length) |
245 | - |
246 | + |
247 | def _update_status_text(self, length): |
248 | """ |
249 | update the text in the status bar |
250 | @@ -280,11 +290,17 @@ |
251 | self.apps_search_term = "" |
252 | self.navigation_bar.remove_id(self.NAV_BUTTON_ID_SEARCH) |
253 | |
254 | + def _check_nav_history(self, display_cb): |
255 | + if self.navigation_bar.get_last().label != self.nav_history.get_last_label(): |
256 | + nav_item = NavigationItem(self, display_cb) |
257 | + self.nav_history.navigate_no_cursor_step(nav_item) |
258 | + return |
259 | + |
260 | # callbacks |
261 | def on_cache_ready(self, cache): |
262 | """ refresh the application list when the cache is re-opened """ |
263 | - # just re-draw in the available pane, nothing but the |
264 | - # "is-installed" overlay icon will change when something |
265 | + # just re-draw in the available pane, nothing but the |
266 | + # "is-installed" overlay icon will change when something |
267 | # is installed or removed in the available pane |
268 | self.app_view.queue_draw() |
269 | |
270 | @@ -322,67 +338,89 @@ |
271 | self.refresh_apps() |
272 | self._show_category_overview() |
273 | |
274 | + def display_category(self): |
275 | + self._clear_search() |
276 | + self._show_category_overview() |
277 | + return |
278 | + |
279 | + def display_search(self): |
280 | + self.navigation_bar.remove_id(self.NAV_BUTTON_ID_DETAILS) |
281 | + self.notebook.set_current_page(self.PAGE_APPLIST) |
282 | + self.emit("app-list-changed", len(self.app_view.get_model())) |
283 | + self.searchentry.show() |
284 | + return |
285 | + |
286 | + def display_list(self): |
287 | + self.navigation_bar.remove_id(self.NAV_BUTTON_ID_SUBCAT) |
288 | + self.navigation_bar.remove_id(self.NAV_BUTTON_ID_DETAILS) |
289 | + |
290 | + if self.apps_subcategory: |
291 | + self.apps_subcategory = None |
292 | + self.set_category(self.apps_category) |
293 | + if self.apps_search_term: |
294 | + self._clear_search() |
295 | + self.refresh_apps() |
296 | + |
297 | + self.notebook.set_current_page(self.PAGE_APPLIST) |
298 | + model = self.app_view.get_model() |
299 | + self.emit("app-list-changed", len(model)) |
300 | + self.searchentry.show() |
301 | + return |
302 | + |
303 | + def display_list_subcat(self): |
304 | + if self.apps_search_term: |
305 | + self._clear_search() |
306 | + self.refresh_apps() |
307 | + self.set_category(self.apps_subcategory) |
308 | + self.navigation_bar.remove_id(self.NAV_BUTTON_ID_DETAILS) |
309 | + self.notebook.set_current_page(self.PAGE_APPLIST) |
310 | + self.emit("app-list-changed", len(self.app_view.get_model())) |
311 | + self.searchentry.show() |
312 | + return |
313 | + |
314 | + def display_details(self): |
315 | + self.notebook.set_current_page(self.PAGE_APP_DETAILS) |
316 | + self.searchentry.hide() |
317 | + return |
318 | + |
319 | def on_navigation_category(self, pathbar, part): |
320 | """callback when the navigation button with id 'category' is clicked""" |
321 | - if pathbar and not pathbar.get_active(): |
322 | - return |
323 | # clear the search |
324 | - self._clear_search() |
325 | - self._show_category_overview() |
326 | - self.nav_history.navigate(CategoryViewNavigationItem(self)) |
327 | + self.display_category() |
328 | + nav_item = NavigationItem(self, self.display_category) |
329 | + self.nav_history.navigate(nav_item) |
330 | |
331 | def on_navigation_search(self, pathbar, part): |
332 | """ callback when the navigation button with id 'search' is clicked""" |
333 | - self.navigation_bar.remove_id(self.NAV_BUTTON_ID_DETAILS) |
334 | - self.notebook.set_current_page(self.PAGE_APPLIST) |
335 | - self.emit("app-list-changed", len(self.app_view.get_model())) |
336 | - self.nav_history.navigate(SearchNavigationItem(self)) |
337 | - self.searchentry.show() |
338 | + self.display_search() |
339 | + nav_item = NavigationItem(self, self.display_search) |
340 | + self.nav_history.navigate(nav_item) |
341 | |
342 | def on_navigation_list(self, pathbar, part): |
343 | """callback when the navigation button with id 'list' is clicked""" |
344 | - if pathbar and not pathbar.get_active(): |
345 | - return |
346 | - self.navigation_bar.remove_id(self.NAV_BUTTON_ID_SUBCAT) |
347 | - self.navigation_bar.remove_id(self.NAV_BUTTON_ID_DETAILS) |
348 | - if self.apps_subcategory: |
349 | - self.apps_subcategory = None |
350 | - self.set_category(self.apps_category) |
351 | - if self.apps_search_term: |
352 | - self._clear_search() |
353 | - self.refresh_apps() |
354 | - self.notebook.set_current_page(self.PAGE_APPLIST) |
355 | - model = self.app_view.get_model() |
356 | - self.emit("app-list-changed", len(model)) |
357 | - self.searchentry.show() |
358 | - self.nav_history.navigate(AppListNavigationItem(self)) |
359 | + self.display_list() |
360 | + nav_item = NavigationItem(self, self.display_list) |
361 | + self.nav_history.navigate(nav_item) |
362 | |
363 | def on_navigation_list_subcategory(self, pathbar, part): |
364 | - if pathbar and not pathbar.get_active(): |
365 | - return |
366 | - if self.apps_search_term: |
367 | - self._clear_search() |
368 | - self.refresh_apps() |
369 | - self.set_category(self.apps_subcategory) |
370 | - self.navigation_bar.remove_id(self.NAV_BUTTON_ID_DETAILS) |
371 | - self.notebook.set_current_page(self.PAGE_APPLIST) |
372 | - self.emit("app-list-changed", len(self.app_view.get_model())) |
373 | - self.searchentry.show() |
374 | - self.nav_history.navigate(AppListSubcategoryNavigationItem(self)) |
375 | + self.display_list_subcat() |
376 | + nav_item = NavigationItem(self, self.display_list_subcat) |
377 | + self.nav_history.navigate(nav_item) |
378 | |
379 | def on_navigation_details(self, pathbar, part): |
380 | """callback when the navigation button with id 'details' is clicked""" |
381 | - if pathbar and not pathbar.get_active(): |
382 | - return |
383 | - self.notebook.set_current_page(self.PAGE_APP_DETAILS) |
384 | - self.searchentry.hide() |
385 | - self.nav_history.navigate(AppDetailsNavigationItem(self)) |
386 | + self.display_details() |
387 | + nav_item = NavigationItem(self, self.display_details) |
388 | + self.nav_history.navigate(nav_item) |
389 | |
390 | def on_subcategory_activated(self, cat_view, category): |
391 | #print cat_view, name, query |
392 | logging.debug("on_subcategory_activated: %s %s" % ( |
393 | category.name, category)) |
394 | self.apps_subcategory = category |
395 | + |
396 | + #self._check_nav_history(self.display_list) |
397 | + |
398 | self.navigation_bar.add_with_id( |
399 | category.name, self.on_navigation_list_subcategory, self.NAV_BUTTON_ID_SUBCAT) |
400 | |
401 | @@ -392,21 +430,24 @@ |
402 | category.name, category)) |
403 | self.apps_category = category |
404 | self.set_category(category) |
405 | - |
406 | + |
407 | def on_application_selected(self, appview, app): |
408 | """callback when an app is selected""" |
409 | logging.debug("on_application_selected: '%s'" % app) |
410 | + |
411 | if self.apps_subcategory: |
412 | + #self._check_nav_history(self.display_list_subcat) |
413 | self.current_app_by_subcategory[self.apps_subcategory] = app |
414 | else: |
415 | + #self._check_nav_history(self.display_list) |
416 | self.current_app_by_category[self.apps_category] = app |
417 | - |
418 | + |
419 | def on_nav_back_clicked(self, widget, event): |
420 | self.nav_history.nav_back() |
421 | |
422 | def on_nav_forward_clicked(self, widget, event): |
423 | self.nav_history.nav_forward() |
424 | - |
425 | + |
426 | def is_category_view_showing(self): |
427 | # check if we are in the category page or if we display a |
428 | # sub-category page that has no visible applications |
429 | @@ -414,9 +455,13 @@ |
430 | not self.scroll_app_list.props.visible) |
431 | |
432 | def set_category(self, category): |
433 | + def _cb(): |
434 | + self.refresh_apps() |
435 | + self.notebook.set_current_page(self.PAGE_APPLIST) |
436 | + return False |
437 | + |
438 | self.update_navigation_button() |
439 | - self.refresh_apps() |
440 | - self.notebook.set_current_page(self.PAGE_APPLIST) |
441 | + gobject.idle_add(_cb) |
442 | |
443 | if __name__ == "__main__": |
444 | #logging.basicConfig(level=logging.DEBUG) |
445 | |
446 | === modified file 'softwarecenter/view/channelpane.py' |
447 | --- softwarecenter/view/channelpane.py 2010-03-23 16:50:23 +0000 |
448 | +++ softwarecenter/view/channelpane.py 2010-04-04 06:00:32 +0000 |
449 | @@ -23,6 +23,7 @@ |
450 | import os |
451 | import sys |
452 | import xapian |
453 | +import gobject |
454 | |
455 | from gettext import gettext as _ |
456 | |
457 | @@ -99,6 +100,10 @@ |
458 | old_model = self.app_view.get_model() |
459 | if old_model is not None: |
460 | old_model.active = False |
461 | + gobject.idle_add(self._make_new_model, query) |
462 | + return False |
463 | + |
464 | + def _make_new_model(self, query): |
465 | # get a new store and attach it to the view |
466 | new_model = AppStore(self.cache, |
467 | self.db, |
468 | @@ -110,7 +115,7 @@ |
469 | self.app_view.set_model(new_model) |
470 | self.emit("app-list-changed", len(new_model)) |
471 | return False |
472 | - |
473 | + |
474 | def set_channel(self, channel): |
475 | """ |
476 | set the current software channel object for display in the channel pane |
477 | |
478 | === modified file 'softwarecenter/view/installedpane.py' |
479 | --- softwarecenter/view/installedpane.py 2010-03-03 15:39:40 +0000 |
480 | +++ softwarecenter/view/installedpane.py 2010-04-04 06:00:32 +0000 |
481 | @@ -50,6 +50,7 @@ |
482 | # UI |
483 | self._build_ui() |
484 | def _build_ui(self): |
485 | + self.navigation_bar.set_size_request(26, -1) |
486 | self.notebook.append_page(self.scroll_app_list, gtk.Label("installed")) |
487 | # details |
488 | self.notebook.append_page(self.scroll_details, gtk.Label("details")) |
489 | @@ -82,7 +83,8 @@ |
490 | query = None |
491 | self.navigation_bar.add_with_id(_("Installed Software"), |
492 | self.on_navigation_list, |
493 | - "list") |
494 | + "list", |
495 | + animate=False) |
496 | # *ugh* deactivate the old model because otherwise it keeps |
497 | # getting progress_changed events and eats CPU time until it's |
498 | # garbage collected |
499 | |
500 | === modified file 'softwarecenter/view/navhistory.py' |
501 | --- softwarecenter/view/navhistory.py 2010-03-19 21:27:31 +0000 |
502 | +++ softwarecenter/view/navhistory.py 2010-04-04 06:00:32 +0000 |
503 | @@ -15,7 +15,8 @@ |
504 | # You should have received a copy of the GNU General Public License along with |
505 | # this program; if not, write to the Free Software Foundation, Inc., |
506 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
507 | -import copy |
508 | + |
509 | +import gobject |
510 | import logging |
511 | |
512 | from softwarecenter.utils import unescape |
513 | @@ -28,94 +29,117 @@ |
514 | class to manage navigation history in the "Get Software" section (the |
515 | available pane). |
516 | """ |
517 | - |
518 | + |
519 | + MAX_NAV_ITEMS = 10 # limit number of NavItems allowed in the NavStack |
520 | + |
521 | + |
522 | def __init__(self, available_pane): |
523 | self.available_pane = available_pane |
524 | - # always start at main category view |
525 | - self._current_nav_item = CategoryViewNavigationItem(available_pane) |
526 | # use stacks to track navigation history |
527 | - self._nav_back_stack = [] |
528 | - self._nav_forward_stack = [] |
529 | - |
530 | - def navigate(self, dest_nav_item): |
531 | + self._nav_stack = NavigationStack(self.MAX_NAV_ITEMS) |
532 | + |
533 | + def navigate(self, nav_item): |
534 | """ |
535 | append a new NavigationItem to the history stack |
536 | """ |
537 | if in_replay_history_mode: |
538 | return |
539 | - logging.debug("submit navitem for history: %s" % dest_nav_item) |
540 | - # TODO: Detect multiple clicks on the same nav button and filter |
541 | - # them out - we don't want them in the history |
542 | - dest_nav_item.parent = self |
543 | - self._nav_back_stack.append(self._current_nav_item) |
544 | - self._current_nav_item = dest_nav_item |
545 | - # reset navigation forward stack on a direct navigation |
546 | - self._nav_forward_stack = [] |
547 | - # update buttons |
548 | - self.available_pane.back_forward.left.set_sensitive(True) |
549 | + |
550 | + nav_item.parent = self |
551 | + self._nav_stack.append(nav_item) |
552 | + |
553 | + if self._nav_stack.cursor > 0: |
554 | + self.available_pane.back_forward.left.set_sensitive(True) |
555 | self.available_pane.back_forward.right.set_sensitive(False) |
556 | - |
557 | + |
558 | + def navigate_no_cursor_step(self, nav_item): |
559 | + if in_replay_history_mode: |
560 | + return |
561 | + |
562 | + nav_item.parent = self |
563 | + self._nav_stack.append_no_cursor_step(nav_item) |
564 | + return |
565 | + |
566 | def nav_forward(self): |
567 | """ |
568 | navigate forward one item in the history stack |
569 | """ |
570 | + nav_item = self._nav_stack.step_forward() |
571 | + nav_item.navigate_to() |
572 | + |
573 | self.available_pane.back_forward.left.set_sensitive(True) |
574 | - if len(self._nav_forward_stack) <= 1: |
575 | + if self._nav_stack.at_end(): |
576 | + if self.available_pane.back_forward.right.has_focus(): |
577 | + self.available_pane.back_forward.left.grab_focus() |
578 | self.available_pane.back_forward.right.set_sensitive(False) |
579 | - nav_item = self._nav_forward_stack.pop() |
580 | - self._nav_back_stack.append(self._current_nav_item) |
581 | - self._current_nav_item = nav_item |
582 | - nav_item.navigate_to() |
583 | - |
584 | + |
585 | def nav_back(self): |
586 | """ |
587 | navigate back one item in the history stack |
588 | """ |
589 | + nav_item = self._nav_stack.step_back() |
590 | + nav_item.navigate_to() |
591 | + |
592 | self.available_pane.back_forward.right.set_sensitive(True) |
593 | - if len(self._nav_back_stack) <= 1: |
594 | + if self._nav_stack.at_start(): |
595 | + if self.available_pane.back_forward.left.has_focus(): |
596 | + self.available_pane.back_forward.right.grab_focus() |
597 | self.available_pane.back_forward.left.set_sensitive(False) |
598 | - nav_item = self._nav_back_stack.pop() |
599 | - logging.debug("nav_back: %s" % nav_item) |
600 | - self._nav_forward_stack.append(self._current_nav_item) |
601 | - self._current_nav_item = nav_item |
602 | - nav_item.navigate_to() |
603 | - |
604 | + |
605 | + def get_last_label(self): |
606 | + if self._nav_stack.stack: |
607 | + if self._nav_stack[-1].parts: |
608 | + return self._nav_stack[-1].parts[-1].label |
609 | + return None |
610 | + |
611 | + |
612 | class NavigationItem(object): |
613 | """ |
614 | class to implement navigation points to be managed in the history queues |
615 | """ |
616 | |
617 | - def __init__(self, available_pane): |
618 | + def __init__(self, available_pane, update_available_pane_cb): |
619 | self.available_pane = available_pane |
620 | + self.update_available_pane = update_available_pane_cb |
621 | self.apps_category = available_pane.apps_category |
622 | self.apps_subcategory = available_pane.apps_subcategory |
623 | self.apps_search_term = available_pane.apps_search_term |
624 | self.current_app = available_pane.get_current_app() |
625 | - self.parts = self.available_pane.navigation_bar.get_parts()[:] |
626 | - |
627 | + self.parts = self.available_pane.navigation_bar.get_parts() |
628 | + |
629 | def navigate_to(self): |
630 | """ |
631 | navigate to the view that corresponds to this NavigationItem |
632 | """ |
633 | global in_replay_history_mode |
634 | in_replay_history_mode = True |
635 | - self.available_pane.apps_category = self.apps_category |
636 | - self.available_pane.apps_subcategory = self.apps_subcategory |
637 | - self.available_pane.apps_search_term = self.apps_search_term |
638 | - self.available_pane.searchentry.set_text(self.apps_search_term) |
639 | - self.available_pane.searchentry.set_position(-1) |
640 | - self.available_pane.app_details.show_app(self.current_app) |
641 | - # first part is special and kept in remove_all |
642 | - self.available_pane.navigation_bar.remove_all() |
643 | + available_pane = self.available_pane |
644 | + available_pane.apps_category = self.apps_category |
645 | + available_pane.apps_subcategory = self.apps_subcategory |
646 | + available_pane.apps_search_term = self.apps_search_term |
647 | + available_pane.searchentry.set_text(self.apps_search_term) |
648 | + available_pane.searchentry.set_position(-1) |
649 | + available_pane.app_details.show_app(self.current_app) |
650 | + |
651 | + nav_bar = self.available_pane.navigation_bar |
652 | + nav_bar.remove_all(do_callback=False) |
653 | + |
654 | for part in self.parts[1:]: |
655 | - self.available_pane.navigation_bar.add_with_id(unescape(part.label), |
656 | - part.callback, |
657 | - part.id, |
658 | - do_callback=False, |
659 | - animate=False) |
660 | - self.parts[-1].activate() |
661 | + nav_bar.add_with_id(unescape(part.label), |
662 | + part.callback, |
663 | + part.get_name(), |
664 | + do_callback=False, |
665 | + animate=False) |
666 | + |
667 | + gobject.idle_add(self._update_available_pane_cb, nav_bar) |
668 | in_replay_history_mode = False |
669 | - |
670 | + |
671 | + def _update_available_pane_cb(self, nav_bar): |
672 | + last_part = nav_bar.get_parts()[-1] |
673 | + nav_bar.set_active_no_callback(last_part) |
674 | + self.update_available_pane() |
675 | + return False |
676 | + |
677 | def __str__(self): |
678 | details = [] |
679 | details.append("\n%s" % type(self)) |
680 | @@ -130,41 +154,76 @@ |
681 | details.append(" current_app: %s" % self.current_app) |
682 | details.append(" apps_search_term: %s" % self.apps_search_term) |
683 | return '\n'.join(details) |
684 | - |
685 | -class CategoryViewNavigationItem(NavigationItem): |
686 | - """ |
687 | - navigation item that corresponds to the main category view |
688 | - Note: all subclasses of NavigationItem are for debug use only and |
689 | - can be collapsed to the NavigationItem class if desired |
690 | - """ |
691 | - |
692 | -class AppListNavigationItem(NavigationItem): |
693 | - """ |
694 | - navigation item that corresponds to the application list for the |
695 | - specified category |
696 | - Note: all subclasses of NavigationItem are for debug use only and |
697 | - can be collapsed to the NavigationItem class if desired |
698 | - """ |
699 | - |
700 | -class AppListSubcategoryNavigationItem(NavigationItem): |
701 | - """ |
702 | - navigation item that corresponds to the application list for the |
703 | - specified category and subcategory |
704 | - Note: all subclasses of NavigationItem are for debug use only and |
705 | - can be collapsed to the NavigationItem class if desired |
706 | - """ |
707 | - |
708 | -class AppDetailsNavigationItem(NavigationItem): |
709 | - """ |
710 | - navigation item that corresponds to the details view for the |
711 | - specified application |
712 | - Note: all subclasses of NavigationItem are for debug use only and |
713 | - can be collapsed to the NavigationItem class if desired |
714 | - """ |
715 | - |
716 | -class SearchNavigationItem(NavigationItem): |
717 | - """ |
718 | - navigation item that corresponds to a search in progress |
719 | - Note: all subclasses of NavigationItem are for debug use only and |
720 | - can be collapsed to the NavigationItem class if desired |
721 | - """ |
722 | + |
723 | + |
724 | +class NavigationStack(object): |
725 | + |
726 | + def __init__(self, max_length): |
727 | + self.max_length = max_length |
728 | + self.stack = [] |
729 | + self.cursor = 0 |
730 | + return |
731 | + |
732 | + def __len__(self): |
733 | + return len(self.stack) |
734 | + |
735 | + def __repr__(self): |
736 | + BOLD = "\033[1m" |
737 | + RESET = "\033[0;0m" |
738 | + s = '[' |
739 | + for i, item in enumerate(self.stack): |
740 | + if i != self.cursor: |
741 | + s += str(item.parts[-1].label) + ', ' |
742 | + else: |
743 | + s += BOLD + str(item.parts[-1].label) + RESET + ', ' |
744 | + return s + ']' |
745 | + |
746 | + def __getitem__(self, item): |
747 | + return self.stack[item] |
748 | + |
749 | + def _isok(self, item): |
750 | + if len(self.stack) == 0: return True |
751 | + pre_item = self.stack[-1] |
752 | + if pre_item.parts[-1].label == item.parts[-1].label: |
753 | + if pre_item.apps_search_term != item.apps_search_term: |
754 | + return True |
755 | + return False |
756 | + return True |
757 | + |
758 | + def append(self, item): |
759 | + if not self._isok(item): |
760 | + self.cursor = len(self.stack)-1 |
761 | + print 'A:', repr(self) |
762 | + return |
763 | + if len(self.stack) + 1 > self.max_length: |
764 | + self.stack.pop(0) |
765 | + self.stack.append(item) |
766 | + self.cursor = len(self.stack)-1 |
767 | + print 'A:', repr(self) |
768 | + return |
769 | + |
770 | + def append_no_cursor_step(self, item): |
771 | + if not self._isok(item): |
772 | + print 'a:', repr(self) |
773 | + return |
774 | + if len(self.stack) + 1 > self.max_length: |
775 | + self.stack.pop(0) |
776 | + self.stack.append(item) |
777 | + print 'a:', repr(self) |
778 | + return |
779 | + |
780 | + def step_back(self): |
781 | + self.cursor -= 1 |
782 | + print 'B:', repr(self) |
783 | + return self.stack[self.cursor] |
784 | + |
785 | + def step_forward(self): |
786 | + self.cursor += 1 |
787 | + print 'B:', repr(self) |
788 | + return self.stack[self.cursor] |
789 | + |
790 | + def at_end(self): |
791 | + return self.cursor == len(self.stack)-1 |
792 | + |
793 | + def at_start(self): |
794 | + return self.cursor == 0 |
795 | |
796 | === modified file 'softwarecenter/view/softwarepane.py' |
797 | --- softwarecenter/view/softwarepane.py 2010-03-29 20:40:17 +0000 |
798 | +++ softwarecenter/view/softwarepane.py 2010-04-04 06:00:32 +0000 |
799 | @@ -29,7 +29,7 @@ |
800 | if "SOFTWARE_CENTER_OLD_PATHBAR" in os.environ: |
801 | from widgets.navigationbar import NavigationBar |
802 | else: |
803 | - from widgets.pathbar2 import NavigationBar |
804 | + from widgets.pathbar_gtk_atk import NavigationBar |
805 | |
806 | from widgets.searchentry import SearchEntry |
807 | |
808 | |
809 | === modified file 'softwarecenter/view/widgets/backforward.py' |
810 | --- softwarecenter/view/widgets/backforward.py 2010-02-15 02:53:26 +0000 |
811 | +++ softwarecenter/view/widgets/backforward.py 2010-04-04 06:00:32 +0000 |
812 | @@ -17,14 +17,14 @@ |
813 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
814 | |
815 | |
816 | - |
817 | -import rgb |
818 | +import atk |
819 | import gtk |
820 | import cairo |
821 | import gobject |
822 | -import pathbar2 |
823 | - |
824 | -from rgb import to_float as f |
825 | +import pathbar_common |
826 | + |
827 | +from gettext import gettext as _ |
828 | + |
829 | |
830 | # pi constants |
831 | M_PI = 3.1415926535897931 |
832 | @@ -43,72 +43,132 @@ |
833 | |
834 | def __init__(self): |
835 | gtk.HBox.__init__(self) |
836 | + self.theme = pathbar_common.PathBarStyle(self) |
837 | sep = SeparatorPart() |
838 | |
839 | if self.get_direction() != gtk.TEXT_DIR_RTL: |
840 | + # ltr |
841 | self.left = ButtonPartLeft('left-clicked') |
842 | self.right = ButtonPartRight('right-clicked') |
843 | + self.set_button_atk_info_ltr() |
844 | else: |
845 | + # rtl |
846 | self.left = ButtonPartRight('left-clicked') |
847 | self.right = ButtonPartLeft('right-clicked') |
848 | + self.set_button_atk_info_rtl() |
849 | + |
850 | + atk_obj = self.get_accessible() |
851 | + atk_obj.set_name(_('History Navigation')) |
852 | + atk_obj.set_description(_('Navigate forwards and backwards.')) |
853 | + atk_obj.set_role(atk.ROLE_PANEL) |
854 | |
855 | self.pack_start(self.left) |
856 | self.pack_start(sep, False) |
857 | self.pack_end(self.right) |
858 | |
859 | - self.theme = self._pick_theme() |
860 | - self.connect("realize", self._on_realize) |
861 | - return |
862 | - |
863 | - def _pick_theme(self, name=None): |
864 | - name = name or gtk.settings_get_default().get_property("gtk-theme-name") |
865 | - themes = pathbar2.PathBarThemes.DICT |
866 | - if themes.has_key(name): |
867 | - return themes[name]() |
868 | - print "No styling hints for %s are available" % name |
869 | - return pathbar2.PathBarThemeHuman() |
870 | - |
871 | - def _on_realize(self, widget): |
872 | - self.theme.load(self.style) |
873 | - return |
874 | - |
875 | + sep.connect_after("style-set", self._on_style_set) |
876 | + return |
877 | + |
878 | + def set_button_atk_info_ltr(self): |
879 | + # left button |
880 | + atk_obj = self.left.get_accessible() |
881 | + atk_obj.set_name(_('Back Button')) |
882 | + atk_obj.set_description(_('Navigates back.')) |
883 | + atk_obj.set_role(atk.ROLE_PUSH_BUTTON) |
884 | + |
885 | + # right button |
886 | + atk_obj = self.right.get_accessible() |
887 | + atk_obj.set_name(_('Forward Button')) |
888 | + atk_obj.set_description(_('Navigates forward.')) |
889 | + atk_obj.set_role(atk.ROLE_PUSH_BUTTON) |
890 | + return |
891 | + |
892 | + def set_button_atk_info_rtl(self): |
893 | + # right button |
894 | + atk_obj = self.right.get_accessible() |
895 | + atk_obj.set_name(_('Back Button')) |
896 | + atk_obj.set_description(_('Navigates back.')) |
897 | + atk_obj.set_role(atk.ROLE_PUSH_BUTTON) |
898 | + |
899 | + # left button |
900 | + atk_obj = self.left.get_accessible() |
901 | + atk_obj.set_name(_('Forward Button')) |
902 | + atk_obj.set_description(_('Navigates forward.')) |
903 | + atk_obj.set_role(atk.ROLE_PUSH_BUTTON) |
904 | + return |
905 | + |
906 | + def _on_style_set(self, widget, oldstyle): |
907 | + # when alloc.width == 1, this is typical of an unallocated widget, |
908 | + # lets not break a sweat for nothing... |
909 | + if self.allocation.width == 1: |
910 | + return |
911 | + |
912 | + old_xthickness = self.theme['xthickness'] |
913 | + self.theme = pathbar_common.PathBarStyle(self) |
914 | + if old_xthickness > self.theme['xthickness']: |
915 | + a = self.allocation |
916 | + self.queue_draw_area(a.x, a.y, |
917 | + a.width+self.theme['xthickness'], a.height) |
918 | + else: |
919 | + self.queue_draw() |
920 | + return |
921 | |
922 | class SeparatorPart(gtk.DrawingArea): |
923 | |
924 | def __init__(self): |
925 | gtk.DrawingArea.__init__(self) |
926 | - self.set_size_request(1, -1) |
927 | + self.theme = pathbar_common.PathBarStyle(self) |
928 | + self.set_size_request(self.theme['xthickness'], -1) |
929 | + |
930 | + atk_obj = self.get_accessible() |
931 | + atk_obj.set_role(atk.ROLE_SEPARATOR) |
932 | + |
933 | self.connect("expose-event", self._on_expose) |
934 | + self.connect("style-set", self._on_style_set) |
935 | return |
936 | |
937 | def _on_expose(self, widget, event): |
938 | + parent = self.get_parent() |
939 | + if not parent: return |
940 | cr = widget.window.cairo_create() |
941 | - a = event.area |
942 | - cr.rectangle(a.x, a.y+1, a.width, a.height-2) |
943 | - cr.set_source_rgba(0, 0, 0, 0.45) |
944 | + cr.rectangle(event.area) |
945 | + cr.set_source_rgb(*self.theme.dark_line[self.state].tofloats()) |
946 | cr.fill() |
947 | del cr |
948 | return |
949 | |
950 | + def _on_style_set(self, widget, old_style): |
951 | + self.theme = pathbar_common.PathBarStyle(self) |
952 | + self.set_size_request(self.theme['xthickness'], -1) |
953 | + return |
954 | + |
955 | |
956 | class ButtonPart(gtk.DrawingArea): |
957 | |
958 | ARROW_SIZE = (12,12) |
959 | - DEFAULT_SIZE = (30, 28) |
960 | + DEFAULT_SIZE = (31, 27) |
961 | |
962 | def __init__(self, arrow_type, signal_name): |
963 | gtk.DrawingArea.__init__(self) |
964 | self.set_size_request(*self.DEFAULT_SIZE) |
965 | + self.shape = pathbar_common.SHAPE_RECTANGLE |
966 | self.button_down = False |
967 | self.shadow_type = gtk.SHADOW_OUT |
968 | self.arrow_type = arrow_type |
969 | + |
970 | + self.set_flags(gtk.CAN_FOCUS) |
971 | self.set_events(gtk.gdk.ENTER_NOTIFY_MASK| |
972 | gtk.gdk.LEAVE_NOTIFY_MASK| |
973 | gtk.gdk.BUTTON_PRESS_MASK| |
974 | gtk.gdk.BUTTON_RELEASE_MASK) |
975 | + |
976 | self.connect("enter-notify-event", self._on_enter) |
977 | self.connect("leave-notify-event", self._on_leave) |
978 | self.connect("button-press-event", self._on_press) |
979 | + self.connect("key-press-event", self._on_key_press) |
980 | + self.connect("key-release-event", self._on_key_release, signal_name) |
981 | + self.connect('focus-in-event', self._on_focus_in) |
982 | + self.connect('focus-out-event', self._on_focus_out) |
983 | self.connect("button-release-event", self._on_release, signal_name) |
984 | return |
985 | |
986 | @@ -135,11 +195,32 @@ |
987 | self.set_active(True) |
988 | return |
989 | |
990 | + def _on_key_press(self, widget, event): |
991 | + # react to spacebar, enter, numpad-enter |
992 | + if event.keyval in (32, 65293, 65421): |
993 | + self.set_state(gtk.STATE_ACTIVE) |
994 | + return |
995 | + |
996 | + def _on_key_release(self, widget, event, signal_name): |
997 | + # react to spacebar, enter, numpad-enter |
998 | + if event.keyval in (32, 65293, 65421): |
999 | + self.set_state(gtk.STATE_SELECTED) |
1000 | + self.get_parent().emit(signal_name, event) |
1001 | + return |
1002 | + |
1003 | def _on_leave(self, widget, event): |
1004 | if self.state == gtk.STATE_INSENSITIVE: return |
1005 | self.set_active(False) |
1006 | return |
1007 | |
1008 | + def _on_focus_in(self, widget, event): |
1009 | + self.queue_draw() |
1010 | + return |
1011 | + |
1012 | + def _on_focus_out(self, widget, event): |
1013 | + self.queue_draw() |
1014 | + return |
1015 | + |
1016 | def _on_press(self, widget, event): |
1017 | if self.state == gtk.STATE_INSENSITIVE: return |
1018 | self.button_down = True |
1019 | @@ -160,117 +241,41 @@ |
1020 | self.set_state(gtk.STATE_NORMAL) |
1021 | return |
1022 | |
1023 | -# def expose_gtk(self, widget, area, x, y, width, height): |
1024 | -# # button background |
1025 | -# widget.style.paint_box(widget.window, |
1026 | -# self.state, |
1027 | -# self.shadow_type, |
1028 | -# area, |
1029 | -# widget, |
1030 | -# "button", |
1031 | -# x, |
1032 | -# y, |
1033 | -# width, |
1034 | -# height) |
1035 | - |
1036 | -# # arrow |
1037 | -# aw, ah = self.ARROW_SIZE |
1038 | -# widget.style.paint_arrow(widget.window, |
1039 | -# self.state, |
1040 | -# self.shadow_type, |
1041 | -# area, |
1042 | -# widget, |
1043 | -# "button", |
1044 | -# self.arrow_type, |
1045 | -# True, |
1046 | -# (area.width - aw)/2, |
1047 | -# (area.height - ah)/2, |
1048 | -# aw, |
1049 | -# ah) |
1050 | -# return |
1051 | - |
1052 | - def expose_pathbar(self, widget, area, x, y, width, height): |
1053 | + def expose_pathbar(self, widget, area, x, y, w, h, xo=0, wo=0): |
1054 | + if not self.parent: return |
1055 | # background |
1056 | cr = widget.window.cairo_create() |
1057 | cr.rectangle(area) |
1058 | cr.clip() |
1059 | |
1060 | - cr.translate(x, y) |
1061 | - |
1062 | - self._draw_bg(cr, |
1063 | - width, |
1064 | - height, |
1065 | - self.state, |
1066 | - self.style, |
1067 | - self.get_parent().theme, |
1068 | - self.get_parent().theme.curvature) |
1069 | + self.parent.theme.paint_bg(cr, |
1070 | + self, |
1071 | + x, y, w, h) |
1072 | del cr |
1073 | |
1074 | # arrow |
1075 | + if self.has_focus(): |
1076 | + self.style.paint_focus(self.window, |
1077 | + self.state, |
1078 | + (x+4+xo, y+4, w-8+wo, h-8), |
1079 | + self, |
1080 | + 'button', |
1081 | + x+4+xo, y+4, |
1082 | + w-8+wo, h-8) |
1083 | + |
1084 | aw, ah = self.ARROW_SIZE |
1085 | - widget.style.paint_arrow(widget.window, |
1086 | - self.state, |
1087 | - self.shadow_type, |
1088 | - area, |
1089 | - widget, |
1090 | - "button", |
1091 | - self.arrow_type, |
1092 | - True, |
1093 | - (area.width - aw)/2, |
1094 | - (area.height - ah)/2, |
1095 | - aw, |
1096 | - ah) |
1097 | - return |
1098 | - |
1099 | - def _draw_bg(self, cr, w, h, state, style, theme, r): |
1100 | - # outer slight bevel or focal highlight |
1101 | - self._draw_rect(cr, 0, 0, w, h, r) |
1102 | - cr.set_source_rgba(0, 0, 0, 0.055) |
1103 | - cr.fill() |
1104 | - |
1105 | - # colour scheme dicts |
1106 | - bg = theme.bg_colors |
1107 | - outer = theme.dark_line_colors |
1108 | - inner = theme.light_line_colors |
1109 | - |
1110 | - # bg linear vertical gradient |
1111 | - if state != gtk.STATE_PRELIGHT: |
1112 | - color1, color2 = bg[state] |
1113 | - else: |
1114 | - if self.state == gtk.STATE_ACTIVE: |
1115 | - color1, color2 = bg[theme.PRELIT_NORMAL] |
1116 | - else: |
1117 | - color1, color2 = bg[theme.PRELIT_ACTIVE] |
1118 | - |
1119 | - self._draw_rect(cr, 1, 1, w-1, h-1, r) |
1120 | - lin = cairo.LinearGradient(0, 0, 0, h-1) |
1121 | - lin.add_color_stop_rgb(0.0, *color1) |
1122 | - lin.add_color_stop_rgb(1.0, *color2) |
1123 | - cr.set_source(lin) |
1124 | - cr.fill() |
1125 | - |
1126 | - cr.set_line_width(1.0) |
1127 | - # strong outline |
1128 | - self._draw_rect(cr, 1.5, 1.5, w-1.5, h-1.5, r) |
1129 | - cr.set_source_rgb(*outer[state]) |
1130 | - cr.stroke() |
1131 | - |
1132 | - # inner bevel/highlight |
1133 | - if theme.light_line_colors[state]: |
1134 | - self._draw_rect(cr, 2.5, 2.5, w-2.5, h-2.5, r) |
1135 | - r, g, b = inner[state] |
1136 | - cr.set_source_rgba(r, g, b, 0.6) |
1137 | - cr.stroke() |
1138 | - return |
1139 | - |
1140 | - def _draw_rect(self, cr, x, y, w, h, r): |
1141 | - global M_PI, PI_OVER_180 |
1142 | - cr.new_sub_path() |
1143 | - cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
1144 | - cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
1145 | - cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
1146 | - cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
1147 | - cr.close_path() |
1148 | + ax, ay = (area.width - aw)/2, (area.height - ah)/2, |
1149 | + |
1150 | + self.style.paint_arrow(self.window, |
1151 | + self.state, |
1152 | + self.shadow_type, |
1153 | + (ax, ay, aw, ah), |
1154 | + self, |
1155 | + "button", |
1156 | + self.arrow_type, |
1157 | + True, |
1158 | + ax, ay, |
1159 | + aw, ah) |
1160 | return |
1161 | |
1162 | |
1163 | @@ -288,7 +293,8 @@ |
1164 | area.x, |
1165 | area.y, |
1166 | area.width + 10, |
1167 | - area.height) |
1168 | + area.height, |
1169 | + wo=-10) |
1170 | return |
1171 | |
1172 | |
1173 | @@ -303,8 +309,10 @@ |
1174 | area = event.area |
1175 | expose_func(widget, |
1176 | area, |
1177 | - area.x - 10, |
1178 | + area.x-10, |
1179 | area.y, |
1180 | - area.width + 10, |
1181 | - area.height) |
1182 | + area.width+10, |
1183 | + area.height, |
1184 | + xo=10, |
1185 | + wo=-10) |
1186 | return |
1187 | |
1188 | === removed file 'softwarecenter/view/widgets/pathbar2.py' |
1189 | --- softwarecenter/view/widgets/pathbar2.py 2010-03-03 09:18:00 +0000 |
1190 | +++ softwarecenter/view/widgets/pathbar2.py 1970-01-01 00:00:00 +0000 |
1191 | @@ -1,1605 +0,0 @@ |
1192 | -# Copyright (C) 2009 Matthew McGowan |
1193 | -# |
1194 | -# Authors: |
1195 | -# Matthew McGowan |
1196 | -# |
1197 | -# This program is free software: you can redistribute it and/or modify |
1198 | -# it under the terms of the GNU General Public License as published by |
1199 | -# the Free Software Foundation, either version 3 of the License, or |
1200 | -# (at your option) any later version. |
1201 | -# |
1202 | -# This program is distributed in the hope that it will be useful, |
1203 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1204 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1205 | -# GNU General Public License for more details. |
1206 | -# |
1207 | -# You should have received a copy of the GNU General Public License |
1208 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1209 | - |
1210 | -import atk |
1211 | -import cairo |
1212 | -import gobject |
1213 | -import gtk |
1214 | -import pango |
1215 | -import rgb |
1216 | - |
1217 | -from rgb import to_float as f |
1218 | - |
1219 | -# pi constants |
1220 | -M_PI = 3.1415926535897931 |
1221 | -PI_OVER_180 = 0.017453292519943295 |
1222 | - |
1223 | -from gettext import gettext as _ |
1224 | - |
1225 | -class PathBar(gtk.DrawingArea): |
1226 | - |
1227 | - # shapes |
1228 | - SHAPE_RECTANGLE = 0 |
1229 | - SHAPE_START_ARROW = 1 |
1230 | - SHAPE_MID_ARROW = 2 |
1231 | - SHAPE_END_CAP = 3 |
1232 | - |
1233 | - def __init__(self, group=None): |
1234 | - gtk.DrawingArea.__init__(self) |
1235 | - self.__init_drawing() |
1236 | - self.set_redraw_on_allocate(False) |
1237 | - |
1238 | - self.__parts = [] |
1239 | - self.__active_part = None |
1240 | - self.__focal_part = None |
1241 | - self.__button_down = False, None |
1242 | - |
1243 | - self.__scroller = None |
1244 | - self.__scroll_xO = 0 |
1245 | - |
1246 | - self.theme = self.__pick_theme() |
1247 | - |
1248 | - atk_desc = self.get_accessible() |
1249 | - # Accessibility name for the pathbar |
1250 | - atk_desc.set_name(_("You are here:")) |
1251 | - atk_desc.set_role(atk.ROLE_PANEL) |
1252 | - |
1253 | - # setup event handling |
1254 | - self.set_flags(gtk.CAN_FOCUS) |
1255 | - self.set_events(gtk.gdk.POINTER_MOTION_MASK| |
1256 | - gtk.gdk.BUTTON_PRESS_MASK| |
1257 | - gtk.gdk.BUTTON_RELEASE_MASK| |
1258 | - gtk.gdk.KEY_RELEASE_MASK| |
1259 | - gtk.gdk.KEY_PRESS_MASK| |
1260 | - gtk.gdk.ENTER_NOTIFY_MASK| |
1261 | - gtk.gdk.LEAVE_NOTIFY_MASK) |
1262 | - |
1263 | - self.connect("motion-notify-event", self.__motion_notify_cb) |
1264 | - self.connect("enter-notify-event", self.__enter_notify_cb) |
1265 | - self.connect("leave-notify-event", self.__leave_notify_cb) |
1266 | - self.connect("button-press-event", self.__button_press_cb) |
1267 | - self.connect("button-release-event", self.__button_release_cb) |
1268 | -# self.connect("key-release-event", self.__key_release_cb) |
1269 | - |
1270 | - self.connect("realize", self.__realize_cb) |
1271 | - self.connect("expose-event", self.__expose_cb) |
1272 | - self.connect("style-set", self.__style_change_cb) |
1273 | - self.connect("size-allocate", self.__allocation_change_cb) |
1274 | - return |
1275 | - |
1276 | - def get_parts(self): |
1277 | - return self.__parts |
1278 | - |
1279 | - def set_active(self, part, do_callback=True): |
1280 | - part.set_state(gtk.STATE_ACTIVE) |
1281 | - prev, redraw = self.__set_active(part, do_callback) |
1282 | - if redraw: |
1283 | - self.queue_draw_area(*prev.get_allocation_tuple()) |
1284 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1285 | - return |
1286 | - |
1287 | - def get_active(self): |
1288 | - return self.__active_part |
1289 | - |
1290 | -# def get_left_part(self): |
1291 | -# active = self.get_active() |
1292 | -# if not active: |
1293 | -# return self.__parts[0] |
1294 | - |
1295 | -# i = self.__parts.index(active)+1 |
1296 | -# if i > len(self.__parts)-1: |
1297 | -# i = 0 |
1298 | -# return self.__parts[i] |
1299 | - |
1300 | -# def get_right_part(self): |
1301 | -# active = self.get_active() |
1302 | -# if not active: |
1303 | -# return self.__parts[0] |
1304 | - |
1305 | -# i = self.__parts.index(active)-1 |
1306 | -# if i < 0: |
1307 | -# i = len(self.__parts)-1 |
1308 | -# return self.__parts[i] |
1309 | - |
1310 | - def append(self, part, do_callback=True, animate=True): |
1311 | - prev, did_shrink = self.__append(part, do_callback) |
1312 | - if not self.get_property("visible"): |
1313 | - return False |
1314 | - |
1315 | - if animate and self.theme.animate and len(self.__parts) > 1: |
1316 | - aw = self.theme.arrow_width |
1317 | - |
1318 | - # calc draw_area |
1319 | - x,y,w,h = part.get_allocation_tuple() |
1320 | - w += aw |
1321 | - |
1322 | - # begin scroll animation |
1323 | - self.__hscroll_out_init( |
1324 | - part.get_width(), |
1325 | - gtk.gdk.Rectangle(x,y,w,h), |
1326 | - self.theme.scroll_duration_ms, |
1327 | - self.theme.scroll_fps |
1328 | - ) |
1329 | - else: |
1330 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1331 | - return False |
1332 | - |
1333 | - def append_no_callback(self, part): |
1334 | - self.append(part, do_callback=False) |
1335 | - |
1336 | - def remove(self, part): |
1337 | - if len(self.__parts)-1 < 1: |
1338 | - print 'The first part is sacred ;)' |
1339 | - return |
1340 | - |
1341 | - old_w = self.__draw_width() |
1342 | - |
1343 | - # remove part from interal part list |
1344 | - try: |
1345 | - del self.__parts[self.__parts.index(part)] |
1346 | - except: |
1347 | - print 'part not in list!' |
1348 | - return |
1349 | - self.__compose_parts(self.__parts[-1], False) |
1350 | - |
1351 | - if old_w >= self.allocation.width: |
1352 | - self.__grow_check(old_w, self.allocation) |
1353 | - self.queue_draw() |
1354 | - |
1355 | - else: |
1356 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1357 | - self.queue_draw_area(*self.__parts[-1].get_allocation_tuple()) |
1358 | - return |
1359 | - |
1360 | - def remove_all(self, keep_first_part=True): |
1361 | - """remove all elements""" |
1362 | - if keep_first_part: |
1363 | - self.__parts = [self.__parts[0],] # keep first part though! |
1364 | - self.__compose_parts(self.__parts[-1], False) |
1365 | - else: |
1366 | - self.__parts = [] |
1367 | - self.id_to_part = {} |
1368 | - self.queue_draw() |
1369 | - return |
1370 | - |
1371 | - def navigate_up(self): |
1372 | - if len(self.__parts) > 1: |
1373 | - nav_part = self.__parts[len(self.__parts) - 2] |
1374 | - self.set_active(nav_part) |
1375 | - return |
1376 | - |
1377 | -# def navigate_up(self, remove_pathparts=False): |
1378 | -# index = self.__parts.index(self.__active_part) |
1379 | -# if index-1 == -1: return None, index-1, len(self.__parts) |
1380 | -# self.set_active(self.__parts[index-1], remove_pathparts) |
1381 | -# return self.__parts[index-1], index-1, len(self.__parts) |
1382 | - |
1383 | -# def navigate_down(self): |
1384 | -# index = self.__parts.index(self.__active_part) |
1385 | -# if self.__parts[index] == self.__parts[-1]: return None, index+1, len(self.__parts) |
1386 | -# self.set_active(self.__parts[index+1], False) |
1387 | -# return self.__parts[index+1], index+1, len(self.__parts) |
1388 | - |
1389 | - def __set_active(self, part, do_callback): |
1390 | - prev_active = self.__active_part |
1391 | - redraw = False |
1392 | - if part.callback and do_callback: |
1393 | - part.callback(self, part) |
1394 | - if prev_active and prev_active != part: |
1395 | - prev_active.set_state(gtk.STATE_NORMAL) |
1396 | - redraw = True |
1397 | - |
1398 | - self.__active_part = part |
1399 | - return prev_active, redraw |
1400 | - |
1401 | - def __append(self, part, do_callback=True): |
1402 | - # clean up any exisitng scroll callbacks |
1403 | - if self.__scroller: |
1404 | - gobject.source_remove(self.__scroller) |
1405 | - self.__scroll_xO = 0 |
1406 | - |
1407 | - # the basics |
1408 | - x = self.__draw_width() |
1409 | - self.__parts.append(part) |
1410 | - part.set_pathbar(self) |
1411 | - |
1412 | - self.set_active(part, do_callback) |
1413 | - |
1414 | - # determin part shapes, and calc modified parts widths |
1415 | - prev = self.__compose_parts(part, True) |
1416 | - # set the position of new part |
1417 | - part.set_x(x) |
1418 | - |
1419 | - # check parts fit to widgets allocated width |
1420 | - if x + part.get_width() > self.allocation.width and \ |
1421 | - self.allocation.width != 1: |
1422 | - self.__shrink_check(self.allocation) |
1423 | - return prev, True |
1424 | - |
1425 | - return prev, False |
1426 | - |
1427 | -# def __shorten(self, n): |
1428 | -# n = int(n) |
1429 | -# old_w = self.__draw_width() |
1430 | -# end_active = self.get_active() == self.__parts[-1] |
1431 | - |
1432 | -# if len(self.__parts)-n < 1: |
1433 | -# print WARNING + 'The first part is sacred ;)' + ENDC |
1434 | -# return old_w, False |
1435 | - |
1436 | -# del self.__parts[-n:] |
1437 | -# self.__compose_parts(self.__parts[-1], False) |
1438 | - |
1439 | -# if end_active: |
1440 | -# self.set_active(self.__parts[-1]) |
1441 | - |
1442 | -# if old_w >= self.allocation.width: |
1443 | -# self.__grow_check(old_w, self.allocation) |
1444 | -# return old_w, True |
1445 | - |
1446 | -# return old_w, False |
1447 | - |
1448 | - def __shrink_check(self, allocation): |
1449 | - path_w = self.__draw_width() |
1450 | - shrinkage = path_w - allocation.width |
1451 | - mpw = self.theme.min_part_width |
1452 | - xO = 0 |
1453 | - |
1454 | - for part in self.__parts[:-1]: |
1455 | - w = part.get_width() |
1456 | - dw = 0 |
1457 | - |
1458 | - if w - shrinkage <= mpw: |
1459 | - dw = w - mpw |
1460 | - shrinkage -= dw |
1461 | - part.set_size(mpw, -1) |
1462 | - part.set_x(part.get_x() - xO) |
1463 | - |
1464 | - else: |
1465 | - part.set_size(w - shrinkage, -1) |
1466 | - part.set_x(part.get_x() - xO) |
1467 | - dw = shrinkage |
1468 | - shrinkage = 0 |
1469 | - |
1470 | - xO += dw |
1471 | - |
1472 | - last = self.__parts[-1] |
1473 | - last.set_x(last.get_x() - xO) |
1474 | - return |
1475 | - |
1476 | - def __grow_check(self, old_width, allocation): |
1477 | - parts = self.__parts |
1478 | - if len(parts) == 0: |
1479 | - return |
1480 | - |
1481 | - growth = old_width - self.__draw_width() |
1482 | - parts.reverse() |
1483 | - |
1484 | - for part in parts: |
1485 | - bw = part.get_size_requisition()[0] |
1486 | - w = part.get_width() |
1487 | - |
1488 | - if w < bw: |
1489 | - dw = bw - w |
1490 | - |
1491 | - if dw <= growth: |
1492 | - growth -= dw |
1493 | - part.set_size(bw, -1) |
1494 | - part.set_x(part.get_x() + growth) |
1495 | - |
1496 | - else: |
1497 | - part.set_size(w + growth, -1) |
1498 | - growth = 0 |
1499 | - |
1500 | - else: |
1501 | - part.set_x(part.get_x() + growth) |
1502 | - |
1503 | - parts.reverse() |
1504 | - shift = parts[0].get_x() |
1505 | - |
1506 | - # left align parts |
1507 | - if shift > 0: |
1508 | - for part in parts: part.set_x(part.get_x() - shift) |
1509 | - return |
1510 | - |
1511 | - def __compose_parts(self, last, prev_set_size): |
1512 | - parts = self.__parts |
1513 | - |
1514 | - if len(parts) == 1: |
1515 | - last.set_shape(self.SHAPE_RECTANGLE) |
1516 | - last.set_size(*last.calc_size_requisition()) |
1517 | - prev = None |
1518 | - |
1519 | - elif len(parts) == 2: |
1520 | - prev = parts[0] |
1521 | - prev.set_shape(self.SHAPE_START_ARROW) |
1522 | - prev.calc_size_requisition() |
1523 | - |
1524 | - last.set_shape(self.SHAPE_END_CAP) |
1525 | - last.set_size(*last.calc_size_requisition()) |
1526 | - |
1527 | - else: |
1528 | - prev = parts[-2] |
1529 | - prev.set_shape(self.SHAPE_MID_ARROW) |
1530 | - prev.calc_size_requisition() |
1531 | - |
1532 | - last.set_shape(self.SHAPE_END_CAP) |
1533 | - last.set_size(*last.calc_size_requisition()) |
1534 | - |
1535 | - if prev and prev_set_size: |
1536 | - prev.set_size(*prev.get_size_requisition()) |
1537 | - return prev |
1538 | - |
1539 | - def __draw_width(self): |
1540 | - l = len(self.__parts) |
1541 | - if l == 0: |
1542 | - return 0 |
1543 | - a = self.__parts[-1].allocation |
1544 | - return a[0] + a[2] |
1545 | - |
1546 | - def __hscroll_out_init(self, distance, draw_area, duration, fps): |
1547 | - self.__scroller = gobject.timeout_add( |
1548 | - int(1000.0 / fps), # interval |
1549 | - self.__hscroll_out_cb, |
1550 | - distance, |
1551 | - duration*0.001, # 1 over duration (converted to seconds) |
1552 | - gobject.get_current_time(), |
1553 | - draw_area.x, |
1554 | - draw_area.y, |
1555 | - draw_area.width, |
1556 | - draw_area.height) |
1557 | - return |
1558 | - |
1559 | - def __hscroll_out_cb(self, distance, duration, start_t, x, y, w, h): |
1560 | - cur_t = gobject.get_current_time() |
1561 | - xO = distance - distance*((cur_t - start_t) / duration) |
1562 | - |
1563 | - if xO > 0: |
1564 | - self.__scroll_xO = xO |
1565 | - self.queue_draw_area(x, y, w, h) |
1566 | - else: # final frame |
1567 | - self.__scroll_xO = 0 |
1568 | - # redraw the entire widget |
1569 | - # incase some timeouts are skipped due to high system load |
1570 | - self.queue_draw() |
1571 | - self.__scroller = None |
1572 | - return False |
1573 | - return True |
1574 | - |
1575 | - def __part_at_xy(self, x, y): |
1576 | - for part in self.__parts: |
1577 | - a = part.get_allocation() |
1578 | - region = gtk.gdk.region_rectangle(a) |
1579 | - |
1580 | - if region.point_in(int(x), int(y)): |
1581 | - return part |
1582 | - return None |
1583 | - |
1584 | - def __draw_hscroll(self, cr): |
1585 | - if len(self.__parts) < 2: |
1586 | - return |
1587 | - |
1588 | - # draw the last two parts |
1589 | - prev, last = self.__parts[-2:] |
1590 | - |
1591 | - # style theme stuff |
1592 | - style, r, aw, shapes = self.style, self.theme.curvature, \ |
1593 | - self.theme.arrow_width, self.__shapes |
1594 | - |
1595 | - # draw part that need scrolling |
1596 | - self.__draw_part(cr, |
1597 | - last, |
1598 | - style, |
1599 | - r, |
1600 | - aw, |
1601 | - shapes, |
1602 | - self.__scroll_xO) |
1603 | - |
1604 | - # draw the last part that does not scroll |
1605 | - self.__draw_part(cr, |
1606 | - prev, |
1607 | - style, |
1608 | - r, |
1609 | - aw, |
1610 | - shapes) |
1611 | - return |
1612 | - |
1613 | - def __draw_all(self, cr, event_area): |
1614 | - style = self.style |
1615 | - r = self.theme.curvature |
1616 | - aw = self.theme.arrow_width |
1617 | - shapes = self.__shapes |
1618 | - region = gtk.gdk.region_rectangle(event_area) |
1619 | - |
1620 | - # if a scroll is pending we want to not draw the final part, |
1621 | - # as we don't want to prematurely reveal the part befor the |
1622 | - # scroll animation has had a chance to start |
1623 | - if self.__scroller: |
1624 | - parts = self.__parts[:-1] |
1625 | - else: |
1626 | - parts = self.__parts |
1627 | - |
1628 | - parts.reverse() |
1629 | - for part in parts: |
1630 | - if region.rect_in(part.get_allocation()) != gtk.gdk.OVERLAP_RECTANGLE_OUT: |
1631 | - self.__draw_part(cr, part, style, r, aw, shapes) |
1632 | - parts.reverse() |
1633 | - return |
1634 | - |
1635 | - def __draw_part_ltr(self, cr, part, style, r, aw, shapes, sxO=0): |
1636 | - x, y, w, h = part.get_allocation() |
1637 | - shape = part.shape |
1638 | - state = part.state |
1639 | - icon_pb = part.icon.pixbuf |
1640 | - |
1641 | - cr.save() |
1642 | - cr.translate(x-sxO, y) |
1643 | - |
1644 | - # draw bg |
1645 | - self.__draw_part_bg(cr, part, w, h, state, shape, style,r, aw, shapes) |
1646 | - |
1647 | - # determine left margin. left margin depends on part shape |
1648 | - # and whether there exists an icon or not |
1649 | - if shape == self.SHAPE_MID_ARROW or shape == self.SHAPE_END_CAP: |
1650 | - margin = int(0.75*self.theme.arrow_width + self.theme.xpadding) |
1651 | - else: |
1652 | - margin = self.theme.xpadding |
1653 | - |
1654 | - # draw icon |
1655 | - if icon_pb: |
1656 | - cr.set_source_pixbuf( |
1657 | - icon_pb, |
1658 | - self.theme.xpadding-sxO, |
1659 | - (alloc.height - icon_pb.get_height())/2) |
1660 | - cr.paint() |
1661 | - margin += icon_pb.get_width() + self.theme.spacing |
1662 | - |
1663 | - # if space is limited and an icon is set, dont draw label |
1664 | - # otherwise, draw label |
1665 | - if w == self.theme.min_part_width and icon_pb: |
1666 | - pass |
1667 | - |
1668 | - else: |
1669 | - layout = part.get_layout() |
1670 | - lw, lh = layout.get_pixel_size() |
1671 | - dst_x = x + margin - int(sxO) |
1672 | - dst_y = (self.allocation.height - lh)/2+1 |
1673 | - style.paint_layout( |
1674 | - self.window, |
1675 | - self.theme.text_state[state], |
1676 | - False, |
1677 | - (dst_x, dst_y, lw+4, lh), # clip area |
1678 | - self, |
1679 | - None, |
1680 | - dst_x, |
1681 | - dst_y, |
1682 | - layout) |
1683 | - |
1684 | - cr.restore() |
1685 | - return |
1686 | - |
1687 | - def __draw_part_rtl(self, cr, part, style, r, aw, shapes, sxO=0): |
1688 | - x, y, w, h = part.get_allocation() |
1689 | - shape = part.shape |
1690 | - state = part.state |
1691 | - icon_pb = part.icon.pixbuf |
1692 | - |
1693 | - cr.save() |
1694 | - cr.translate(x+sxO, y) |
1695 | - |
1696 | - # draw bg |
1697 | - self.__draw_part_bg(cr, part, w, h, state, shape, style,r, aw, shapes) |
1698 | - |
1699 | - # determine left margin. left margin depends on part shape |
1700 | - # and whether there exists an icon or not |
1701 | - if shape == self.SHAPE_MID_ARROW or shape == self.SHAPE_END_CAP: |
1702 | - margin = self.theme.arrow_width + self.theme.xpadding |
1703 | - else: |
1704 | - margin = self.theme.xpadding |
1705 | - |
1706 | - # draw icon |
1707 | - if icon_pb: |
1708 | - margin += icon_pb.get_width() |
1709 | - cr.set_source_pixbuf( |
1710 | - icon_pb, |
1711 | - w - margin + sxO, |
1712 | - (h - icon_pb.get_height())/2) |
1713 | - cr.paint() |
1714 | - margin += self.spacing |
1715 | - |
1716 | - # if space is limited and an icon is set, dont draw label |
1717 | - # otherwise, draw label |
1718 | - if w == self.theme.min_part_width and icon_pb: |
1719 | - pass |
1720 | - |
1721 | - else: |
1722 | - layout = part.get_layout() |
1723 | - lw, lh = layout.get_pixel_size() |
1724 | - dst_x = x + part.get_width() - margin - lw + int(sxO) |
1725 | - dst_y = (self.allocation.height - lh)/2+1 |
1726 | - style.paint_layout( |
1727 | - self.window, |
1728 | - self.theme.text_state[state], |
1729 | - False, |
1730 | - None, |
1731 | - self, |
1732 | - None, |
1733 | - dst_x, |
1734 | - dst_y, |
1735 | - layout) |
1736 | - |
1737 | - cr.restore() |
1738 | - return |
1739 | - |
1740 | - def __draw_part_bg(self, cr, part, w, h, state, shape, style, r, aw, shapes): |
1741 | - # outer slight bevel or focal highlight |
1742 | - shapes[shape](cr, 0, 0, w, h, r, aw) |
1743 | - cr.set_source_rgba(0, 0, 0, 0.055) |
1744 | - cr.fill() |
1745 | - |
1746 | - # colour scheme dicts |
1747 | - bg = self.theme.bg_colors |
1748 | - outer = self.theme.dark_line_colors |
1749 | - inner = self.theme.light_line_colors |
1750 | - |
1751 | - # bg linear vertical gradient |
1752 | - if state != gtk.STATE_PRELIGHT: |
1753 | - color1, color2 = bg[state] |
1754 | - else: |
1755 | - if part != self.get_active(): |
1756 | - color1, color2 = bg[self.theme.PRELIT_NORMAL] |
1757 | - else: |
1758 | - color1, color2 = bg[self.theme.PRELIT_ACTIVE] |
1759 | - |
1760 | - shapes[shape](cr, 1, 1, w-1, h-1, r, aw) |
1761 | - lin = cairo.LinearGradient(0, 0, 0, h-1) |
1762 | - lin.add_color_stop_rgb(0.0, *color1) |
1763 | - lin.add_color_stop_rgb(1.0, *color2) |
1764 | - cr.set_source(lin) |
1765 | - cr.fill() |
1766 | - |
1767 | - cr.set_line_width(1.0) |
1768 | - # strong outline |
1769 | - shapes[shape](cr, 1.5, 1.5, w-1.5, h-1.5, r, aw) |
1770 | - cr.set_source_rgb(*outer[state]) |
1771 | - cr.stroke() |
1772 | - |
1773 | - # inner bevel/highlight |
1774 | - if self.theme.light_line_colors[state]: |
1775 | - shapes[shape](cr, 2.5, 2.5, w-2.5, h-2.5, r, aw) |
1776 | - r, g, b = inner[state] |
1777 | - cr.set_source_rgba(r, g, b, 0.6) |
1778 | - cr.stroke() |
1779 | - return |
1780 | - |
1781 | - def __shape_rect(self, cr, x, y, w, h, r, aw): |
1782 | - global M_PI, PI_OVER_180 |
1783 | - cr.new_sub_path() |
1784 | - cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
1785 | - cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
1786 | - cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
1787 | - cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
1788 | - cr.close_path() |
1789 | - return |
1790 | - |
1791 | - def __shape_start_arrow_ltr(self, cr, x, y, w, h, r, aw): |
1792 | - global M_PI, PI_OVER_180 |
1793 | - cr.new_sub_path() |
1794 | - cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
1795 | - # arrow head |
1796 | - cr.line_to(w-aw+1, y) |
1797 | - cr.line_to(w, (h+y)*0.5) |
1798 | - cr.line_to(w-aw+1, h) |
1799 | - cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
1800 | - cr.close_path() |
1801 | - return |
1802 | - |
1803 | - def __shape_mid_arrow_ltr(self, cr, x, y, w, h, r, aw): |
1804 | - cr.move_to(-1, y) |
1805 | - # arrow head |
1806 | - cr.line_to(w-aw+1, y) |
1807 | - cr.line_to(w, (h+y)*0.5) |
1808 | - cr.line_to(w-aw+1, h) |
1809 | - cr.line_to(-1, h) |
1810 | - cr.close_path() |
1811 | - return |
1812 | - |
1813 | - def __shape_end_cap_ltr(self, cr, x, y, w, h, r, aw): |
1814 | - global M_PI, PI_OVER_180 |
1815 | - cr.move_to(-1, y) |
1816 | - cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
1817 | - cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
1818 | - cr.line_to(-1, h) |
1819 | - cr.close_path() |
1820 | - return |
1821 | - |
1822 | - def __shape_start_arrow_rtl(self, cr, x, y, w, h, r, aw): |
1823 | - global M_PI, PI_OVER_180 |
1824 | - cr.new_sub_path() |
1825 | - cr.move_to(x, (h+y)*0.5) |
1826 | - cr.line_to(aw-1, y) |
1827 | - cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
1828 | - cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
1829 | - cr.line_to(aw-1, h) |
1830 | - cr.close_path() |
1831 | - return |
1832 | - |
1833 | - def __shape_mid_arrow_rtl(self, cr, x, y, w, h, r, aw): |
1834 | - cr.move_to(x, (h+y)*0.5) |
1835 | - cr.line_to(aw-1, y) |
1836 | - cr.line_to(w+1, y) |
1837 | - cr.line_to(w+1, h) |
1838 | - cr.line_to(aw-1, h) |
1839 | - cr.close_path() |
1840 | - return |
1841 | - |
1842 | - def __shape_end_cap_rtl(self, cr, x, y, w, h, r, aw): |
1843 | - global M_PI, PI_OVER_180 |
1844 | - cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
1845 | - cr.line_to(w+1, y) |
1846 | - cr.line_to(w+1, h) |
1847 | - cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
1848 | - cr.close_path() |
1849 | - return |
1850 | - |
1851 | - def __state(self, part): |
1852 | - # returns the idle state of the part depending on |
1853 | - # whether part is active or not. |
1854 | - if part == self.__active_part: |
1855 | - return gtk.STATE_ACTIVE |
1856 | - return gtk.STATE_NORMAL |
1857 | - |
1858 | - def __tooltip_check(self, part): |
1859 | - # only show a tooltip if part is truncated, i.e. not all label text is |
1860 | - # visible. |
1861 | - if part.is_truncated(): |
1862 | - self.set_has_tooltip(False) |
1863 | - gobject.timeout_add(50, self.__set_tooltip_cb, part.label) |
1864 | - else: |
1865 | - self.set_has_tooltip(False) |
1866 | - return |
1867 | - |
1868 | - def __set_tooltip_cb(self, text): |
1869 | - # callback allows the tooltip position to be updated as pointer moves |
1870 | - # accross different parts |
1871 | - self.set_has_tooltip(True) |
1872 | - self.set_tooltip_markup(text) |
1873 | - return False |
1874 | - |
1875 | - def __pick_theme(self, name=None): |
1876 | - name = name or gtk.settings_get_default().get_property("gtk-theme-name") |
1877 | - themes = PathBarThemes.DICT |
1878 | - if themes.has_key(name): |
1879 | - return themes[name]() |
1880 | - print "No styling hints for %s are available" % name |
1881 | - return PathBarThemeHuman() |
1882 | - |
1883 | - def __init_drawing(self): |
1884 | - if self.get_direction() != gtk.TEXT_DIR_RTL: |
1885 | - self.__draw_part = self.__draw_part_ltr |
1886 | - self.__shapes = { |
1887 | - self.SHAPE_RECTANGLE : self.__shape_rect, |
1888 | - self.SHAPE_START_ARROW : self.__shape_start_arrow_ltr, |
1889 | - self.SHAPE_MID_ARROW : self.__shape_mid_arrow_ltr, |
1890 | - self.SHAPE_END_CAP : self.__shape_end_cap_ltr} |
1891 | - else: |
1892 | - self.__draw_part = self.__draw_part_rtl |
1893 | - self.__shapes = { |
1894 | - self.SHAPE_RECTANGLE : self.__shape_rect, |
1895 | - self.SHAPE_START_ARROW : self.__shape_start_arrow_rtl, |
1896 | - self.SHAPE_MID_ARROW : self.__shape_mid_arrow_rtl, |
1897 | - self.SHAPE_END_CAP : self.__shape_end_cap_rtl} |
1898 | - return |
1899 | - |
1900 | - def __motion_notify_cb(self, widget, event): |
1901 | - if self.__scroll_xO > 0: |
1902 | - return |
1903 | - |
1904 | - part = self.__part_at_xy(event.x, event.y) |
1905 | - prev_focal = self.__focal_part |
1906 | - |
1907 | - if self.__button_down[0]: |
1908 | - if part and prev_focal and part != prev_focal: |
1909 | - if self.__button_down[1] == part: |
1910 | - part.set_state(gtk.STATE_SELECTED) |
1911 | - else: |
1912 | - part.set_state(gtk.STATE_PRELIGHT) |
1913 | - |
1914 | - prev_focal.set_state(self.__state(prev_focal)) |
1915 | - self.queue_draw_area(*prev_focal.get_allocation_tuple()) |
1916 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1917 | - self.__focal_part = part |
1918 | - return |
1919 | - |
1920 | - if part and part.state != gtk.STATE_PRELIGHT: |
1921 | - self.__tooltip_check(part) |
1922 | - part.set_state(gtk.STATE_PRELIGHT) |
1923 | - |
1924 | - if prev_focal: |
1925 | - prev_focal.set_state(self.__state(prev_focal)) |
1926 | - self.queue_draw_area(*prev_focal.get_allocation_tuple()) |
1927 | - |
1928 | - self.__focal_part = part |
1929 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1930 | - |
1931 | - elif not part and prev_focal != None and \ |
1932 | - not widget.window.get_pointer()[2] & gtk.gdk.BUTTON1_MASK: |
1933 | - prev_focal.set_state(self.__state(prev_focal)) |
1934 | - self.queue_draw_area(*prev_focal.get_allocation_tuple()) |
1935 | - self.__focal_part = None |
1936 | - return |
1937 | - |
1938 | - def __enter_notify_cb(self, widget, event): |
1939 | - if not self.__button_down[0] and not widget.window.get_pointer()[2] & gtk.gdk.BUTTON1_MASK: |
1940 | - return |
1941 | - |
1942 | - part = self.__part_at_xy(event.x, event.y) |
1943 | - prev_focal = self.__focal_part |
1944 | - |
1945 | - if part and prev_focal == part: |
1946 | - part.set_state(gtk.STATE_SELECTED) |
1947 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1948 | - return |
1949 | - |
1950 | - def __leave_notify_cb(self, widget, event): |
1951 | - prev_focal = self.__focal_part |
1952 | - if prev_focal: |
1953 | - prev_focal.set_state(self.__state(prev_focal)) |
1954 | - self.queue_draw_area(*prev_focal.get_allocation_tuple()) |
1955 | - |
1956 | - if not widget.window.get_pointer()[2] & gtk.gdk.BUTTON1_MASK: |
1957 | - self.__focal_part = None |
1958 | - return |
1959 | - |
1960 | - def __button_press_cb(self, widget, event): |
1961 | - part = self.__part_at_xy(event.x, event.y) |
1962 | - self.__button_down = True, part |
1963 | - if part: |
1964 | - part.set_state(gtk.STATE_SELECTED) |
1965 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1966 | - self.__focal_part = part |
1967 | - return |
1968 | - |
1969 | - def __button_release_cb(self, widget, event): |
1970 | - part = self.__part_at_xy(event.x, event.y) |
1971 | - if self.__focal_part and self.__focal_part != part: |
1972 | - pass |
1973 | - elif part and self.__button_down[0]: |
1974 | - prev_active, redraw = self.__set_active(part, True) |
1975 | - part.set_state(gtk.STATE_PRELIGHT) |
1976 | - self.queue_draw_area(*part.get_allocation_tuple()) |
1977 | - |
1978 | - if redraw: |
1979 | - self.queue_draw_area(*prev_active.get_allocation_tuple()) |
1980 | - self.__button_down = False, None |
1981 | - return |
1982 | - |
1983 | -# def __key_release_cb(self, widget, event): |
1984 | -# part = None |
1985 | - |
1986 | -# # left key pressed |
1987 | -# if event.keyval == 65363: |
1988 | -# part = self.get_left_part() |
1989 | - |
1990 | -# # right key pressed |
1991 | -# elif event.keyval == 65361: |
1992 | -# part = self.get_right_part() |
1993 | - |
1994 | -# if not part: return |
1995 | - |
1996 | -# prev_active = self.set_active(part) |
1997 | -# self.queue_draw_area(*part.allocation) |
1998 | -# if prev_active: |
1999 | -# self.queue_draw_area(*prev_active.allocation) |
2000 | - |
2001 | -# part.emit("clicked", event.copy()) |
2002 | -# return |
2003 | - |
2004 | - def __realize_cb(self, widget): |
2005 | - self.theme.load(widget.style) |
2006 | - return |
2007 | - |
2008 | - def __expose_cb(self, widget, event): |
2009 | - cr = widget.window.cairo_create() |
2010 | - |
2011 | - if self.theme.base_hack: |
2012 | - cr.set_source_rgb(*self.theme.base_hack) |
2013 | - cr.paint() |
2014 | - |
2015 | - if self.__scroll_xO: |
2016 | - self.__draw_hscroll(cr) |
2017 | - else: |
2018 | - self.__draw_all(cr, event.area) |
2019 | - |
2020 | - del cr |
2021 | - return |
2022 | - |
2023 | - def __style_change_cb(self, widget, old_style): |
2024 | - # when alloc.width == 1, this is typical of an unallocated widget, |
2025 | - # lets not break a sweat for nothing... |
2026 | - if self.allocation.width == 1: |
2027 | - return |
2028 | - |
2029 | - self.theme = self.__pick_theme() |
2030 | - self.theme.load(widget.style) |
2031 | - # set height to 0 so that if part height has been reduced the widget will |
2032 | - # shrink to an appropriate new height based on new font size |
2033 | - self.set_size_request(-1, 28) |
2034 | - |
2035 | - parts = self.__parts |
2036 | - self.__parts = [] |
2037 | - |
2038 | - # recalc best fits, re-append then draw all |
2039 | - for part in parts: |
2040 | - |
2041 | - if part.icon.pixbuf: |
2042 | - part.icon.load_pixbuf() |
2043 | - |
2044 | - part.calc_size_requisition() |
2045 | - self.__append(part) |
2046 | - |
2047 | - self.queue_draw() |
2048 | - return |
2049 | - |
2050 | - def __allocation_change_cb(self, widget, allocation): |
2051 | - if allocation.width == 1: |
2052 | - return |
2053 | - |
2054 | - path_w = self.__draw_width() |
2055 | - if path_w == allocation.width: |
2056 | - return |
2057 | - elif path_w > allocation.width: |
2058 | - self.__shrink_check(allocation) |
2059 | - else: |
2060 | - self.__grow_check(allocation.width, allocation) |
2061 | - |
2062 | - self.queue_draw() |
2063 | - return |
2064 | - |
2065 | -# FIXME: stubs currently and not working |
2066 | -class IAtkComponent(atk.Component): |
2067 | - # atk -------------------------------------------------------- |
2068 | - def contains(x, y, coord_type): |
2069 | - # atk stub |
2070 | - return False |
2071 | - def ref_accessible_at_point(x, y, coord_type): |
2072 | - # atk stub |
2073 | - pass |
2074 | - def get_extents(coord_type): |
2075 | - # atk stub |
2076 | - (0, 0, 0, 0) |
2077 | - def get_position(coord_type): |
2078 | - # atk stub |
2079 | - (0, 0) |
2080 | - def get_size(self): |
2081 | - # atk stub |
2082 | - (0, 0) |
2083 | - def grab_focus(self): |
2084 | - # atk stub |
2085 | - return False |
2086 | - def remove_focus_handler(self, handler_id): |
2087 | - # atk stub |
2088 | - pass |
2089 | - def set_extents(self, x, y, width, height, coord_type): |
2090 | - # atk stub |
2091 | - return False |
2092 | - def set_position(self, x, y, coord_type): |
2093 | - # atk stub |
2094 | - return False |
2095 | - def set_size(self, width, height): |
2096 | - # atk stub |
2097 | - return False |
2098 | - def get_layer(self): |
2099 | - # atk stub |
2100 | - return atk.LAYER_WIDGET |
2101 | - def get_mdi_zorder(self): |
2102 | - # atk stub |
2103 | - return 1 |
2104 | - #-------------------------------- |
2105 | - |
2106 | - |
2107 | -class PathPart(atk.Object, IAtkComponent): |
2108 | - |
2109 | - def __init__(self, parent, label=None, callback=None): |
2110 | - atk.Object.__init__(self) |
2111 | - self.__requisition = (0,0) |
2112 | - self.__layout = None |
2113 | - self.__pbar = None |
2114 | - |
2115 | - # self.set_name() would work as well, *but* we have that |
2116 | - # function already for a different purpose, so we need to |
2117 | - # explicitely call |
2118 | - parent_atk = parent.get_accessible() |
2119 | - atk.Object.set_name(self, label) |
2120 | - atk.Object.set_role(self, atk.ROLE_PUSH_BUTTON) |
2121 | - atk.Object.add_relationship(self, atk.RELATION_MEMBER_OF, parent_atk) |
2122 | - atk.Object.set_parent(self, parent_atk) |
2123 | - #print parent_atk |
2124 | - #print parent_atk.get_n_accessible_children() |
2125 | - |
2126 | - self.allocation = [0, 0, 0, 0] |
2127 | - self.state = gtk.STATE_NORMAL |
2128 | - self.shape = PathBar.SHAPE_RECTANGLE |
2129 | - |
2130 | - self.name = None |
2131 | - self.callback = callback |
2132 | - self.set_label(label or "") |
2133 | - self.icon = PathBarIcon() |
2134 | - return |
2135 | - |
2136 | - def set_callback(self, cb): |
2137 | - self.callback = cb |
2138 | - return |
2139 | - |
2140 | - def set_name(self, name): |
2141 | - self.name = name |
2142 | - return |
2143 | - |
2144 | - def set_label(self, label): |
2145 | - # escape special characters |
2146 | - label = gobject.markup_escape_text(label.strip()) |
2147 | - # some hackery to preserve italics markup |
2148 | - label = label.replace('<i>', '<i>').replace('</i>', '</i>') |
2149 | - self.label = label |
2150 | - atk.Object.set_name(self, label) |
2151 | - return |
2152 | - |
2153 | - def set_icon(self, stock_icon, size=gtk.ICON_SIZE_BUTTON): |
2154 | - self.icon.specify(stock_icon, size) |
2155 | - self.icon.load_pixbuf() |
2156 | - return |
2157 | - |
2158 | - def set_state(self, gtk_state): |
2159 | - self.state = gtk_state |
2160 | - return |
2161 | - |
2162 | - def set_shape(self, shape): |
2163 | - self.shape = shape |
2164 | - return |
2165 | - |
2166 | - def set_x(self, x): |
2167 | - self.allocation[0] = int(x) |
2168 | - return |
2169 | - |
2170 | - def set_size(self, w, h): |
2171 | - if w != -1: self.allocation[2] = int(w) |
2172 | - if h != -1: self.allocation[3] = int(h) |
2173 | - self.__calc_layout_width(self.__layout, self.shape, self.__pbar) |
2174 | - return |
2175 | - |
2176 | - def set_pathbar(self, path_bar): |
2177 | - self.__pbar = path_bar |
2178 | - return |
2179 | - |
2180 | - def get_x(self): |
2181 | - return self.allocation[0] |
2182 | - |
2183 | - def get_width(self): |
2184 | - return self.allocation[2] |
2185 | - |
2186 | - def get_height(self): |
2187 | - return self.allocation[3] |
2188 | - |
2189 | - def get_label(self): |
2190 | - return self.label |
2191 | - |
2192 | - def get_allocation(self): |
2193 | - return gtk.gdk.Rectangle(*self.get_allocation_tuple()) |
2194 | - |
2195 | - def get_allocation_tuple(self): |
2196 | - if self.__pbar.get_direction() != gtk.TEXT_DIR_RTL: |
2197 | - return self.allocation |
2198 | - x, y, w, h = self.allocation |
2199 | - x = self.__pbar.allocation[2]-x-w |
2200 | - return x, y, w, h |
2201 | - |
2202 | - def get_size_requisition(self): |
2203 | - return self.__requisition |
2204 | - |
2205 | - def get_layout(self): |
2206 | - return self.__layout |
2207 | - |
2208 | - def activate(self, do_callback=True): |
2209 | - self.__pbar.set_active(self, do_callback) |
2210 | - return |
2211 | - |
2212 | - def calc_size_requisition(self): |
2213 | - pbar = self.__pbar |
2214 | - |
2215 | - # determine widget size base on label width |
2216 | - self.__layout = self.__layout_text(self.label, pbar.get_pango_context()) |
2217 | - extents = self.__layout.get_pixel_extents() |
2218 | - |
2219 | - # calc text width + 2 * padding, text height + 2 * ypadding |
2220 | - w = extents[1][2] + 2*pbar.theme.xpadding |
2221 | - h = max(extents[1][3] + 2*pbar.theme.ypadding, pbar.get_size_request()[1]) |
2222 | - |
2223 | - # if has icon add some more pixels on |
2224 | - if self.icon.pixbuf: |
2225 | - w += self.icon.pixbuf.get_width() + pbar.theme.spacing |
2226 | - h = max(self.icon.pixbuf.get_height() + 2*pbar.theme.ypadding, h) |
2227 | - |
2228 | - # extend width depending on part shape ... |
2229 | - if self.shape == PathBar.SHAPE_START_ARROW or \ |
2230 | - self.shape == PathBar.SHAPE_END_CAP: |
2231 | - w += pbar.theme.arrow_width |
2232 | - |
2233 | - elif self.shape == PathBar.SHAPE_MID_ARROW: |
2234 | - w += 2*pbar.theme.arrow_width |
2235 | - |
2236 | - # if height greater than current height request, |
2237 | - # reset height request to higher value |
2238 | - # i get the feeling this should be in set_size_request(), but meh |
2239 | - if h > pbar.get_size_request()[1]: |
2240 | - pbar.set_size_request(-1, h) |
2241 | - |
2242 | - self.__requisition = (w,h) |
2243 | - return w, h |
2244 | - |
2245 | - def is_truncated(self): |
2246 | - return self.__requisition[0] != self.allocation[2] |
2247 | - |
2248 | - def __layout_text(self, text, pango_context): |
2249 | - layout = pango.Layout(pango_context) |
2250 | - layout.set_markup('%s' % text) |
2251 | - layout.set_ellipsize(pango.ELLIPSIZE_END) |
2252 | - return layout |
2253 | - |
2254 | - def __calc_layout_width(self, layout, shape, pbar): |
2255 | - # set layout width |
2256 | - if self.icon.pixbuf: |
2257 | - icon_w = self.icon.pixbuf.get_width() + pbar.theme.spacing |
2258 | - else: |
2259 | - icon_w = 0 |
2260 | - |
2261 | - w = self.allocation[2] |
2262 | - if shape == PathBar.SHAPE_MID_ARROW: |
2263 | - layout.set_width((w - 2*pbar.theme.arrow_width - |
2264 | - 2*pbar.theme.xpadding - icon_w)*pango.SCALE) |
2265 | - |
2266 | - elif shape == PathBar.SHAPE_START_ARROW or \ |
2267 | - shape == PathBar.SHAPE_END_CAP: |
2268 | - layout.set_width((w - pbar.theme.arrow_width - 2*pbar.theme.xpadding - |
2269 | - icon_w)*pango.SCALE) |
2270 | - else: |
2271 | - layout.set_width((w - 2*pbar.theme.xpadding - icon_w)*pango.SCALE) |
2272 | - return |
2273 | - |
2274 | - |
2275 | -class PathBarIcon: |
2276 | - |
2277 | - def __init__(self, name=None, size=None): |
2278 | - self.name = name |
2279 | - self.size = size |
2280 | - self.pixbuf = None |
2281 | - return |
2282 | - |
2283 | - def specify(self, name, size): |
2284 | - self.name = name |
2285 | - self.size = size |
2286 | - return |
2287 | - |
2288 | - def load_pixbuf(self): |
2289 | - if not self.name: |
2290 | - print 'Error: No icon specified.' |
2291 | - return |
2292 | - if not self.size: |
2293 | - print 'Note: No icon size specified.' |
2294 | - |
2295 | - def render_icon(icon_set, name, size): |
2296 | - self.pixbuf = icon_set.render_icon( |
2297 | - style, |
2298 | - gtk.TEXT_DIR_NONE, |
2299 | - gtk.STATE_NORMAL, |
2300 | - self.size or gtk.ICON_SIZE_BUTTON, |
2301 | - gtk.Image(), |
2302 | - None) |
2303 | - return |
2304 | - |
2305 | - style = gtk.Style() |
2306 | - icon_set = style.lookup_icon_set(self.name) |
2307 | - |
2308 | - if not icon_set: |
2309 | - t = gtk.icon_theme_get_default() |
2310 | - self.pixbuf = t.lookup_icon(self.name, self.size, 0).load_icon() |
2311 | - else: |
2312 | - icon_set = style.lookup_icon_set(self.name) |
2313 | - render_icon(icon_set, self.name, self.size) |
2314 | - |
2315 | - if not self.pixbuf: |
2316 | - print 'Error: No name failed to match any installed icon set.' |
2317 | - self.name = gtk.STOCK_MISSING_IMAGE |
2318 | - icon_set = style.lookup_icon_set(self.name) |
2319 | - render_icon(icon_set, self.name, self.size) |
2320 | - return |
2321 | - |
2322 | - |
2323 | -class PathBarThemeHuman: |
2324 | - |
2325 | - PRELIT_NORMAL = 10 |
2326 | - PRELIT_ACTIVE = 11 |
2327 | - |
2328 | - curvature = 2.5 |
2329 | - min_part_width = 56 |
2330 | - xpadding = 8 |
2331 | - ypadding = 2 |
2332 | - spacing = 4 |
2333 | - arrow_width = 13 |
2334 | - scroll_duration_ms = 150 |
2335 | - scroll_fps = 50 |
2336 | - animate = gtk.settings_get_default().get_property("gtk-enable-animations") |
2337 | - |
2338 | - def __init__(self): |
2339 | - return |
2340 | - |
2341 | - def load(self, style): |
2342 | - mid = style.mid |
2343 | - dark = style.dark |
2344 | - light = style.light |
2345 | - text = style.text |
2346 | - active = rgb.mix_color(mid[gtk.STATE_NORMAL], |
2347 | - mid[gtk.STATE_SELECTED], 0.25) |
2348 | - |
2349 | - self.bg_colors = { |
2350 | - gtk.STATE_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.2)), |
2351 | - f(mid[gtk.STATE_NORMAL])), |
2352 | - |
2353 | - gtk.STATE_ACTIVE: (f(rgb.shade(active, 1.2)), |
2354 | - f(active)), |
2355 | - |
2356 | - gtk.STATE_SELECTED: (f(mid[gtk.STATE_ACTIVE]), |
2357 | - f(mid[gtk.STATE_ACTIVE])), |
2358 | - |
2359 | - gtk.STATE_INSENSITIVE: (f(mid[gtk.STATE_INSENSITIVE]), |
2360 | - f(mid[gtk.STATE_INSENSITIVE])), |
2361 | - |
2362 | - self.PRELIT_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.25)), |
2363 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 1.05))), |
2364 | - |
2365 | - self.PRELIT_ACTIVE: (f(rgb.shade(active, 1.25)), |
2366 | - f(rgb.shade(active, 1.05))) |
2367 | - } |
2368 | - |
2369 | - self.dark_line_colors = { |
2370 | - gtk.STATE_NORMAL: f(dark[gtk.STATE_NORMAL]), |
2371 | - gtk.STATE_ACTIVE: f(dark[gtk.STATE_ACTIVE]), |
2372 | - gtk.STATE_SELECTED: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.9)), |
2373 | - gtk.STATE_PRELIGHT: f(dark[gtk.STATE_PRELIGHT]), |
2374 | - gtk.STATE_INSENSITIVE: f(dark[gtk.STATE_PRELIGHT]) |
2375 | - } |
2376 | - |
2377 | - self.light_line_colors = { |
2378 | - gtk.STATE_NORMAL: f(light[gtk.STATE_NORMAL]), |
2379 | - gtk.STATE_ACTIVE: f(light[gtk.STATE_ACTIVE]), |
2380 | - gtk.STATE_SELECTED: None, |
2381 | - gtk.STATE_PRELIGHT: f(light[gtk.STATE_PRELIGHT]), |
2382 | - gtk.STATE_INSENSITIVE: f(mid[gtk.STATE_PRELIGHT]) |
2383 | - } |
2384 | - |
2385 | - self.text_state = { |
2386 | - gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
2387 | - gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
2388 | - gtk.STATE_SELECTED: gtk.STATE_ACTIVE, |
2389 | - gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
2390 | - gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE |
2391 | - } |
2392 | - |
2393 | - self.base_hack = None |
2394 | - return |
2395 | - |
2396 | - |
2397 | -class PathBarThemeInHuman(PathBarThemeHuman): |
2398 | - |
2399 | - def __init__(self): |
2400 | - PathBarThemeHuman.__init__(self) |
2401 | - return |
2402 | - |
2403 | - def load(self, style): |
2404 | - mid = style.mid |
2405 | - dark = style.dark |
2406 | - light = style.light |
2407 | - text = style.text |
2408 | - active = rgb.mix_color(mid[gtk.STATE_NORMAL], |
2409 | - mid[gtk.STATE_SELECTED], 0.25) |
2410 | - |
2411 | - self.bg_colors = { |
2412 | - gtk.STATE_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.175)), |
2413 | - f(mid[gtk.STATE_NORMAL])), |
2414 | - |
2415 | - gtk.STATE_ACTIVE: (f(rgb.shade(active, 1.2)), |
2416 | - f(active)), |
2417 | - |
2418 | - gtk.STATE_SELECTED: (f(mid[gtk.STATE_ACTIVE]), |
2419 | - f(mid[gtk.STATE_ACTIVE])), |
2420 | - |
2421 | - gtk.STATE_INSENSITIVE: (f(rgb.shade(mid[gtk.STATE_INSENSITIVE], 1.15)), |
2422 | - f(rgb.shade(mid[gtk.STATE_INSENSITIVE], 1.1))), |
2423 | - |
2424 | - self.PRELIT_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.25)), |
2425 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 1.05))), |
2426 | - |
2427 | - self.PRELIT_ACTIVE: (f(rgb.shade(active, 1.25)), |
2428 | - f(rgb.shade(active, 1.05))) |
2429 | - } |
2430 | - |
2431 | - self.dark_line_colors = { |
2432 | - gtk.STATE_NORMAL: f(dark[gtk.STATE_NORMAL]), |
2433 | - gtk.STATE_ACTIVE: f(dark[gtk.STATE_ACTIVE]), |
2434 | - gtk.STATE_SELECTED: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.9)), |
2435 | - gtk.STATE_PRELIGHT: f(dark[gtk.STATE_PRELIGHT]), |
2436 | - gtk.STATE_INSENSITIVE: f(dark[gtk.STATE_PRELIGHT]) |
2437 | - } |
2438 | - |
2439 | - self.light_line_colors = { |
2440 | - gtk.STATE_NORMAL: f(light[gtk.STATE_NORMAL]), |
2441 | - gtk.STATE_ACTIVE: f(light[gtk.STATE_ACTIVE]), |
2442 | - gtk.STATE_SELECTED: None, |
2443 | - gtk.STATE_PRELIGHT: f(light[gtk.STATE_PRELIGHT]), |
2444 | - gtk.STATE_INSENSITIVE: f(light[gtk.STATE_PRELIGHT]) |
2445 | - } |
2446 | - |
2447 | - self.text_state = { |
2448 | - gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
2449 | - gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
2450 | - gtk.STATE_SELECTED: gtk.STATE_ACTIVE, |
2451 | - gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
2452 | - gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE |
2453 | - } |
2454 | - |
2455 | - self.base_hack = None |
2456 | - return |
2457 | - |
2458 | - |
2459 | -class PathBarThemeHumanClearlooks(PathBarThemeHuman): |
2460 | - |
2461 | - def __init__(self): |
2462 | - PathBarThemeHuman.__init__(self) |
2463 | - return |
2464 | - |
2465 | - def load(self, style): |
2466 | - mid = style.mid |
2467 | - dark = style.dark |
2468 | - light = style.light |
2469 | - text = style.text |
2470 | - active = rgb.mix_color(mid[gtk.STATE_NORMAL], |
2471 | - mid[gtk.STATE_SELECTED], 0.25) |
2472 | - |
2473 | - self.bg_colors = { |
2474 | - gtk.STATE_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.20)), |
2475 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 1.05))), |
2476 | - |
2477 | - gtk.STATE_ACTIVE: (f(rgb.shade(active, 1.20)), |
2478 | - f(rgb.shade(active, 1.05))), |
2479 | - |
2480 | - gtk.STATE_SELECTED: (f(rgb.shade(mid[gtk.STATE_ACTIVE], 1.15)), |
2481 | - f(mid[gtk.STATE_ACTIVE])), |
2482 | - |
2483 | - gtk.STATE_INSENSITIVE: (f(mid[gtk.STATE_INSENSITIVE]), |
2484 | - f(mid[gtk.STATE_INSENSITIVE])), |
2485 | - |
2486 | - self.PRELIT_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.35)), |
2487 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 1.15))), |
2488 | - |
2489 | - self.PRELIT_ACTIVE: (f(rgb.shade(active, 1.35)), |
2490 | - f(rgb.shade(active, 1.15))) |
2491 | - } |
2492 | - |
2493 | - self.dark_line_colors = { |
2494 | - gtk.STATE_NORMAL: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.975)), |
2495 | - gtk.STATE_ACTIVE: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.975)), |
2496 | - gtk.STATE_SELECTED: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.95)), |
2497 | - gtk.STATE_PRELIGHT: f(dark[gtk.STATE_PRELIGHT]), |
2498 | - gtk.STATE_INSENSITIVE: f(dark[gtk.STATE_INSENSITIVE]) |
2499 | - } |
2500 | - |
2501 | - self.light_line_colors = { |
2502 | - gtk.STATE_NORMAL: None, |
2503 | - gtk.STATE_ACTIVE: None, |
2504 | - gtk.STATE_SELECTED: f(mid[gtk.STATE_ACTIVE]), |
2505 | - gtk.STATE_PRELIGHT: f(light[gtk.STATE_PRELIGHT]), |
2506 | - gtk.STATE_INSENSITIVE: f(light[gtk.STATE_INSENSITIVE]) |
2507 | - } |
2508 | - |
2509 | - self.text_state = { |
2510 | - gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
2511 | - gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
2512 | - gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
2513 | - gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
2514 | - gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE |
2515 | - } |
2516 | - |
2517 | - self.base_hack = None |
2518 | - return |
2519 | - |
2520 | - |
2521 | -class PathBarThemeDust(PathBarThemeHuman): |
2522 | - |
2523 | - def __init__(self): |
2524 | - PathBarThemeHuman.__init__(self) |
2525 | - return |
2526 | - |
2527 | - def load(self, style): |
2528 | - mid = style.mid |
2529 | - dark = style.dark |
2530 | - light = style.light |
2531 | - text = style.text |
2532 | - active = rgb.mix_color(mid[gtk.STATE_NORMAL], |
2533 | - light[gtk.STATE_SELECTED], 0.3) |
2534 | - |
2535 | - self.bg_colors = { |
2536 | - gtk.STATE_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.3)), |
2537 | - f(mid[gtk.STATE_NORMAL])), |
2538 | - |
2539 | - gtk.STATE_ACTIVE: (f(rgb.shade(active, 1.3)), |
2540 | - f(active)), |
2541 | - |
2542 | - gtk.STATE_SELECTED: (f(rgb.shade(mid[gtk.STATE_NORMAL], 0.95)), |
2543 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 0.95))), |
2544 | - |
2545 | - self.PRELIT_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.35)), |
2546 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 1.15))), |
2547 | - |
2548 | - gtk.STATE_INSENSITIVE: (f(rgb.shade(mid[gtk.STATE_INSENSITIVE], 1.09)), |
2549 | - f(rgb.shade(mid[gtk.STATE_INSENSITIVE], 1.08))), |
2550 | - |
2551 | - self.PRELIT_ACTIVE: (f(rgb.shade(active, 1.35)), |
2552 | - f(rgb.shade(active, 1.15))) |
2553 | - } |
2554 | - |
2555 | - self.dark_line_colors = { |
2556 | - gtk.STATE_NORMAL: f(dark[gtk.STATE_ACTIVE]), |
2557 | - gtk.STATE_ACTIVE: f(dark[gtk.STATE_ACTIVE]), |
2558 | - gtk.STATE_SELECTED: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.95)), |
2559 | - gtk.STATE_PRELIGHT: f(dark[gtk.STATE_PRELIGHT]), |
2560 | - gtk.STATE_INSENSITIVE: f(dark[gtk.STATE_INSENSITIVE]) |
2561 | - } |
2562 | - |
2563 | - self.light_line_colors = { |
2564 | - gtk.STATE_NORMAL: f(light[gtk.STATE_NORMAL]), |
2565 | - gtk.STATE_ACTIVE: f(light[gtk.STATE_NORMAL]), |
2566 | - gtk.STATE_SELECTED: None, |
2567 | - gtk.STATE_PRELIGHT: f(light[gtk.STATE_PRELIGHT]), |
2568 | - gtk.STATE_INSENSITIVE: f(rgb.shade(light[gtk.STATE_INSENSITIVE], 0.96)) |
2569 | - } |
2570 | - |
2571 | - self.text_state = { |
2572 | - gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
2573 | - gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
2574 | - gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
2575 | - gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
2576 | - gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE |
2577 | - } |
2578 | - |
2579 | - self.base_hack = None |
2580 | - return |
2581 | - |
2582 | - |
2583 | -class PathBarThemeNewWave(PathBarThemeHuman): |
2584 | - |
2585 | - curvature = 1.5 |
2586 | - |
2587 | - def __init__(self): |
2588 | - PathBarThemeHuman.__init__(self) |
2589 | - return |
2590 | - |
2591 | - def load(self, style): |
2592 | - mid = style.mid |
2593 | - dark = style.dark |
2594 | - light = style.light |
2595 | - text = style.text |
2596 | - active = rgb.mix_color(mid[gtk.STATE_NORMAL], |
2597 | - light[gtk.STATE_SELECTED], 0.5) |
2598 | - top_step = gtk.gdk.color_parse('#FDCF9D') |
2599 | - btm_step = gtk.gdk.color_parse('#FCAE87') |
2600 | - |
2601 | - self.bg_colors = { |
2602 | - gtk.STATE_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.01)), |
2603 | - f(mid[gtk.STATE_NORMAL])), |
2604 | - |
2605 | - gtk.STATE_ACTIVE: (f(top_step), |
2606 | - f(btm_step)), |
2607 | - |
2608 | - gtk.STATE_SELECTED: (f(top_step), |
2609 | - f(btm_step)), |
2610 | - |
2611 | - gtk.STATE_INSENSITIVE: (f(rgb.shade(mid[gtk.STATE_INSENSITIVE], 1.075)), |
2612 | - f(rgb.shade(mid[gtk.STATE_INSENSITIVE], 1.075))), |
2613 | - |
2614 | - self.PRELIT_NORMAL: (f(rgb.shade(mid[gtk.STATE_NORMAL], 1.2)), |
2615 | - f(rgb.shade(mid[gtk.STATE_NORMAL], 1.15))), |
2616 | - |
2617 | - self.PRELIT_ACTIVE: (f(rgb.shade(top_step, 1.11)), |
2618 | - f(rgb.shade(btm_step, 1.06))), |
2619 | - } |
2620 | - |
2621 | - self.dark_line_colors = { |
2622 | - gtk.STATE_NORMAL: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.95)), |
2623 | - gtk.STATE_ACTIVE: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.95)), |
2624 | - gtk.STATE_SELECTED: f(rgb.shade(dark[gtk.STATE_ACTIVE], 0.95)), |
2625 | - gtk.STATE_PRELIGHT: f(dark[gtk.STATE_PRELIGHT]), |
2626 | - gtk.STATE_INSENSITIVE: f(dark[gtk.STATE_INSENSITIVE]) |
2627 | - } |
2628 | - |
2629 | - self.light_line_colors = { |
2630 | - gtk.STATE_NORMAL: f(rgb.shade(light[gtk.STATE_NORMAL], 1.2)), |
2631 | - gtk.STATE_ACTIVE: f(rgb.shade(light[gtk.STATE_NORMAL], 1.2)), |
2632 | - gtk.STATE_SELECTED: None, |
2633 | - gtk.STATE_PRELIGHT: f(rgb.shade(light[gtk.STATE_PRELIGHT], 1.2)), |
2634 | - gtk.STATE_INSENSITIVE: f(light[gtk.STATE_INSENSITIVE]) |
2635 | - } |
2636 | - |
2637 | - self.text_state = { |
2638 | - gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
2639 | - gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
2640 | - gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
2641 | - gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
2642 | - gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE |
2643 | - } |
2644 | - |
2645 | - self.base_hack = f(gtk.gdk.color_parse("#F2F2F2")) |
2646 | - return |
2647 | - |
2648 | - |
2649 | -class PathBarThemeHicolor: |
2650 | - |
2651 | - PRELIT_NORMAL = 10 |
2652 | - PRELIT_ACTIVE = 11 |
2653 | - |
2654 | - curvature = 0.5 |
2655 | - min_part_width = 56 |
2656 | - xpadding = 15 |
2657 | - ypadding = 10 |
2658 | - spacing = 10 |
2659 | - arrow_width = 15 |
2660 | - scroll_duration_ms = 150 |
2661 | - scroll_fps = 50 |
2662 | - animate = gtk.settings_get_default().get_property("gtk-enable-animations") |
2663 | - |
2664 | - def __init__(self): |
2665 | - return |
2666 | - |
2667 | - def load(self, style): |
2668 | - mid = style.mid |
2669 | - dark = style.dark |
2670 | - light = style.light |
2671 | - text = style.text |
2672 | - |
2673 | - self.bg_colors = { |
2674 | - gtk.STATE_NORMAL: (f(mid[gtk.STATE_NORMAL]), |
2675 | - f(mid[gtk.STATE_NORMAL])), |
2676 | - |
2677 | - gtk.STATE_ACTIVE: (f(mid[gtk.STATE_ACTIVE]), |
2678 | - f(mid[gtk.STATE_ACTIVE])), |
2679 | - |
2680 | - gtk.STATE_SELECTED: (f(mid[gtk.STATE_SELECTED]), |
2681 | - f(mid[gtk.STATE_SELECTED])), |
2682 | - |
2683 | - gtk.STATE_INSENSITIVE: (f(mid[gtk.STATE_INSENSITIVE]), |
2684 | - f(mid[gtk.STATE_INSENSITIVE])), |
2685 | - |
2686 | - self.PRELIT_NORMAL: (f(mid[gtk.STATE_PRELIGHT]), |
2687 | - f(mid[gtk.STATE_PRELIGHT])), |
2688 | - |
2689 | - self.PRELIT_ACTIVE: (f(mid[gtk.STATE_PRELIGHT]), |
2690 | - f(mid[gtk.STATE_PRELIGHT])) |
2691 | - } |
2692 | - |
2693 | - self.dark_line_colors = { |
2694 | - gtk.STATE_NORMAL: f(dark[gtk.STATE_NORMAL]), |
2695 | - gtk.STATE_ACTIVE: f(dark[gtk.STATE_ACTIVE]), |
2696 | - gtk.STATE_SELECTED: f(dark[gtk.STATE_SELECTED]), |
2697 | - gtk.STATE_PRELIGHT: f(dark[gtk.STATE_PRELIGHT]), |
2698 | - gtk.STATE_INSENSITIVE: f(dark[gtk.STATE_INSENSITIVE]) |
2699 | - } |
2700 | - |
2701 | - self.light_line_colors = { |
2702 | - gtk.STATE_NORMAL: f(light[gtk.STATE_NORMAL]), |
2703 | - gtk.STATE_ACTIVE: f(light[gtk.STATE_ACTIVE]), |
2704 | - gtk.STATE_SELECTED: None, |
2705 | - gtk.STATE_PRELIGHT: f(light[gtk.STATE_PRELIGHT]), |
2706 | - gtk.STATE_INSENSITIVE: f(light[gtk.STATE_INSENSITIVE]) |
2707 | - } |
2708 | - |
2709 | - self.text_state = { |
2710 | - gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
2711 | - gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
2712 | - gtk.STATE_SELECTED: gtk.STATE_SELECTED, |
2713 | - gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
2714 | - gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE |
2715 | - } |
2716 | - |
2717 | - self.base_hack = None |
2718 | - return |
2719 | - |
2720 | - |
2721 | -class PathBarThemes: |
2722 | - |
2723 | - DICT = { |
2724 | - "Human": PathBarThemeHuman, |
2725 | - "Human-Clearlooks": PathBarThemeHumanClearlooks, |
2726 | - "InHuman": PathBarThemeInHuman, |
2727 | - "HighContrastInverse": PathBarThemeHicolor, |
2728 | - "HighContrastLargePrintInverse": PathBarThemeHicolor, |
2729 | - "Dust": PathBarThemeDust, |
2730 | - "Dust Sand": PathBarThemeDust, |
2731 | - "New Wave": PathBarThemeNewWave |
2732 | - } |
2733 | - |
2734 | - |
2735 | -class NavigationBar(PathBar): |
2736 | - def __init__(self, group=None): |
2737 | - PathBar.__init__(self) |
2738 | - self.set_size_request(-1, 28) |
2739 | - self.id_to_part = {} |
2740 | - return |
2741 | - |
2742 | - def add_with_id(self, label, callback, id, icon=None, do_callback=True, animate=True): |
2743 | - """ |
2744 | - Add a new button with the given label/callback |
2745 | - |
2746 | - If there is the same id already, replace the existing one |
2747 | - with the new one |
2748 | - """ |
2749 | - |
2750 | - # check if we have the button of that id or need a new one |
2751 | - if id in self.id_to_part: |
2752 | - part = self.id_to_part[id] |
2753 | - part.set_label(label) |
2754 | - else: |
2755 | - part = PathPart(parent=self, label=label, callback=callback) |
2756 | - part.set_name(id) |
2757 | - part.set_pathbar(self) |
2758 | - part.id = id |
2759 | - self.id_to_part[id] = part |
2760 | - # check if animation should be used |
2761 | - if animate: |
2762 | - if do_callback: |
2763 | - gobject.timeout_add(150, self.append, part) |
2764 | - else: |
2765 | - gobject.timeout_add(150, self.append_no_callback, part) |
2766 | - else: |
2767 | - self.append(part, do_callback, animate=False) |
2768 | - |
2769 | - if icon: |
2770 | - part.set_icon(icon) |
2771 | - return |
2772 | - |
2773 | - def remove_id(self, id): |
2774 | - if not id in self.id_to_part: |
2775 | - return |
2776 | - |
2777 | - part = self.id_to_part[id] |
2778 | - del self.id_to_part[id] |
2779 | - self.remove(part) |
2780 | - return |
2781 | - |
2782 | - def get_button_from_id(self, id): |
2783 | - """ |
2784 | - return the button for the given id (or None) |
2785 | - """ |
2786 | - if not id in self.id_to_part: |
2787 | - return None |
2788 | - return self.id_to_part[id] |
2789 | - |
2790 | - def get_label(self, id): |
2791 | - """ |
2792 | - Return the label of the navigation button with the given id |
2793 | - """ |
2794 | - if not id in self.id_to_part: |
2795 | - return |
2796 | - |
2797 | |
2798 | === added file 'softwarecenter/view/widgets/pathbar_common.py' |
2799 | --- softwarecenter/view/widgets/pathbar_common.py 1970-01-01 00:00:00 +0000 |
2800 | +++ softwarecenter/view/widgets/pathbar_common.py 2010-04-04 06:00:32 +0000 |
2801 | @@ -0,0 +1,827 @@ |
2802 | +# Copyright (C) 2010 Matthew McGowan |
2803 | +# |
2804 | +# Authors: |
2805 | +# Matthew McGowan |
2806 | +# |
2807 | +# This program is free software: you can redistribute it and/or modify |
2808 | +# it under the terms of the GNU General Public License as published by |
2809 | +# the Free Software Foundation, either version 3 of the License, or |
2810 | +# (at your option) any later version. |
2811 | +# |
2812 | +# This program is distributed in the hope that it will be useful, |
2813 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2814 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2815 | +# GNU General Public License for more details. |
2816 | +# |
2817 | +# You should have received a copy of the GNU General Public License |
2818 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2819 | + |
2820 | + |
2821 | +import gtk |
2822 | +import cairo |
2823 | +import colorsys |
2824 | + |
2825 | + |
2826 | +# pi constants |
2827 | +M_PI = 3.1415926535897931 |
2828 | +PI_OVER_180 = 0.017453292519943295 |
2829 | + |
2830 | +SHAPE_RECTANGLE = 0 |
2831 | +SHAPE_START_ARROW = 1 |
2832 | +SHAPE_MID_ARROW = 2 |
2833 | +SHAPE_END_CAP = 3 |
2834 | + |
2835 | + |
2836 | +class PathBarStyle: |
2837 | + |
2838 | + def __init__(self, pathbar): |
2839 | + self.shape_map = self._load_shape_map(pathbar) |
2840 | + |
2841 | + gtk_settings = gtk.settings_get_default() |
2842 | + self.theme = self._load_theme(gtk_settings) |
2843 | + self.theme.build_palette(gtk_settings) |
2844 | + self.properties = self.theme.get_properties(gtk_settings) |
2845 | + self.gradients = self.theme.get_grad_palette() |
2846 | + self.dark_line = self.theme.get_dark_line_palette() |
2847 | + self.light_line = self.theme.get_light_line_palette() |
2848 | + self.text = self.theme.get_text_palette() |
2849 | + self.text_states = self.theme.get_text_states() |
2850 | + self.base_color = None |
2851 | + return |
2852 | + |
2853 | + def __getitem__(self, item): |
2854 | + if self.properties.has_key(item): |
2855 | + return self.properties[item] |
2856 | + print 'Key does not exist in the style profile:', item |
2857 | + return None |
2858 | + |
2859 | + def _load_shape_map(self, pathbar): |
2860 | + if pathbar.get_direction() != gtk.TEXT_DIR_RTL: |
2861 | + shmap = {SHAPE_RECTANGLE: self._shape_rectangle, |
2862 | + SHAPE_START_ARROW: self._shape_start_arrow_ltr, |
2863 | + SHAPE_MID_ARROW: self._shape_mid_arrow_ltr, |
2864 | + SHAPE_END_CAP: self._shape_end_cap_ltr} |
2865 | + else: |
2866 | + shmap = {SHAPE_RECTANGLE: self._shape_rectangle, |
2867 | + SHAPE_START_ARROW: self._shape_start_arrow_rtl, |
2868 | + SHAPE_MID_ARROW: self._shape_mid_arrow_rtl, |
2869 | + SHAPE_END_CAP: self._shape_end_cap_rtl} |
2870 | + return shmap |
2871 | + |
2872 | + def _load_theme(self, gtksettings): |
2873 | + name = gtksettings.get_property("gtk-theme-name") |
2874 | + r = ThemeRegistry() |
2875 | + return r.retrieve(name) |
2876 | + |
2877 | + def _shape_rectangle(self, cr, x, y, w, h, r, aw): |
2878 | + global M_PI, PI_OVER_180 |
2879 | + cr.new_sub_path() |
2880 | + cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
2881 | + cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
2882 | + cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
2883 | + cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
2884 | + cr.close_path() |
2885 | + return |
2886 | + |
2887 | + def _shape_start_arrow_ltr(self, cr, x, y, w, h, r, aw): |
2888 | + global M_PI, PI_OVER_180 |
2889 | + cr.new_sub_path() |
2890 | + cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
2891 | + # arrow head |
2892 | + cr.line_to(w-aw, y) |
2893 | + cr.line_to(w-x+1, (h+y)/2) |
2894 | + cr.line_to(w-aw, h) |
2895 | + cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
2896 | + cr.close_path() |
2897 | + return |
2898 | + |
2899 | + def _shape_mid_arrow_ltr(self, cr, x, y, w, h, r, aw): |
2900 | + cr.move_to(0, y) |
2901 | + # arrow head |
2902 | + cr.line_to(w-aw, y) |
2903 | + cr.line_to(w-x+1, (h+y)/2) |
2904 | + cr.line_to(w-aw, h) |
2905 | + cr.line_to(0, h) |
2906 | + cr.close_path() |
2907 | + return |
2908 | + |
2909 | + def _shape_end_cap_ltr(self, cr, x, y, w, h, r, aw): |
2910 | + global M_PI, PI_OVER_180 |
2911 | + cr.move_to(0, y) |
2912 | + cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
2913 | + cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
2914 | + cr.line_to(0, h) |
2915 | + cr.close_path() |
2916 | + return |
2917 | + |
2918 | + def _shape_start_arrow_rtl(self, cr, x, y, w, h, r, aw): |
2919 | + global M_PI, PI_OVER_180 |
2920 | + cr.new_sub_path() |
2921 | + cr.move_to(x, (h+y)/2) |
2922 | + cr.line_to(aw, y) |
2923 | + cr.arc(w-r, r+y, r, 270*PI_OVER_180, 0) |
2924 | + cr.arc(w-r, h-r, r, 0, 90*PI_OVER_180) |
2925 | + cr.line_to(aw, h) |
2926 | + cr.close_path() |
2927 | + return |
2928 | + |
2929 | + def _shape_mid_arrow_rtl(self, cr, x, y, w, h, r, aw): |
2930 | + cr.move_to(x, (h+y)/2) |
2931 | + cr.line_to(aw, y) |
2932 | + cr.line_to(w, y) |
2933 | + cr.line_to(w, h) |
2934 | + cr.line_to(aw, h) |
2935 | + cr.close_path() |
2936 | + return |
2937 | + |
2938 | + def _shape_end_cap_rtl(self, cr, x, y, w, h, r, aw): |
2939 | + global M_PI, PI_OVER_180 |
2940 | + cr.arc(r+x, r+y, r, M_PI, 270*PI_OVER_180) |
2941 | + cr.line_to(w, y) |
2942 | + cr.line_to(w, h) |
2943 | + cr.arc(r+x, h-r, r, 90*PI_OVER_180, M_PI) |
2944 | + cr.close_path() |
2945 | + return |
2946 | + |
2947 | + def set_direction(self, direction): |
2948 | + if direction != gtk.TEXT_DIR_RTL: |
2949 | + self.shape_map = {SHAPE_RECTANGLE: self._shape_rectangle, |
2950 | + SHAPE_START_ARROW: self._shape_start_arrow_ltr, |
2951 | + SHAPE_MID_ARROW: self._shape_mid_arrow_ltr, |
2952 | + SHAPE_END_CAP: self._shape_end_cap_ltr} |
2953 | + else: |
2954 | + self.shape_map = {SHAPE_RECTANGLE: self._shape_rectangle, |
2955 | + SHAPE_START_ARROW: self._shape_start_arrow_rtl, |
2956 | + SHAPE_MID_ARROW: self._shape_mid_arrow_rtl, |
2957 | + SHAPE_END_CAP: self._shape_end_cap_rtl} |
2958 | + return |
2959 | + |
2960 | + def paint_bg(self, cr, part, x, y, w, h, sxO=0): |
2961 | + shape = self.shape_map[part.shape] |
2962 | + state = part.state |
2963 | + r = self["curvature"] |
2964 | + aw = self["arrow_width"] |
2965 | + |
2966 | + cr.save() |
2967 | + cr.rectangle(x, y, w+1, h) |
2968 | + cr.clip() |
2969 | + cr.translate(x+0.5-sxO, y+0.5) |
2970 | + |
2971 | + w -= 1 |
2972 | + h -= 1 |
2973 | + |
2974 | + # bg linear vertical gradient |
2975 | + color1, color2 = self.gradients[state] |
2976 | + |
2977 | + shape(cr, 0, 0, w, h, r, aw) |
2978 | + lin = cairo.LinearGradient(0, 0, 0, h) |
2979 | + lin.add_color_stop_rgb(0.0, *color1.tofloats()) |
2980 | + lin.add_color_stop_rgb(1.0, *color2.tofloats()) |
2981 | + cr.set_source(lin) |
2982 | + cr.fill() |
2983 | + |
2984 | + cr.set_line_width(1.0) |
2985 | + # strong outline |
2986 | + shape(cr, 0, 0, w, h, r, aw) |
2987 | + cr.set_source_rgb(*self.dark_line[state].tofloats()) |
2988 | + cr.stroke() |
2989 | + |
2990 | + # inner bevel/highlight |
2991 | + if r == 0: w += 1 |
2992 | + shape(cr, 1, 1, w-1, h-1, r, aw) |
2993 | + cr.set_source_rgb(*self.light_line[state].tofloats()) |
2994 | + cr.stroke() |
2995 | + cr.restore() |
2996 | + return |
2997 | + |
2998 | + def paint_layout(self, widget, part, x, y, sxO=0): |
2999 | + # draw layout |
3000 | + layout = part.get_layout() |
3001 | + widget.style.paint_layout(widget.window, |
3002 | + self.text_states[part.state], |
3003 | + False, |
3004 | + None, # clip area |
3005 | + widget, |
3006 | + None, |
3007 | + x, y, |
3008 | + layout) |
3009 | + return |
3010 | + |
3011 | + def paint_focus(self, cr, x, y, w, h): |
3012 | + self._shape_rectangle(cr, 4, 4, w-4, h-4, self["curvature"], 0) |
3013 | + cr.set_source_rgb(*self.theme.bg[gtk.STATE_SELECTED].tofloats()) |
3014 | + cr.stroke() |
3015 | + return |
3016 | + |
3017 | + |
3018 | +class PathBarColorArray: |
3019 | + |
3020 | + def __init__(self, color_array): |
3021 | + self.color_array = {} |
3022 | + for state in (gtk.STATE_NORMAL, gtk.STATE_ACTIVE, gtk.STATE_SELECTED, \ |
3023 | + gtk.STATE_PRELIGHT, gtk.STATE_INSENSITIVE): |
3024 | + self.color_array[state] = color_from_gdkcolor(color_array[state]) |
3025 | + return |
3026 | + |
3027 | + def __getitem__(self, state): |
3028 | + return self.color_array[state] |
3029 | + |
3030 | + |
3031 | +class PathBarColor: |
3032 | + |
3033 | + def __init__(self, red, green, blue): |
3034 | + self.red = red |
3035 | + self.green = green |
3036 | + self.blue = blue |
3037 | + return |
3038 | + |
3039 | + def set_alpha(self, value): |
3040 | + self.alpha = value |
3041 | + return |
3042 | + |
3043 | + def tofloats(self): |
3044 | + return self.red, self.green, self.blue |
3045 | + |
3046 | + def toclutter(self): |
3047 | + try: |
3048 | + from clutter import Color |
3049 | + except Exception, e: |
3050 | + print 'Error parsing color:', e |
3051 | + raise SystemExit |
3052 | + r,g,b = self.tofloats() |
3053 | + return Color(int(r*255), int(g*255), int(b*255)) |
3054 | + |
3055 | + def togtkgdk(self): |
3056 | + r,g,b = self.tofloats() |
3057 | + return gtk.gdk.Color(int(r*65535), int(g*65535), int(b*65535)) |
3058 | + |
3059 | + def lighten(self): |
3060 | + return self.shade(1.3) |
3061 | + |
3062 | + def darken(self): |
3063 | + return self.shade(0.7) |
3064 | + |
3065 | + def shade(self, factor): |
3066 | + # as seen in clutter-color.c |
3067 | + h,l,s = colorsys.rgb_to_hls(*self.tofloats()) |
3068 | + |
3069 | + l *= factor |
3070 | + if l > 1.0: |
3071 | + l = 1.0 |
3072 | + elif l < 0: |
3073 | + l = 0 |
3074 | + |
3075 | + s *= factor |
3076 | + if s > 1.0: |
3077 | + s = 1.0 |
3078 | + elif s < 0: |
3079 | + s = 0 |
3080 | + |
3081 | + r,g,b = colorsys.hls_to_rgb(h,l,s) |
3082 | + return PathBarColor(r,g,b) |
3083 | + |
3084 | + def mix(self, color2, mix_factor): |
3085 | + # as seen in Murrine's cairo-support.c |
3086 | + r1, g1, b1 = self.tofloats() |
3087 | + r2, g2, b2 = color2.tofloats() |
3088 | + r = r1*(1-mix_factor)+r2*mix_factor |
3089 | + g = g1*(1-mix_factor)+g2*mix_factor |
3090 | + b = b1*(1-mix_factor)+b2*mix_factor |
3091 | + return PathBarColor(r,g,b) |
3092 | + |
3093 | + |
3094 | +class Theme: |
3095 | + |
3096 | + def build_palette(self, gtksettings): |
3097 | + style = gtk.rc_get_style_by_paths(gtksettings, |
3098 | + 'GtkWindow', |
3099 | + 'GtkWindow', |
3100 | + gtk.Window) |
3101 | + |
3102 | + style = style or gtk.widget_get_default_style() |
3103 | + |
3104 | + # build pathbar color palette |
3105 | + self.fg = PathBarColorArray(style.fg) |
3106 | + self.bg = PathBarColorArray(style.bg) |
3107 | + self.text = PathBarColorArray(style.text) |
3108 | + self.base = PathBarColorArray(style.base) |
3109 | + self.light = PathBarColorArray(style.base) |
3110 | + self.mid = PathBarColorArray(style.base) |
3111 | + self.dark = PathBarColorArray(style.base) |
3112 | + return |
3113 | + |
3114 | + |
3115 | +class Human(Theme): |
3116 | + |
3117 | + def get_properties(self, gtksettings): |
3118 | + props = { |
3119 | + 'curvature': 2.5, |
3120 | + 'min_part_width': 48, |
3121 | + 'xpad': 8, |
3122 | + 'ypad': 4, |
3123 | + 'xthickness': 1, |
3124 | + 'ythickness': 1, |
3125 | + 'spacing': 5, |
3126 | + 'arrow_width': 13, |
3127 | + 'scroll_duration': 150, |
3128 | + 'enable-animations': gtksettings.get_property("gtk-enable-animations"), |
3129 | + 'override_base': False |
3130 | + } |
3131 | + return props |
3132 | + |
3133 | + def get_grad_palette(self): |
3134 | + # provide two colours per state for background vertical linear gradients |
3135 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.1), |
3136 | + self.bg[gtk.STATE_NORMAL].shade(0.95)), |
3137 | + |
3138 | + gtk.STATE_ACTIVE: (self.bg[gtk.STATE_NORMAL].shade(1.00), |
3139 | + self.bg[gtk.STATE_NORMAL].shade(0.75)), |
3140 | + |
3141 | + gtk.STATE_SELECTED: (self.bg[gtk.STATE_NORMAL].shade(1.11), |
3142 | + self.bg[gtk.STATE_NORMAL]), |
3143 | + |
3144 | + gtk.STATE_PRELIGHT: (self.bg[gtk.STATE_NORMAL].shade(0.96), |
3145 | + self.bg[gtk.STATE_NORMAL].shade(0.91)), |
3146 | + |
3147 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3148 | + self.bg[gtk.STATE_INSENSITIVE]) |
3149 | + } |
3150 | + return palette |
3151 | + |
3152 | + def get_text_palette(self): |
3153 | + palette = {gtk.STATE_NORMAL: self.fg[gtk.STATE_NORMAL], |
3154 | + gtk.STATE_ACTIVE: self.fg[gtk.STATE_NORMAL], |
3155 | + gtk.STATE_SELECTED: self.fg[gtk.STATE_NORMAL], |
3156 | + gtk.STATE_PRELIGHT: self.fg[gtk.STATE_NORMAL], |
3157 | + gtk.STATE_INSENSITIVE: self.text[gtk.STATE_INSENSITIVE]} |
3158 | + return palette |
3159 | + |
3160 | + def get_dark_line_palette(self): |
3161 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].darken(), |
3162 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_NORMAL].darken(), |
3163 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_NORMAL].darken(), |
3164 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_NORMAL].darken(), |
3165 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_INSENSITIVE].darken()} |
3166 | + return palette |
3167 | + |
3168 | + def get_light_line_palette(self): |
3169 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].lighten(), |
3170 | + gtk.STATE_ACTIVE: self.fg[gtk.STATE_NORMAL], |
3171 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_NORMAL].lighten(), |
3172 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_NORMAL].lighten(), |
3173 | + gtk.STATE_INSENSITIVE: self.light[gtk.STATE_INSENSITIVE]} |
3174 | + return palette |
3175 | + |
3176 | + def get_text_states(self): |
3177 | + states = {gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
3178 | + gtk.STATE_ACTIVE: gtk.STATE_NORMAL, |
3179 | + gtk.STATE_PRELIGHT: gtk.STATE_NORMAL, |
3180 | + gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
3181 | + gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE} |
3182 | + return states |
3183 | + |
3184 | + |
3185 | +class Clearlooks(Human): |
3186 | + |
3187 | + def get_properties(self, gtksettings): |
3188 | + props = Human.get_properties(self, gtksettings) |
3189 | + props['curvature'] = 3.5 |
3190 | + return props |
3191 | + |
3192 | + def get_grad_palette(self): |
3193 | + # provide two colours per state for background vertical linear gradients |
3194 | + |
3195 | + selected_color = self.bg[gtk.STATE_NORMAL].mix(self.bg[gtk.STATE_SELECTED], |
3196 | + 0.2) |
3197 | + |
3198 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.15), |
3199 | + self.bg[gtk.STATE_NORMAL].shade(0.95)), |
3200 | + |
3201 | + gtk.STATE_ACTIVE: (self.bg[gtk.STATE_ACTIVE], |
3202 | + self.bg[gtk.STATE_ACTIVE]), |
3203 | + |
3204 | + gtk.STATE_SELECTED: (selected_color.shade(1.175), |
3205 | + selected_color), |
3206 | + |
3207 | + gtk.STATE_PRELIGHT: (self.bg[gtk.STATE_NORMAL].shade(1.3), |
3208 | + selected_color.shade(1.1)), |
3209 | + |
3210 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3211 | + self.bg[gtk.STATE_INSENSITIVE]) |
3212 | + } |
3213 | + return palette |
3214 | + |
3215 | + def get_light_line_palette(self): |
3216 | + palette = Human.get_light_line_palette(self) |
3217 | + palette[gtk.STATE_ACTIVE] = self.bg[gtk.STATE_ACTIVE] |
3218 | + return palette |
3219 | + |
3220 | + |
3221 | +class InHuman(Theme): |
3222 | + |
3223 | + def get_properties(self, gtksettings): |
3224 | + props = { |
3225 | + 'curvature': 2.5, |
3226 | + 'min_part_width': 48, |
3227 | + 'xpad': 8, |
3228 | + 'ypad': 4, |
3229 | + 'xthickness': 1, |
3230 | + 'ythickness': 1, |
3231 | + 'spacing': 5, |
3232 | + 'arrow_width': 13, |
3233 | + 'scroll_duration': 150, |
3234 | + 'enable-animations': gtksettings.get_property("gtk-enable-animations"), |
3235 | + 'override_base': False |
3236 | + } |
3237 | + return props |
3238 | + |
3239 | + def get_grad_palette(self): |
3240 | + # provide two colours per state for background vertical linear gradients |
3241 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.1), |
3242 | + self.bg[gtk.STATE_NORMAL].shade(0.95)), |
3243 | + |
3244 | + gtk.STATE_ACTIVE: (self.bg[gtk.STATE_NORMAL].shade(1.00), |
3245 | + self.bg[gtk.STATE_NORMAL].shade(0.75)), |
3246 | + |
3247 | + gtk.STATE_SELECTED: (self.bg[gtk.STATE_NORMAL].shade(1.09), |
3248 | + self.bg), |
3249 | + |
3250 | + gtk.STATE_PRELIGHT: (self.bg[gtk.STATE_SELECTED].shade(1.35), |
3251 | + self.bg[gtk.STATE_SELECTED].shade(1.1)), |
3252 | + |
3253 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3254 | + self.bg[gtk.STATE_INSENSITIVE]) |
3255 | + } |
3256 | + return palette |
3257 | + |
3258 | + def get_text_palette(self): |
3259 | + palette = {gtk.STATE_NORMAL: self.text[gtk.STATE_NORMAL], |
3260 | + gtk.STATE_ACTIVE: self.text[gtk.STATE_NORMAL], |
3261 | + gtk.STATE_SELECTED: self.text[gtk.STATE_NORMAL], |
3262 | + gtk.STATE_PRELIGHT: self.text[gtk.STATE_PRELIGHT], |
3263 | + gtk.STATE_INSENSITIVE: self.text[gtk.STATE_INSENSITIVE]} |
3264 | + return palette |
3265 | + |
3266 | + def get_dark_line_palette(self): |
3267 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].darken(), |
3268 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_NORMAL].darken(), |
3269 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_NORMAL].darken(), |
3270 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_NORMAL].darken(), |
3271 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_INSENSITIVE].darken()} |
3272 | + return palette |
3273 | + |
3274 | + def get_light_line_palette(self): |
3275 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].lighten(), |
3276 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_ACTIVE].lighten(), |
3277 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_NORMAL].lighten(), |
3278 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_NORMAL].lighten(), |
3279 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_INSENSITIVE]} |
3280 | + return palette |
3281 | + |
3282 | + def get_text_states(self): |
3283 | + states = {gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
3284 | + gtk.STATE_ACTIVE: gtk.STATE_NORMAL, |
3285 | + gtk.STATE_PRELIGHT: gtk.STATE_NORMAL, |
3286 | + gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
3287 | + gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE} |
3288 | + return states |
3289 | + |
3290 | + |
3291 | +class DustSand(Theme): |
3292 | + |
3293 | + def get_properties(self, gtksettings): |
3294 | + props = { |
3295 | + 'curvature': 2.5, |
3296 | + 'min_part_width': 48, |
3297 | + 'xpad': 8, |
3298 | + 'ypad': 4, |
3299 | + 'xthickness': 1, |
3300 | + 'ythickness': 1, |
3301 | + 'spacing': 5, |
3302 | + 'arrow_width': 13, |
3303 | + 'scroll_duration': 150, |
3304 | + 'enable-animations': gtksettings.get_property("gtk-enable-animations"), |
3305 | + 'override_base': False |
3306 | + } |
3307 | + return props |
3308 | + |
3309 | + def get_grad_palette(self): |
3310 | + |
3311 | + selected_color = self.bg[gtk.STATE_NORMAL].mix(self.bg[gtk.STATE_SELECTED], |
3312 | + 0.4) |
3313 | + |
3314 | + prelight_color = self.bg[gtk.STATE_NORMAL].mix(self.bg[gtk.STATE_SELECTED], |
3315 | + 0.175) |
3316 | + |
3317 | + # provide two colours per state for background vertical linear gradients |
3318 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.42), |
3319 | + self.bg[gtk.STATE_NORMAL].shade(1.1)), |
3320 | + |
3321 | + gtk.STATE_ACTIVE: (prelight_color, |
3322 | + prelight_color.shade(1.07)), |
3323 | + |
3324 | + gtk.STATE_SELECTED: (selected_color.shade(1.35), |
3325 | + selected_color.shade(1.1)), |
3326 | + |
3327 | + gtk.STATE_PRELIGHT: (prelight_color.shade(1.74), |
3328 | + prelight_color.shade(1.42)), |
3329 | + |
3330 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3331 | + self.bg[gtk.STATE_INSENSITIVE]) |
3332 | + } |
3333 | + return palette |
3334 | + |
3335 | + def get_text_palette(self): |
3336 | + palette = {gtk.STATE_NORMAL: self.text[gtk.STATE_NORMAL], |
3337 | + gtk.STATE_ACTIVE: self.text[gtk.STATE_ACTIVE], |
3338 | + gtk.STATE_SELECTED: self.text[gtk.STATE_SELECTED], |
3339 | + gtk.STATE_PRELIGHT: self.text[gtk.STATE_PRELIGHT], |
3340 | + gtk.STATE_INSENSITIVE: self.text[gtk.STATE_INSENSITIVE]} |
3341 | + return palette |
3342 | + |
3343 | + def get_dark_line_palette(self): |
3344 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].shade(0.575), |
3345 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_ACTIVE].shade(0.5), |
3346 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_PRELIGHT].shade(0.575), |
3347 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_SELECTED].shade(0.575), |
3348 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_NORMAL].darken()} |
3349 | + return palette |
3350 | + |
3351 | + def get_light_line_palette(self): |
3352 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].lighten(), |
3353 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_ACTIVE].shade(0.95), |
3354 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_PRELIGHT].lighten(), |
3355 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_NORMAL].lighten(), |
3356 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_INSENSITIVE]} |
3357 | + return palette |
3358 | + |
3359 | + def get_text_states(self): |
3360 | + states = {gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
3361 | + gtk.STATE_ACTIVE: gtk.STATE_NORMAL, |
3362 | + gtk.STATE_PRELIGHT: gtk.STATE_NORMAL, |
3363 | + gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
3364 | + gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE} |
3365 | + return states |
3366 | + |
3367 | + |
3368 | +class Dust(DustSand): |
3369 | + |
3370 | + def get_grad_palette(self): |
3371 | + |
3372 | + selected_color = self.bg[gtk.STATE_NORMAL].mix(self.bg[gtk.STATE_SELECTED], |
3373 | + 0.5) |
3374 | + |
3375 | + prelight_color = self.bg[gtk.STATE_NORMAL].mix(self.bg[gtk.STATE_SELECTED], |
3376 | + 0.175) |
3377 | + |
3378 | + # provide two colours per state for background vertical linear gradients |
3379 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.4), |
3380 | + self.bg[gtk.STATE_NORMAL].shade(1.1)), |
3381 | + |
3382 | + gtk.STATE_ACTIVE: (self.bg[gtk.STATE_ACTIVE].shade(1.2), |
3383 | + self.bg[gtk.STATE_ACTIVE]), |
3384 | + |
3385 | + gtk.STATE_SELECTED: (selected_color.shade(1.5), |
3386 | + selected_color.shade(1.2)), |
3387 | + |
3388 | + gtk.STATE_PRELIGHT: (prelight_color.shade(1.74), |
3389 | + prelight_color.shade(1.42)), |
3390 | + |
3391 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3392 | + self.bg[gtk.STATE_INSENSITIVE]) |
3393 | + } |
3394 | + return palette |
3395 | + |
3396 | + def get_dark_line_palette(self): |
3397 | + palette = DustSand.get_dark_line_palette(self) |
3398 | + palette[gtk.STATE_SELECTED] = self.bg[gtk.STATE_NORMAL].shade(0.575) |
3399 | + return palette |
3400 | + |
3401 | + def get_light_line_palette(self): |
3402 | + palette = DustSand.get_light_line_palette(self) |
3403 | + palette[gtk.STATE_SELECTED] = self.bg[gtk.STATE_NORMAL].shade(1.15) |
3404 | + return palette |
3405 | + |
3406 | + |
3407 | +class Ambiance(DustSand): |
3408 | + |
3409 | + def get_properties(self, gtksettings): |
3410 | + props = DustSand.get_properties(self, gtksettings) |
3411 | + props['curvature'] = 4.5 |
3412 | + return props |
3413 | + |
3414 | + def get_grad_palette(self): |
3415 | + focus_color = color_from_string('#FE765E') |
3416 | + selected_color = self.bg[gtk.STATE_NORMAL].mix(focus_color, |
3417 | + 0.07) |
3418 | + prelight_color = self.bg[gtk.STATE_NORMAL].mix(focus_color, |
3419 | + 0.33) |
3420 | + |
3421 | + # provide two colours per state for background vertical linear gradients |
3422 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.2), |
3423 | + self.bg[gtk.STATE_NORMAL].shade(0.85)), |
3424 | + |
3425 | + gtk.STATE_ACTIVE: (self.bg[gtk.STATE_NORMAL].shade(0.96), |
3426 | + self.bg[gtk.STATE_NORMAL].shade(0.65)), |
3427 | + |
3428 | + gtk.STATE_SELECTED: (selected_color.shade(1.075), |
3429 | + selected_color.shade(0.875)), |
3430 | + |
3431 | + gtk.STATE_PRELIGHT: (prelight_color.shade(1.35), |
3432 | + prelight_color.shade(1.1)), |
3433 | + |
3434 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3435 | + self.bg[gtk.STATE_INSENSITIVE]) |
3436 | + } |
3437 | + return palette |
3438 | + |
3439 | + |
3440 | +class Radiance(Ambiance): |
3441 | + |
3442 | + def get_grad_palette(self): |
3443 | + palette = Ambiance.get_grad_palette(self) |
3444 | + palette[gtk.STATE_NORMAL] = (self.mid[gtk.STATE_NORMAL].shade(1.25), |
3445 | + self.bg[gtk.STATE_NORMAL].shade(0.9)) |
3446 | + return palette |
3447 | + |
3448 | + |
3449 | +class NewWave(Theme): |
3450 | + |
3451 | + def get_properties(self, gtksettings): |
3452 | + props = { |
3453 | + 'curvature': 2, |
3454 | + 'min_part_width': 48, |
3455 | + 'xpad': 8, |
3456 | + 'ypad': 4, |
3457 | + 'xthickness': 1, |
3458 | + 'ythickness': 1, |
3459 | + 'spacing': 4, |
3460 | + 'arrow_width': 13, |
3461 | + 'scroll_duration': 150, |
3462 | + 'enable-animations': gtksettings.get_property("gtk-enable-animations"), |
3463 | + 'override_base': True |
3464 | + } |
3465 | + return props |
3466 | + |
3467 | + def get_grad_palette(self): |
3468 | + # provide two colours per state for background vertical linear gradients |
3469 | + |
3470 | + active_color = self.bg[gtk.STATE_ACTIVE].mix(color_from_string('#FDCF9D'), |
3471 | + 0.45) |
3472 | + |
3473 | + selected_color = self.bg[gtk.STATE_NORMAL].mix(color_from_string('#FDCF9D'), |
3474 | + 0.2) |
3475 | + |
3476 | + palette = {gtk.STATE_NORMAL: (self.bg[gtk.STATE_NORMAL].shade(1.1), |
3477 | + self.bg[gtk.STATE_NORMAL].shade(0.95)), |
3478 | + |
3479 | + gtk.STATE_ACTIVE: (active_color.shade(1.1), |
3480 | + self.bg[gtk.STATE_ACTIVE].shade(0.95)), |
3481 | + |
3482 | + gtk.STATE_PRELIGHT: (color_from_string('#FDCF9D'), |
3483 | + color_from_string('#FCAE87')), |
3484 | + |
3485 | + gtk.STATE_SELECTED: (selected_color.shade(1.2), |
3486 | + selected_color), |
3487 | + |
3488 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3489 | + self.bg[gtk.STATE_INSENSITIVE]) |
3490 | + } |
3491 | + return palette |
3492 | + |
3493 | + def get_text_palette(self): |
3494 | + palette = {gtk.STATE_NORMAL: self.text[gtk.STATE_NORMAL], |
3495 | + gtk.STATE_ACTIVE: self.text[gtk.STATE_NORMAL], |
3496 | + gtk.STATE_PRELIGHT: self.text[gtk.STATE_NORMAL], |
3497 | + gtk.STATE_SELECTED: self.text[gtk.STATE_SELECTED], |
3498 | + gtk.STATE_INSENSITIVE: self.text[gtk.STATE_INSENSITIVE]} |
3499 | + return palette |
3500 | + |
3501 | + def get_dark_line_palette(self): |
3502 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].darken(), |
3503 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_NORMAL].darken(), |
3504 | + gtk.STATE_PRELIGHT: self.bg[gtk.STATE_NORMAL].darken(), |
3505 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_NORMAL].darken(), |
3506 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_INSENSITIVE].darken()} |
3507 | + return palette |
3508 | + |
3509 | + def get_light_line_palette(self): |
3510 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_NORMAL].lighten(), |
3511 | + gtk.STATE_ACTIVE: self.bg[gtk.STATE_ACTIVE].shade(0.97), |
3512 | + gtk.STATE_PRELIGHT: color_from_string('#FDCF9D'), |
3513 | + gtk.STATE_SELECTED: self.bg[gtk.STATE_SELECTED].lighten(), |
3514 | + gtk.STATE_INSENSITIVE: self.bg[gtk.STATE_INSENSITIVE]} |
3515 | + return palette |
3516 | + |
3517 | + def get_text_states(self): |
3518 | + states = {gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
3519 | + gtk.STATE_ACTIVE: gtk.STATE_NORMAL, |
3520 | + gtk.STATE_PRELIGHT: gtk.STATE_NORMAL, |
3521 | + gtk.STATE_SELECTED: gtk.STATE_NORMAL, |
3522 | + gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE} |
3523 | + return states |
3524 | + |
3525 | + |
3526 | +class Hicolor(Theme): |
3527 | + |
3528 | + def get_properties(self, gtksettings): |
3529 | + props = { |
3530 | + 'curvature': 0, |
3531 | + 'min_part_width': 48, |
3532 | + 'xpad': 15, |
3533 | + 'ypad': 10, |
3534 | + 'xthickness': 2, |
3535 | + 'ythickness': 2, |
3536 | + 'spacing': 10, |
3537 | + 'arrow_width': 15, |
3538 | + 'scroll_duration': 150, |
3539 | + 'enable-animations': gtksettings.get_property("gtk-enable-animations"), |
3540 | + 'override_base': False |
3541 | + } |
3542 | + return props |
3543 | + |
3544 | + def get_grad_palette(self): |
3545 | + # provide two colours per state for background vertical linear gradients |
3546 | + palette = {gtk.STATE_NORMAL: (self.mid[gtk.STATE_NORMAL], |
3547 | + self.mid[gtk.STATE_NORMAL]), |
3548 | + |
3549 | + gtk.STATE_ACTIVE: (self.mid[gtk.STATE_ACTIVE], |
3550 | + self.mid[gtk.STATE_ACTIVE]), |
3551 | + |
3552 | + gtk.STATE_SELECTED: (self.mid[gtk.STATE_SELECTED], |
3553 | + self.mid[gtk.STATE_SELECTED]), |
3554 | + |
3555 | + gtk.STATE_PRELIGHT: (self.mid[gtk.STATE_PRELIGHT], |
3556 | + self.mid[gtk.STATE_PRELIGHT]), |
3557 | + |
3558 | + gtk.STATE_INSENSITIVE: (self.bg[gtk.STATE_INSENSITIVE], |
3559 | + self.bg[gtk.STATE_INSENSITIVE]) |
3560 | + } |
3561 | + return palette |
3562 | + |
3563 | + def get_text_palette(self): |
3564 | + palette = {gtk.STATE_NORMAL: self.text[gtk.STATE_NORMAL], |
3565 | + gtk.STATE_ACTIVE: self.text[gtk.STATE_ACTIVE], |
3566 | + gtk.STATE_SELECTED: self.text[gtk.STATE_SELECTED], |
3567 | + gtk.STATE_PRELIGHT: self.text[gtk.STATE_PRELIGHT], |
3568 | + gtk.STATE_INSENSITIVE: self.text[gtk.STATE_INSENSITIVE]} |
3569 | + return palette |
3570 | + |
3571 | + def get_dark_line_palette(self): |
3572 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_SELECTED], |
3573 | + gtk.STATE_ACTIVE: self.dark[gtk.STATE_ACTIVE], |
3574 | + gtk.STATE_PRELIGHT: self.dark[gtk.STATE_PRELIGHT], |
3575 | + gtk.STATE_SELECTED: self.dark[gtk.STATE_SELECTED], |
3576 | + gtk.STATE_INSENSITIVE: self.dark[gtk.STATE_INSENSITIVE]} |
3577 | + return palette |
3578 | + |
3579 | + def get_light_line_palette(self): |
3580 | + palette = {gtk.STATE_NORMAL: self.bg[gtk.STATE_SELECTED], |
3581 | + gtk.STATE_ACTIVE: self.light[gtk.STATE_ACTIVE], |
3582 | + gtk.STATE_PRELIGHT: self.light[gtk.STATE_PRELIGHT], |
3583 | + gtk.STATE_SELECTED: self.light[gtk.STATE_SELECTED], |
3584 | + gtk.STATE_INSENSITIVE: self.light[gtk.STATE_INSENSITIVE]} |
3585 | + return palette |
3586 | + |
3587 | + def get_text_states(self): |
3588 | + states = {gtk.STATE_NORMAL: gtk.STATE_NORMAL, |
3589 | + gtk.STATE_ACTIVE: gtk.STATE_ACTIVE, |
3590 | + gtk.STATE_PRELIGHT: gtk.STATE_PRELIGHT, |
3591 | + gtk.STATE_SELECTED: gtk.STATE_SELECTED, |
3592 | + gtk.STATE_INSENSITIVE: gtk.STATE_INSENSITIVE} |
3593 | + return states |
3594 | + |
3595 | + |
3596 | +class ThemeRegistry: |
3597 | + |
3598 | + REGISTRY = {"Human": Human, |
3599 | + "Human-Clearlooks": Clearlooks, |
3600 | + "Clearlooks": Clearlooks, |
3601 | + "InHuman": InHuman, |
3602 | + "HighContrastInverse": Hicolor, |
3603 | + "HighContrastLargePrintInverse": Hicolor, |
3604 | + "Dust": Dust, |
3605 | + "Dust Sand": DustSand, |
3606 | + "New Wave": NewWave, |
3607 | + "Ambiance": Ambiance, |
3608 | + "Radiance": Radiance} |
3609 | + |
3610 | + def retrieve(self, theme_name): |
3611 | + if self.REGISTRY.has_key(theme_name): |
3612 | + print 'Styling hints found for %s...' % theme_name |
3613 | + return self.REGISTRY[theme_name]() |
3614 | + print "No styling hints for %s were found... using Human hints." % theme_name |
3615 | + return Clearlooks() |
3616 | + |
3617 | + |
3618 | +def color_from_gdkcolor(gdkcolor): |
3619 | + return PathBarColor(gdkcolor.red_float, gdkcolor.green_float, gdkcolor.blue_float) |
3620 | + |
3621 | + |
3622 | +def color_from_string(spec): |
3623 | + color = gtk.gdk.color_parse(spec) |
3624 | + return PathBarColor(color.red_float, color.green_float, color.blue_float) |
3625 | + |
3626 | + |
3627 | + |
3628 | + |
3629 | |
3630 | === added file 'softwarecenter/view/widgets/pathbar_gtk_atk.py' |
3631 | --- softwarecenter/view/widgets/pathbar_gtk_atk.py 1970-01-01 00:00:00 +0000 |
3632 | +++ softwarecenter/view/widgets/pathbar_gtk_atk.py 2010-04-04 06:00:32 +0000 |
3633 | @@ -0,0 +1,703 @@ |
3634 | +# Copyright (C) 2010 Matthew McGowan |
3635 | +# |
3636 | +# Authors: |
3637 | +# Matthew McGowan |
3638 | +# |
3639 | +# This program is free software: you can redistribute it and/or modify |
3640 | +# it under the terms of the GNU General Public License as published by |
3641 | +# the Free Software Foundation, either version 3 of the License, or |
3642 | +# (at your option) any later version. |
3643 | +# |
3644 | +# This program is distributed in the hope that it will be useful, |
3645 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3646 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3647 | +# GNU General Public License for more details. |
3648 | +# |
3649 | +# You should have received a copy of the GNU General Public License |
3650 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
3651 | + |
3652 | +import atk |
3653 | +import cairo |
3654 | +import gobject |
3655 | +import gtk |
3656 | +import pango |
3657 | +import pathbar_common |
3658 | + |
3659 | +from gettext import gettext as _ |
3660 | + |
3661 | + |
3662 | +class PathBar(gtk.HBox): |
3663 | + |
3664 | + ANIMATE_FPS = 50 |
3665 | + ANIMATE_DELAY = 150 |
3666 | + ANIMATE_DURATION = 150 |
3667 | + |
3668 | + def __init__(self, group=None): |
3669 | + gtk.HBox.__init__(self) |
3670 | + self.set_redraw_on_allocate(False) |
3671 | + |
3672 | + self._width = 0 |
3673 | + self._queue = [] |
3674 | + self._active_part = None |
3675 | + self._out_of_width = False |
3676 | + self._button_press_origin = None |
3677 | + |
3678 | + self._animate = False, None |
3679 | + self._scroll_xO = 0 |
3680 | + self._no_draw = False |
3681 | + self._scroller = None |
3682 | + |
3683 | + self.theme = pathbar_common.PathBarStyle(self) |
3684 | + |
3685 | + # Accessibility info |
3686 | + atk_desc = self.get_accessible() |
3687 | + atk_desc.set_name(_("You are here:")) |
3688 | + atk_desc.set_role(atk.ROLE_PANEL) |
3689 | + |
3690 | + self.set_events(gtk.gdk.EXPOSURE_MASK) |
3691 | + self.connect('expose-event', self._on_expose_event) |
3692 | + self.connect('size-allocate', self._on_size_allocate) |
3693 | + self.connect('style-set', self._on_style_set) |
3694 | + self.connect('realize', self._append_on_realize) |
3695 | + return |
3696 | + |
3697 | + def _shrink_check(self, allocation): |
3698 | + path_w = self._width |
3699 | + overhang = path_w - allocation.width |
3700 | + self._width -= overhang |
3701 | + mpw = self.theme['min_part_width'] |
3702 | + for part in self.get_children(): |
3703 | + w = part.get_size_request()[0] |
3704 | + dw = 0 |
3705 | + if w - overhang <= mpw: |
3706 | + overhang -= w-mpw |
3707 | + part.set_width(mpw) |
3708 | + else: |
3709 | + part.set_width(w-overhang) |
3710 | + break |
3711 | + self._out_of_width = True |
3712 | + self.queue_draw() |
3713 | + return |
3714 | + |
3715 | + def _grow_check(self, allocation): |
3716 | + w_freed = allocation.width - self._width |
3717 | + parts = self.get_children() |
3718 | + parts.reverse() |
3719 | + for part in parts: |
3720 | + bw = part.get_best_width() |
3721 | + w = part.get_size_request()[0] |
3722 | + if w < bw: |
3723 | + dw = bw - w |
3724 | + if dw <= w_freed: |
3725 | + w_freed -= dw |
3726 | + part.restore_best_width() |
3727 | + else: |
3728 | + part.set_width(w + w_freed) |
3729 | + w_freed = 0 |
3730 | + break |
3731 | + |
3732 | + self._width = allocation.width - w_freed |
3733 | + if self._width < allocation.width: |
3734 | + self._out_of_width = False |
3735 | + self.queue_draw() |
3736 | + return |
3737 | + |
3738 | + def _compose_on_append(self, last_part): |
3739 | + parts = self.get_children() |
3740 | + if len(parts) == 0: |
3741 | + last_part.set_shape(pathbar_common.SHAPE_RECTANGLE) |
3742 | + elif len(parts) == 1: |
3743 | + root_part = parts[0] |
3744 | + root_part.set_shape(pathbar_common.SHAPE_START_ARROW) |
3745 | + last_part.set_shape(pathbar_common.SHAPE_END_CAP) |
3746 | + else: |
3747 | + tail_part = parts[-1] |
3748 | + tail_part.set_shape(pathbar_common.SHAPE_MID_ARROW) |
3749 | + last_part.set_shape(pathbar_common.SHAPE_END_CAP) |
3750 | + return |
3751 | + |
3752 | + def _compose_on_remove(self, last_part): |
3753 | + parts = self.get_children() |
3754 | + if len(parts) == 1: |
3755 | + last_part.set_shape(pathbar_common.SHAPE_RECTANGLE) |
3756 | + elif len(parts) == 2: |
3757 | + root_part = parts[0] |
3758 | + root_part.set_shape(pathbar_common.SHAPE_START_ARROW) |
3759 | + last_part.set_shape(pathbar_common.SHAPE_END_CAP) |
3760 | + else: |
3761 | + tail_part = parts[-1] |
3762 | + tail_part.set_shape(pathbar_common.SHAPE_MID_ARROW) |
3763 | + last_part.set_shape(pathbar_common.SHAPE_END_CAP) |
3764 | + return |
3765 | + |
3766 | + def _part_enter_notify(self, part, event): |
3767 | + if part == self._button_press_origin: |
3768 | + part.set_state(gtk.STATE_ACTIVE) |
3769 | + else: |
3770 | + part.set_state(gtk.STATE_PRELIGHT) |
3771 | + self._part_queue_draw(part) |
3772 | + return |
3773 | + |
3774 | + def _part_leave_notify(self, part, event): |
3775 | + if part == self._active_part: |
3776 | + part.set_state(gtk.STATE_SELECTED) |
3777 | + else: |
3778 | + part.set_state(gtk.STATE_NORMAL) |
3779 | + self._part_queue_draw(part) |
3780 | + return |
3781 | + |
3782 | + def _part_button_press(self, part, event): |
3783 | + if event.button != 1: return |
3784 | + self._button_press_origin = part |
3785 | + part.set_state(gtk.STATE_ACTIVE) |
3786 | + self._part_queue_draw(part) |
3787 | + return |
3788 | + |
3789 | + def _part_button_release(self, part, event): |
3790 | + if event.button != 1: return |
3791 | + |
3792 | + part_region = gtk.gdk.region_rectangle(part.allocation) |
3793 | + if not part_region.point_in(*self.window.get_pointer()[:2]): |
3794 | + self._button_press_origin = None |
3795 | + return |
3796 | + if part != self._button_press_origin: return |
3797 | + if self._active_part: |
3798 | + self._active_part.set_state(gtk.STATE_NORMAL) |
3799 | + self._part_queue_draw(self._active_part) |
3800 | + |
3801 | + self.set_active(part) |
3802 | + part.set_state(gtk.STATE_PRELIGHT) |
3803 | + self._button_press_origin = None |
3804 | + self._part_queue_draw(part) |
3805 | + return |
3806 | + |
3807 | + def _part_key_press(self, part, event): |
3808 | + # react to spacebar, enter, numpad-enter |
3809 | + if event.keyval in (32, 65293, 65421): |
3810 | + part.set_state(gtk.STATE_ACTIVE) |
3811 | + self._part_queue_draw(part) |
3812 | + return |
3813 | + |
3814 | + def _part_key_release(self, part, event): |
3815 | + # react to spacebar, enter, numpad-enter |
3816 | + if event.keyval in (32, 65293, 65421): |
3817 | + self.set_active(part) |
3818 | + part.set_state(gtk.STATE_SELECTED) |
3819 | + self._part_queue_draw(part) |
3820 | + return |
3821 | + |
3822 | + def _part_focus_in(self, part, event): |
3823 | + self._part_queue_draw(part) |
3824 | + return |
3825 | + |
3826 | + def _part_focus_out(self, part, event): |
3827 | + self._part_queue_draw(part) |
3828 | + return |
3829 | + |
3830 | + def _part_connect_signals(self, part): |
3831 | + part.connect('enter-notify-event', self._part_enter_notify) |
3832 | + part.connect('leave-notify-event', self._part_leave_notify) |
3833 | + part.connect("button-press-event", self._part_button_press) |
3834 | + part.connect("button-release-event", self._part_button_release) |
3835 | + part.connect("key-press-event", self._part_key_press) |
3836 | + part.connect("key-release-event", self._part_key_release) |
3837 | + part.connect('focus-in-event', self._part_focus_in) |
3838 | + part.connect('focus-out-event', self._part_focus_out) |
3839 | + return |
3840 | + |
3841 | + def _part_queue_draw(self, part): |
3842 | + a = part.get_allocation() |
3843 | + x, y, h = a.x, a.y, a.height |
3844 | + w = part.get_draw_width() |
3845 | + xo = part.get_draw_xoffset() |
3846 | + self.queue_draw_area(x+xo, y, w, h) |
3847 | + return |
3848 | + |
3849 | + def _on_expose_event(self, widget, event): |
3850 | + if self._scroll_xO: |
3851 | + self._expose_scroll(widget, event) |
3852 | + else: |
3853 | + self._expose_normal(widget, event) |
3854 | + return |
3855 | + |
3856 | + def _expose_normal(self, widget, event): |
3857 | + theme = self.theme |
3858 | + parts = self.get_children() |
3859 | + parts.reverse() |
3860 | + region = gtk.gdk.region_rectangle(event.area) |
3861 | + |
3862 | + cr = widget.window.cairo_create() |
3863 | + cr.rectangle(event.area) |
3864 | + cr.clip() |
3865 | + |
3866 | + for part in parts: |
3867 | + if not part.invisible: |
3868 | + a = part.get_allocation() |
3869 | + xo = part.get_draw_xoffset() |
3870 | + x, y, w, h = a.x, a.y, a.width, a.height |
3871 | + w = part.get_draw_width() |
3872 | + theme.paint_bg(cr, part, x+xo, y, w, h) |
3873 | + |
3874 | + x, y, w, h = part.get_layout_points() |
3875 | + |
3876 | + if part.has_focus(): |
3877 | + self.style.paint_focus(self.window, |
3878 | + part.state, |
3879 | + (a.x+x-4, a.y+y-2, w+8, h+4), |
3880 | + self, |
3881 | + 'button', |
3882 | + a.x+x-4, a.y+y-2, w+8, h+4) |
3883 | + |
3884 | + theme.paint_layout(widget, part, a.x+x, a.y+y) |
3885 | + else: |
3886 | + part.invisible = False |
3887 | + del cr |
3888 | + return |
3889 | + |
3890 | + def _expose_scroll(self, widget, event): |
3891 | + parts = self.get_children() |
3892 | + if len(parts) < 2: return |
3893 | + static_tail, scroller = parts[-2:] |
3894 | + |
3895 | + if self.get_direction() != gtk.TEXT_DIR_RTL: |
3896 | + sxO = self._scroll_xO |
3897 | + else: |
3898 | + sxO = -self._scroll_xO |
3899 | + |
3900 | + theme = self.theme |
3901 | + |
3902 | + cr = widget.window.cairo_create() |
3903 | + cr.rectangle(event.area) |
3904 | + cr.clip() |
3905 | + |
3906 | + a = scroller.get_allocation() |
3907 | + x, y, w, h = a.x, a.y, a.width, a.height |
3908 | + w = scroller.get_draw_width() |
3909 | + xo = scroller.get_draw_xoffset() |
3910 | + theme.paint_bg(cr, scroller, x+xo-sxO, y, w, h) |
3911 | + x, y, w, h = scroller.get_layout_points() |
3912 | + theme.paint_layout(widget, scroller, a.x+x-int(sxO), a.y+y) |
3913 | + |
3914 | + a = static_tail.get_allocation() |
3915 | + x, y, w, h = a.x, a.y, a.width, a.height |
3916 | + w = static_tail.get_draw_width() |
3917 | + xo = static_tail.get_draw_xoffset() |
3918 | + theme.paint_bg(cr, static_tail, x+xo, y, w, h) |
3919 | + del cr |
3920 | + return |
3921 | + |
3922 | + def _on_size_allocate(self, widget, allocation): |
3923 | + if self._width < allocation.width and self._out_of_width: |
3924 | + self._grow_check(allocation) |
3925 | + elif self._width >= allocation.width: |
3926 | + self._shrink_check(allocation) |
3927 | + |
3928 | + if self._animate[0] and self.theme['enable-animations']: |
3929 | + part = self._animate[1] |
3930 | + part.invisible = True |
3931 | + self._animate = False, None |
3932 | + gobject.timeout_add(self.ANIMATE_DELAY, self._scroll_out_init, part) |
3933 | + else: |
3934 | + self.queue_draw() |
3935 | + return |
3936 | + |
3937 | + def _on_style_set(self, widget, old_style): |
3938 | + self.theme = pathbar_common.PathBarStyle(self) |
3939 | + for part in self.get_children(): |
3940 | + part.recalc_dimensions() |
3941 | + self.queue_draw() |
3942 | + return |
3943 | + |
3944 | + def _append_on_realize(self, widget): |
3945 | + for part, do_callback, animate in self._queue: |
3946 | + self.append(part, do_callback, animate) |
3947 | + return |
3948 | + |
3949 | + def _scroll_out_init(self, part): |
3950 | + draw_area = part.get_allocation() |
3951 | + self._scroller = gobject.timeout_add( |
3952 | + max(int(1000.0 / self.ANIMATE_FPS), 10), # interval |
3953 | + self._scroll_out_cb, |
3954 | + part.get_size_request()[0], |
3955 | + self.ANIMATE_DURATION*0.001, # 1 over duration (converted to seconds) |
3956 | + gobject.get_current_time(), |
3957 | + (draw_area.x, draw_area.y, |
3958 | + draw_area.width, draw_area.height)) |
3959 | + return False |
3960 | + |
3961 | + def _scroll_out_cb(self, distance, duration, start_t, draw_area): |
3962 | + cur_t = gobject.get_current_time() |
3963 | + xO = distance - distance*((cur_t - start_t) / duration) |
3964 | + |
3965 | + if xO > 0: |
3966 | + self._scroll_xO = xO |
3967 | + self.queue_draw_area(*draw_area) |
3968 | + |
3969 | + else: # final frame |
3970 | + self._scroll_xO = 0 |
3971 | + # redraw the entire widget |
3972 | + # incase some timeouts are skipped due to high system load |
3973 | + self.queue_draw_area(*draw_area) |
3974 | + self._scroller = None |
3975 | + return False |
3976 | + return True |
3977 | + |
3978 | + def has_parts(self): |
3979 | + return self.get_children() == True |
3980 | + |
3981 | + def get_parts(self): |
3982 | + return self.get_children() |
3983 | + |
3984 | + def get_last(self): |
3985 | + if self.get_children(): |
3986 | + return self.get_children()[-1] |
3987 | + return None |
3988 | + |
3989 | + def set_active(self, part, do_callback=True): |
3990 | + if part == self._active_part: return |
3991 | + if self._active_part: |
3992 | + self._active_part.set_state(gtk.STATE_NORMAL) |
3993 | + self._part_queue_draw(self._active_part) |
3994 | + |
3995 | + part.set_state(gtk.STATE_SELECTED) |
3996 | + self._part_queue_draw(part) |
3997 | + self._active_part = part |
3998 | + if do_callback and part.callback: |
3999 | + part.callback(self, part) |
4000 | + return |
4001 | + |
4002 | + def get_active(self): |
4003 | + return self._active_part |
4004 | + |
4005 | + def set_active_no_callback(self, part): |
4006 | + self.set_active(part, False) |
4007 | + return |
4008 | + |
4009 | + def append(self, part, do_callback=True, animate=True): |
4010 | + if not self.get_property('visible'): |
4011 | + self._queue.append([part, do_callback, animate]) |
4012 | + return |
4013 | + |
4014 | + if self._scroller: |
4015 | + gobject.source_remove(self._scroller) |
4016 | + self._scroll_xO = 0 |
4017 | + |
4018 | + self._compose_on_append(part) |
4019 | + self._width += part.get_size_request()[0] |
4020 | + |
4021 | + self.pack_start(part, False) |
4022 | + self._part_connect_signals(part) |
4023 | + self._animate = animate, part |
4024 | + part.show() |
4025 | + |
4026 | + if do_callback: |
4027 | + self.set_active(part) |
4028 | + else: |
4029 | + self.set_active_no_callback(part) |
4030 | + return |
4031 | + |
4032 | + def append_no_callback(self, part): |
4033 | + self.append(part, do_callback=False) |
4034 | + |
4035 | + def remove(self, part): |
4036 | + parts = self.get_children() |
4037 | + if len(parts) <= 1: return # protect last part |
4038 | + self._width -= part.get_size_request()[0] |
4039 | + part.destroy() |
4040 | + self._compose_on_remove(parts[-2]) |
4041 | + return |
4042 | + |
4043 | + def remove_all(self, keep_first_part=True, do_callback=True): |
4044 | + parts = self.get_children() |
4045 | + if len(parts) < 1: return |
4046 | + if keep_first_part: |
4047 | + if len(parts) <= 1: return |
4048 | + parts = parts[1:] |
4049 | + for part in parts: |
4050 | + part.destroy() |
4051 | + |
4052 | + self._width = 0 |
4053 | + if keep_first_part: |
4054 | + root = self.get_parts()[0] |
4055 | + root.set_shape(pathbar_common.SHAPE_RECTANGLE) |
4056 | + self._width = root.get_size_request()[0] |
4057 | + if do_callback: root.callback(self, root) |
4058 | + return |
4059 | + |
4060 | + def navigate_up(self): |
4061 | + parts = self.get_children() |
4062 | + if len(parts) > 1: |
4063 | + nav_part = parts[len(parts) - 2] |
4064 | + self.set_active(nav_part) |
4065 | + return |
4066 | + |
4067 | + |
4068 | +class PathPart(gtk.EventBox): |
4069 | + |
4070 | + def __init__(self, parent, label, callback=None): |
4071 | + gtk.EventBox.__init__(self) |
4072 | + self.set_redraw_on_allocate(False) |
4073 | + self.set_visible_window(False) |
4074 | + |
4075 | + part_atk = self.get_accessible() |
4076 | + part_atk.set_name(label) |
4077 | + part_atk.set_description(_('Navigates to the %s page.' % label)) |
4078 | + part_atk.set_role(atk.ROLE_PUSH_BUTTON) |
4079 | + |
4080 | + self.invisible = False |
4081 | + self._parent = parent |
4082 | + self._draw_shift = 0 |
4083 | + self._draw_width = 0 |
4084 | + self._best_width = 0 |
4085 | + self._layout_points = 0,0,0,0 |
4086 | + self._size_requisition = 0,0 |
4087 | + |
4088 | + self.label = None |
4089 | + self.shape = pathbar_common.SHAPE_RECTANGLE |
4090 | + self.layout = None |
4091 | + self.callback = callback |
4092 | + self.set_label(label) |
4093 | + |
4094 | + self.set_flags(gtk.CAN_FOCUS) |
4095 | + self.set_events(gtk.gdk.BUTTON_PRESS_MASK| |
4096 | + gtk.gdk.BUTTON_RELEASE_MASK| |
4097 | + gtk.gdk.KEY_RELEASE_MASK| |
4098 | + gtk.gdk.KEY_PRESS_MASK| |
4099 | + gtk.gdk.ENTER_NOTIFY_MASK| |
4100 | + gtk.gdk.LEAVE_NOTIFY_MASK) |
4101 | + return |
4102 | + |
4103 | + def __repr__(self): |
4104 | + return self.label |
4105 | + |
4106 | + def _make_layout(self): |
4107 | + pc = self._parent.get_pango_context() |
4108 | + layout = pango.Layout(pc) |
4109 | + layout.set_markup(self.label) |
4110 | + layout.set_ellipsize(pango.ELLIPSIZE_END) |
4111 | + self.layout = layout |
4112 | + return |
4113 | + |
4114 | + def _set_best_width(self, best_width): |
4115 | + self._best_width = best_width |
4116 | + return |
4117 | + |
4118 | + def _calc_layout_points(self): |
4119 | + if not self.layout: self._make_layout() |
4120 | + x = self._parent.theme['xpad'] |
4121 | + y = self._parent.theme['ypad'] |
4122 | + w, h = self.layout.get_pixel_extents()[1][2:] |
4123 | + self._layout_points = [x, y, w, h] |
4124 | + return |
4125 | + |
4126 | + def _adjust_width(self, shape, w): |
4127 | + self._draw_xoffset = 0 |
4128 | + self._draw_width = w |
4129 | + |
4130 | + arrow_width = self._parent.theme['arrow_width'] |
4131 | + if shape == pathbar_common.SHAPE_RECTANGLE: |
4132 | + return w |
4133 | + |
4134 | + elif shape == pathbar_common.SHAPE_START_ARROW: |
4135 | + self._draw_width += arrow_width |
4136 | + if self.get_direction() == gtk.TEXT_DIR_RTL: |
4137 | + self._draw_xoffset -= arrow_width |
4138 | + |
4139 | + elif shape == pathbar_common.SHAPE_END_CAP: |
4140 | + w += arrow_width |
4141 | + self._draw_width += arrow_width |
4142 | + if self.get_direction() != gtk.TEXT_DIR_RTL: |
4143 | + self._layout_points[0] += arrow_width |
4144 | + |
4145 | + elif shape == pathbar_common.SHAPE_MID_ARROW: |
4146 | + w += arrow_width |
4147 | + self._draw_width += 2*arrow_width |
4148 | + if self.get_direction() == gtk.TEXT_DIR_RTL: |
4149 | + self._draw_xoffset -= arrow_width |
4150 | + else: |
4151 | + self._layout_points[0] += arrow_width |
4152 | + return w |
4153 | + |
4154 | + def _calc_size(self, shape): |
4155 | + lx, ly, w, h = self.layout.get_pixel_extents()[1] |
4156 | + w += 2*self._parent.theme['xpad'] |
4157 | + h += 2*self._parent.theme['ypad'] |
4158 | + |
4159 | + w = self._adjust_width(shape, w) |
4160 | + if not self.get_best_width(): |
4161 | + self._set_best_width(w) |
4162 | + self.set_size_request(w, h) |
4163 | + return |
4164 | + |
4165 | + def do_callback(self): |
4166 | + self.callback(self._parent, self) |
4167 | + return |
4168 | + |
4169 | + def set_label(self, label): |
4170 | + if label == self.label: return |
4171 | + self.label = gobject.markup_escape_text(label.strip()) |
4172 | + if not self.layout: |
4173 | + self._make_layout() |
4174 | + else: |
4175 | + self.layout.set_markup(self.label) |
4176 | + |
4177 | + self._calc_layout_points() |
4178 | + self._calc_size(self.shape) |
4179 | + return |
4180 | + |
4181 | + def set_shape(self, shape): |
4182 | + self.shape = shape |
4183 | + self._calc_layout_points() |
4184 | + self._calc_size(shape) |
4185 | + return |
4186 | + |
4187 | + def set_width(self, w): |
4188 | + theme = self._parent.theme |
4189 | + lw = w-theme['arrow_width'] |
4190 | + if self.shape != pathbar_common.SHAPE_START_ARROW: |
4191 | + lw -= theme['xpad'] |
4192 | + if self.shape == pathbar_common.SHAPE_MID_ARROW: |
4193 | + lw -= theme['arrow_width'] |
4194 | + self.layout.set_width(lw*pango.SCALE) |
4195 | + |
4196 | + self._draw_width = w+theme['arrow_width'] |
4197 | + self.set_size_request(w, -1) |
4198 | + return |
4199 | + |
4200 | + def restore_best_width(self): |
4201 | + w = self.get_best_width() |
4202 | + arrow_width = self._parent.theme['arrow_width'] |
4203 | + |
4204 | + if self.shape == pathbar_common.SHAPE_MID_ARROW: |
4205 | + w += arrow_width |
4206 | + if self.shape == pathbar_common.SHAPE_END_CAP and \ |
4207 | + self.get_direction() == gtk.TEXT_DIR_RTL: |
4208 | + self._draw_xoffset -= arrow_width |
4209 | + self._layout_points[0] -= arrow_width |
4210 | + |
4211 | + self.layout.set_width(-1) |
4212 | + self._draw_width = w+arrow_width |
4213 | + self.set_size_request(w, -1) |
4214 | + return |
4215 | + |
4216 | + def get_draw_width(self): |
4217 | + return self._draw_width |
4218 | + |
4219 | + def get_draw_xoffset(self): |
4220 | + return self._draw_xoffset |
4221 | + |
4222 | + def get_best_width(self): |
4223 | + return self._best_width |
4224 | + |
4225 | + def get_layout_points(self): |
4226 | + x, y, w, h = self._layout_points |
4227 | + y = int(max((self.allocation.height-h)*0.5+0.5, y)) |
4228 | + return x, y, w, h |
4229 | + |
4230 | + def get_layout(self): |
4231 | + return self.layout |
4232 | + |
4233 | + def recalc_dimensions(self): |
4234 | + self.layout = None |
4235 | + self._calc_layout_points() |
4236 | + self._calc_size(self.shape) |
4237 | + return |
4238 | + |
4239 | +class NavigationBar(PathBar): |
4240 | + |
4241 | + APPEND_DELAY = 150 |
4242 | + |
4243 | + def __init__(self, group=None): |
4244 | + PathBar.__init__(self) |
4245 | + self.id_to_part = {} |
4246 | + return |
4247 | + |
4248 | + def add_with_id(self, label, callback, id, do_callback=True, animate=True): |
4249 | + """ |
4250 | + Add a new button with the given label/callback |
4251 | + |
4252 | + If there is the same id already, replace the existing one |
4253 | + with the new one |
4254 | + """ |
4255 | + |
4256 | + # check if we have the button of that id or need a new one |
4257 | + if id in self.id_to_part: |
4258 | + part = self.id_to_part[id] |
4259 | + part.set_label(label) |
4260 | + else: |
4261 | + part = PathPart(parent=self, label=label, callback=callback) |
4262 | + part.set_name(id) |
4263 | + self.id_to_part[id] = part |
4264 | + self.append(part, do_callback, animate) |
4265 | + return |
4266 | + |
4267 | + def remove_id(self, id): |
4268 | + if not id in self.id_to_part: |
4269 | + return |
4270 | + part = self.id_to_part[id] |
4271 | + del self.id_to_part[id] |
4272 | + self.remove(part) |
4273 | + return |
4274 | + |
4275 | + def remove_all(self, keep_first_part=True, do_callback=True): |
4276 | + if len(self.get_parts()) <= 1: return |
4277 | + root = self.get_children()[0] |
4278 | + self.id_to_part = {root.get_name(): root} |
4279 | + PathBar.remove_all(self, do_callback=do_callback) |
4280 | + return |
4281 | + |
4282 | + def get_button_from_id(self, id): |
4283 | + """ |
4284 | + return the button for the given id (or None) |
4285 | + """ |
4286 | + if not id in self.id_to_part: |
4287 | + return None |
4288 | + return self.id_to_part[id] |
4289 | + |
4290 | + |
4291 | +class Test: |
4292 | + |
4293 | + def __init__(self): |
4294 | + self.counter = 0 |
4295 | + w = gtk.Window() |
4296 | + w.connect("destroy", gtk.main_quit) |
4297 | + w.set_size_request(384, -1) |
4298 | + w.set_default_size(512, -1) |
4299 | + w.set_border_width(3) |
4300 | + |
4301 | + vb = gtk.VBox() |
4302 | + w.add(vb) |
4303 | + |
4304 | + pb = PathBar() |
4305 | + vb.pack_start(pb, False) |
4306 | + part = PathPart(pb, 'Get Free Software?') |
4307 | + pb.append(part) |
4308 | + |
4309 | + add = gtk.Button(stock=gtk.STOCK_ADD) |
4310 | + rem = gtk.Button(stock=gtk.STOCK_REMOVE) |
4311 | + self.entry = gtk.Entry() |
4312 | + |
4313 | + vb.pack_start(add, False) |
4314 | + vb.pack_start(self.entry, False) |
4315 | + vb.pack_start(rem, False) |
4316 | + add.connect('clicked', self.add_cb, pb) |
4317 | + rem.connect('clicked', self.rem_cb, pb) |
4318 | + |
4319 | + w.show_all() |
4320 | + gtk.main() |
4321 | + return |
4322 | + |
4323 | + def add_cb(self, widget, pb): |
4324 | + text = self.entry.get_text() or ('unnammed%s' % self.counter) |
4325 | + part = PathPart(pb, text) |
4326 | + pb.append(part) |
4327 | + self.counter += 1 |
4328 | + return |
4329 | + |
4330 | + def rem_cb(self, widget, pb): |
4331 | + last = pb.get_children()[-1] |
4332 | + pb.remove(last) |
4333 | + return |
4334 | + |
4335 | +if __name__ == '__main__': |
4336 | + Test() |
4337 | |
4338 | === removed file 'softwarecenter/view/widgets/rgb.py' |
4339 | --- softwarecenter/view/widgets/rgb.py 2009-10-09 13:44:41 +0000 |
4340 | +++ softwarecenter/view/widgets/rgb.py 1970-01-01 00:00:00 +0000 |
4341 | @@ -1,67 +0,0 @@ |
4342 | -# Copyright (C) 2009 Matthew McGowan |
4343 | -# |
4344 | -# Authors: |
4345 | -# Matthew McGowan |
4346 | -# |
4347 | -# This program is free software: you can redistribute it and/or modify |
4348 | -# it under the terms of the GNU General Public License as published by |
4349 | -# the Free Software Foundation, either version 3 of the License, or |
4350 | -# (at your option) any later version. |
4351 | -# |
4352 | -# This program is distributed in the hope that it will be useful, |
4353 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4354 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4355 | -# GNU General Public License for more details. |
4356 | -# |
4357 | -# You should have received a copy of the GNU General Public License |
4358 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
4359 | - |
4360 | - |
4361 | -import colorsys |
4362 | -from gtk.gdk import Color |
4363 | - |
4364 | - |
4365 | -def parse_colour_scheme(colour_scheme_str): |
4366 | - scheme_dict = {} |
4367 | - for ln in colour_scheme_str.splitlines(): |
4368 | - k, v = ln.split(':') |
4369 | - scheme_dict[k.strip()] = gtk.gdk.color_parse(v.strip()) |
4370 | - return scheme_dict |
4371 | - |
4372 | - |
4373 | -def shade(color, k): |
4374 | - # as seen in Murrine's cairo-support.c |
4375 | - r = color.red_float |
4376 | - g = color.green_float |
4377 | - b = color.blue_float |
4378 | - |
4379 | - if (k == 1.0): |
4380 | - return color |
4381 | - |
4382 | - h,l,s = colorsys.rgb_to_hls(r,g,b) |
4383 | - |
4384 | - l *= k |
4385 | - if (l > 1.0): |
4386 | - l = 1.0 |
4387 | - elif (l < 0.0): |
4388 | - l = 0.0 |
4389 | - |
4390 | - s *= k |
4391 | - if (s > 1.0): |
4392 | - s = 1.0 |
4393 | - elif (s < 0.0): |
4394 | - s = 0.0 |
4395 | - |
4396 | - r, g, b = colorsys.hls_to_rgb(h,l,s) |
4397 | - |
4398 | - return Color(int(r*65535), int(g*65535), int(b*65535)) |
4399 | - |
4400 | -def mix_color(color1, color2, mix_factor): |
4401 | - # as seen in Murrine's cairo-support.c |
4402 | - r = color1.red_float*(1-mix_factor)+color2.red_float*mix_factor |
4403 | - g = color1.green_float*(1-mix_factor)+color2.green_float*mix_factor |
4404 | - b = color1.blue_float*(1-mix_factor)+color2.blue_float*mix_factor |
4405 | - return Color(int(r*65535), int(g*65535), int(b*65535)) |
4406 | - |
4407 | -def to_float(color): |
4408 | - return color.red_float, color.green_float, color.blue_float |