Merge lp:~codeforger/simplegc/TabController into lp:simplegc
- TabController
- Merge into trunk
Proposed by
Michael Rochester
Status: | Needs review | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~codeforger/simplegc/TabController | ||||
Merge into: | lp:simplegc | ||||
Diff against target: |
561 lines (+482/-0) 6 files modified
docs/conf.py (+1/-0) docs/sgc.widgets.rst (+13/-0) example/test.py (+13/-0) sgc/__init__.py (+2/-0) sgc/widgets/progress.py (+168/-0) sgc/widgets/tab_controller.py (+285/-0) |
||||
To merge this branch: | bzr merge lp:~codeforger/simplegc/TabController | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sam Bull | Pending | ||
Review via email: mp+219938@code.launchpad.net |
Commit message
Description of the change
I have added a TabController widget that allows the creation of a tab container where each tab has a title and a singe child widget.
To post a comment you must log in.
Unmerged revisions
- 357. By Michael Rochester
-
Created the TabController widget
- 356. By Sam Bull
-
Add ProgressBar widget.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'docs/conf.py' |
2 | --- docs/conf.py 2013-03-23 16:16:35 +0000 |
3 | +++ docs/conf.py 2014-05-17 14:54:22 +0000 |
4 | @@ -12,6 +12,7 @@ |
5 | # serve to show the default. |
6 | |
7 | import sys, os |
8 | +sys.path.insert(0, "..") |
9 | |
10 | # Initalise pygame for sgc to function properly |
11 | import pygame |
12 | |
13 | === modified file 'docs/sgc.widgets.rst' |
14 | --- docs/sgc.widgets.rst 2013-03-22 17:46:43 +0000 |
15 | +++ docs/sgc.widgets.rst 2014-05-17 14:54:22 +0000 |
16 | @@ -116,6 +116,19 @@ |
17 | |
18 | .. automethod:: config |
19 | |
20 | +:mod:`progress` Module |
21 | +-------------------------- |
22 | + |
23 | +.. automodule:: sgc.widgets.progress |
24 | + |
25 | + .. autoclass:: sgc.widgets.progress.ProgressBar |
26 | + :members: |
27 | + :undoc-members: |
28 | + :show-inheritance: |
29 | + :exclude-members: update, groups, selected |
30 | + |
31 | + .. automethod:: config |
32 | + |
33 | :mod:`radio_button` Module |
34 | -------------------------- |
35 | |
36 | |
37 | === modified file 'example/test.py' |
38 | --- example/test.py 2013-03-22 17:46:43 +0000 |
39 | +++ example/test.py 2014-05-17 14:54:22 +0000 |
40 | @@ -63,6 +63,10 @@ |
41 | input_box = sgc.InputBox(label="Input Box", default="default text...") |
42 | input_box.config(pos=(30,120)) |
43 | input_box.add(order=0) |
44 | +# Create progress bar |
45 | +progress_bar = sgc.ProgressBar() |
46 | +progress_bar.config(pos=(400,120)) |
47 | +progress_bar.add() |
48 | # Change colour button, on_click event caught in event loop |
49 | button = sgc.Button(label="Change\ncolour", pos=(40,200)) |
50 | # Create FPS counter |
51 | @@ -129,6 +133,8 @@ |
52 | label.rect.midtop = title.rect.midbottom |
53 | label.add() |
54 | |
55 | +progress_fraction = 0. |
56 | + |
57 | while True: |
58 | time = clock.tick(30) |
59 | for event in pygame.event.get(): |
60 | @@ -139,6 +145,7 @@ |
61 | print "Button event" |
62 | if event.widget is button and event.gui_type == "click": |
63 | button.config(col=[random.randrange(1,200) for x in range(3)]) |
64 | + progress_fraction = 0. if progress_fraction is False else False |
65 | elif event.widget is input_box: |
66 | clear() |
67 | elif event.type == KEYDOWN: |
68 | @@ -147,6 +154,12 @@ |
69 | elif event.type == QUIT: |
70 | exit() |
71 | |
72 | + if progress_fraction is not False: |
73 | + progress_fraction = (progress_fraction + .02) % 1 |
74 | + progress_bar.set_fraction(progress_fraction) |
75 | + else: |
76 | + progress_bar.pulse() |
77 | + |
78 | # Cleanup removed windows |
79 | for widget in dialogs: |
80 | if not widget.active(): |
81 | |
82 | === modified file 'sgc/__init__.py' |
83 | --- sgc/__init__.py 2013-03-23 16:16:35 +0000 |
84 | +++ sgc/__init__.py 2014-05-17 14:54:22 +0000 |
85 | @@ -31,11 +31,13 @@ |
86 | from widgets.fps_counter import FPSCounter |
87 | from widgets.input_box import InputBox |
88 | from widgets.label import Label |
89 | +from widgets.progress import ProgressBar |
90 | from widgets.radio_button import Radio |
91 | from widgets.scroll_box import ScrollBox |
92 | from widgets.settings import Keys |
93 | from widgets.scale import Scale |
94 | from widgets.switch import Switch |
95 | +from widgets.tab_controller import TabController |
96 | |
97 | # Import Menu last, so it can import the other widgets from here. |
98 | from widgets.menu import Menu |
99 | |
100 | === added file 'sgc/widgets/progress.py' |
101 | --- sgc/widgets/progress.py 1970-01-01 00:00:00 +0000 |
102 | +++ sgc/widgets/progress.py 2014-05-17 14:54:22 +0000 |
103 | @@ -0,0 +1,168 @@ |
104 | +# Copyright 2013 the SGC project developers. |
105 | +# See the LICENSE file at the top-level directory of this distribution |
106 | +# and at http://program.sambull.org/sgc/license.html. |
107 | + |
108 | +""" |
109 | +Progress Bar widget. Indicates progress to the user with either a progress |
110 | +estimate or activity throbber. |
111 | + |
112 | +""" |
113 | + |
114 | +import pygame |
115 | +from pygame.locals import * |
116 | +from pygame import draw |
117 | + |
118 | +from _locals import * |
119 | +from base_widget import Simple |
120 | + |
121 | + |
122 | +class ProgressBar(Simple): |
123 | + """ |
124 | + A Progress Bar. |
125 | + |
126 | + Images: |
127 | + 'image': The background of the bar. |
128 | + 'bar': The image to be used for the percent bar |
129 | + (bar will be cropped, not stretched). |
130 | + 'throbber': The image used for the 'activity' throbber. |
131 | + 'overlay': This image will always be displayed on top of the widget |
132 | + regardless of mode, it is by default blank, however passing the |
133 | + keyword 'text' to the config function will draw this text onto this |
134 | + surface. |
135 | + """ |
136 | + |
137 | + _default_size = (100, 20) |
138 | + _extra_images = {"bar": ((1, -4), (1, -4)), |
139 | + "throbber": ((.2, -6), (1, -6)), |
140 | + "overlay": ((1, 0), (1, 0))} |
141 | + _settings_default = {"col": (118, 45, 215), "font": Font["widget"], |
142 | + "text": "", "text_col": (10, 10, 10), "total_time": 1., |
143 | + "pulse_duration": .1} |
144 | + _surf_flags = SRCALPHA |
145 | + |
146 | + _bar_fraction = 0. |
147 | + _throbber_move_timer = 0 |
148 | + _activity_mode = False |
149 | + |
150 | + def _config(self, **kwargs): |
151 | + """ |
152 | + col: ``tuple`` (r,g,b) The color to be used for the bar, to avoid |
153 | + saturation of the throbber use values below 200 |
154 | + pulse_duration: ``float`` time in seconds each pulse should last, |
155 | + useful if your update loop is slower than the default of .25. |
156 | + total_time: ``float`` time in seconds the throbber should take to |
157 | + travel the full distance of the bar. |
158 | + font: font to be used for the text. |
159 | + text: ``str`` the text to be shown in the center of the widget. |
160 | + text_col: the colour of the text. |
161 | + |
162 | + """ |
163 | + for key in ("col", "font", "total_time", |
164 | + "pulse_duration", "text_col"): |
165 | + if key in kwargs: |
166 | + self._settings[key] = kwargs[key] |
167 | + |
168 | + if "text" in kwargs: |
169 | + self._settings["text"] = kwargs["text"] |
170 | + overlay = self._images["overlay"] |
171 | + overlay.image.fill((0, 0, 0, 0)) |
172 | + label = self._settings["font"].render(self._settings["text"], True, |
173 | + self._settings["text_col"]) |
174 | + overlay.image.blit(label, (overlay.rect.w / 2 - |
175 | + label.get_rect().w / 2, |
176 | + overlay.rect.h / 2 - |
177 | + label.get_rect().h / 2)) |
178 | + |
179 | + if "total_time" in kwargs or "pulse_duration" in kwargs: |
180 | + total_time_ms = self._settings["total_time"] * 1000. |
181 | + self._throbber_velocity = self.rect.w / total_time_ms |
182 | + |
183 | + if "init" in kwargs: |
184 | + self._images["bar"]._show = False |
185 | + self._images["throbber"]._show = False |
186 | + self._images["throbber"].pos = [0, 3] |
187 | + |
188 | + total_time_ms = self._settings["total_time"] * 1000. |
189 | + self._throbber_velocity = self.rect.w / total_time_ms |
190 | + |
191 | + self._throbber_x = 0 |
192 | + |
193 | + def _draw_base(self): |
194 | + draw.rect(self._images["image"], (100, 100, 100), |
195 | + (0, 0, self.rect.w, self.rect.h)) |
196 | + draw.rect(self._images["image"], (240, 240, 240), |
197 | + (1, 1, self.rect.w - 2, self.rect.h - 2)) |
198 | + |
199 | + def _draw_bar(self, image, size): |
200 | + draw.rect(image, self._settings["col"], |
201 | + (0, 0, size[0], size[1])) |
202 | + |
203 | + def _draw_throbber(self, image, size): |
204 | + brightened_color = [x + 20 for x in self._settings["col"]] |
205 | + draw.rect(image, brightened_color, (0, 0, size[0], size[1])) |
206 | + |
207 | + def _draw_overlay(self, image, size): |
208 | + pass |
209 | + |
210 | + def update(self, time): |
211 | + if self._activity_mode: |
212 | + self._images["bar"]._show = False |
213 | + if self._throbber_move_timer > 0: |
214 | + self._throbber_move_timer -= time |
215 | + # Move throbber. |
216 | + self._throbber_x += self._throbber_velocity * time |
217 | + self._images["throbber"].rect.x = self._throbber_x |
218 | + # If outside box, change direction and move back in. |
219 | + left_edge = self._images["throbber"].rect.x - 3 |
220 | + right_edge = left_edge + self._images["throbber"].rect.w + 6 |
221 | + if left_edge < 0 or right_edge > self.rect.w: |
222 | + self._throbber_velocity = - self._throbber_velocity |
223 | + self._throbber_x += self._throbber_velocity * time |
224 | + self._images["throbber"].rect.x = self._throbber_x |
225 | + else: |
226 | + bar_rect = (0, 0, self.rect.w * self._bar_fraction, self.rect.h) |
227 | + draw.rect(self.image, (100, 100, 100), |
228 | + (0, 0, self.rect.w, self.rect.h)) |
229 | + draw.rect(self.image, (240, 240, 240), |
230 | + (1, 1, self.rect.w - 2, self.rect.h - 2)) |
231 | + self.image.set_clip(bar_rect) |
232 | + self.image.blit(self._images["bar"].image, (2, 2)) |
233 | + self.image.set_clip(None) |
234 | + |
235 | + def pulse(self): |
236 | + """ |
237 | + Moves the activity mode throbber. |
238 | + |
239 | + The throbber will move for the number of seconds described by the |
240 | + pulse_duration config argument. |
241 | + |
242 | + Note: This will cause the Widget to change to activity mode if it |
243 | + was in percent mode before. |
244 | + |
245 | + """ |
246 | + if not self._activity_mode: |
247 | + self._activity_mode = True |
248 | + bar_rect = (0, 0, self.rect.w * self._bar_fraction, self.rect.h) |
249 | + draw.rect(self.image, (100, 100, 100), |
250 | + (0, 0, self.rect.w, self.rect.h)) |
251 | + draw.rect(self.image, (240, 240, 240), |
252 | + (1, 1, self.rect.w - 2, self.rect.h - 2)) |
253 | + self._images["throbber"]._show = True |
254 | + self._throbber_move_timer = self._settings["pulse_duration"] * 1000 |
255 | + |
256 | + @property |
257 | + def fraction(self): |
258 | + """Returns the current fraction the bar is at as a float.""" |
259 | + return self._bar_fraction |
260 | + |
261 | + def set_fraction(self, fraction): |
262 | + """ |
263 | + Sets the fraction the bar should be as a float. |
264 | + |
265 | + Note: This will cause the widget to change to percent mode if it |
266 | + was in activity mode before. |
267 | + """ |
268 | + if self._activity_mode: |
269 | + self._activity_mode = False |
270 | + self._images["throbber"]._show = False |
271 | + self._bar_fraction = min(max(fraction, 0.), 1.) |
272 | |
273 | === added file 'sgc/widgets/tab_controller.py' |
274 | --- sgc/widgets/tab_controller.py 1970-01-01 00:00:00 +0000 |
275 | +++ sgc/widgets/tab_controller.py 2014-05-17 14:54:22 +0000 |
276 | @@ -0,0 +1,285 @@ |
277 | +# Copyright 2010-2014 the SGC project developers. |
278 | +# See the LICENSE file at the top-level directory of this distribution |
279 | +# and at http://program.sambull.org/sgc/license.html. |
280 | + |
281 | +""" |
282 | +Tabbed Container. A container that swaps the content in its area based upon the |
283 | +selected tab |
284 | + |
285 | +""" |
286 | + |
287 | +import pygame.mouse |
288 | +from pygame.locals import * |
289 | +from pygame import draw, gfxdraw |
290 | + |
291 | +from _locals import * |
292 | +from base_widget import Simple |
293 | + |
294 | + |
295 | +class TabController(Simple): |
296 | + """ |
297 | + TabController |
298 | + |
299 | + container that has multiple tabs and swaps content within its area. |
300 | + """ |
301 | + |
302 | + _surf_flags = SRCALPHA |
303 | + _can_focus = True |
304 | + _extra_images = {"back": ((0, 1), (0, 20)), "front": ((0, 1), (0, 20))} |
305 | + _settings_default = {"tab_col": (200, 200, 200), "col": (255, 255, 255), |
306 | + "font": Font["widget"], "text_col": (10, 10, 10), |
307 | + "max_width": 100, "min_width": 50} |
308 | + |
309 | + _current_tab = False |
310 | + |
311 | + def __len__(self): |
312 | + return len(self._ordered_tabs) |
313 | + |
314 | + def _config(self, **kwargs): |
315 | + """ |
316 | + col: ``tuple`` (r,g,b) background color of the content area. |
317 | + tab_col: ``tuple`` (r,g,b) color to be used in drawing front tabs |
318 | + font: Font object the tab title will render with. |
319 | + padding: ``int`` padding in content area |
320 | + text_col: ``tuple`` (r,g,b) color to draw the tab titles with |
321 | + """ |
322 | + for key in ("col", "tab_col", "font", "text_col", |
323 | + "max_width", "min_width"): |
324 | + if key in kwargs: |
325 | + self._settings[key] = kwargs[key] |
326 | + |
327 | + if "init" in kwargs: |
328 | + self._tab_widget = {} |
329 | + self._tab_images = {} |
330 | + self._tab_sizes = {} |
331 | + self._ordered_tabs = [] |
332 | + |
333 | + self._images["back"]._show = False |
334 | + self._images["front"]._show = False |
335 | + |
336 | + def add_tab(self, tab_name, widget, pos=None): |
337 | + """ |
338 | + Add a tab with a child widget. |
339 | + |
340 | + tab_name: ``str`` The name of the tab that should be created. |
341 | + widget: The widget to be placed in the content area of this tab. |
342 | + """ |
343 | + if pos is None: |
344 | + self._ordered_tabs.append(tab_name) |
345 | + else: |
346 | + self._ordered_tabs.insert(pos, tab_name) |
347 | + |
348 | + widget.pos = (widget.pos[0] + 1, widget.pos[1] + 20) |
349 | + |
350 | + self._tab_widget[tab_name] = widget |
351 | + self._tab_widget[tab_name]._parent = self |
352 | + if not self._current_tab: |
353 | + self._current_tab = self._ordered_tabs[0] |
354 | + |
355 | + cut_tab_name, tab_width = self._cut_string(tab_name, |
356 | + self._settings["max_width"]) |
357 | + if tab_width < self._settings["min_width"]: |
358 | + tab_width = self._settings["min_width"] |
359 | + |
360 | + tab_images = self._tab_images[tab_name] = {} |
361 | + |
362 | + tab_images["back"] = pygame.Surface((tab_width + 1, 20)) |
363 | + self._draw_back(tab_images["back"], (tab_width, 20)) |
364 | + |
365 | + tab_images["front"] = pygame.Surface((tab_width + 1, 20)) |
366 | + self._draw_front(tab_images["front"], (tab_width, 20)) |
367 | + |
368 | + tab_title = self._settings["font"].render(cut_tab_name, True, |
369 | + self._settings["text_col"]) |
370 | + |
371 | + tab_images["back"].blit(tab_title, (5, 3)) |
372 | + tab_images["front"].blit(tab_title, (5, 3)) |
373 | + |
374 | + self._tab_sizes[tab_name] = tab_width |
375 | + |
376 | + def _cut_string(self, s, w, ellipsis=True): |
377 | + size = self._settings["font"].size(s)[0] |
378 | + if size < w: |
379 | + return s, size + 10 |
380 | + if ellipsis: |
381 | + for i in range(len(s)): |
382 | + size = self._settings["font"].size(s+"...")[0] |
383 | + if size < w: |
384 | + return s+"...", size + 10 |
385 | + s = s[:-1] |
386 | + else: |
387 | + for i in range(len(s)): |
388 | + size = self._settings["font"].size(s)[0] |
389 | + if size < w: |
390 | + return s, size + 10 |
391 | + s = s[:-1] |
392 | + |
393 | + def remove_tab(self, pos): |
394 | + del self._tab_widget[self._ordered_tabs[pos]] |
395 | + del self._tab_images[self._ordered_tabs[pos]] |
396 | + del self._tab_sizes[self._ordered_tabs[pos]] |
397 | + del self._ordered_tabs[pos] |
398 | + |
399 | + def _draw_back(self, image, size): |
400 | + image.fill((255, 255, 255)) |
401 | + self._gradientline(image, 200, 0, size[1], 2) |
402 | + self._gradientline(image, 200, size[0], size[1], 2) |
403 | + draw.line(image, (200, 200, 200), (0, size[1] - 1), |
404 | + (size[0], size[1] - 1)) |
405 | + |
406 | + def _draw_front(self, image, size): |
407 | + image.fill(self._settings["col"]) |
408 | + draw.rect(image, self._settings["tab_col"], |
409 | + Rect(0, 0, size[0] + 1, 30)) |
410 | + draw.rect(image, self._settings["col"], |
411 | + Rect(1, 1, size[0] - 1, 30)) |
412 | + |
413 | + def _event(self, event): |
414 | + if event.type == MOUSEBUTTONDOWN and event.button == 1: |
415 | + internal_pos = [event.pos[0] - self.rect.x, |
416 | + event.pos[1] - self.rect.y] |
417 | + #if and internal_pos[0] < 300 and\ |
418 | + # internal_pos[0] > 0: |
419 | + # self._current_tab = self._ordered_tabs[internal_pos[0] / 100] |
420 | + tab_hit = 0 |
421 | + if internal_pos[1] < 20 and internal_pos[1] > 0: |
422 | + for tab in self._ordered_tabs: |
423 | + if (internal_pos[0] > tab_hit and |
424 | + internal_pos[0] < (tab_hit + self._tab_sizes[tab])): |
425 | + self._current_tab = tab |
426 | + break |
427 | + else: |
428 | + tab_hit += self._tab_sizes[tab] |
429 | + |
430 | + if event.type == KEYDOWN: |
431 | + if (pygame.key.get_mods() & KMOD_CTRL) and\ |
432 | + (pygame.key.get_mods() & KMOD_ALT): |
433 | + if event.key == K_PAGEUP: |
434 | + self.previous_tab() |
435 | + elif event.key == K_PAGEDOWN: |
436 | + self.next_tab() |
437 | + elif event.key >= K_0 and\ |
438 | + event.key <= K_9 and\ |
439 | + (pygame.key.get_mods() & KMOD_ALT): |
440 | + number = event.key - K_0 |
441 | + if number <= len(self._ordered_tabs) and number >= 1: |
442 | + self._current_tab = self._ordered_tabs[number-1] |
443 | + |
444 | + # pass event to child widget. |
445 | + if hasattr(event, "pos"): |
446 | + internal_pos = [event.pos[0] - self.rect.x, |
447 | + event.pos[1] - self.rect.y] |
448 | + if self._tab_widget[self._current_tab].rect.collidepoint(internal_pos): |
449 | + self._tab_widget[self._current_tab]._event(event) |
450 | + else: |
451 | + self._tab_widget[self._current_tab]._event(event) |
452 | + |
453 | + def update(self, time): |
454 | + # fill content area with user defined color |
455 | + self.image.fill(self._settings["col"], |
456 | + rect=Rect(0, 20, self.rect.w, self.rect.h)) |
457 | + |
458 | + # update content and blit into content area |
459 | + if self._current_tab: |
460 | + self._tab_widget[self._current_tab].update(time) |
461 | + self.image.blit(self._tab_widget[self._current_tab].image, |
462 | + self._tab_widget[self._current_tab].pos) |
463 | + |
464 | + # draw content area border |
465 | + draw.rect(self.image, (200, 200, 200), |
466 | + Rect(0, 19, self.rect.w, self.rect.h - 19), 1) |
467 | + |
468 | + # force transparency and Draw all tabs |
469 | + self.image.fill((255, 255, 255, 0), rect=Rect(0, 0, self.rect.w, 19)) |
470 | + |
471 | + selected_tab_number = 0 |
472 | + selected_tab_pos = 0 |
473 | + tab_pos = 0 |
474 | + for i, tab in enumerate(self._ordered_tabs): |
475 | + if tab == self._current_tab: |
476 | + selected_tab_number = i |
477 | + selected_tab_pos = tab_pos |
478 | + tab_pos += self._tab_sizes[tab] |
479 | + else: |
480 | + self.image.blit(self._tab_images[tab]["back"], (tab_pos, 0)) |
481 | + tab_pos += self._tab_sizes[tab] |
482 | + |
483 | + self.image.blit(self._tab_images[self._current_tab]["front"], |
484 | + (selected_tab_pos, 0)) |
485 | + |
486 | + def _gradientline(self, surface, color, x, start_y, end_y): |
487 | + alpha_gradient = 255 / abs(start_y - end_y) |
488 | + alpha = 255 |
489 | + for i in range(start_y - end_y): |
490 | + pygame.gfxdraw.pixel(surface, x, start_y - i, |
491 | + (color, color, color, alpha)) |
492 | + alpha -= alpha_gradient |
493 | + |
494 | + def rename_tab(self, pos, tab_name): |
495 | + if tab_name not in self._ordered_tabs: |
496 | + self._tab_widget[tab_name] = self._tab_widget[self._ordered_tabs[pos]] |
497 | + del self._tab_widget[self._ordered_tabs[pos]] |
498 | + del self._tab_sizes[self._ordered_tabs[pos]] |
499 | + |
500 | + del self._tab_images[self._ordered_tabs[pos]] |
501 | + self._tab_images[tab_name] = {} |
502 | + |
503 | + cut_tab_name, tab_width = self._cut_string(tab_name, self._settings["max_width"]) |
504 | + |
505 | + if tab_width < self._settings["min_width"]: |
506 | + tab_width = self._settings["min_width"] |
507 | + |
508 | + self._tab_images[tab_name]["back"] =\ |
509 | + pygame.Surface((tab_width + 1, 20)) |
510 | + self._draw_back(self._tab_images[tab_name]["back"], (tab_width, |
511 | + 20)) |
512 | + |
513 | + self._tab_images[tab_name]["front"] =\ |
514 | + pygame.Surface((tab_width + 1, 20)) |
515 | + self._draw_front(self._tab_images[tab_name]["front"], (tab_width, |
516 | + 20)) |
517 | + |
518 | + tab_title =\ |
519 | + self._settings["font"].render(cut_tab_name, True, |
520 | + self._settings["text_col"]) |
521 | + |
522 | + self._tab_images[tab_name]["back"].blit(tab_title, (5, 3)) |
523 | + self._tab_images[tab_name]["front"].blit(tab_title, (5, 3)) |
524 | + |
525 | + self._tab_sizes[tab_name] = self._settings["max_width"] |
526 | + |
527 | + self._ordered_tabs[pos] = tab_name |
528 | + |
529 | + def get_child(self, pos): |
530 | + return self._tab_widget[self._ordered_tabs[pos]] |
531 | + |
532 | + def get_tab_name(self, pos): |
533 | + return self._ordered_tabs[pos] |
534 | + |
535 | + def get_child_pos(self, child): |
536 | + for i, w in enumerate(self._tab_widget.values()): |
537 | + if w is child: |
538 | + return i |
539 | + return -1 |
540 | + |
541 | + def get_tab_name_pos(self, tab_name): |
542 | + return self._ordered_tabs.index(tab_name) |
543 | + |
544 | + def next_tab(self): |
545 | + next = ((self._ordered_tabs.index(self._current_tab) + 1) % |
546 | + len(self._ordered_tabs)) |
547 | + self._current_tab = self._ordered_tabs[next] |
548 | + |
549 | + def previous_tab(self): |
550 | + prev = ((self._ordered_tabs.index(self._current_tab) - 1) % |
551 | + len(self._ordered_tabs)) |
552 | + self._current_tab = self._ordered_tabs[prev] |
553 | + |
554 | + @property |
555 | + def current_tab(self): |
556 | + return self._ordered_tabs.index(self._current_tab) |
557 | + |
558 | + @current_tab.setter |
559 | + def current_tab(self, pos): |
560 | + if pos >= 0 and pos < len(self._ordered_tabs): |
561 | + self._current_tab = self._ordered_tabs[pos] |