Mercurial > traipse_dev
comparison orpg/tools/FlatNotebook.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | fdcca00696ea |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4385a7d0efd1 |
---|---|
1 # --------------------------------------------------------------------------- # | |
2 # FLATNOTEBOOK Widget wxPython IMPLEMENTATION | |
3 # | |
4 # Original C++ Code From Eran. You Can Find It At: | |
5 # | |
6 # http://wxforum.shadonet.com/viewtopic.php?t=5761&start=0 | |
7 # | |
8 # License: wxWidgets license | |
9 # | |
10 # | |
11 # Python Code By: | |
12 # | |
13 # Andrea Gavana, @ 02 Oct 2006 | |
14 # Latest Revision: 22 Nov 2007, 14.00 GMT | |
15 # | |
16 # | |
17 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please | |
18 # Write To Me At: | |
19 # | |
20 # andrea.gavana@gmail.com | |
21 # gavana@kpo.kz | |
22 # | |
23 # Or, Obviously, To The wxPython Mailing List!!! | |
24 # | |
25 # | |
26 # End Of Comments | |
27 # --------------------------------------------------------------------------- # | |
28 | |
29 """ | |
30 The FlatNotebook is a full implementation of the wx.Notebook, and designed to be | |
31 a drop-in replacement for wx.Notebook. The API functions are similar so one can | |
32 expect the function to behave in the same way. | |
33 | |
34 Some features: | |
35 | |
36 - The buttons are highlighted a la Firefox style | |
37 - The scrolling is done for bulks of tabs (so, the scrolling is faster and better) | |
38 - The buttons area is never overdrawn by tabs (unlike many other implementations I saw) | |
39 - It is a generic control | |
40 - Currently there are 5 differnt styles - VC8, VC 71, Standard, Fancy and Firefox 2; | |
41 - Mouse middle click can be used to close tabs | |
42 - A function to add right click menu for tabs (simple as SetRightClickMenu) | |
43 - All styles has bottom style as well (they can be drawn in the bottom of screen) | |
44 - An option to hide 'X' button or navigation buttons (separately) | |
45 - Gradient coloring of the selected tabs and border | |
46 - Support for drag 'n' drop of tabs, both in the same notebook or to another notebook | |
47 - Possibility to have closing button on the active tab directly | |
48 - Support for disabled tabs | |
49 - Colours for active/inactive tabs, and captions | |
50 - Background of tab area can be painted in gradient (VC8 style only) | |
51 - Colourful tabs - a random gentle colour is generated for each new tab (very cool, VC8 style only) | |
52 | |
53 | |
54 And much more. | |
55 | |
56 | |
57 License And Version: | |
58 | |
59 FlatNotebook Is Freeware And Distributed Under The wxPython License. | |
60 | |
61 Latest Revision: Andrea Gavana @ 22 Nov 2007, 14.00 GMT | |
62 | |
63 Version 2.4. | |
64 | |
65 @undocumented: FNB_HEIGHT_SPACER, VERTICAL_BORDER_PADDING, VC8_SHAPE_LEN, | |
66 wxEVT*, left_arrow_*, right_arrow*, x_button*, down_arrow*, | |
67 FNBDragInfo, FNBDropTarget, GetMondrian* | |
68 """ | |
69 | |
70 __docformat__ = "epytext" | |
71 | |
72 | |
73 #---------------------------------------------------------------------- | |
74 # Beginning Of FLATNOTEBOOK wxPython Code | |
75 #---------------------------------------------------------------------- | |
76 | |
77 import wx | |
78 import random | |
79 import math | |
80 import weakref | |
81 import cPickle | |
82 | |
83 if wx.Platform == '__WXMAC__': | |
84 import Carbon.Appearance | |
85 | |
86 # Check for the new method in 2.7 (not present in 2.6.3.3) | |
87 if wx.VERSION_STRING < "2.7": | |
88 wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point) | |
89 | |
90 FNB_HEIGHT_SPACER = 10 | |
91 | |
92 # Use Visual Studio 2003 (VC7.1) style for tabs | |
93 FNB_VC71 = 1 | |
94 """Use Visual Studio 2003 (VC7.1) style for tabs""" | |
95 | |
96 # Use fancy style - square tabs filled with gradient coloring | |
97 FNB_FANCY_TABS = 2 | |
98 """Use fancy style - square tabs filled with gradient coloring""" | |
99 | |
100 # Draw thin border around the page | |
101 FNB_TABS_BORDER_SIMPLE = 4 | |
102 """Draw thin border around the page""" | |
103 | |
104 # Do not display the 'X' button | |
105 FNB_NO_X_BUTTON = 8 | |
106 """Do not display the 'X' button""" | |
107 | |
108 # Do not display the Right / Left arrows | |
109 FNB_NO_NAV_BUTTONS = 16 | |
110 """Do not display the right/left arrows""" | |
111 | |
112 # Use the mouse middle button for cloing tabs | |
113 FNB_MOUSE_MIDDLE_CLOSES_TABS = 32 | |
114 """Use the mouse middle button for cloing tabs""" | |
115 | |
116 # Place tabs at bottom - the default is to place them | |
117 # at top | |
118 FNB_BOTTOM = 64 | |
119 """Place tabs at bottom - the default is to place them at top""" | |
120 | |
121 # Disable dragging of tabs | |
122 FNB_NODRAG = 128 | |
123 """Disable dragging of tabs""" | |
124 | |
125 # Use Visual Studio 2005 (VC8) style for tabs | |
126 FNB_VC8 = 256 | |
127 """Use Visual Studio 2005 (VC8) style for tabs""" | |
128 | |
129 # Firefox 2 tabs style | |
130 FNB_FF2 = 131072 | |
131 """Use Firefox 2 style for tabs""" | |
132 | |
133 # Place 'X' on a tab | |
134 FNB_X_ON_TAB = 512 | |
135 """Place 'X' close button on the active tab""" | |
136 | |
137 FNB_BACKGROUND_GRADIENT = 1024 | |
138 """Use gradients to paint the tabs background""" | |
139 | |
140 FNB_COLORFUL_TABS = 2048 | |
141 """Use colourful tabs (VC8 style only)""" | |
142 | |
143 # Style to close tab using double click - styles 1024, 2048 are reserved | |
144 FNB_DCLICK_CLOSES_TABS = 4096 | |
145 """Style to close tab using double click""" | |
146 | |
147 FNB_SMART_TABS = 8192 | |
148 """Use Smart Tabbing, like Alt+Tab on Windows""" | |
149 | |
150 FNB_DROPDOWN_TABS_LIST = 16384 | |
151 """Use a dropdown menu on the left in place of the arrows""" | |
152 | |
153 FNB_ALLOW_FOREIGN_DND = 32768 | |
154 """Allows drag 'n' drop operations between different L{FlatNotebook}s""" | |
155 | |
156 FNB_HIDE_ON_SINGLE_TAB = 65536 | |
157 """Hides the Page Container when there is one or fewer tabs""" | |
158 | |
159 VERTICAL_BORDER_PADDING = 4 | |
160 | |
161 # Button size is a 16x16 xpm bitmap | |
162 BUTTON_SPACE = 16 | |
163 """Button size is a 16x16 xpm bitmap""" | |
164 | |
165 VC8_SHAPE_LEN = 16 | |
166 | |
167 MASK_COLOR = wx.Colour(0, 128, 128) | |
168 """Mask colour for the arrow bitmaps""" | |
169 | |
170 # Button status | |
171 FNB_BTN_PRESSED = 2 | |
172 """Navigation button is pressed""" | |
173 FNB_BTN_HOVER = 1 | |
174 """Navigation button is hovered""" | |
175 FNB_BTN_NONE = 0 | |
176 """No navigation""" | |
177 | |
178 # Hit Test results | |
179 FNB_TAB = 1 # On a tab | |
180 """Indicates mouse coordinates inside a tab""" | |
181 FNB_X = 2 # On the X button | |
182 """Indicates mouse coordinates inside the I{X} region""" | |
183 FNB_TAB_X = 3 # On the 'X' button (tab's X button) | |
184 """Indicates mouse coordinates inside the I{X} region in a tab""" | |
185 FNB_LEFT_ARROW = 4 # On the rotate left arrow button | |
186 """Indicates mouse coordinates inside the left arrow region""" | |
187 FNB_RIGHT_ARROW = 5 # On the rotate right arrow button | |
188 """Indicates mouse coordinates inside the right arrow region""" | |
189 FNB_DROP_DOWN_ARROW = 6 # On the drop down arrow button | |
190 """Indicates mouse coordinates inside the drop down arrow region""" | |
191 FNB_NOWHERE = 0 # Anywhere else | |
192 """Indicates mouse coordinates not on any tab of the notebook""" | |
193 | |
194 FNB_DEFAULT_STYLE = FNB_MOUSE_MIDDLE_CLOSES_TABS | FNB_HIDE_ON_SINGLE_TAB | |
195 """L{FlatNotebook} default style""" | |
196 | |
197 # FlatNotebook Events: | |
198 # wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page; | |
199 # wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch | |
200 # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call | |
201 # event.Skip() In Your Event Handler; | |
202 # wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But | |
203 # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip() | |
204 # In Your Event Handler; | |
205 # wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed. | |
206 # wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab. | |
207 | |
208 wxEVT_FLATNOTEBOOK_PAGE_CHANGED = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED | |
209 wxEVT_FLATNOTEBOOK_PAGE_CHANGING = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING | |
210 wxEVT_FLATNOTEBOOK_PAGE_CLOSING = wx.NewEventType() | |
211 wxEVT_FLATNOTEBOOK_PAGE_CLOSED = wx.NewEventType() | |
212 wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.NewEventType() | |
213 | |
214 #-----------------------------------# | |
215 # FlatNotebookEvent | |
216 #-----------------------------------# | |
217 | |
218 EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.EVT_NOTEBOOK_PAGE_CHANGED | |
219 """Notify client objects when the active page in L{FlatNotebook} | |
220 has changed.""" | |
221 EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.EVT_NOTEBOOK_PAGE_CHANGING | |
222 """Notify client objects when the active page in L{FlatNotebook} | |
223 is about to change.""" | |
224 EVT_FLATNOTEBOOK_PAGE_CLOSING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, 1) | |
225 """Notify client objects when a page in L{FlatNotebook} is closing.""" | |
226 EVT_FLATNOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, 1) | |
227 """Notify client objects when a page in L{FlatNotebook} has been closed.""" | |
228 EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, 1) | |
229 """Notify client objects when a pop-up menu should appear next to a tab.""" | |
230 | |
231 | |
232 # Some icons in XPM format | |
233 | |
234 left_arrow_disabled_xpm = [ | |
235 " 16 16 8 1", | |
236 "` c #008080", | |
237 ". c #555555", | |
238 "# c #000000", | |
239 "a c #000000", | |
240 "b c #000000", | |
241 "c c #000000", | |
242 "d c #000000", | |
243 "e c #000000", | |
244 "````````````````", | |
245 "````````````````", | |
246 "````````````````", | |
247 "````````.```````", | |
248 "```````..```````", | |
249 "``````.`.```````", | |
250 "`````.``.```````", | |
251 "````.```.```````", | |
252 "`````.``.```````", | |
253 "``````.`.```````", | |
254 "```````..```````", | |
255 "````````.```````", | |
256 "````````````````", | |
257 "````````````````", | |
258 "````````````````", | |
259 "````````````````" | |
260 ] | |
261 | |
262 x_button_pressed_xpm = [ | |
263 " 16 16 8 1", | |
264 "` c #008080", | |
265 ". c #4766e0", | |
266 "# c #9e9ede", | |
267 "a c #000000", | |
268 "b c #000000", | |
269 "c c #000000", | |
270 "d c #000000", | |
271 "e c #000000", | |
272 "````````````````", | |
273 "`..............`", | |
274 "`.############.`", | |
275 "`.############.`", | |
276 "`.############.`", | |
277 "`.###aa####aa#.`", | |
278 "`.####aa##aa##.`", | |
279 "`.#####aaaa###.`", | |
280 "`.######aa####.`", | |
281 "`.#####aaaa###.`", | |
282 "`.####aa##aa##.`", | |
283 "`.###aa####aa#.`", | |
284 "`.############.`", | |
285 "`..............`", | |
286 "````````````````", | |
287 "````````````````" | |
288 ] | |
289 | |
290 | |
291 left_arrow_xpm = [ | |
292 " 16 16 8 1", | |
293 "` c #008080", | |
294 ". c #555555", | |
295 "# c #000000", | |
296 "a c #000000", | |
297 "b c #000000", | |
298 "c c #000000", | |
299 "d c #000000", | |
300 "e c #000000", | |
301 "````````````````", | |
302 "````````````````", | |
303 "````````````````", | |
304 "````````.```````", | |
305 "```````..```````", | |
306 "``````...```````", | |
307 "`````....```````", | |
308 "````.....```````", | |
309 "`````....```````", | |
310 "``````...```````", | |
311 "```````..```````", | |
312 "````````.```````", | |
313 "````````````````", | |
314 "````````````````", | |
315 "````````````````", | |
316 "````````````````" | |
317 ] | |
318 | |
319 x_button_hilite_xpm = [ | |
320 " 16 16 8 1", | |
321 "` c #008080", | |
322 ". c #4766e0", | |
323 "# c #c9dafb", | |
324 "a c #000000", | |
325 "b c #000000", | |
326 "c c #000000", | |
327 "d c #000000", | |
328 "e c #000000", | |
329 "````````````````", | |
330 "`..............`", | |
331 "`.############.`", | |
332 "`.############.`", | |
333 "`.##aa####aa##.`", | |
334 "`.###aa##aa###.`", | |
335 "`.####aaaa####.`", | |
336 "`.#####aa#####.`", | |
337 "`.####aaaa####.`", | |
338 "`.###aa##aa###.`", | |
339 "`.##aa####aa##.`", | |
340 "`.############.`", | |
341 "`.############.`", | |
342 "`..............`", | |
343 "````````````````", | |
344 "````````````````" | |
345 ] | |
346 | |
347 x_button_xpm = [ | |
348 " 16 16 8 1", | |
349 "` c #008080", | |
350 ". c #555555", | |
351 "# c #000000", | |
352 "a c #000000", | |
353 "b c #000000", | |
354 "c c #000000", | |
355 "d c #000000", | |
356 "e c #000000", | |
357 "````````````````", | |
358 "````````````````", | |
359 "````````````````", | |
360 "````````````````", | |
361 "````..````..````", | |
362 "`````..``..`````", | |
363 "``````....``````", | |
364 "```````..```````", | |
365 "``````....``````", | |
366 "`````..``..`````", | |
367 "````..````..````", | |
368 "````````````````", | |
369 "````````````````", | |
370 "````````````````", | |
371 "````````````````", | |
372 "````````````````" | |
373 ] | |
374 | |
375 left_arrow_pressed_xpm = [ | |
376 " 16 16 8 1", | |
377 "` c #008080", | |
378 ". c #4766e0", | |
379 "# c #9e9ede", | |
380 "a c #000000", | |
381 "b c #000000", | |
382 "c c #000000", | |
383 "d c #000000", | |
384 "e c #000000", | |
385 "````````````````", | |
386 "`..............`", | |
387 "`.############.`", | |
388 "`.############.`", | |
389 "`.#######a####.`", | |
390 "`.######aa####.`", | |
391 "`.#####aaa####.`", | |
392 "`.####aaaa####.`", | |
393 "`.###aaaaa####.`", | |
394 "`.####aaaa####.`", | |
395 "`.#####aaa####.`", | |
396 "`.######aa####.`", | |
397 "`.#######a####.`", | |
398 "`..............`", | |
399 "````````````````", | |
400 "````````````````" | |
401 ] | |
402 | |
403 left_arrow_hilite_xpm = [ | |
404 " 16 16 8 1", | |
405 "` c #008080", | |
406 ". c #4766e0", | |
407 "# c #c9dafb", | |
408 "a c #000000", | |
409 "b c #000000", | |
410 "c c #000000", | |
411 "d c #000000", | |
412 "e c #000000", | |
413 "````````````````", | |
414 "`..............`", | |
415 "`.############.`", | |
416 "`.######a#####.`", | |
417 "`.#####aa#####.`", | |
418 "`.####aaa#####.`", | |
419 "`.###aaaa#####.`", | |
420 "`.##aaaaa#####.`", | |
421 "`.###aaaa#####.`", | |
422 "`.####aaa#####.`", | |
423 "`.#####aa#####.`", | |
424 "`.######a#####.`", | |
425 "`.############.`", | |
426 "`..............`", | |
427 "````````````````", | |
428 "````````````````" | |
429 ] | |
430 | |
431 right_arrow_disabled_xpm = [ | |
432 " 16 16 8 1", | |
433 "` c #008080", | |
434 ". c #555555", | |
435 "# c #000000", | |
436 "a c #000000", | |
437 "b c #000000", | |
438 "c c #000000", | |
439 "d c #000000", | |
440 "e c #000000", | |
441 "````````````````", | |
442 "````````````````", | |
443 "````````````````", | |
444 "```````.````````", | |
445 "```````..```````", | |
446 "```````.`.``````", | |
447 "```````.``.`````", | |
448 "```````.```.````", | |
449 "```````.``.`````", | |
450 "```````.`.``````", | |
451 "```````..```````", | |
452 "```````.````````", | |
453 "````````````````", | |
454 "````````````````", | |
455 "````````````````", | |
456 "````````````````" | |
457 ] | |
458 | |
459 right_arrow_hilite_xpm = [ | |
460 " 16 16 8 1", | |
461 "` c #008080", | |
462 ". c #4766e0", | |
463 "# c #c9dafb", | |
464 "a c #000000", | |
465 "b c #000000", | |
466 "c c #000000", | |
467 "d c #000000", | |
468 "e c #000000", | |
469 "````````````````", | |
470 "`..............`", | |
471 "`.############.`", | |
472 "`.####a#######.`", | |
473 "`.####aa######.`", | |
474 "`.####aaa#####.`", | |
475 "`.####aaaa####.`", | |
476 "`.####aaaaa###.`", | |
477 "`.####aaaa####.`", | |
478 "`.####aaa#####.`", | |
479 "`.####aa######.`", | |
480 "`.####a#######.`", | |
481 "`.############.`", | |
482 "`..............`", | |
483 "````````````````", | |
484 "````````````````" | |
485 ] | |
486 | |
487 right_arrow_pressed_xpm = [ | |
488 " 16 16 8 1", | |
489 "` c #008080", | |
490 ". c #4766e0", | |
491 "# c #9e9ede", | |
492 "a c #000000", | |
493 "b c #000000", | |
494 "c c #000000", | |
495 "d c #000000", | |
496 "e c #000000", | |
497 "````````````````", | |
498 "`..............`", | |
499 "`.############.`", | |
500 "`.############.`", | |
501 "`.#####a######.`", | |
502 "`.#####aa#####.`", | |
503 "`.#####aaa####.`", | |
504 "`.#####aaaa###.`", | |
505 "`.#####aaaaa##.`", | |
506 "`.#####aaaa###.`", | |
507 "`.#####aaa####.`", | |
508 "`.#####aa#####.`", | |
509 "`.#####a######.`", | |
510 "`..............`", | |
511 "````````````````", | |
512 "````````````````" | |
513 ] | |
514 | |
515 | |
516 right_arrow_xpm = [ | |
517 " 16 16 8 1", | |
518 "` c #008080", | |
519 ". c #555555", | |
520 "# c #000000", | |
521 "a c #000000", | |
522 "b c #000000", | |
523 "c c #000000", | |
524 "d c #000000", | |
525 "e c #000000", | |
526 "````````````````", | |
527 "````````````````", | |
528 "````````````````", | |
529 "```````.````````", | |
530 "```````..```````", | |
531 "```````...``````", | |
532 "```````....`````", | |
533 "```````.....````", | |
534 "```````....`````", | |
535 "```````...``````", | |
536 "```````..```````", | |
537 "```````.````````", | |
538 "````````````````", | |
539 "````````````````", | |
540 "````````````````", | |
541 "````````````````" | |
542 ] | |
543 | |
544 down_arrow_hilite_xpm = [ | |
545 " 16 16 8 1", | |
546 "` c #008080", | |
547 ". c #4766e0", | |
548 "# c #c9dafb", | |
549 "a c #000000", | |
550 "b c #000000", | |
551 "c c #000000", | |
552 "d c #000000", | |
553 "e c #000000", | |
554 "````````````````", | |
555 "``.............`", | |
556 "``.###########.`", | |
557 "``.###########.`", | |
558 "``.###########.`", | |
559 "``.#aaaaaaaaa#.`", | |
560 "``.##aaaaaaa##.`", | |
561 "``.###aaaaa###.`", | |
562 "``.####aaa####.`", | |
563 "``.#####a#####.`", | |
564 "``.###########.`", | |
565 "``.###########.`", | |
566 "``.###########.`", | |
567 "``.............`", | |
568 "````````````````", | |
569 "````````````````" | |
570 ] | |
571 | |
572 down_arrow_pressed_xpm = [ | |
573 " 16 16 8 1", | |
574 "` c #008080", | |
575 ". c #4766e0", | |
576 "# c #9e9ede", | |
577 "a c #000000", | |
578 "b c #000000", | |
579 "c c #000000", | |
580 "d c #000000", | |
581 "e c #000000", | |
582 "````````````````", | |
583 "``.............`", | |
584 "``.###########.`", | |
585 "``.###########.`", | |
586 "``.###########.`", | |
587 "``.###########.`", | |
588 "``.###########.`", | |
589 "``.#aaaaaaaaa#.`", | |
590 "``.##aaaaaaa##.`", | |
591 "``.###aaaaa###.`", | |
592 "``.####aaa####.`", | |
593 "``.#####a#####.`", | |
594 "``.###########.`", | |
595 "``.............`", | |
596 "````````````````", | |
597 "````````````````" | |
598 ] | |
599 | |
600 | |
601 down_arrow_xpm = [ | |
602 " 16 16 8 1", | |
603 "` c #008080", | |
604 ". c #000000", | |
605 "# c #000000", | |
606 "a c #000000", | |
607 "b c #000000", | |
608 "c c #000000", | |
609 "d c #000000", | |
610 "e c #000000", | |
611 "````````````````", | |
612 "````````````````", | |
613 "````````````````", | |
614 "````````````````", | |
615 "````````````````", | |
616 "````````````````", | |
617 "````.........```", | |
618 "`````.......````", | |
619 "``````.....`````", | |
620 "```````...``````", | |
621 "````````.```````", | |
622 "````````````````", | |
623 "````````````````", | |
624 "````````````````", | |
625 "````````````````", | |
626 "````````````````" | |
627 ] | |
628 | |
629 | |
630 #---------------------------------------------------------------------- | |
631 def GetMondrianData(): | |
632 return \ | |
633 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ | |
634 \x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\ | |
635 ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\ | |
636 o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\ | |
637 \xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\ | |
638 \x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\ | |
639 \x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82' | |
640 | |
641 | |
642 def GetMondrianBitmap(): | |
643 return wx.BitmapFromImage(GetMondrianImage().Scale(16, 16)) | |
644 | |
645 | |
646 def GetMondrianImage(): | |
647 import cStringIO | |
648 stream = cStringIO.StringIO(GetMondrianData()) | |
649 return wx.ImageFromStream(stream) | |
650 | |
651 | |
652 def GetMondrianIcon(): | |
653 icon = wx.EmptyIcon() | |
654 icon.CopyFromBitmap(GetMondrianBitmap()) | |
655 return icon | |
656 #---------------------------------------------------------------------- | |
657 | |
658 | |
659 def LightColour(color, percent): | |
660 """ Brighten input colour by percent. """ | |
661 | |
662 end_color = wx.WHITE | |
663 | |
664 rd = end_color.Red() - color.Red() | |
665 gd = end_color.Green() - color.Green() | |
666 bd = end_color.Blue() - color.Blue() | |
667 | |
668 high = 100 | |
669 | |
670 # We take the percent way of the color from color -. white | |
671 i = percent | |
672 r = color.Red() + ((i*rd*100)/high)/100 | |
673 g = color.Green() + ((i*gd*100)/high)/100 | |
674 b = color.Blue() + ((i*bd*100)/high)/100 | |
675 return wx.Colour(r, g, b) | |
676 | |
677 | |
678 def RandomColour(): | |
679 """ Creates a random colour. """ | |
680 | |
681 r = random.randint(0, 255) # Random value betweem 0-255 | |
682 g = random.randint(0, 255) # Random value betweem 0-255 | |
683 b = random.randint(0, 255) # Random value betweem 0-255 | |
684 | |
685 return wx.Colour(r, g, b) | |
686 | |
687 | |
688 def PaintStraightGradientBox(dc, rect, startColor, endColor, vertical=True): | |
689 """ Draws a gradient colored box from startColor to endColor. """ | |
690 | |
691 rd = endColor.Red() - startColor.Red() | |
692 gd = endColor.Green() - startColor.Green() | |
693 bd = endColor.Blue() - startColor.Blue() | |
694 | |
695 # Save the current pen and brush | |
696 savedPen = dc.GetPen() | |
697 savedBrush = dc.GetBrush() | |
698 | |
699 if vertical: | |
700 high = rect.GetHeight()-1 | |
701 else: | |
702 high = rect.GetWidth()-1 | |
703 | |
704 if high < 1: | |
705 return | |
706 | |
707 for i in xrange(high+1): | |
708 | |
709 r = startColor.Red() + ((i*rd*100)/high)/100 | |
710 g = startColor.Green() + ((i*gd*100)/high)/100 | |
711 b = startColor.Blue() + ((i*bd*100)/high)/100 | |
712 | |
713 p = wx.Pen(wx.Colour(r, g, b)) | |
714 dc.SetPen(p) | |
715 | |
716 if vertical: | |
717 dc.DrawLine(rect.x, rect.y+i, rect.x+rect.width, rect.y+i) | |
718 else: | |
719 dc.DrawLine(rect.x+i, rect.y, rect.x+i, rect.y+rect.height) | |
720 | |
721 # Restore the pen and brush | |
722 dc.SetPen(savedPen) | |
723 dc.SetBrush(savedBrush) | |
724 | |
725 | |
726 | |
727 # ----------------------------------------------------------------------------- | |
728 # Util functions | |
729 # ----------------------------------------------------------------------------- | |
730 | |
731 def DrawButton(dc, rect, focus, upperTabs): | |
732 | |
733 # Define the rounded rectangle base on the given rect | |
734 # we need an array of 9 points for it | |
735 regPts = [wx.Point() for indx in xrange(9)] | |
736 | |
737 if focus: | |
738 if upperTabs: | |
739 leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*8) | |
740 rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*8) | |
741 else: | |
742 leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*5) | |
743 rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*5) | |
744 else: | |
745 leftPt = wx.Point(rect.x, rect.y + (rect.height / 2)) | |
746 rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 2)) | |
747 | |
748 # Define the top region | |
749 top = wx.RectPP(rect.GetTopLeft(), rightPt) | |
750 bottom = wx.RectPP(leftPt, rect.GetBottomRight()) | |
751 | |
752 topStartColor = wx.WHITE | |
753 | |
754 if not focus: | |
755 topStartColor = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 50) | |
756 | |
757 topEndColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) | |
758 bottomStartColor = topEndColor | |
759 bottomEndColor = topEndColor | |
760 | |
761 # Incase we use bottom tabs, switch the colors | |
762 if upperTabs: | |
763 if focus: | |
764 PaintStraightGradientBox(dc, top, topStartColor, topEndColor) | |
765 PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor) | |
766 else: | |
767 PaintStraightGradientBox(dc, top, topEndColor , topStartColor) | |
768 PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor) | |
769 | |
770 else: | |
771 if focus: | |
772 PaintStraightGradientBox(dc, bottom, topEndColor, bottomEndColor) | |
773 PaintStraightGradientBox(dc, top,topStartColor, topStartColor) | |
774 else: | |
775 PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor) | |
776 PaintStraightGradientBox(dc, top, topEndColor, topStartColor) | |
777 | |
778 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
779 | |
780 | |
781 # ---------------------------------------------------------------------------- # | |
782 # Class FNBDropSource | |
783 # Gives Some Custom UI Feedback during the DnD Operations | |
784 # ---------------------------------------------------------------------------- # | |
785 | |
786 class FNBDropSource(wx.DropSource): | |
787 """ | |
788 Give some custom UI feedback during the drag and drop operation in this | |
789 function. It is called on each mouse move, so your implementation must | |
790 not be too slow. | |
791 """ | |
792 | |
793 def __init__(self, win): | |
794 """ Default class constructor. Used internally. """ | |
795 | |
796 wx.DropSource.__init__(self, win) | |
797 self._win = win | |
798 | |
799 | |
800 def GiveFeedback(self, effect): | |
801 """ Provides user with a nice feedback when tab is being dragged. """ | |
802 | |
803 self._win.DrawDragHint() | |
804 return False | |
805 | |
806 | |
807 # ---------------------------------------------------------------------------- # | |
808 # Class FNBDragInfo | |
809 # Stores All The Information To Allow Drag And Drop Between Different | |
810 # FlatNotebooks. | |
811 # ---------------------------------------------------------------------------- # | |
812 | |
813 class FNBDragInfo: | |
814 | |
815 _map = weakref.WeakValueDictionary() | |
816 | |
817 def __init__(self, container, pageindex): | |
818 """ Default class constructor. """ | |
819 | |
820 self._id = id(container) | |
821 FNBDragInfo._map[self._id] = container | |
822 self._pageindex = pageindex | |
823 | |
824 | |
825 def GetContainer(self): | |
826 """ Returns the L{FlatNotebook} page (usually a panel). """ | |
827 | |
828 return FNBDragInfo._map.get(self._id, None) | |
829 | |
830 | |
831 def GetPageIndex(self): | |
832 """ Returns the page index associated with a page. """ | |
833 | |
834 return self._pageindex | |
835 | |
836 | |
837 # ---------------------------------------------------------------------------- # | |
838 # Class FNBDropTarget | |
839 # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between | |
840 # Different FlatNotebooks. | |
841 # ---------------------------------------------------------------------------- # | |
842 | |
843 class FNBDropTarget(wx.DropTarget): | |
844 | |
845 def __init__(self, parent): | |
846 """ Default class constructor. """ | |
847 | |
848 wx.DropTarget.__init__(self) | |
849 | |
850 self._parent = parent | |
851 self._dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook")) | |
852 self.SetDataObject(self._dataobject) | |
853 | |
854 | |
855 def OnData(self, x, y, dragres): | |
856 """ Handles the OnData() method to call the real DnD routine. """ | |
857 | |
858 if not self.GetData(): | |
859 return wx.DragNone | |
860 | |
861 draginfo = self._dataobject.GetData() | |
862 drginfo = cPickle.loads(draginfo) | |
863 | |
864 return self._parent.OnDropTarget(x, y, drginfo.GetPageIndex(), drginfo.GetContainer()) | |
865 | |
866 | |
867 # ---------------------------------------------------------------------------- # | |
868 # Class PageInfo | |
869 # Contains parameters for every FlatNotebook page | |
870 # ---------------------------------------------------------------------------- # | |
871 | |
872 class PageInfo: | |
873 """ | |
874 This class holds all the information (caption, image, etc...) belonging to a | |
875 single tab in L{FlatNotebook}. | |
876 """ | |
877 | |
878 def __init__(self, caption="", imageindex=-1, tabangle=0, enabled=True): | |
879 """ | |
880 Default Class Constructor. | |
881 | |
882 Parameters: | |
883 @param caption: the tab caption; | |
884 @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any); | |
885 @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees); | |
886 @param enabled: sets enabled or disabled the tab. | |
887 """ | |
888 | |
889 self._strCaption = caption | |
890 self._TabAngle = tabangle | |
891 self._ImageIndex = imageindex | |
892 self._bEnabled = enabled | |
893 self._pos = wx.Point(-1, -1) | |
894 self._size = wx.Size(-1, -1) | |
895 self._region = wx.Region() | |
896 self._xRect = wx.Rect() | |
897 self._color = None | |
898 self._hasFocus = False | |
899 | |
900 | |
901 def SetCaption(self, value): | |
902 """ Sets the tab caption. """ | |
903 | |
904 self._strCaption = value | |
905 | |
906 | |
907 def GetCaption(self): | |
908 """ Returns the tab caption. """ | |
909 | |
910 return self._strCaption | |
911 | |
912 | |
913 def SetPosition(self, value): | |
914 """ Sets the tab position. """ | |
915 | |
916 self._pos = value | |
917 | |
918 | |
919 def GetPosition(self): | |
920 """ Returns the tab position. """ | |
921 | |
922 return self._pos | |
923 | |
924 | |
925 def SetSize(self, value): | |
926 """ Sets the tab size. """ | |
927 | |
928 self._size = value | |
929 | |
930 | |
931 def GetSize(self): | |
932 """ Returns the tab size. """ | |
933 | |
934 return self._size | |
935 | |
936 | |
937 def SetTabAngle(self, value): | |
938 """ Sets the tab header angle (0 <= tab <= 15 degrees). """ | |
939 | |
940 self._TabAngle = min(45, value) | |
941 | |
942 | |
943 def GetTabAngle(self): | |
944 """ Returns the tab angle. """ | |
945 | |
946 return self._TabAngle | |
947 | |
948 | |
949 def SetImageIndex(self, value): | |
950 """ Sets the tab image index. """ | |
951 | |
952 self._ImageIndex = value | |
953 | |
954 | |
955 def GetImageIndex(self): | |
956 """ Returns the tab umage index. """ | |
957 | |
958 return self._ImageIndex | |
959 | |
960 | |
961 def GetEnabled(self): | |
962 """ Returns whether the tab is enabled or not. """ | |
963 | |
964 return self._bEnabled | |
965 | |
966 | |
967 def EnableTab(self, enabled): | |
968 """ Sets the tab enabled or disabled. """ | |
969 | |
970 self._bEnabled = enabled | |
971 | |
972 | |
973 def SetRegion(self, points=[]): | |
974 """ Sets the tab region. """ | |
975 | |
976 self._region = wx.RegionFromPoints(points) | |
977 | |
978 | |
979 def GetRegion(self): | |
980 """ Returns the tab region. """ | |
981 | |
982 return self._region | |
983 | |
984 | |
985 def SetXRect(self, xrect): | |
986 """ Sets the button 'X' area rect. """ | |
987 | |
988 self._xRect = xrect | |
989 | |
990 | |
991 def GetXRect(self): | |
992 """ Returns the button 'X' area rect. """ | |
993 | |
994 return self._xRect | |
995 | |
996 | |
997 def GetColour(self): | |
998 """ Returns the tab colour. """ | |
999 | |
1000 return self._color | |
1001 | |
1002 | |
1003 def SetColour(self, color): | |
1004 """ Sets the tab colour. """ | |
1005 | |
1006 self._color = color | |
1007 | |
1008 | |
1009 # ---------------------------------------------------------------------------- # | |
1010 # Class FlatNotebookEvent | |
1011 # ---------------------------------------------------------------------------- # | |
1012 | |
1013 class FlatNotebookEvent(wx.PyCommandEvent): | |
1014 """ | |
1015 This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED, | |
1016 EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING, | |
1017 EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is | |
1018 mapped in the parent. | |
1019 """ | |
1020 | |
1021 def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1): | |
1022 """ Default class constructor. """ | |
1023 | |
1024 wx.PyCommandEvent.__init__(self, eventType, id) | |
1025 self._eventType = eventType | |
1026 | |
1027 self.notify = wx.NotifyEvent(eventType, id) | |
1028 | |
1029 | |
1030 def GetNotifyEvent(self): | |
1031 """Returns the actual wx.NotifyEvent.""" | |
1032 | |
1033 return self.notify | |
1034 | |
1035 | |
1036 def IsAllowed(self): | |
1037 """Returns whether the event is allowed or not.""" | |
1038 | |
1039 return self.notify.IsAllowed() | |
1040 | |
1041 | |
1042 def Veto(self): | |
1043 """Vetos the event.""" | |
1044 | |
1045 self.notify.Veto() | |
1046 | |
1047 | |
1048 def Allow(self): | |
1049 """The event is allowed.""" | |
1050 | |
1051 self.notify.Allow() | |
1052 | |
1053 | |
1054 def SetSelection(self, nSel): | |
1055 """ Sets event selection. """ | |
1056 | |
1057 self._selection = nSel | |
1058 | |
1059 | |
1060 def SetOldSelection(self, nOldSel): | |
1061 """ Sets old event selection. """ | |
1062 | |
1063 self._oldselection = nOldSel | |
1064 | |
1065 | |
1066 def GetSelection(self): | |
1067 """ Returns event selection. """ | |
1068 | |
1069 return self._selection | |
1070 | |
1071 | |
1072 def GetOldSelection(self): | |
1073 """ Returns old event selection """ | |
1074 | |
1075 return self._oldselection | |
1076 | |
1077 | |
1078 # ---------------------------------------------------------------------------- # | |
1079 # Class TabNavigatorWindow | |
1080 # ---------------------------------------------------------------------------- # | |
1081 | |
1082 class TabNavigatorWindow(wx.Dialog): | |
1083 """ | |
1084 This class is used to create a modal dialog that enables "Smart Tabbing", | |
1085 similar to what you would get by hitting Alt+Tab on Windows. | |
1086 """ | |
1087 | |
1088 def __init__(self, parent=None, icon=None): | |
1089 """ Default class constructor. Used internally.""" | |
1090 | |
1091 wx.Dialog.__init__(self, parent, wx.ID_ANY, "", style=0) | |
1092 | |
1093 self._selectedItem = -1 | |
1094 self._indexMap = [] | |
1095 | |
1096 if icon is None: | |
1097 self._bmp = GetMondrianBitmap() | |
1098 else: | |
1099 self._bmp = icon | |
1100 | |
1101 sz = wx.BoxSizer(wx.VERTICAL) | |
1102 | |
1103 self._listBox = wx.ListBox(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, 150), [], wx.LB_SINGLE | wx.NO_BORDER) | |
1104 | |
1105 mem_dc = wx.MemoryDC() | |
1106 mem_dc.SelectObject(wx.EmptyBitmap(1,1)) | |
1107 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1108 font.SetWeight(wx.BOLD) | |
1109 mem_dc.SetFont(font) | |
1110 | |
1111 panelHeight = mem_dc.GetCharHeight() | |
1112 panelHeight += 4 # Place a spacer of 2 pixels | |
1113 | |
1114 # Out signpost bitmap is 24 pixels | |
1115 if panelHeight < 24: | |
1116 panelHeight = 24 | |
1117 | |
1118 self._panel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, panelHeight)) | |
1119 | |
1120 sz.Add(self._panel) | |
1121 sz.Add(self._listBox, 1, wx.EXPAND) | |
1122 | |
1123 self.SetSizer(sz) | |
1124 | |
1125 # Connect events to the list box | |
1126 self._listBox.Bind(wx.EVT_KEY_UP, self.OnKeyUp) | |
1127 self._listBox.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey) | |
1128 self._listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnItemSelected) | |
1129 | |
1130 # Connect paint event to the panel | |
1131 self._panel.Bind(wx.EVT_PAINT, self.OnPanelPaint) | |
1132 self._panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnPanelEraseBg) | |
1133 | |
1134 self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)) | |
1135 self._listBox.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)) | |
1136 self.PopulateListControl(parent) | |
1137 | |
1138 self.GetSizer().Fit(self) | |
1139 self.GetSizer().SetSizeHints(self) | |
1140 self.GetSizer().Layout() | |
1141 self.Centre() | |
1142 | |
1143 | |
1144 def OnKeyUp(self, event): | |
1145 """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}.""" | |
1146 | |
1147 if event.GetKeyCode() == wx.WXK_CONTROL: | |
1148 self.CloseDialog() | |
1149 | |
1150 | |
1151 def OnNavigationKey(self, event): | |
1152 """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """ | |
1153 | |
1154 selected = self._listBox.GetSelection() | |
1155 bk = self.GetParent() | |
1156 maxItems = bk.GetPageCount() | |
1157 | |
1158 if event.GetDirection(): | |
1159 | |
1160 # Select next page | |
1161 if selected == maxItems - 1: | |
1162 itemToSelect = 0 | |
1163 else: | |
1164 itemToSelect = selected + 1 | |
1165 | |
1166 else: | |
1167 | |
1168 # Previous page | |
1169 if selected == 0: | |
1170 itemToSelect = maxItems - 1 | |
1171 else: | |
1172 itemToSelect = selected - 1 | |
1173 | |
1174 self._listBox.SetSelection(itemToSelect) | |
1175 | |
1176 | |
1177 def PopulateListControl(self, book): | |
1178 """Populates the L{TabNavigatorWindow} listbox with a list of tabs.""" | |
1179 | |
1180 selection = book.GetSelection() | |
1181 count = book.GetPageCount() | |
1182 | |
1183 self._listBox.Append(book.GetPageText(selection)) | |
1184 self._indexMap.append(selection) | |
1185 | |
1186 prevSel = book.GetPreviousSelection() | |
1187 | |
1188 if prevSel != wx.NOT_FOUND: | |
1189 | |
1190 # Insert the previous selection as second entry | |
1191 self._listBox.Append(book.GetPageText(prevSel)) | |
1192 self._indexMap.append(prevSel) | |
1193 | |
1194 for c in xrange(count): | |
1195 | |
1196 # Skip selected page | |
1197 if c == selection: | |
1198 continue | |
1199 | |
1200 # Skip previous selected page as well | |
1201 if c == prevSel: | |
1202 continue | |
1203 | |
1204 self._listBox.Append(book.GetPageText(c)) | |
1205 self._indexMap.append(c) | |
1206 | |
1207 # Select the next entry after the current selection | |
1208 self._listBox.SetSelection(0) | |
1209 dummy = wx.NavigationKeyEvent() | |
1210 dummy.SetDirection(True) | |
1211 self.OnNavigationKey(dummy) | |
1212 | |
1213 | |
1214 def OnItemSelected(self, event): | |
1215 """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """ | |
1216 | |
1217 self.CloseDialog() | |
1218 | |
1219 | |
1220 def CloseDialog(self): | |
1221 """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}.""" | |
1222 | |
1223 bk = self.GetParent() | |
1224 self._selectedItem = self._listBox.GetSelection() | |
1225 iter = self._indexMap[self._selectedItem] | |
1226 bk._pages.FireEvent(iter) | |
1227 self.EndModal(wx.ID_OK) | |
1228 | |
1229 | |
1230 def OnPanelPaint(self, event): | |
1231 """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """ | |
1232 | |
1233 dc = wx.PaintDC(self._panel) | |
1234 rect = self._panel.GetClientRect() | |
1235 | |
1236 bmp = wx.EmptyBitmap(rect.width, rect.height) | |
1237 | |
1238 mem_dc = wx.MemoryDC() | |
1239 mem_dc.SelectObject(bmp) | |
1240 | |
1241 endColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW) | |
1242 startColour = LightColour(endColour, 50) | |
1243 PaintStraightGradientBox(mem_dc, rect, startColour, endColour) | |
1244 | |
1245 # Draw the caption title and place the bitmap | |
1246 # get the bitmap optimal position, and draw it | |
1247 bmpPt, txtPt = wx.Point(), wx.Point() | |
1248 bmpPt.y = (rect.height - self._bmp.GetHeight())/2 | |
1249 bmpPt.x = 3 | |
1250 mem_dc.DrawBitmap(self._bmp, bmpPt.x, bmpPt.y, True) | |
1251 | |
1252 # get the text position, and draw it | |
1253 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1254 font.SetWeight(wx.BOLD) | |
1255 mem_dc.SetFont(font) | |
1256 fontHeight = mem_dc.GetCharHeight() | |
1257 | |
1258 txtPt.x = bmpPt.x + self._bmp.GetWidth() + 4 | |
1259 txtPt.y = (rect.height - fontHeight)/2 | |
1260 mem_dc.SetTextForeground(wx.WHITE) | |
1261 mem_dc.DrawText("Opened tabs:", txtPt.x, txtPt.y) | |
1262 mem_dc.SelectObject(wx.NullBitmap) | |
1263 | |
1264 dc.DrawBitmap(bmp, 0, 0) | |
1265 | |
1266 | |
1267 def OnPanelEraseBg(self, event): | |
1268 """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """ | |
1269 | |
1270 pass | |
1271 | |
1272 | |
1273 # ---------------------------------------------------------------------------- # | |
1274 # Class FNBRenderer | |
1275 # ---------------------------------------------------------------------------- # | |
1276 | |
1277 class FNBRenderer: | |
1278 """ | |
1279 Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy} | |
1280 and I{VC8}. This class implements the common methods of all 4 renderers. | |
1281 """ | |
1282 | |
1283 def __init__(self): | |
1284 """Default class constructor. """ | |
1285 | |
1286 self._tabHeight = None | |
1287 | |
1288 if wx.Platform == "__WXMAC__": | |
1289 # Hack to get proper highlight color for focus rectangle from | |
1290 # current theme by creating a theme brush and getting its color. | |
1291 # kThemeBrushFocusHighlight is available on Mac OS 8.5 and higher | |
1292 brush = wx.BLACK_BRUSH | |
1293 brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight) | |
1294 self._focusPen = wx.Pen(brush.GetColour(), 2, wx.SOLID) | |
1295 else: | |
1296 self._focusPen = wx.Pen(wx.BLACK, 1, wx.USER_DASH) | |
1297 self._focusPen.SetDashes([1, 1]) | |
1298 self._focusPen.SetCap(wx.CAP_BUTT) | |
1299 | |
1300 | |
1301 def GetLeftButtonPos(self, pageContainer): | |
1302 """ Returns the left button position in the navigation area. """ | |
1303 | |
1304 pc = pageContainer | |
1305 style = pc.GetParent().GetWindowStyleFlag() | |
1306 rect = pc.GetClientRect() | |
1307 clientWidth = rect.width | |
1308 | |
1309 if style & FNB_NO_X_BUTTON: | |
1310 return clientWidth - 38 | |
1311 else: | |
1312 return clientWidth - 54 | |
1313 | |
1314 | |
1315 def GetRightButtonPos(self, pageContainer): | |
1316 """ Returns the right button position in the navigation area. """ | |
1317 | |
1318 pc = pageContainer | |
1319 style = pc.GetParent().GetWindowStyleFlag() | |
1320 rect = pc.GetClientRect() | |
1321 clientWidth = rect.width | |
1322 | |
1323 if style & FNB_NO_X_BUTTON: | |
1324 return clientWidth - 22 | |
1325 else: | |
1326 return clientWidth - 38 | |
1327 | |
1328 | |
1329 def GetDropArrowButtonPos(self, pageContainer): | |
1330 """ Returns the drop down button position in the navigation area. """ | |
1331 | |
1332 return self.GetRightButtonPos(pageContainer) | |
1333 | |
1334 | |
1335 def GetXPos(self, pageContainer): | |
1336 """ Returns the 'X' button position in the navigation area. """ | |
1337 | |
1338 pc = pageContainer | |
1339 style = pc.GetParent().GetWindowStyleFlag() | |
1340 rect = pc.GetClientRect() | |
1341 clientWidth = rect.width | |
1342 | |
1343 if style & FNB_NO_X_BUTTON: | |
1344 return clientWidth | |
1345 else: | |
1346 return clientWidth - 22 | |
1347 | |
1348 | |
1349 def GetButtonsAreaLength(self, pageContainer): | |
1350 """ Returns the navigation area width. """ | |
1351 | |
1352 pc = pageContainer | |
1353 style = pc.GetParent().GetWindowStyleFlag() | |
1354 | |
1355 # '' | |
1356 if style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST: | |
1357 return 0 | |
1358 | |
1359 # 'x' | |
1360 elif style & FNB_NO_NAV_BUTTONS and not style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST: | |
1361 return 22 | |
1362 | |
1363 # '<>' | |
1364 if not style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST: | |
1365 return 53 - 16 | |
1366 | |
1367 # 'vx' | |
1368 if style & FNB_DROPDOWN_TABS_LIST and not style & FNB_NO_X_BUTTON: | |
1369 return 22 + 16 | |
1370 | |
1371 # 'v' | |
1372 if style & FNB_DROPDOWN_TABS_LIST and style & FNB_NO_X_BUTTON: | |
1373 return 22 | |
1374 | |
1375 # '<>x' | |
1376 return 53 | |
1377 | |
1378 | |
1379 def DrawArrowAccordingToState(self, dc, pc, rect): | |
1380 | |
1381 lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0] | |
1382 PaintStraightGradientBox(dc, rect, pc._tabAreaColor, LightColour(pc._tabAreaColor, lightFactor)) | |
1383 | |
1384 | |
1385 def DrawLeftArrow(self, pageContainer, dc): | |
1386 """ Draw the left navigation arrow. """ | |
1387 | |
1388 pc = pageContainer | |
1389 | |
1390 style = pc.GetParent().GetWindowStyleFlag() | |
1391 if style & FNB_NO_NAV_BUTTONS: | |
1392 return | |
1393 | |
1394 # Make sure that there are pages in the container | |
1395 if not pc._pagesInfoVec: | |
1396 return | |
1397 | |
1398 # Set the bitmap according to the button status | |
1399 if pc._nLeftButtonStatus == FNB_BTN_HOVER: | |
1400 arrowBmp = wx.BitmapFromXPMData(left_arrow_hilite_xpm) | |
1401 elif pc._nLeftButtonStatus == FNB_BTN_PRESSED: | |
1402 arrowBmp = wx.BitmapFromXPMData(left_arrow_pressed_xpm) | |
1403 else: | |
1404 arrowBmp = wx.BitmapFromXPMData(left_arrow_xpm) | |
1405 | |
1406 if pc._nFrom == 0: | |
1407 # Handle disabled arrow | |
1408 arrowBmp = wx.BitmapFromXPMData(left_arrow_disabled_xpm) | |
1409 | |
1410 arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR)) | |
1411 | |
1412 # Erase old bitmap | |
1413 posx = self.GetLeftButtonPos(pc) | |
1414 self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14)) | |
1415 | |
1416 # Draw the new bitmap | |
1417 dc.DrawBitmap(arrowBmp, posx, 6, True) | |
1418 | |
1419 | |
1420 def DrawRightArrow(self, pageContainer, dc): | |
1421 """ Draw the right navigation arrow. """ | |
1422 | |
1423 pc = pageContainer | |
1424 | |
1425 style = pc.GetParent().GetWindowStyleFlag() | |
1426 if style & FNB_NO_NAV_BUTTONS: | |
1427 return | |
1428 | |
1429 # Make sure that there are pages in the container | |
1430 if not pc._pagesInfoVec: | |
1431 return | |
1432 | |
1433 # Set the bitmap according to the button status | |
1434 if pc._nRightButtonStatus == FNB_BTN_HOVER: | |
1435 arrowBmp = wx.BitmapFromXPMData(right_arrow_hilite_xpm) | |
1436 elif pc._nRightButtonStatus == FNB_BTN_PRESSED: | |
1437 arrowBmp = wx.BitmapFromXPMData(right_arrow_pressed_xpm) | |
1438 else: | |
1439 arrowBmp = wx.BitmapFromXPMData(right_arrow_xpm) | |
1440 | |
1441 # Check if the right most tab is visible, if it is | |
1442 # don't rotate right anymore | |
1443 if pc._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1): | |
1444 arrowBmp = wx.BitmapFromXPMData(right_arrow_disabled_xpm) | |
1445 | |
1446 arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR)) | |
1447 | |
1448 # erase old bitmap | |
1449 posx = self.GetRightButtonPos(pc) | |
1450 self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14)) | |
1451 | |
1452 # Draw the new bitmap | |
1453 dc.DrawBitmap(arrowBmp, posx, 6, True) | |
1454 | |
1455 | |
1456 def DrawDropDownArrow(self, pageContainer, dc): | |
1457 """ Draws the drop-down arrow in the navigation area. """ | |
1458 | |
1459 pc = pageContainer | |
1460 | |
1461 # Check if this style is enabled | |
1462 style = pc.GetParent().GetWindowStyleFlag() | |
1463 if not style & FNB_DROPDOWN_TABS_LIST: | |
1464 return | |
1465 | |
1466 # Make sure that there are pages in the container | |
1467 if not pc._pagesInfoVec: | |
1468 return | |
1469 | |
1470 if pc._nArrowDownButtonStatus == FNB_BTN_HOVER: | |
1471 downBmp = wx.BitmapFromXPMData(down_arrow_hilite_xpm) | |
1472 elif pc._nArrowDownButtonStatus == FNB_BTN_PRESSED: | |
1473 downBmp = wx.BitmapFromXPMData(down_arrow_pressed_xpm) | |
1474 else: | |
1475 downBmp = wx.BitmapFromXPMData(down_arrow_xpm) | |
1476 | |
1477 downBmp.SetMask(wx.Mask(downBmp, MASK_COLOR)) | |
1478 | |
1479 # erase old bitmap | |
1480 posx = self.GetDropArrowButtonPos(pc) | |
1481 self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14)) | |
1482 | |
1483 # Draw the new bitmap | |
1484 dc.DrawBitmap(downBmp, posx, 6, True) | |
1485 | |
1486 | |
1487 def DrawX(self, pageContainer, dc): | |
1488 """ Draw the 'X' navigation button in the navigation area. """ | |
1489 | |
1490 pc = pageContainer | |
1491 | |
1492 # Check if this style is enabled | |
1493 style = pc.GetParent().GetWindowStyleFlag() | |
1494 if style & FNB_NO_X_BUTTON: | |
1495 return | |
1496 | |
1497 # Make sure that there are pages in the container | |
1498 if not pc._pagesInfoVec: | |
1499 return | |
1500 | |
1501 # Set the bitmap according to the button status | |
1502 if pc._nXButtonStatus == FNB_BTN_HOVER: | |
1503 xbmp = wx.BitmapFromXPMData(x_button_hilite_xpm) | |
1504 elif pc._nXButtonStatus == FNB_BTN_PRESSED: | |
1505 xbmp = wx.BitmapFromXPMData(x_button_pressed_xpm) | |
1506 else: | |
1507 xbmp = wx.BitmapFromXPMData(x_button_xpm) | |
1508 | |
1509 xbmp.SetMask(wx.Mask(xbmp, MASK_COLOR)) | |
1510 | |
1511 # erase old bitmap | |
1512 posx = self.GetXPos(pc) | |
1513 self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14)) | |
1514 | |
1515 # Draw the new bitmap | |
1516 dc.DrawBitmap(xbmp, posx, 6, True) | |
1517 | |
1518 | |
1519 def DrawTabX(self, pageContainer, dc, rect, tabIdx, btnStatus): | |
1520 """ Draws the 'X' in the selected tab. """ | |
1521 | |
1522 pc = pageContainer | |
1523 if not pc.HasFlag(FNB_X_ON_TAB): | |
1524 return | |
1525 | |
1526 # We draw the 'x' on the active tab only | |
1527 if tabIdx != pc.GetSelection() or tabIdx < 0: | |
1528 return | |
1529 | |
1530 # Set the bitmap according to the button status | |
1531 | |
1532 if btnStatus == FNB_BTN_HOVER: | |
1533 xBmp = wx.BitmapFromXPMData(x_button_hilite_xpm) | |
1534 elif btnStatus == FNB_BTN_PRESSED: | |
1535 xBmp = wx.BitmapFromXPMData(x_button_pressed_xpm) | |
1536 else: | |
1537 xBmp = wx.BitmapFromXPMData(x_button_xpm) | |
1538 | |
1539 # Set the masking | |
1540 xBmp.SetMask(wx.Mask(xBmp, MASK_COLOR)) | |
1541 | |
1542 # Draw the new bitmap | |
1543 dc.DrawBitmap(xBmp, rect.x, rect.y, True) | |
1544 | |
1545 # Update the vector | |
1546 rr = wx.Rect(rect.x, rect.y, 14, 13) | |
1547 pc._pagesInfoVec[tabIdx].SetXRect(rr) | |
1548 | |
1549 | |
1550 def DrawTabsLine(self, pageContainer, dc, selTabX1=-1, selTabX2=-1): | |
1551 """ Draws a line over the tabs. """ | |
1552 | |
1553 pc = pageContainer | |
1554 | |
1555 clntRect = pc.GetClientRect() | |
1556 clientRect3 = wx.Rect(0, 0, clntRect.width, clntRect.height) | |
1557 | |
1558 if pc.HasFlag(FNB_FF2): | |
1559 if not pc.HasFlag(FNB_BOTTOM): | |
1560 fillColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) | |
1561 else: | |
1562 fillColor = wx.WHITE | |
1563 | |
1564 dc.SetPen(wx.Pen(fillColor)) | |
1565 | |
1566 if pc.HasFlag(FNB_BOTTOM): | |
1567 | |
1568 dc.DrawLine(1, 0, clntRect.width-1, 0) | |
1569 dc.DrawLine(1, 1, clntRect.width-1, 1) | |
1570 | |
1571 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))) | |
1572 dc.DrawLine(1, 2, clntRect.width-1, 2) | |
1573 | |
1574 dc.SetPen(wx.Pen(fillColor)) | |
1575 dc.DrawLine(selTabX1 + 2, 2, selTabX2 - 1, 2) | |
1576 | |
1577 else: | |
1578 | |
1579 dc.DrawLine(1, clntRect.height, clntRect.width-1, clntRect.height) | |
1580 dc.DrawLine(1, clntRect.height-1, clntRect.width-1, clntRect.height-1) | |
1581 | |
1582 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))) | |
1583 dc.DrawLine(1, clntRect.height-2, clntRect.width-1, clntRect.height-2) | |
1584 | |
1585 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))) | |
1586 dc.DrawLine(selTabX1 + 2, clntRect.height-2, selTabX2-1, clntRect.height-2) | |
1587 | |
1588 else: | |
1589 | |
1590 if pc.HasFlag(FNB_BOTTOM): | |
1591 | |
1592 clientRect = wx.Rect(0, 2, clntRect.width, clntRect.height - 2) | |
1593 clientRect2 = wx.Rect(0, 1, clntRect.width, clntRect.height - 1) | |
1594 | |
1595 else: | |
1596 | |
1597 clientRect = wx.Rect(0, 0, clntRect.width, clntRect.height - 2) | |
1598 clientRect2 = wx.Rect(0, 0, clntRect.width, clntRect.height - 1) | |
1599 | |
1600 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
1601 dc.SetPen(wx.Pen(pc.GetSingleLineBorderColour())) | |
1602 dc.DrawRectangleRect(clientRect2) | |
1603 dc.DrawRectangleRect(clientRect3) | |
1604 | |
1605 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))) | |
1606 dc.DrawRectangleRect(clientRect) | |
1607 | |
1608 if not pc.HasFlag(FNB_TABS_BORDER_SIMPLE): | |
1609 | |
1610 dc.SetPen(wx.Pen((pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc._tabAreaColor])[0])) | |
1611 dc.DrawLine(0, 0, 0, clientRect.height+1) | |
1612 | |
1613 if pc.HasFlag(FNB_BOTTOM): | |
1614 | |
1615 dc.DrawLine(0, clientRect.height+1, clientRect.width, clientRect.height+1) | |
1616 | |
1617 else: | |
1618 | |
1619 dc.DrawLine(0, 0, clientRect.width, 0) | |
1620 | |
1621 dc.DrawLine(clientRect.width - 1, 0, clientRect.width - 1, clientRect.height+1) | |
1622 | |
1623 | |
1624 def CalcTabWidth(self, pageContainer, tabIdx, tabHeight): | |
1625 """ Calculates the width of the input tab. """ | |
1626 | |
1627 pc = pageContainer | |
1628 dc = wx.MemoryDC() | |
1629 dc.SelectObject(wx.EmptyBitmap(1,1)) | |
1630 | |
1631 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1632 boldFont.SetWeight(wx.FONTWEIGHT_BOLD) | |
1633 | |
1634 if pc.IsDefaultTabs(): | |
1635 shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi)) | |
1636 | |
1637 # Calculate the text length using the bold font, so when selecting a tab | |
1638 # its width will not change | |
1639 dc.SetFont(boldFont) | |
1640 width, pom = dc.GetTextExtent(pc.GetPageText(tabIdx)) | |
1641 | |
1642 # Set a minimum size to a tab | |
1643 if width < 20: | |
1644 width = 20 | |
1645 | |
1646 tabWidth = 2*pc._pParent.GetPadding() + width | |
1647 | |
1648 # Style to add a small 'x' button on the top right | |
1649 # of the tab | |
1650 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection(): | |
1651 # The xpm image that contains the 'x' button is 9 pixels | |
1652 spacer = 9 | |
1653 if pc.HasFlag(FNB_VC8): | |
1654 spacer = 4 | |
1655 | |
1656 tabWidth += pc._pParent.GetPadding() + spacer | |
1657 | |
1658 if pc.IsDefaultTabs(): | |
1659 # Default style | |
1660 tabWidth += 2*shapePoints | |
1661 | |
1662 hasImage = pc._ImageList != None and pc._pagesInfoVec[tabIdx].GetImageIndex() != -1 | |
1663 | |
1664 # For VC71 style, we only add the icon size (16 pixels) | |
1665 if hasImage: | |
1666 | |
1667 if not pc.IsDefaultTabs(): | |
1668 tabWidth += 16 + pc._pParent.GetPadding() | |
1669 else: | |
1670 # Default style | |
1671 tabWidth += 16 + pc._pParent.GetPadding() + shapePoints/2 | |
1672 | |
1673 return tabWidth | |
1674 | |
1675 | |
1676 def CalcTabHeight(self, pageContainer): | |
1677 """ Calculates the height of the input tab. """ | |
1678 | |
1679 if self._tabHeight: | |
1680 return self._tabHeight | |
1681 | |
1682 pc = pageContainer | |
1683 dc = wx.MemoryDC() | |
1684 dc.SelectObject(wx.EmptyBitmap(1,1)) | |
1685 | |
1686 # For GTK it seems that we must do this steps in order | |
1687 # for the tabs will get the proper height on initialization | |
1688 # on MSW, preforming these steps yields wierd results | |
1689 normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1690 boldFont = normalFont | |
1691 | |
1692 if "__WXGTK__" in wx.PlatformInfo: | |
1693 boldFont.SetWeight(wx.FONTWEIGHT_BOLD) | |
1694 dc.SetFont(boldFont) | |
1695 | |
1696 height = dc.GetCharHeight() | |
1697 | |
1698 tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding | |
1699 if "__WXGTK__" in wx.PlatformInfo: | |
1700 # On GTK the tabs are should be larger | |
1701 tabHeight += 6 | |
1702 | |
1703 self._tabHeight = tabHeight | |
1704 | |
1705 return tabHeight | |
1706 | |
1707 | |
1708 def DrawTabs(self, pageContainer, dc): | |
1709 """ Actually draws the tabs in L{FlatNotebook}.""" | |
1710 | |
1711 pc = pageContainer | |
1712 if "__WXMAC__" in wx.PlatformInfo: | |
1713 # Works well on MSW & GTK, however this lines should be skipped on MAC | |
1714 if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec): | |
1715 pc.Hide() | |
1716 return | |
1717 | |
1718 # Get the text hight | |
1719 tabHeight = self.CalcTabHeight(pageContainer) | |
1720 style = pc.GetParent().GetWindowStyleFlag() | |
1721 | |
1722 # Calculate the number of rows required for drawing the tabs | |
1723 rect = pc.GetClientRect() | |
1724 clientWidth = rect.width | |
1725 | |
1726 # Set the maximum client size | |
1727 pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight) | |
1728 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
1729 | |
1730 if style & FNB_VC71: | |
1731 backBrush = wx.Brush(wx.Colour(247, 243, 233)) | |
1732 else: | |
1733 backBrush = wx.Brush(pc._tabAreaColor) | |
1734 | |
1735 noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)) | |
1736 selBrush = wx.Brush(pc._activeTabColor) | |
1737 | |
1738 size = pc.GetSize() | |
1739 | |
1740 # Background | |
1741 dc.SetTextBackground((style & FNB_VC71 and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0]) | |
1742 dc.SetTextForeground(pc._activeTextColor) | |
1743 dc.SetBrush(backBrush) | |
1744 | |
1745 # If border style is set, set the pen to be border pen | |
1746 if pc.HasFlag(FNB_TABS_BORDER_SIMPLE): | |
1747 dc.SetPen(borderPen) | |
1748 else: | |
1749 colr = (pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0] | |
1750 dc.SetPen(wx.Pen(colr)) | |
1751 | |
1752 if pc.HasFlag(FNB_FF2): | |
1753 lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0] | |
1754 PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, LightColour(pc._tabAreaColor, lightFactor)) | |
1755 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
1756 | |
1757 dc.DrawRectangle(0, 0, size.x, size.y) | |
1758 | |
1759 # We always draw the bottom/upper line of the tabs | |
1760 # regradless the style | |
1761 dc.SetPen(borderPen) | |
1762 | |
1763 if not pc.HasFlag(FNB_FF2): | |
1764 self.DrawTabsLine(pc, dc) | |
1765 | |
1766 # Restore the pen | |
1767 dc.SetPen(borderPen) | |
1768 | |
1769 if pc.HasFlag(FNB_VC71): | |
1770 | |
1771 greyLineYVal = (pc.HasFlag(FNB_BOTTOM) and [0] or [size.y - 2])[0] | |
1772 whiteLineYVal = (pc.HasFlag(FNB_BOTTOM) and [3] or [size.y - 3])[0] | |
1773 | |
1774 pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)) | |
1775 dc.SetPen(pen) | |
1776 | |
1777 # Draw thik grey line between the windows area and | |
1778 # the tab area | |
1779 for num in xrange(3): | |
1780 dc.DrawLine(0, greyLineYVal + num, size.x, greyLineYVal + num) | |
1781 | |
1782 wbPen = (pc.HasFlag(FNB_BOTTOM) and [wx.BLACK_PEN] or [wx.WHITE_PEN])[0] | |
1783 dc.SetPen(wbPen) | |
1784 dc.DrawLine(1, whiteLineYVal, size.x - 1, whiteLineYVal) | |
1785 | |
1786 # Restore the pen | |
1787 dc.SetPen(borderPen) | |
1788 | |
1789 # Draw labels | |
1790 normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1791 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1792 boldFont.SetWeight(wx.FONTWEIGHT_BOLD) | |
1793 dc.SetFont(boldFont) | |
1794 | |
1795 posx = pc._pParent.GetPadding() | |
1796 | |
1797 # Update all the tabs from 0 to 'pc._nFrom' to be non visible | |
1798 for i in xrange(pc._nFrom): | |
1799 | |
1800 pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1)) | |
1801 pc._pagesInfoVec[i].GetRegion().Clear() | |
1802 | |
1803 count = pc._nFrom | |
1804 | |
1805 #---------------------------------------------------------- | |
1806 # Go over and draw the visible tabs | |
1807 #---------------------------------------------------------- | |
1808 x1 = x2 = -1 | |
1809 for i in xrange(pc._nFrom, len(pc._pagesInfoVec)): | |
1810 | |
1811 dc.SetPen(borderPen) | |
1812 | |
1813 if not pc.HasFlag(FNB_FF2): | |
1814 dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0]) | |
1815 | |
1816 # Now set the font to the correct font | |
1817 dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0]) | |
1818 | |
1819 # Add the padding to the tab width | |
1820 # Tab width: | |
1821 # +-----------------------------------------------------------+ | |
1822 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING | | |
1823 # +-----------------------------------------------------------+ | |
1824 tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight) | |
1825 | |
1826 # Check if we can draw more | |
1827 if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth: | |
1828 break | |
1829 | |
1830 count = count + 1 | |
1831 | |
1832 # By default we clean the tab region | |
1833 pc._pagesInfoVec[i].GetRegion().Clear() | |
1834 | |
1835 # Clean the 'x' buttn on the tab. | |
1836 # A 'Clean' rectangle, is a rectangle with width or height | |
1837 # with values lower than or equal to 0 | |
1838 pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1)) | |
1839 | |
1840 # Draw the tab (border, text, image & 'x' on tab) | |
1841 self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus) | |
1842 | |
1843 if pc.GetSelection() == i: | |
1844 x1 = posx | |
1845 x2 = posx + tabWidth + 2 | |
1846 | |
1847 # Restore the text forground | |
1848 dc.SetTextForeground(pc._activeTextColor) | |
1849 | |
1850 # Update the tab position & size | |
1851 posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0] | |
1852 | |
1853 pc._pagesInfoVec[i].SetPosition(wx.Point(posx, posy)) | |
1854 pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight)) | |
1855 self.DrawFocusRectangle(dc, pc, pc._pagesInfoVec[i]) | |
1856 | |
1857 posx += tabWidth | |
1858 | |
1859 # Update all tabs that can not fit into the screen as non-visible | |
1860 for i in xrange(count, len(pc._pagesInfoVec)): | |
1861 pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1)) | |
1862 pc._pagesInfoVec[i].GetRegion().Clear() | |
1863 | |
1864 # Draw the left/right/close buttons | |
1865 # Left arrow | |
1866 self.DrawLeftArrow(pc, dc) | |
1867 self.DrawRightArrow(pc, dc) | |
1868 self.DrawX(pc, dc) | |
1869 self.DrawDropDownArrow(pc, dc) | |
1870 | |
1871 if pc.HasFlag(FNB_FF2): | |
1872 self.DrawTabsLine(pc, dc, x1, x2) | |
1873 | |
1874 | |
1875 def DrawFocusRectangle(self, dc, pageContainer, page): | |
1876 """ Draws a focus rectangle like the native Notebooks. """ | |
1877 | |
1878 if not page._hasFocus: | |
1879 return | |
1880 | |
1881 tabPos = wx.Point(*page.GetPosition()) | |
1882 if pageContainer.GetParent().GetWindowStyleFlag() & FNB_VC8: | |
1883 vc8ShapeLen = self.CalcTabHeight(pageContainer) - VERTICAL_BORDER_PADDING - 2 | |
1884 tabPos.x += vc8ShapeLen | |
1885 | |
1886 rect = wx.RectPS(tabPos, page.GetSize()) | |
1887 rect = wx.Rect(rect.x+2, rect.y+2, rect.width-4, rect.height-8) | |
1888 | |
1889 if wx.Platform == '__WXMAC__': | |
1890 rect.SetWidth(rect.GetWidth() + 1) | |
1891 | |
1892 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
1893 dc.SetPen(self._focusPen) | |
1894 dc.DrawRoundedRectangleRect(rect, 2) | |
1895 | |
1896 | |
1897 def DrawDragHint(self, pc, tabIdx): | |
1898 """ | |
1899 Draws tab drag hint, the default implementation is to do nothing. | |
1900 You can override this function to provide a nice feedback to user. | |
1901 """ | |
1902 | |
1903 pass | |
1904 | |
1905 | |
1906 def NumberTabsCanFit(self, pageContainer, fr=-1): | |
1907 | |
1908 pc = pageContainer | |
1909 | |
1910 rect = pc.GetClientRect() | |
1911 clientWidth = rect.width | |
1912 | |
1913 vTabInfo = [] | |
1914 | |
1915 tabHeight = self.CalcTabHeight(pageContainer) | |
1916 | |
1917 # The drawing starts from posx | |
1918 posx = pc._pParent.GetPadding() | |
1919 | |
1920 if fr < 0: | |
1921 fr = pc._nFrom | |
1922 | |
1923 for i in xrange(fr, len(pc._pagesInfoVec)): | |
1924 | |
1925 tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight) | |
1926 if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth: | |
1927 break; | |
1928 | |
1929 # Add a result to the returned vector | |
1930 tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth , tabHeight) | |
1931 vTabInfo.append(tabRect) | |
1932 | |
1933 # Advance posx | |
1934 posx += tabWidth + FNB_HEIGHT_SPACER | |
1935 | |
1936 return vTabInfo | |
1937 | |
1938 | |
1939 # ---------------------------------------------------------------------------- # | |
1940 # Class FNBRendererMgr | |
1941 # A manager that handles all the renderers defined below and calls the | |
1942 # appropriate one when drawing is needed | |
1943 # ---------------------------------------------------------------------------- # | |
1944 | |
1945 class FNBRendererMgr: | |
1946 """ | |
1947 This class represents a manager that handles all the 4 renderers defined | |
1948 and calls the appropriate one when drawing is needed. | |
1949 """ | |
1950 | |
1951 def __init__(self): | |
1952 """ Default class constructor. """ | |
1953 | |
1954 # register renderers | |
1955 | |
1956 self._renderers = {} | |
1957 self._renderers.update({-1: FNBRendererDefault()}) | |
1958 self._renderers.update({FNB_VC71: FNBRendererVC71()}) | |
1959 self._renderers.update({FNB_FANCY_TABS: FNBRendererFancy()}) | |
1960 self._renderers.update({FNB_VC8: FNBRendererVC8()}) | |
1961 self._renderers.update({FNB_FF2: FNBRendererFirefox2()}) | |
1962 | |
1963 | |
1964 def GetRenderer(self, style): | |
1965 """ Returns the current renderer based on the style selected. """ | |
1966 | |
1967 if style & FNB_VC71: | |
1968 return self._renderers[FNB_VC71] | |
1969 | |
1970 if style & FNB_FANCY_TABS: | |
1971 return self._renderers[FNB_FANCY_TABS] | |
1972 | |
1973 if style & FNB_VC8: | |
1974 return self._renderers[FNB_VC8] | |
1975 | |
1976 if style & FNB_FF2: | |
1977 return self._renderers[FNB_FF2] | |
1978 | |
1979 # the default is to return the default renderer | |
1980 return self._renderers[-1] | |
1981 | |
1982 | |
1983 #------------------------------------------ | |
1984 # Default renderer | |
1985 #------------------------------------------ | |
1986 | |
1987 class FNBRendererDefault(FNBRenderer): | |
1988 """ | |
1989 This class handles the drawing of tabs using the I{Standard} renderer. | |
1990 """ | |
1991 | |
1992 def __init__(self): | |
1993 """ Default class constructor. """ | |
1994 | |
1995 FNBRenderer.__init__(self) | |
1996 | |
1997 | |
1998 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus): | |
1999 """ Draws a tab using the I{Standard} style. """ | |
2000 | |
2001 # Default style | |
2002 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
2003 pc = pageContainer | |
2004 | |
2005 tabPoints = [wx.Point() for ii in xrange(7)] | |
2006 tabPoints[0].x = posx | |
2007 tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0] | |
2008 | |
2009 tabPoints[1].x = int(posx+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi)) | |
2010 tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0] | |
2011 | |
2012 tabPoints[2].x = tabPoints[1].x+2 | |
2013 tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0] | |
2014 | |
2015 tabPoints[3].x = int(posx+tabWidth-(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))-2 | |
2016 tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0] | |
2017 | |
2018 tabPoints[4].x = tabPoints[3].x+2 | |
2019 tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0] | |
2020 | |
2021 tabPoints[5].x = int(tabPoints[4].x+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi)) | |
2022 tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0] | |
2023 | |
2024 tabPoints[6].x = tabPoints[0].x | |
2025 tabPoints[6].y = tabPoints[0].y | |
2026 | |
2027 if tabIdx == pc.GetSelection(): | |
2028 | |
2029 # Draw the tab as rounded rectangle | |
2030 dc.DrawPolygon(tabPoints) | |
2031 | |
2032 else: | |
2033 | |
2034 if tabIdx != pc.GetSelection() - 1: | |
2035 | |
2036 # Draw a vertical line to the right of the text | |
2037 pt1x = tabPoints[5].x | |
2038 pt1y = (pc.HasFlag(FNB_BOTTOM) and [4] or [tabHeight - 6])[0] | |
2039 pt2x = tabPoints[5].x | |
2040 pt2y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 4] or [4])[0] | |
2041 dc.DrawLine(pt1x, pt1y, pt2x, pt2y) | |
2042 | |
2043 if tabIdx == pc.GetSelection(): | |
2044 | |
2045 savePen = dc.GetPen() | |
2046 whitePen = wx.Pen(wx.WHITE) | |
2047 whitePen.SetWidth(1) | |
2048 dc.SetPen(whitePen) | |
2049 | |
2050 secPt = wx.Point(tabPoints[5].x + 1, tabPoints[5].y) | |
2051 dc.DrawLine(tabPoints[0].x, tabPoints[0].y, secPt.x, secPt.y) | |
2052 | |
2053 # Restore the pen | |
2054 dc.SetPen(savePen) | |
2055 | |
2056 # ----------------------------------- | |
2057 # Text and image drawing | |
2058 # ----------------------------------- | |
2059 | |
2060 # Text drawing offset from the left border of the | |
2061 # rectangle | |
2062 | |
2063 # The width of the images are 16 pixels | |
2064 padding = pc.GetParent().GetPadding() | |
2065 shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi)) | |
2066 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1 | |
2067 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0] | |
2068 | |
2069 if hasImage: | |
2070 textOffset = 2*pc._pParent._nPadding + 16 + shapePoints/2 | |
2071 else: | |
2072 textOffset = pc._pParent._nPadding + shapePoints/2 | |
2073 | |
2074 textOffset += 2 | |
2075 | |
2076 if tabIdx != pc.GetSelection(): | |
2077 | |
2078 # Set the text background to be like the vertical lines | |
2079 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour()) | |
2080 | |
2081 if hasImage: | |
2082 | |
2083 imageXOffset = textOffset - 16 - padding | |
2084 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc, | |
2085 posx + imageXOffset, imageYCoord, | |
2086 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
2087 | |
2088 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord) | |
2089 | |
2090 # draw 'x' on tab (if enabled) | |
2091 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection(): | |
2092 | |
2093 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx)) | |
2094 tabCloseButtonXCoord = posx + textOffset + textWidth + 1 | |
2095 | |
2096 # take a bitmap from the position of the 'x' button (the x on tab button) | |
2097 # this bitmap will be used later to delete old buttons | |
2098 tabCloseButtonYCoord = imageYCoord | |
2099 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16) | |
2100 | |
2101 # Draw the tab | |
2102 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus) | |
2103 | |
2104 | |
2105 #------------------------------------------ | |
2106 # Firefox2 renderer | |
2107 #------------------------------------------ | |
2108 class FNBRendererFirefox2(FNBRenderer): | |
2109 """ | |
2110 This class handles the drawing of tabs using the I{Firefox 2} renderer. | |
2111 """ | |
2112 | |
2113 def __init__(self): | |
2114 """ Default class constructor. """ | |
2115 | |
2116 FNBRenderer.__init__(self) | |
2117 | |
2118 | |
2119 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus): | |
2120 """ Draws a tab using the I{Firefox 2} style. """ | |
2121 | |
2122 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
2123 pc = pageContainer | |
2124 | |
2125 tabPoints = [wx.Point() for indx in xrange(7)] | |
2126 tabPoints[0].x = posx + 2 | |
2127 tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0] | |
2128 | |
2129 tabPoints[1].x = tabPoints[0].x | |
2130 tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0] | |
2131 | |
2132 tabPoints[2].x = tabPoints[1].x+2 | |
2133 tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0] | |
2134 | |
2135 tabPoints[3].x = posx + tabWidth - 2 | |
2136 tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0] | |
2137 | |
2138 tabPoints[4].x = tabPoints[3].x + 2 | |
2139 tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0] | |
2140 | |
2141 tabPoints[5].x = tabPoints[4].x | |
2142 tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0] | |
2143 | |
2144 tabPoints[6].x = tabPoints[0].x | |
2145 tabPoints[6].y = tabPoints[0].y | |
2146 | |
2147 #------------------------------------ | |
2148 # Paint the tab with gradient | |
2149 #------------------------------------ | |
2150 rr = wx.RectPP(tabPoints[2], tabPoints[5]) | |
2151 DrawButton(dc, rr, pc.GetSelection() == tabIdx , not pc.HasFlag(FNB_BOTTOM)) | |
2152 | |
2153 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
2154 dc.SetPen(borderPen) | |
2155 | |
2156 # Draw the tab as rounded rectangle | |
2157 dc.DrawPolygon(tabPoints) | |
2158 | |
2159 # ----------------------------------- | |
2160 # Text and image drawing | |
2161 # ----------------------------------- | |
2162 | |
2163 # The width of the images are 16 pixels | |
2164 padding = pc.GetParent().GetPadding() | |
2165 shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi)) | |
2166 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1 | |
2167 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0] | |
2168 | |
2169 if hasImage: | |
2170 textOffset = 2*padding + 16 + shapePoints/2 | |
2171 else: | |
2172 textOffset = padding + shapePoints/2 | |
2173 | |
2174 textOffset += 2 | |
2175 | |
2176 if tabIdx != pc.GetSelection(): | |
2177 | |
2178 # Set the text background to be like the vertical lines | |
2179 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour()) | |
2180 | |
2181 if hasImage: | |
2182 imageXOffset = textOffset - 16 - padding | |
2183 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc, | |
2184 posx + imageXOffset, imageYCoord, | |
2185 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
2186 | |
2187 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord) | |
2188 | |
2189 # draw 'x' on tab (if enabled) | |
2190 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection(): | |
2191 | |
2192 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx)) | |
2193 tabCloseButtonXCoord = posx + textOffset + textWidth + 1 | |
2194 | |
2195 # take a bitmap from the position of the 'x' button (the x on tab button) | |
2196 # this bitmap will be used later to delete old buttons | |
2197 tabCloseButtonYCoord = imageYCoord | |
2198 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16) | |
2199 | |
2200 # Draw the tab | |
2201 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus) | |
2202 | |
2203 | |
2204 #------------------------------------------------------------------ | |
2205 # Visual studio 7.1 | |
2206 #------------------------------------------------------------------ | |
2207 | |
2208 class FNBRendererVC71(FNBRenderer): | |
2209 """ | |
2210 This class handles the drawing of tabs using the I{VC71} renderer. | |
2211 """ | |
2212 | |
2213 def __init__(self): | |
2214 """ Default class constructor. """ | |
2215 | |
2216 FNBRenderer.__init__(self) | |
2217 | |
2218 | |
2219 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus): | |
2220 """ Draws a tab using the I{VC71} style. """ | |
2221 | |
2222 # Visual studio 7.1 style | |
2223 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
2224 pc = pageContainer | |
2225 | |
2226 dc.SetPen((tabIdx == pc.GetSelection() and [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [borderPen])[0]) | |
2227 dc.SetBrush((tabIdx == pc.GetSelection() and [wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [wx.Brush(wx.Colour(247, 243, 233))])[0]) | |
2228 | |
2229 if tabIdx == pc.GetSelection(): | |
2230 | |
2231 posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0] | |
2232 tabH = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 5] or [tabHeight - 3])[0] | |
2233 dc.DrawRectangle(posx, posy, tabWidth, tabH) | |
2234 | |
2235 # Draw a black line on the left side of the | |
2236 # rectangle | |
2237 dc.SetPen(wx.BLACK_PEN) | |
2238 | |
2239 blackLineY1 = VERTICAL_BORDER_PADDING | |
2240 blackLineY2 = tabH | |
2241 dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2) | |
2242 | |
2243 # To give the tab more 3D look we do the following | |
2244 # Incase the tab is on top, | |
2245 # Draw a thik white line on topof the rectangle | |
2246 # Otherwise, draw a thin (1 pixel) black line at the bottom | |
2247 | |
2248 pen = wx.Pen((pc.HasFlag(FNB_BOTTOM) and [wx.BLACK] or [wx.WHITE])[0]) | |
2249 dc.SetPen(pen) | |
2250 whiteLinePosY = (pc.HasFlag(FNB_BOTTOM) and [blackLineY2] or [VERTICAL_BORDER_PADDING ])[0] | |
2251 dc.DrawLine(posx , whiteLinePosY, posx + tabWidth + 1, whiteLinePosY) | |
2252 | |
2253 # Draw a white vertical line to the left of the tab | |
2254 dc.SetPen(wx.WHITE_PEN) | |
2255 if not pc.HasFlag(FNB_BOTTOM): | |
2256 blackLineY2 += 1 | |
2257 | |
2258 dc.DrawLine(posx, blackLineY1, posx, blackLineY2) | |
2259 | |
2260 else: | |
2261 | |
2262 # We dont draw a rectangle for non selected tabs, but only | |
2263 # vertical line on the left | |
2264 | |
2265 blackLineY1 = (pc.HasFlag(FNB_BOTTOM) and [VERTICAL_BORDER_PADDING + 2] or [VERTICAL_BORDER_PADDING + 1])[0] | |
2266 blackLineY2 = pc.GetSize().y - 5 | |
2267 dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2) | |
2268 | |
2269 # ----------------------------------- | |
2270 # Text and image drawing | |
2271 # ----------------------------------- | |
2272 | |
2273 # Text drawing offset from the left border of the | |
2274 # rectangle | |
2275 | |
2276 # The width of the images are 16 pixels | |
2277 padding = pc.GetParent().GetPadding() | |
2278 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1 | |
2279 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [5] or [8])[0] | |
2280 | |
2281 if hasImage: | |
2282 textOffset = 2*pc._pParent._nPadding + 16 | |
2283 else: | |
2284 textOffset = pc._pParent._nPadding | |
2285 | |
2286 if tabIdx != pc.GetSelection(): | |
2287 | |
2288 # Set the text background to be like the vertical lines | |
2289 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour()) | |
2290 | |
2291 if hasImage: | |
2292 | |
2293 imageXOffset = textOffset - 16 - padding | |
2294 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc, | |
2295 posx + imageXOffset, imageYCoord, | |
2296 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
2297 | |
2298 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord) | |
2299 | |
2300 # draw 'x' on tab (if enabled) | |
2301 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection(): | |
2302 | |
2303 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx)) | |
2304 tabCloseButtonXCoord = posx + textOffset + textWidth + 1 | |
2305 | |
2306 # take a bitmap from the position of the 'x' button (the x on tab button) | |
2307 # this bitmap will be used later to delete old buttons | |
2308 tabCloseButtonYCoord = imageYCoord | |
2309 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16) | |
2310 | |
2311 # Draw the tab | |
2312 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus) | |
2313 | |
2314 | |
2315 #------------------------------------------------------------------ | |
2316 # Fancy style | |
2317 #------------------------------------------------------------------ | |
2318 | |
2319 class FNBRendererFancy(FNBRenderer): | |
2320 """ | |
2321 This class handles the drawing of tabs using the I{Fancy} renderer. | |
2322 """ | |
2323 | |
2324 def __init__(self): | |
2325 """ Default class constructor. """ | |
2326 | |
2327 FNBRenderer.__init__(self) | |
2328 | |
2329 | |
2330 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus): | |
2331 """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """ | |
2332 | |
2333 # Fancy tabs - like with VC71 but with the following differences: | |
2334 # - The Selected tab is colored with gradient color | |
2335 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
2336 pc = pageContainer | |
2337 | |
2338 pen = (tabIdx == pc.GetSelection() and [wx.Pen(pc._pParent.GetBorderColour())] or [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))])[0] | |
2339 | |
2340 if tabIdx == pc.GetSelection(): | |
2341 | |
2342 posy = (pc.HasFlag(FNB_BOTTOM) and [2] or [VERTICAL_BORDER_PADDING])[0] | |
2343 th = tabHeight - 5 | |
2344 | |
2345 rect = wx.Rect(posx, posy, tabWidth, th) | |
2346 | |
2347 col2 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourTo()] or [pc._pParent.GetGradientColourFrom()])[0] | |
2348 col1 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourFrom()] or [pc._pParent.GetGradientColourTo()])[0] | |
2349 | |
2350 PaintStraightGradientBox(dc, rect, col1, col2) | |
2351 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
2352 dc.SetPen(pen) | |
2353 dc.DrawRectangleRect(rect) | |
2354 | |
2355 # erase the bottom/top line of the rectangle | |
2356 dc.SetPen(wx.Pen(pc._pParent.GetGradientColourFrom())) | |
2357 if pc.HasFlag(FNB_BOTTOM): | |
2358 dc.DrawLine(rect.x, 2, rect.x + rect.width, 2) | |
2359 else: | |
2360 dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1) | |
2361 | |
2362 else: | |
2363 | |
2364 # We dont draw a rectangle for non selected tabs, but only | |
2365 # vertical line on the left | |
2366 dc.SetPen(borderPen) | |
2367 dc.DrawLine(posx + tabWidth, VERTICAL_BORDER_PADDING + 3, posx + tabWidth, tabHeight - 4) | |
2368 | |
2369 | |
2370 # ----------------------------------- | |
2371 # Text and image drawing | |
2372 # ----------------------------------- | |
2373 | |
2374 # Text drawing offset from the left border of the | |
2375 # rectangle | |
2376 | |
2377 # The width of the images are 16 pixels | |
2378 padding = pc.GetParent().GetPadding() | |
2379 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1 | |
2380 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0] | |
2381 | |
2382 if hasImage: | |
2383 textOffset = 2*pc._pParent._nPadding + 16 | |
2384 else: | |
2385 textOffset = pc._pParent._nPadding | |
2386 | |
2387 textOffset += 2 | |
2388 | |
2389 if tabIdx != pc.GetSelection(): | |
2390 | |
2391 # Set the text background to be like the vertical lines | |
2392 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour()) | |
2393 | |
2394 if hasImage: | |
2395 | |
2396 imageXOffset = textOffset - 16 - padding | |
2397 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc, | |
2398 posx + imageXOffset, imageYCoord, | |
2399 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
2400 | |
2401 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord) | |
2402 | |
2403 # draw 'x' on tab (if enabled) | |
2404 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection(): | |
2405 | |
2406 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx)) | |
2407 tabCloseButtonXCoord = posx + textOffset + textWidth + 1 | |
2408 | |
2409 # take a bitmap from the position of the 'x' button (the x on tab button) | |
2410 # this bitmap will be used later to delete old buttons | |
2411 tabCloseButtonYCoord = imageYCoord | |
2412 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16) | |
2413 | |
2414 # Draw the tab | |
2415 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus) | |
2416 | |
2417 | |
2418 #------------------------------------------------------------------ | |
2419 # Visual studio 2005 (VS8) | |
2420 #------------------------------------------------------------------ | |
2421 class FNBRendererVC8(FNBRenderer): | |
2422 """ | |
2423 This class handles the drawing of tabs using the I{VC8} renderer. | |
2424 """ | |
2425 | |
2426 def __init__(self): | |
2427 """ Default class constructor. """ | |
2428 | |
2429 FNBRenderer.__init__(self) | |
2430 self._first = True | |
2431 self._factor = 1 | |
2432 | |
2433 | |
2434 def DrawTabs(self, pageContainer, dc): | |
2435 """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """ | |
2436 | |
2437 pc = pageContainer | |
2438 | |
2439 if "__WXMAC__" in wx.PlatformInfo: | |
2440 # Works well on MSW & GTK, however this lines should be skipped on MAC | |
2441 if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec): | |
2442 pc.Hide() | |
2443 return | |
2444 | |
2445 # Get the text hight | |
2446 tabHeight = self.CalcTabHeight(pageContainer) | |
2447 | |
2448 # Set the font for measuring the tab height | |
2449 normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
2450 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
2451 boldFont.SetWeight(wx.FONTWEIGHT_BOLD) | |
2452 | |
2453 # Calculate the number of rows required for drawing the tabs | |
2454 rect = pc.GetClientRect() | |
2455 | |
2456 # Set the maximum client size | |
2457 pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight) | |
2458 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
2459 | |
2460 # Create brushes | |
2461 backBrush = wx.Brush(pc._tabAreaColor) | |
2462 noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)) | |
2463 selBrush = wx.Brush(pc._activeTabColor) | |
2464 size = pc.GetSize() | |
2465 | |
2466 # Background | |
2467 dc.SetTextBackground(pc.GetBackgroundColour()) | |
2468 dc.SetTextForeground(pc._activeTextColor) | |
2469 | |
2470 # If border style is set, set the pen to be border pen | |
2471 if pc.HasFlag(FNB_TABS_BORDER_SIMPLE): | |
2472 dc.SetPen(borderPen) | |
2473 else: | |
2474 dc.SetPen(wx.TRANSPARENT_PEN) | |
2475 | |
2476 lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0] | |
2477 | |
2478 # For VC8 style, we color the tab area in gradient coloring | |
2479 lightcolour = LightColour(pc._tabAreaColor, lightFactor) | |
2480 PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, lightcolour) | |
2481 | |
2482 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
2483 dc.DrawRectangle(0, 0, size.x, size.y) | |
2484 | |
2485 # We always draw the bottom/upper line of the tabs | |
2486 # regradless the style | |
2487 dc.SetPen(borderPen) | |
2488 self.DrawTabsLine(pc, dc) | |
2489 | |
2490 # Restore the pen | |
2491 dc.SetPen(borderPen) | |
2492 | |
2493 # Draw labels | |
2494 dc.SetFont(boldFont) | |
2495 | |
2496 # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible | |
2497 for i in xrange(pc._nFrom): | |
2498 | |
2499 pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1)) | |
2500 pc._pagesInfoVec[i].GetRegion().Clear() | |
2501 | |
2502 # Draw the visible tabs, in VC8 style, we draw them from right to left | |
2503 vTabsInfo = self.NumberTabsCanFit(pc) | |
2504 | |
2505 activeTabPosx = 0 | |
2506 activeTabWidth = 0 | |
2507 activeTabHeight = 0 | |
2508 | |
2509 for cur in xrange(len(vTabsInfo)-1, -1, -1): | |
2510 | |
2511 # 'i' points to the index of the currently drawn tab | |
2512 # in pc.GetPageInfoVector() vector | |
2513 i = pc._nFrom + cur | |
2514 dc.SetPen(borderPen) | |
2515 dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0]) | |
2516 | |
2517 # Now set the font to the correct font | |
2518 dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0]) | |
2519 | |
2520 # Add the padding to the tab width | |
2521 # Tab width: | |
2522 # +-----------------------------------------------------------+ | |
2523 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING | | |
2524 # +-----------------------------------------------------------+ | |
2525 | |
2526 tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight) | |
2527 posx = vTabsInfo[cur].x | |
2528 | |
2529 # By default we clean the tab region | |
2530 # incase we use the VC8 style which requires | |
2531 # the region, it will be filled by the function | |
2532 # drawVc8Tab | |
2533 pc._pagesInfoVec[i].GetRegion().Clear() | |
2534 | |
2535 # Clean the 'x' buttn on the tab | |
2536 # 'Clean' rectanlge is a rectangle with width or height | |
2537 # with values lower than or equal to 0 | |
2538 pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1)) | |
2539 | |
2540 # Draw the tab | |
2541 # Incase we are drawing the active tab | |
2542 # we need to redraw so it will appear on top | |
2543 # of all other tabs | |
2544 | |
2545 # when using the vc8 style, we keep the position of the active tab so we will draw it again later | |
2546 if i == pc.GetSelection() and pc.HasFlag(FNB_VC8): | |
2547 | |
2548 activeTabPosx = posx | |
2549 activeTabWidth = tabWidth | |
2550 activeTabHeight = tabHeight | |
2551 | |
2552 else: | |
2553 | |
2554 self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus) | |
2555 | |
2556 # Restore the text forground | |
2557 dc.SetTextForeground(pc._activeTextColor) | |
2558 | |
2559 # Update the tab position & size | |
2560 pc._pagesInfoVec[i].SetPosition(wx.Point(posx, VERTICAL_BORDER_PADDING)) | |
2561 pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight)) | |
2562 | |
2563 # Incase we are in VC8 style, redraw the active tab (incase it is visible) | |
2564 if pc.GetSelection() >= pc._nFrom and pc.GetSelection() < pc._nFrom + len(vTabsInfo): | |
2565 | |
2566 self.DrawTab(pc, dc, activeTabPosx, pc.GetSelection(), activeTabWidth, activeTabHeight, pc._nTabXButtonStatus) | |
2567 | |
2568 # Update all tabs that can not fit into the screen as non-visible | |
2569 for xx in xrange(pc._nFrom + len(vTabsInfo), len(pc._pagesInfoVec)): | |
2570 | |
2571 pc._pagesInfoVec[xx].SetPosition(wx.Point(-1, -1)) | |
2572 pc._pagesInfoVec[xx].GetRegion().Clear() | |
2573 | |
2574 # Draw the left/right/close buttons | |
2575 # Left arrow | |
2576 self.DrawLeftArrow(pc, dc) | |
2577 self.DrawRightArrow(pc, dc) | |
2578 self.DrawX(pc, dc) | |
2579 self.DrawDropDownArrow(pc, dc) | |
2580 | |
2581 | |
2582 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus): | |
2583 """ Draws a tab using VC8 style. """ | |
2584 | |
2585 pc = pageContainer | |
2586 borderPen = wx.Pen(pc._pParent.GetBorderColour()) | |
2587 tabPoints = [wx.Point() for ii in xrange(8)] | |
2588 | |
2589 # If we draw the first tab or the active tab, | |
2590 # we draw a full tab, else we draw a truncated tab | |
2591 # | |
2592 # X(2) X(3) | |
2593 # X(1) X(4) | |
2594 # | |
2595 # X(5) | |
2596 # | |
2597 # X(0),(7) X(6) | |
2598 # | |
2599 # | |
2600 | |
2601 tabPoints[0].x = (pc.HasFlag(FNB_BOTTOM) and [posx] or [posx+self._factor])[0] | |
2602 tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 3])[0] | |
2603 | |
2604 tabPoints[1].x = tabPoints[0].x + tabHeight - VERTICAL_BORDER_PADDING - 3 - self._factor | |
2605 tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0] | |
2606 | |
2607 tabPoints[2].x = tabPoints[1].x + 4 | |
2608 tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0] | |
2609 | |
2610 tabPoints[3].x = tabPoints[2].x + tabWidth - 2 | |
2611 tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0] | |
2612 | |
2613 tabPoints[4].x = tabPoints[3].x + 1 | |
2614 tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0] | |
2615 | |
2616 tabPoints[5].x = tabPoints[4].x + 1 | |
2617 tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0] | |
2618 | |
2619 tabPoints[6].x = tabPoints[2].x + tabWidth | |
2620 tabPoints[6].y = tabPoints[0].y | |
2621 | |
2622 tabPoints[7].x = tabPoints[0].x | |
2623 tabPoints[7].y = tabPoints[0].y | |
2624 | |
2625 pc._pagesInfoVec[tabIdx].SetRegion(tabPoints) | |
2626 | |
2627 # Draw the polygon | |
2628 br = dc.GetBrush() | |
2629 dc.SetBrush(wx.Brush((tabIdx == pc.GetSelection() and [pc._activeTabColor] or [pc._colorTo])[0])) | |
2630 dc.SetPen(wx.Pen((tabIdx == pc.GetSelection() and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0])) | |
2631 dc.DrawPolygon(tabPoints) | |
2632 | |
2633 # Restore the brush | |
2634 dc.SetBrush(br) | |
2635 rect = pc.GetClientRect() | |
2636 | |
2637 if tabIdx != pc.GetSelection() and not pc.HasFlag(FNB_BOTTOM): | |
2638 | |
2639 # Top default tabs | |
2640 dc.SetPen(wx.Pen(pc._pParent.GetBorderColour())) | |
2641 lineY = rect.height | |
2642 curPen = dc.GetPen() | |
2643 curPen.SetWidth(1) | |
2644 dc.SetPen(curPen) | |
2645 dc.DrawLine(posx, lineY, posx+rect.width, lineY) | |
2646 | |
2647 # Incase we are drawing the selected tab, we draw the border of it as well | |
2648 # but without the bottom (upper line incase of wxBOTTOM) | |
2649 if tabIdx == pc.GetSelection(): | |
2650 | |
2651 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
2652 dc.SetPen(borderPen) | |
2653 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
2654 dc.DrawPolygon(tabPoints) | |
2655 | |
2656 # Delete the bottom line (or the upper one, incase we use wxBOTTOM) | |
2657 dc.SetPen(wx.WHITE_PEN) | |
2658 dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y) | |
2659 | |
2660 self.FillVC8GradientColour(pc, dc, tabPoints, tabIdx == pc.GetSelection(), tabIdx) | |
2661 | |
2662 # Draw a thin line to the right of the non-selected tab | |
2663 if tabIdx != pc.GetSelection(): | |
2664 | |
2665 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))) | |
2666 dc.DrawLine(tabPoints[4].x-1, tabPoints[4].y, tabPoints[5].x-1, tabPoints[5].y) | |
2667 dc.DrawLine(tabPoints[5].x-1, tabPoints[5].y, tabPoints[6].x-1, tabPoints[6].y) | |
2668 | |
2669 # Text drawing offset from the left border of the | |
2670 # rectangle | |
2671 | |
2672 # The width of the images are 16 pixels | |
2673 vc8ShapeLen = tabHeight - VERTICAL_BORDER_PADDING - 2 | |
2674 if pc.TabHasImage(tabIdx): | |
2675 textOffset = 2*pc._pParent.GetPadding() + 16 + vc8ShapeLen | |
2676 else: | |
2677 textOffset = pc._pParent.GetPadding() + vc8ShapeLen | |
2678 | |
2679 # Draw the image for the tab if any | |
2680 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0] | |
2681 | |
2682 if pc.TabHasImage(tabIdx): | |
2683 | |
2684 imageXOffset = textOffset - 16 - pc._pParent.GetPadding() | |
2685 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc, | |
2686 posx + imageXOffset, imageYCoord, | |
2687 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
2688 | |
2689 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
2690 | |
2691 # if selected tab, draw text in bold | |
2692 if tabIdx == pc.GetSelection(): | |
2693 boldFont.SetWeight(wx.FONTWEIGHT_BOLD) | |
2694 | |
2695 dc.SetFont(boldFont) | |
2696 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord) | |
2697 | |
2698 # draw 'x' on tab (if enabled) | |
2699 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection(): | |
2700 | |
2701 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx)) | |
2702 tabCloseButtonXCoord = posx + textOffset + textWidth + 1 | |
2703 | |
2704 # take a bitmap from the position of the 'x' button (the x on tab button) | |
2705 # this bitmap will be used later to delete old buttons | |
2706 tabCloseButtonYCoord = imageYCoord | |
2707 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16) | |
2708 # Draw the tab | |
2709 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus) | |
2710 | |
2711 self.DrawFocusRectangle(dc, pc, pc._pagesInfoVec[tabIdx]) | |
2712 | |
2713 | |
2714 def FillVC8GradientColour(self, pageContainer, dc, tabPoints, bSelectedTab, tabIdx): | |
2715 """ Fills a tab with a gradient shading. """ | |
2716 | |
2717 # calculate gradient coefficients | |
2718 pc = pageContainer | |
2719 | |
2720 if self._first: | |
2721 self._first = False | |
2722 pc._colorTo = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 0) | |
2723 pc._colorFrom = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 60) | |
2724 | |
2725 col2 = pc._pParent.GetGradientColourTo() | |
2726 col1 = pc._pParent.GetGradientColourFrom() | |
2727 | |
2728 # If colorful tabs style is set, override the tab color | |
2729 if pc.HasFlag(FNB_COLORFUL_TABS): | |
2730 | |
2731 if not pc._pagesInfoVec[tabIdx].GetColour(): | |
2732 | |
2733 # First time, generate color, and keep it in the vector | |
2734 tabColor = RandomColour() | |
2735 pc._pagesInfoVec[tabIdx].SetColour(tabColor) | |
2736 | |
2737 if pc.HasFlag(FNB_BOTTOM): | |
2738 | |
2739 col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50) | |
2740 col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80) | |
2741 | |
2742 else: | |
2743 | |
2744 col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50) | |
2745 col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80) | |
2746 | |
2747 size = abs(tabPoints[2].y - tabPoints[0].y) - 1 | |
2748 | |
2749 rf, gf, bf = 0, 0, 0 | |
2750 rstep = float(col2.Red() - col1.Red())/float(size) | |
2751 gstep = float(col2.Green() - col1.Green())/float(size) | |
2752 bstep = float(col2.Blue() - col1.Blue())/float(size) | |
2753 | |
2754 y = tabPoints[0].y | |
2755 | |
2756 # If we are drawing the selected tab, we need also to draw a line | |
2757 # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this | |
2758 # by drawing the rectangle with transparent brush | |
2759 # the line under the selected tab will be deleted by the drwaing loop | |
2760 if bSelectedTab: | |
2761 self.DrawTabsLine(pc, dc) | |
2762 | |
2763 while 1: | |
2764 | |
2765 if pc.HasFlag(FNB_BOTTOM): | |
2766 | |
2767 if y > tabPoints[0].y + size: | |
2768 break | |
2769 | |
2770 else: | |
2771 | |
2772 if y < tabPoints[0].y - size: | |
2773 break | |
2774 | |
2775 currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf) | |
2776 | |
2777 dc.SetPen((bSelectedTab and [wx.Pen(pc._activeTabColor)] or [wx.Pen(currCol)])[0]) | |
2778 startX = self.GetStartX(tabPoints, y, pc.GetParent().GetWindowStyleFlag()) | |
2779 endX = self.GetEndX(tabPoints, y, pc.GetParent().GetWindowStyleFlag()) | |
2780 dc.DrawLine(startX, y, endX, y) | |
2781 | |
2782 # Draw the border using the 'edge' point | |
2783 dc.SetPen(wx.Pen((bSelectedTab and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0])) | |
2784 | |
2785 dc.DrawPoint(startX, y) | |
2786 dc.DrawPoint(endX, y) | |
2787 | |
2788 # Progress the color | |
2789 rf += rstep | |
2790 gf += gstep | |
2791 bf += bstep | |
2792 | |
2793 if pc.HasFlag(FNB_BOTTOM): | |
2794 y = y + 1 | |
2795 else: | |
2796 y = y - 1 | |
2797 | |
2798 | |
2799 def GetStartX(self, tabPoints, y, style): | |
2800 """ Returns the x start position of a tab. """ | |
2801 | |
2802 x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0 | |
2803 | |
2804 # We check the 3 points to the left | |
2805 | |
2806 bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0] | |
2807 match = False | |
2808 | |
2809 if bBottomStyle: | |
2810 | |
2811 for i in xrange(3): | |
2812 | |
2813 if y >= tabPoints[i].y and y < tabPoints[i+1].y: | |
2814 | |
2815 x1 = tabPoints[i].x | |
2816 x2 = tabPoints[i+1].x | |
2817 y1 = tabPoints[i].y | |
2818 y2 = tabPoints[i+1].y | |
2819 match = True | |
2820 break | |
2821 | |
2822 else: | |
2823 | |
2824 for i in xrange(3): | |
2825 | |
2826 if y <= tabPoints[i].y and y > tabPoints[i+1].y: | |
2827 | |
2828 x1 = tabPoints[i].x | |
2829 x2 = tabPoints[i+1].x | |
2830 y1 = tabPoints[i].y | |
2831 y2 = tabPoints[i+1].y | |
2832 match = True | |
2833 break | |
2834 | |
2835 if not match: | |
2836 return tabPoints[2].x | |
2837 | |
2838 # According to the equation y = ax + b => x = (y-b)/a | |
2839 # We know the first 2 points | |
2840 | |
2841 if x2 == x1: | |
2842 return x2 | |
2843 else: | |
2844 a = (y2 - y1)/(x2 - x1) | |
2845 | |
2846 b = y1 - ((y2 - y1)/(x2 - x1))*x1 | |
2847 | |
2848 if a == 0: | |
2849 return int(x1) | |
2850 | |
2851 x = (y - b)/a | |
2852 | |
2853 return int(x) | |
2854 | |
2855 | |
2856 def GetEndX(self, tabPoints, y, style): | |
2857 """ Returns the x end position of a tab. """ | |
2858 | |
2859 x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0 | |
2860 | |
2861 # We check the 3 points to the left | |
2862 bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0] | |
2863 match = False | |
2864 | |
2865 if bBottomStyle: | |
2866 | |
2867 for i in xrange(7, 3, -1): | |
2868 | |
2869 if y >= tabPoints[i].y and y < tabPoints[i-1].y: | |
2870 | |
2871 x1 = tabPoints[i].x | |
2872 x2 = tabPoints[i-1].x | |
2873 y1 = tabPoints[i].y | |
2874 y2 = tabPoints[i-1].y | |
2875 match = True | |
2876 break | |
2877 | |
2878 else: | |
2879 | |
2880 for i in xrange(7, 3, -1): | |
2881 | |
2882 if y <= tabPoints[i].y and y > tabPoints[i-1].y: | |
2883 | |
2884 x1 = tabPoints[i].x | |
2885 x2 = tabPoints[i-1].x | |
2886 y1 = tabPoints[i].y | |
2887 y2 = tabPoints[i-1].y | |
2888 match = True | |
2889 break | |
2890 | |
2891 if not match: | |
2892 return tabPoints[3].x | |
2893 | |
2894 # According to the equation y = ax + b => x = (y-b)/a | |
2895 # We know the first 2 points | |
2896 | |
2897 # Vertical line | |
2898 if x1 == x2: | |
2899 return int(x1) | |
2900 | |
2901 a = (y2 - y1)/(x2 - x1) | |
2902 b = y1 - ((y2 - y1)/(x2 - x1))*x1 | |
2903 | |
2904 if a == 0: | |
2905 return int(x1) | |
2906 | |
2907 x = (y - b)/a | |
2908 | |
2909 return int(x) | |
2910 | |
2911 | |
2912 def NumberTabsCanFit(self, pageContainer, fr=-1): | |
2913 """ Returns the number of tabs that can fit in the visible area. """ | |
2914 | |
2915 pc = pageContainer | |
2916 | |
2917 rect = pc.GetClientRect() | |
2918 clientWidth = rect.width | |
2919 | |
2920 # Empty results | |
2921 vTabInfo = [] | |
2922 tabHeight = self.CalcTabHeight(pageContainer) | |
2923 | |
2924 # The drawing starts from posx | |
2925 posx = pc._pParent.GetPadding() | |
2926 | |
2927 if fr < 0: | |
2928 fr = pc._nFrom | |
2929 | |
2930 for i in xrange(fr, len(pc._pagesInfoVec)): | |
2931 | |
2932 vc8glitch = tabHeight + FNB_HEIGHT_SPACER | |
2933 tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight) | |
2934 | |
2935 if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength(pc) >= clientWidth: | |
2936 break | |
2937 | |
2938 # Add a result to the returned vector | |
2939 tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth, tabHeight) | |
2940 vTabInfo.append(tabRect) | |
2941 | |
2942 # Advance posx | |
2943 posx += tabWidth + FNB_HEIGHT_SPACER | |
2944 | |
2945 return vTabInfo | |
2946 | |
2947 | |
2948 # ---------------------------------------------------------------------------- # | |
2949 # Class FlatNotebook | |
2950 # ---------------------------------------------------------------------------- # | |
2951 | |
2952 class FlatNotebook(wx.PyPanel): | |
2953 """ | |
2954 Display one or more windows in a notebook. | |
2955 | |
2956 B{Events}: | |
2957 - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active | |
2958 page in the notebook is changing | |
2959 - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active | |
2960 page in the notebook has changed | |
2961 - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the | |
2962 notebook is closing | |
2963 - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the | |
2964 notebook has been closed | |
2965 - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user | |
2966 clicks a tab in the notebook with the right mouse | |
2967 button | |
2968 """ | |
2969 | |
2970 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, | |
2971 style=0, name="FlatNotebook"): | |
2972 """ | |
2973 Default class constructor. | |
2974 | |
2975 All the parameters are as in wxPython class construction, except the | |
2976 'style': this can be assigned to whatever combination of FNB_* styles. | |
2977 | |
2978 """ | |
2979 | |
2980 self._bForceSelection = False | |
2981 self._nPadding = 6 | |
2982 self._nFrom = 0 | |
2983 style |= wx.TAB_TRAVERSAL | |
2984 self._pages = None | |
2985 self._windows = [] | |
2986 self._popupWin = None | |
2987 self._naviIcon = None | |
2988 | |
2989 wx.PyPanel.__init__(self, parent, id, pos, size, style) | |
2990 | |
2991 self._pages = PageContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style) | |
2992 | |
2993 self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey) | |
2994 | |
2995 self.Init() | |
2996 | |
2997 | |
2998 def Init(self): | |
2999 """ Initializes all the class attributes. """ | |
3000 | |
3001 self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW) | |
3002 | |
3003 self._mainSizer = wx.BoxSizer(wx.VERTICAL) | |
3004 self.SetSizer(self._mainSizer) | |
3005 | |
3006 # The child panels will inherit this bg color, so leave it at the default value | |
3007 #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE)) | |
3008 | |
3009 # Set default page height | |
3010 dc = wx.ClientDC(self) | |
3011 | |
3012 if "__WXGTK__" in wx.PlatformInfo: | |
3013 # For GTK it seems that we must do this steps in order | |
3014 # for the tabs will get the proper height on initialization | |
3015 # on MSW, preforming these steps yields wierd results | |
3016 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
3017 boldFont.SetWeight(wx.FONTWEIGHT_BOLD) | |
3018 dc.SetFont(boldFont) | |
3019 | |
3020 height = dc.GetCharHeight() | |
3021 | |
3022 tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding | |
3023 | |
3024 if "__WXGTK__" in wx.PlatformInfo: | |
3025 tabHeight += 6 | |
3026 | |
3027 self._pages.SetSizeHints(-1, tabHeight) | |
3028 # Add the tab container to the sizer | |
3029 self._mainSizer.Insert(0, self._pages, 0, wx.EXPAND) | |
3030 self._mainSizer.Layout() | |
3031 | |
3032 self._pages._nFrom = self._nFrom | |
3033 self._pDropTarget = FNBDropTarget(self) | |
3034 self.SetDropTarget(self._pDropTarget) | |
3035 | |
3036 | |
3037 def DoGetBestSize(self): | |
3038 """ Overrides DoGetBestSize to handle sizers nicely. """ | |
3039 | |
3040 if not self._windows: | |
3041 # Something is better than nothing... no pages! | |
3042 return wx.Size(20, 20) | |
3043 | |
3044 maxWidth = maxHeight = 0 | |
3045 tabHeight = self.GetPageBestSize().height | |
3046 | |
3047 for win in self._windows: | |
3048 # Loop over all the windows to get their best size | |
3049 width, height = win.GetBestSize() | |
3050 maxWidth, maxHeight = max(maxWidth, width), max(maxHeight, height) | |
3051 | |
3052 return wx.Size(maxWidth, maxHeight+tabHeight) | |
3053 | |
3054 | |
3055 def SetActiveTabTextColour(self, textColour): | |
3056 """ Sets the text colour for the active tab. """ | |
3057 | |
3058 self._pages._activeTextColor = textColour | |
3059 | |
3060 | |
3061 def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer): | |
3062 """ Handles the drop action from a DND operation. """ | |
3063 | |
3064 return self._pages.OnDropTarget(x, y, nTabPage, wnd_oldContainer) | |
3065 | |
3066 | |
3067 def GetPreviousSelection(self): | |
3068 """ Returns the previous selection. """ | |
3069 | |
3070 return self._pages._iPreviousActivePage | |
3071 | |
3072 | |
3073 def AddPage(self, page, text, select=True, imageId=-1): | |
3074 """ | |
3075 Add a page to the L{FlatNotebook}. | |
3076 | |
3077 @param page: Specifies the new page. | |
3078 @param text: Specifies the text for the new page. | |
3079 @param select: Specifies whether the page should be selected. | |
3080 @param imageId: Specifies the optional image index for the new page. | |
3081 | |
3082 Return value: | |
3083 True if successful, False otherwise. | |
3084 """ | |
3085 | |
3086 # sanity check | |
3087 if not page: | |
3088 return False | |
3089 | |
3090 # reparent the window to us | |
3091 page.Reparent(self) | |
3092 | |
3093 # Add tab | |
3094 bSelected = select or len(self._windows) == 0 | |
3095 | |
3096 if bSelected: | |
3097 | |
3098 bSelected = False | |
3099 | |
3100 # Check for selection and send events | |
3101 oldSelection = self._pages._iActivePage | |
3102 tabIdx = len(self._windows) | |
3103 | |
3104 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId()) | |
3105 event.SetSelection(tabIdx) | |
3106 event.SetOldSelection(oldSelection) | |
3107 event.SetEventObject(self) | |
3108 | |
3109 if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0: | |
3110 bSelected = True | |
3111 | |
3112 curSel = self._pages.GetSelection() | |
3113 | |
3114 if not self._pages.IsShown(): | |
3115 self._pages.Show() | |
3116 | |
3117 self._pages.AddPage(text, bSelected, imageId) | |
3118 self._windows.append(page) | |
3119 | |
3120 self.Freeze() | |
3121 | |
3122 # Check if a new selection was made | |
3123 if bSelected: | |
3124 | |
3125 if curSel >= 0: | |
3126 | |
3127 # Remove the window from the main sizer | |
3128 self._mainSizer.Detach(self._windows[curSel]) | |
3129 self._windows[curSel].Hide() | |
3130 | |
3131 if self.GetWindowStyleFlag() & FNB_BOTTOM: | |
3132 | |
3133 self._mainSizer.Insert(0, page, 1, wx.EXPAND) | |
3134 | |
3135 else: | |
3136 | |
3137 # We leave a space of 1 pixel around the window | |
3138 self._mainSizer.Add(page, 1, wx.EXPAND) | |
3139 | |
3140 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event | |
3141 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED) | |
3142 event.SetOldSelection(oldSelection) | |
3143 self.GetEventHandler().ProcessEvent(event) | |
3144 | |
3145 else: | |
3146 | |
3147 # Hide the page | |
3148 page.Hide() | |
3149 | |
3150 self.Thaw() | |
3151 self._mainSizer.Layout() | |
3152 self.Refresh() | |
3153 | |
3154 return True | |
3155 | |
3156 | |
3157 def SetImageList(self, imageList): | |
3158 """ Sets the image list for the page control. """ | |
3159 | |
3160 self._pages.SetImageList(imageList) | |
3161 | |
3162 | |
3163 def AssignImageList(self, imageList): | |
3164 """ Assigns the image list for the page control. """ | |
3165 | |
3166 self._pages.AssignImageList(imageList) | |
3167 | |
3168 | |
3169 def GetImageList(self): | |
3170 """ Returns the associated image list. """ | |
3171 | |
3172 return self._pages.GetImageList() | |
3173 | |
3174 | |
3175 def InsertPage(self, indx, page, text, select=True, imageId=-1): | |
3176 """ | |
3177 Inserts a new page at the specified position. | |
3178 | |
3179 @param indx: Specifies the position of the new page. | |
3180 @param page: Specifies the new page. | |
3181 @param text: Specifies the text for the new page. | |
3182 @param select: Specifies whether the page should be selected. | |
3183 @param imageId: Specifies the optional image index for the new page. | |
3184 | |
3185 Return value: | |
3186 True if successful, False otherwise. | |
3187 """ | |
3188 | |
3189 # sanity check | |
3190 if not page: | |
3191 return False | |
3192 | |
3193 # reparent the window to us | |
3194 page.Reparent(self) | |
3195 | |
3196 if not self._windows: | |
3197 | |
3198 self.AddPage(page, text, select, imageId) | |
3199 return True | |
3200 | |
3201 # Insert tab | |
3202 bSelected = select or not self._windows | |
3203 curSel = self._pages.GetSelection() | |
3204 | |
3205 indx = max(0, min(indx, len(self._windows))) | |
3206 | |
3207 if indx <= len(self._windows): | |
3208 | |
3209 self._windows.insert(indx, page) | |
3210 | |
3211 else: | |
3212 | |
3213 self._windows.append(page) | |
3214 | |
3215 if bSelected: | |
3216 | |
3217 bSelected = False | |
3218 | |
3219 # Check for selection and send events | |
3220 oldSelection = self._pages._iActivePage | |
3221 | |
3222 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId()) | |
3223 event.SetSelection(indx) | |
3224 event.SetOldSelection(oldSelection) | |
3225 event.SetEventObject(self) | |
3226 | |
3227 if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0: | |
3228 bSelected = True | |
3229 | |
3230 self._pages.InsertPage(indx, text, bSelected, imageId) | |
3231 | |
3232 if indx <= curSel: | |
3233 curSel = curSel + 1 | |
3234 | |
3235 self.Freeze() | |
3236 | |
3237 # Check if a new selection was made | |
3238 if bSelected: | |
3239 | |
3240 if curSel >= 0: | |
3241 | |
3242 # Remove the window from the main sizer | |
3243 self._mainSizer.Detach(self._windows[curSel]) | |
3244 self._windows[curSel].Hide() | |
3245 | |
3246 self._pages.SetSelection(indx) | |
3247 | |
3248 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event | |
3249 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED) | |
3250 event.SetOldSelection(oldSelection) | |
3251 self.GetEventHandler().ProcessEvent(event) | |
3252 | |
3253 else: | |
3254 | |
3255 # Hide the page | |
3256 page.Hide() | |
3257 | |
3258 self.Thaw() | |
3259 self._mainSizer.Layout() | |
3260 self.Refresh() | |
3261 | |
3262 return True | |
3263 | |
3264 | |
3265 def SetSelection(self, page): | |
3266 """ | |
3267 Sets the selection for the given page. | |
3268 The call to this function generates the page changing events | |
3269 """ | |
3270 | |
3271 if page >= len(self._windows) or not self._windows: | |
3272 return | |
3273 | |
3274 # Support for disabed tabs | |
3275 if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection: | |
3276 return | |
3277 | |
3278 curSel = self._pages.GetSelection() | |
3279 | |
3280 # program allows the page change | |
3281 self.Freeze() | |
3282 if curSel >= 0: | |
3283 | |
3284 # Remove the window from the main sizer | |
3285 self._mainSizer.Detach(self._windows[curSel]) | |
3286 self._windows[curSel].Hide() | |
3287 | |
3288 if self.GetWindowStyleFlag() & FNB_BOTTOM: | |
3289 | |
3290 self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND) | |
3291 | |
3292 else: | |
3293 | |
3294 # We leave a space of 1 pixel around the window | |
3295 self._mainSizer.Add(self._windows[page], 1, wx.EXPAND) | |
3296 | |
3297 self._windows[page].Show() | |
3298 self.Thaw() | |
3299 | |
3300 self._mainSizer.Layout() | |
3301 | |
3302 if page != self._pages._iActivePage: | |
3303 # there is a real page changing | |
3304 self._pages._iPreviousActivePage = self._pages._iActivePage | |
3305 | |
3306 self._pages._iActivePage = page | |
3307 self._pages.DoSetSelection(page) | |
3308 | |
3309 | |
3310 def DeletePage(self, page): | |
3311 """ | |
3312 Deletes the specified page, and the associated window. | |
3313 The call to this function generates the page changing events. | |
3314 """ | |
3315 | |
3316 if page >= len(self._windows) or page < 0: | |
3317 return | |
3318 | |
3319 # Fire a closing event | |
3320 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId()) | |
3321 event.SetSelection(page) | |
3322 event.SetEventObject(self) | |
3323 self.GetEventHandler().ProcessEvent(event) | |
3324 | |
3325 # The event handler allows it? | |
3326 if not event.IsAllowed(): | |
3327 return | |
3328 | |
3329 self.Freeze() | |
3330 | |
3331 # Delete the requested page | |
3332 pageRemoved = self._windows[page] | |
3333 | |
3334 # If the page is the current window, remove it from the sizer | |
3335 # as well | |
3336 if page == self._pages.GetSelection(): | |
3337 self._mainSizer.Detach(pageRemoved) | |
3338 | |
3339 # Remove it from the array as well | |
3340 self._windows.pop(page) | |
3341 | |
3342 # Now we can destroy it in wxWidgets use Destroy instead of delete | |
3343 pageRemoved.Destroy() | |
3344 | |
3345 self.Thaw() | |
3346 | |
3347 self._pages.DoDeletePage(page) | |
3348 self.Refresh() | |
3349 self.Update() | |
3350 | |
3351 # Fire a closed event | |
3352 closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId()) | |
3353 closedEvent.SetSelection(page) | |
3354 closedEvent.SetEventObject(self) | |
3355 self.GetEventHandler().ProcessEvent(closedEvent) | |
3356 | |
3357 | |
3358 def DeleteAllPages(self): | |
3359 """ Deletes all the pages. """ | |
3360 | |
3361 if not self._windows: | |
3362 return False | |
3363 | |
3364 self.Freeze() | |
3365 | |
3366 for page in self._windows: | |
3367 page.Destroy() | |
3368 | |
3369 self._windows = [] | |
3370 self.Thaw() | |
3371 | |
3372 # Clear the container of the tabs as well | |
3373 self._pages.DeleteAllPages() | |
3374 return True | |
3375 | |
3376 | |
3377 def GetCurrentPage(self): | |
3378 """ Returns the currently selected notebook page or None. """ | |
3379 | |
3380 sel = self._pages.GetSelection() | |
3381 if sel < 0: | |
3382 return None | |
3383 | |
3384 return self._windows[sel] | |
3385 | |
3386 | |
3387 def GetPage(self, page): | |
3388 """ Returns the window at the given page position, or None. """ | |
3389 | |
3390 if page >= len(self._windows): | |
3391 return None | |
3392 | |
3393 return self._windows[page] | |
3394 | |
3395 | |
3396 def GetPageIndex(self, win): | |
3397 """ Returns the index at which the window is found. """ | |
3398 | |
3399 try: | |
3400 return self._windows.index(win) | |
3401 except: | |
3402 return -1 | |
3403 | |
3404 | |
3405 def GetSelection(self): | |
3406 """ Returns the currently selected page, or -1 if none was selected. """ | |
3407 | |
3408 return self._pages.GetSelection() | |
3409 | |
3410 | |
3411 def AdvanceSelection(self, forward=True): | |
3412 """ | |
3413 Cycles through the tabs. | |
3414 The call to this function generates the page changing events. | |
3415 """ | |
3416 | |
3417 self._pages.AdvanceSelection(forward) | |
3418 | |
3419 | |
3420 def GetPageCount(self): | |
3421 """ Returns the number of pages in the L{FlatNotebook} control. """ | |
3422 | |
3423 return self._pages.GetPageCount() | |
3424 | |
3425 def SetNavigatorIcon(self, bmp): | |
3426 """ Set the icon used by the L{TabNavigatorWindow} """ | |
3427 if isinstance(bmp, wx.Bitmap) and bmp.IsOk(): | |
3428 # Make sure image is proper size | |
3429 if bmp.GetSize() != (16, 16): | |
3430 img = bmp.ConvertToImage() | |
3431 img.Rescale(16, 16, wx.IMAGE_QUALITY_HIGH) | |
3432 bmp = wx.BitmapFromImage(img) | |
3433 self._naviIcon = bmp | |
3434 else: | |
3435 raise TypeError, "SetNavigatorIcon requires a valid bitmap" | |
3436 | |
3437 def OnNavigationKey(self, event): | |
3438 """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """ | |
3439 | |
3440 if event.IsWindowChange(): | |
3441 if len(self._windows) == 0: | |
3442 return | |
3443 # change pages | |
3444 if self.HasFlag(FNB_SMART_TABS): | |
3445 if not self._popupWin: | |
3446 self._popupWin = TabNavigatorWindow(self, self._naviIcon) | |
3447 self._popupWin.SetReturnCode(wx.ID_OK) | |
3448 self._popupWin.ShowModal() | |
3449 self._popupWin.Destroy() | |
3450 self._popupWin = None | |
3451 else: | |
3452 # a dialog is already opened | |
3453 self._popupWin.OnNavigationKey(event) | |
3454 return | |
3455 else: | |
3456 # change pages | |
3457 self.AdvanceSelection(event.GetDirection()) | |
3458 | |
3459 else: | |
3460 event.Skip() | |
3461 | |
3462 | |
3463 def GetPageShapeAngle(self, page_index): | |
3464 """ Returns the angle associated to a tab. """ | |
3465 | |
3466 if page_index < 0 or page_index >= len(self._pages._pagesInfoVec): | |
3467 return None, False | |
3468 | |
3469 result = self._pages._pagesInfoVec[page_index].GetTabAngle() | |
3470 return result, True | |
3471 | |
3472 | |
3473 def SetPageShapeAngle(self, page_index, angle): | |
3474 """ Sets the angle associated to a tab. """ | |
3475 | |
3476 if page_index < 0 or page_index >= len(self._pages._pagesInfoVec): | |
3477 return | |
3478 | |
3479 if angle > 15: | |
3480 return | |
3481 | |
3482 self._pages._pagesInfoVec[page_index].SetTabAngle(angle) | |
3483 | |
3484 | |
3485 def SetAllPagesShapeAngle(self, angle): | |
3486 """ Sets the angle associated to all the tab. """ | |
3487 | |
3488 if angle > 15: | |
3489 return | |
3490 | |
3491 for ii in xrange(len(self._pages._pagesInfoVec)): | |
3492 self._pages._pagesInfoVec[ii].SetTabAngle(angle) | |
3493 | |
3494 self.Refresh() | |
3495 | |
3496 | |
3497 def GetPageBestSize(self): | |
3498 """ Return the page best size. """ | |
3499 | |
3500 return self._pages.GetClientSize() | |
3501 | |
3502 | |
3503 def SetPageText(self, page, text): | |
3504 """ Sets the text for the given page. """ | |
3505 | |
3506 bVal = self._pages.SetPageText(page, text) | |
3507 self._pages.Refresh() | |
3508 | |
3509 return bVal | |
3510 | |
3511 | |
3512 def SetPadding(self, padding): | |
3513 """ | |
3514 Sets the amount of space around each page's icon and label, in pixels. | |
3515 NB: only the horizontal padding is considered. | |
3516 """ | |
3517 | |
3518 self._nPadding = padding.GetWidth() | |
3519 | |
3520 | |
3521 def GetTabArea(self): | |
3522 """ Returns the associated page. """ | |
3523 | |
3524 return self._pages | |
3525 | |
3526 | |
3527 def GetPadding(self): | |
3528 """ Returns the amount of space around each page's icon and label, in pixels. """ | |
3529 | |
3530 return self._nPadding | |
3531 | |
3532 | |
3533 def SetWindowStyleFlag(self, style): | |
3534 """ Sets the L{FlatNotebook} window style flags. """ | |
3535 | |
3536 wx.PyPanel.SetWindowStyleFlag(self, style) | |
3537 renderer = self._pages._mgr.GetRenderer(self.GetWindowStyleFlag()) | |
3538 renderer._tabHeight = None | |
3539 | |
3540 if self._pages: | |
3541 | |
3542 # For changing the tab position (i.e. placing them top/bottom) | |
3543 # refreshing the tab container is not enough | |
3544 self.SetSelection(self._pages._iActivePage) | |
3545 | |
3546 if not self._pages.HasFlag(FNB_HIDE_ON_SINGLE_TAB): | |
3547 #For Redrawing the Tabs once you remove the Hide tyle | |
3548 self._pages._ReShow() | |
3549 | |
3550 | |
3551 def RemovePage(self, page): | |
3552 """ Deletes the specified page, without deleting the associated window. """ | |
3553 | |
3554 if page >= len(self._windows): | |
3555 return False | |
3556 | |
3557 # Fire a closing event | |
3558 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId()) | |
3559 event.SetSelection(page) | |
3560 event.SetEventObject(self) | |
3561 self.GetEventHandler().ProcessEvent(event) | |
3562 | |
3563 # The event handler allows it? | |
3564 if not event.IsAllowed(): | |
3565 return False | |
3566 | |
3567 self.Freeze() | |
3568 | |
3569 # Remove the requested page | |
3570 pageRemoved = self._windows[page] | |
3571 | |
3572 # If the page is the current window, remove it from the sizer | |
3573 # as well | |
3574 if page == self._pages.GetSelection(): | |
3575 self._mainSizer.Detach(pageRemoved) | |
3576 | |
3577 # Remove it from the array as well | |
3578 self._windows.pop(page) | |
3579 self.Thaw() | |
3580 | |
3581 self._pages.DoDeletePage(page) | |
3582 | |
3583 return True | |
3584 | |
3585 | |
3586 def SetRightClickMenu(self, menu): | |
3587 """ Sets the popup menu associated to a right click on a tab. """ | |
3588 | |
3589 self._pages._pRightClickMenu = menu | |
3590 | |
3591 | |
3592 def GetPageText(self, nPage): | |
3593 """ Returns the tab caption. """ | |
3594 | |
3595 return self._pages.GetPageText(nPage) | |
3596 | |
3597 | |
3598 def SetGradientColours(self, fr, to, border): | |
3599 """ Sets the gradient colours for the tab. """ | |
3600 | |
3601 self._pages._colorFrom = fr | |
3602 self._pages._colorTo = to | |
3603 self._pages._colorBorder = border | |
3604 | |
3605 | |
3606 def SetGradientColourFrom(self, fr): | |
3607 """ Sets the starting colour for the gradient. """ | |
3608 | |
3609 self._pages._colorFrom = fr | |
3610 | |
3611 | |
3612 def SetGradientColourTo(self, to): | |
3613 """ Sets the ending colour for the gradient. """ | |
3614 | |
3615 self._pages._colorTo = to | |
3616 | |
3617 | |
3618 def SetGradientColourBorder(self, border): | |
3619 """ Sets the tab border colour. """ | |
3620 | |
3621 self._pages._colorBorder = border | |
3622 | |
3623 | |
3624 def GetGradientColourFrom(self): | |
3625 """ Gets first gradient colour. """ | |
3626 | |
3627 return self._pages._colorFrom | |
3628 | |
3629 | |
3630 def GetGradientColourTo(self): | |
3631 """ Gets second gradient colour. """ | |
3632 | |
3633 return self._pages._colorTo | |
3634 | |
3635 | |
3636 def GetGradientColourBorder(self): | |
3637 """ Gets the tab border colour. """ | |
3638 | |
3639 return self._pages._colorBorder | |
3640 | |
3641 | |
3642 def GetBorderColour(self): | |
3643 """ Returns the border colour. """ | |
3644 | |
3645 return self._pages._colorBorder | |
3646 | |
3647 | |
3648 def GetActiveTabTextColour(self): | |
3649 """ Get the active tab text colour. """ | |
3650 | |
3651 return self._pages._activeTextColor | |
3652 | |
3653 | |
3654 def SetPageImage(self, page, image): | |
3655 """ | |
3656 Sets the image index for the given page. Image is an index into the | |
3657 image list which was set with SetImageList. | |
3658 """ | |
3659 | |
3660 self._pages.SetPageImage(page, image) | |
3661 | |
3662 | |
3663 def GetPageImage(self, nPage): | |
3664 """ | |
3665 Returns the image index for the given page. Image is an index into the | |
3666 image list which was set with SetImageList. | |
3667 """ | |
3668 | |
3669 return self._pages.GetPageImage(nPage) | |
3670 | |
3671 | |
3672 def GetEnabled(self, page): | |
3673 """ Returns whether a tab is enabled or not. """ | |
3674 | |
3675 return self._pages.GetEnabled(page) | |
3676 | |
3677 | |
3678 def EnableTab(self, page, enabled=True): | |
3679 """ Enables or disables a tab. """ | |
3680 | |
3681 if page >= len(self._windows): | |
3682 return | |
3683 | |
3684 self._windows[page].Enable(enabled) | |
3685 self._pages.EnableTab(page, enabled) | |
3686 | |
3687 | |
3688 def GetNonActiveTabTextColour(self): | |
3689 """ Returns the non active tabs text colour. """ | |
3690 | |
3691 return self._pages._nonActiveTextColor | |
3692 | |
3693 | |
3694 def SetNonActiveTabTextColour(self, color): | |
3695 """ Sets the non active tabs text colour. """ | |
3696 | |
3697 self._pages._nonActiveTextColor = color | |
3698 | |
3699 | |
3700 def SetTabAreaColour(self, color): | |
3701 """ Sets the area behind the tabs colour. """ | |
3702 | |
3703 self._pages._tabAreaColor = color | |
3704 | |
3705 | |
3706 def GetTabAreaColour(self): | |
3707 """ Returns the area behind the tabs colour. """ | |
3708 | |
3709 return self._pages._tabAreaColor | |
3710 | |
3711 | |
3712 def SetActiveTabColour(self, color): | |
3713 """ Sets the active tab colour. """ | |
3714 | |
3715 self._pages._activeTabColor = color | |
3716 | |
3717 | |
3718 def GetActiveTabColour(self): | |
3719 """ Returns the active tab colour. """ | |
3720 | |
3721 return self._pages._activeTabColor | |
3722 | |
3723 | |
3724 # ---------------------------------------------------------------------------- # | |
3725 # Class PageContainer | |
3726 # Acts as a container for the pages you add to FlatNotebook | |
3727 # ---------------------------------------------------------------------------- # | |
3728 | |
3729 class PageContainer(wx.Panel): | |
3730 """ | |
3731 This class acts as a container for the pages you add to L{FlatNotebook}. | |
3732 """ | |
3733 | |
3734 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, | |
3735 size=wx.DefaultSize, style=0): | |
3736 """ Default class constructor. """ | |
3737 | |
3738 self._ImageList = None | |
3739 self._iActivePage = -1 | |
3740 self._pDropTarget = None | |
3741 self._nLeftClickZone = FNB_NOWHERE | |
3742 self._iPreviousActivePage = -1 | |
3743 | |
3744 self._pRightClickMenu = None | |
3745 self._nXButtonStatus = FNB_BTN_NONE | |
3746 self._nArrowDownButtonStatus = FNB_BTN_NONE | |
3747 self._pParent = parent | |
3748 self._nRightButtonStatus = FNB_BTN_NONE | |
3749 self._nLeftButtonStatus = FNB_BTN_NONE | |
3750 self._nTabXButtonStatus = FNB_BTN_NONE | |
3751 | |
3752 self._pagesInfoVec = [] | |
3753 | |
3754 self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION) | |
3755 self._colorFrom = wx.WHITE | |
3756 self._activeTabColor = wx.WHITE | |
3757 self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT) | |
3758 self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT) | |
3759 self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) | |
3760 | |
3761 self._nFrom = 0 | |
3762 self._isdragging = False | |
3763 | |
3764 # Set default page height, this is done according to the system font | |
3765 memDc = wx.MemoryDC() | |
3766 memDc.SelectObject(wx.EmptyBitmap(1,1)) | |
3767 | |
3768 if "__WXGTK__" in wx.PlatformInfo: | |
3769 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
3770 boldFont.SetWeight(wx.BOLD) | |
3771 memDc.SetFont(boldFont) | |
3772 | |
3773 height = memDc.GetCharHeight() | |
3774 tabHeight = height + FNB_HEIGHT_SPACER # We use 10 pixels as padding | |
3775 | |
3776 wx.Panel.__init__(self, parent, id, pos, wx.Size(size.x, tabHeight), | |
3777 style|wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE|wx.WANTS_CHARS) | |
3778 | |
3779 self._pDropTarget = FNBDropTarget(self) | |
3780 self.SetDropTarget(self._pDropTarget) | |
3781 self._mgr = FNBRendererMgr() | |
3782 | |
3783 self.Bind(wx.EVT_PAINT, self.OnPaint) | |
3784 self.Bind(wx.EVT_SIZE, self.OnSize) | |
3785 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) | |
3786 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) | |
3787 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) | |
3788 self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown) | |
3789 self.Bind(wx.EVT_MOTION, self.OnMouseMove) | |
3790 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) | |
3791 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave) | |
3792 self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow) | |
3793 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) | |
3794 self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) | |
3795 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) | |
3796 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) | |
3797 | |
3798 | |
3799 def OnEraseBackground(self, event): | |
3800 """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing).""" | |
3801 | |
3802 pass | |
3803 | |
3804 | |
3805 def _ReShow(self): | |
3806 """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """ | |
3807 self.Show() | |
3808 self.GetParent()._mainSizer.Layout() | |
3809 self.Refresh() | |
3810 | |
3811 | |
3812 def OnPaint(self, event): | |
3813 """ Handles the wx.EVT_PAINT event for L{PageContainer}.""" | |
3814 | |
3815 dc = wx.BufferedPaintDC(self) | |
3816 renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()) | |
3817 renderer.DrawTabs(self, dc) | |
3818 | |
3819 if self.HasFlag(FNB_HIDE_ON_SINGLE_TAB) and len(self._pagesInfoVec) <= 1: | |
3820 self.Hide() | |
3821 self.GetParent()._mainSizer.Layout() | |
3822 self.Refresh() | |
3823 | |
3824 | |
3825 def AddPage(self, caption, selected=True, imgindex=-1): | |
3826 """ | |
3827 Add a page to the L{FlatNotebook}. | |
3828 | |
3829 @param window: Specifies the new page. | |
3830 @param caption: Specifies the text for the new page. | |
3831 @param selected: Specifies whether the page should be selected. | |
3832 @param imgindex: Specifies the optional image index for the new page. | |
3833 | |
3834 Return value: | |
3835 True if successful, False otherwise. | |
3836 """ | |
3837 | |
3838 if selected: | |
3839 | |
3840 self._iPreviousActivePage = self._iActivePage | |
3841 self._iActivePage = len(self._pagesInfoVec) | |
3842 | |
3843 # Create page info and add it to the vector | |
3844 pageInfo = PageInfo(caption, imgindex) | |
3845 self._pagesInfoVec.append(pageInfo) | |
3846 self.Refresh() | |
3847 | |
3848 | |
3849 def InsertPage(self, indx, text, selected=True, imgindex=-1): | |
3850 """ | |
3851 Inserts a new page at the specified position. | |
3852 | |
3853 @param indx: Specifies the position of the new page. | |
3854 @param page: Specifies the new page. | |
3855 @param text: Specifies the text for the new page. | |
3856 @param select: Specifies whether the page should be selected. | |
3857 @param imgindex: Specifies the optional image index for the new page. | |
3858 | |
3859 Return value: | |
3860 True if successful, False otherwise. | |
3861 """ | |
3862 | |
3863 if selected: | |
3864 | |
3865 self._iPreviousActivePage = self._iActivePage | |
3866 self._iActivePage = len(self._pagesInfoVec) | |
3867 | |
3868 self._pagesInfoVec.insert(indx, PageInfo(text, imgindex)) | |
3869 | |
3870 self.Refresh() | |
3871 return True | |
3872 | |
3873 | |
3874 def OnSize(self, event): | |
3875 """ Handles the wx.EVT_SIZE events for L{PageContainer}. """ | |
3876 | |
3877 # When resizing the control, try to fit to screen as many tabs as we can | |
3878 style = self.GetParent().GetWindowStyleFlag() | |
3879 renderer = self._mgr.GetRenderer(style) | |
3880 | |
3881 fr = 0 | |
3882 page = self.GetSelection() | |
3883 | |
3884 for fr in xrange(self._nFrom): | |
3885 vTabInfo = renderer.NumberTabsCanFit(self, fr) | |
3886 if page - fr >= len(vTabInfo): | |
3887 continue | |
3888 break | |
3889 | |
3890 self._nFrom = fr | |
3891 | |
3892 self.Refresh() # Call on paint | |
3893 event.Skip() | |
3894 | |
3895 | |
3896 def OnMiddleDown(self, event): | |
3897 """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """ | |
3898 | |
3899 # Test if this style is enabled | |
3900 style = self.GetParent().GetWindowStyleFlag() | |
3901 | |
3902 if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS: | |
3903 return | |
3904 | |
3905 where, tabIdx = self.HitTest(event.GetPosition()) | |
3906 | |
3907 if where == FNB_TAB: | |
3908 self.DeletePage(tabIdx) | |
3909 | |
3910 event.Skip() | |
3911 | |
3912 | |
3913 def OnRightDown(self, event): | |
3914 """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """ | |
3915 | |
3916 where, tabIdx = self.HitTest(event.GetPosition()) | |
3917 | |
3918 if where in [FNB_TAB, FNB_TAB_X]: | |
3919 | |
3920 if self._pagesInfoVec[tabIdx].GetEnabled(): | |
3921 # Fire events and eventually (if allowed) change selection | |
3922 self.FireEvent(tabIdx) | |
3923 | |
3924 # send a message to popup a custom menu | |
3925 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId()) | |
3926 event.SetSelection(tabIdx) | |
3927 event.SetOldSelection(self._iActivePage) | |
3928 event.SetEventObject(self.GetParent()) | |
3929 self.GetParent().GetEventHandler().ProcessEvent(event) | |
3930 | |
3931 if self._pRightClickMenu: | |
3932 self.PopupMenu(self._pRightClickMenu) | |
3933 | |
3934 event.Skip() | |
3935 | |
3936 | |
3937 def OnLeftDown(self, event): | |
3938 """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """ | |
3939 | |
3940 # Reset buttons status | |
3941 self._nXButtonStatus = FNB_BTN_NONE | |
3942 self._nLeftButtonStatus = FNB_BTN_NONE | |
3943 self._nRightButtonStatus = FNB_BTN_NONE | |
3944 self._nTabXButtonStatus = FNB_BTN_NONE | |
3945 self._nArrowDownButtonStatus = FNB_BTN_NONE | |
3946 | |
3947 self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition()) | |
3948 | |
3949 if self._nLeftClickZone == FNB_DROP_DOWN_ARROW: | |
3950 self._nArrowDownButtonStatus = FNB_BTN_PRESSED | |
3951 self.Refresh() | |
3952 elif self._nLeftClickZone == FNB_LEFT_ARROW: | |
3953 self._nLeftButtonStatus = FNB_BTN_PRESSED | |
3954 self.Refresh() | |
3955 elif self._nLeftClickZone == FNB_RIGHT_ARROW: | |
3956 self._nRightButtonStatus = FNB_BTN_PRESSED | |
3957 self.Refresh() | |
3958 elif self._nLeftClickZone == FNB_X: | |
3959 self._nXButtonStatus = FNB_BTN_PRESSED | |
3960 self.Refresh() | |
3961 elif self._nLeftClickZone == FNB_TAB_X: | |
3962 self._nTabXButtonStatus = FNB_BTN_PRESSED | |
3963 self.Refresh() | |
3964 | |
3965 elif self._nLeftClickZone == FNB_TAB: | |
3966 | |
3967 if self._iActivePage != tabIdx: | |
3968 | |
3969 # In case the tab is disabled, we dont allow to choose it | |
3970 if self._pagesInfoVec[tabIdx].GetEnabled(): | |
3971 self.FireEvent(tabIdx) | |
3972 | |
3973 | |
3974 def RotateLeft(self): | |
3975 | |
3976 if self._nFrom == 0: | |
3977 return | |
3978 | |
3979 # Make sure that the button was pressed before | |
3980 if self._nLeftButtonStatus != FNB_BTN_PRESSED: | |
3981 return | |
3982 | |
3983 self._nLeftButtonStatus = FNB_BTN_HOVER | |
3984 | |
3985 # We scroll left with bulks of 5 | |
3986 scrollLeft = self.GetNumTabsCanScrollLeft() | |
3987 | |
3988 self._nFrom -= scrollLeft | |
3989 if self._nFrom < 0: | |
3990 self._nFrom = 0 | |
3991 | |
3992 self.Refresh() | |
3993 | |
3994 | |
3995 def RotateRight(self): | |
3996 | |
3997 if self._nFrom >= len(self._pagesInfoVec) - 1: | |
3998 return | |
3999 | |
4000 # Make sure that the button was pressed before | |
4001 if self._nRightButtonStatus != FNB_BTN_PRESSED: | |
4002 return | |
4003 | |
4004 self._nRightButtonStatus = FNB_BTN_HOVER | |
4005 | |
4006 # Check if the right most tab is visible, if it is | |
4007 # don't rotate right anymore | |
4008 if self._pagesInfoVec[len(self._pagesInfoVec)-1].GetPosition() != wx.Point(-1, -1): | |
4009 return | |
4010 | |
4011 self._nFrom += 1 | |
4012 self.Refresh() | |
4013 | |
4014 | |
4015 def OnLeftUp(self, event): | |
4016 """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """ | |
4017 | |
4018 # forget the zone that was initially clicked | |
4019 self._nLeftClickZone = FNB_NOWHERE | |
4020 | |
4021 where, tabIdx = self.HitTest(event.GetPosition()) | |
4022 | |
4023 # Make sure selected tab has focus | |
4024 self.SetFocus() | |
4025 | |
4026 if where == FNB_LEFT_ARROW: | |
4027 self.RotateLeft() | |
4028 | |
4029 elif where == FNB_RIGHT_ARROW: | |
4030 self.RotateRight() | |
4031 | |
4032 elif where == FNB_X: | |
4033 | |
4034 # Make sure that the button was pressed before | |
4035 if self._nXButtonStatus != FNB_BTN_PRESSED: | |
4036 return | |
4037 | |
4038 self._nXButtonStatus = FNB_BTN_HOVER | |
4039 | |
4040 self.DeletePage(self._iActivePage) | |
4041 | |
4042 elif where == FNB_TAB_X: | |
4043 | |
4044 # Make sure that the button was pressed before | |
4045 if self._nTabXButtonStatus != FNB_BTN_PRESSED: | |
4046 return | |
4047 | |
4048 self._nTabXButtonStatus = FNB_BTN_HOVER | |
4049 | |
4050 self.DeletePage(self._iActivePage) | |
4051 | |
4052 elif where == FNB_DROP_DOWN_ARROW: | |
4053 | |
4054 # Make sure that the button was pressed before | |
4055 if self._nArrowDownButtonStatus != FNB_BTN_PRESSED: | |
4056 return | |
4057 | |
4058 self._nArrowDownButtonStatus = FNB_BTN_NONE | |
4059 | |
4060 # Refresh the button status | |
4061 renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()) | |
4062 dc = wx.ClientDC(self) | |
4063 renderer.DrawDropDownArrow(self, dc) | |
4064 | |
4065 self.PopupTabsMenu() | |
4066 | |
4067 event.Skip() | |
4068 | |
4069 | |
4070 def HitTest(self, pt): | |
4071 """ | |
4072 HitTest method for L{PageContainer}. | |
4073 Returns the flag (if any) and the hit page (if any). | |
4074 """ | |
4075 | |
4076 style = self.GetParent().GetWindowStyleFlag() | |
4077 render = self._mgr.GetRenderer(style) | |
4078 | |
4079 fullrect = self.GetClientRect() | |
4080 btnLeftPos = render.GetLeftButtonPos(self) | |
4081 btnRightPos = render.GetRightButtonPos(self) | |
4082 btnXPos = render.GetXPos(self) | |
4083 | |
4084 tabIdx = -1 | |
4085 | |
4086 if len(self._pagesInfoVec) == 0: | |
4087 return FNB_NOWHERE, tabIdx | |
4088 | |
4089 rect = wx.Rect(btnXPos, 8, 16, 16) | |
4090 if rect.Contains(pt): | |
4091 return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], tabIdx | |
4092 | |
4093 rect = wx.Rect(btnRightPos, 8, 16, 16) | |
4094 if style & FNB_DROPDOWN_TABS_LIST: | |
4095 rect = wx.Rect(render.GetDropArrowButtonPos(self), 8, 16, 16) | |
4096 if rect.Contains(pt): | |
4097 return FNB_DROP_DOWN_ARROW, tabIdx | |
4098 | |
4099 if rect.Contains(pt): | |
4100 return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], tabIdx | |
4101 | |
4102 rect = wx.Rect(btnLeftPos, 8, 16, 16) | |
4103 if rect.Contains(pt): | |
4104 return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], tabIdx | |
4105 | |
4106 # Test whether a left click was made on a tab | |
4107 bFoundMatch = False | |
4108 | |
4109 for cur in xrange(self._nFrom, len(self._pagesInfoVec)): | |
4110 | |
4111 pgInfo = self._pagesInfoVec[cur] | |
4112 | |
4113 if pgInfo.GetPosition() == wx.Point(-1, -1): | |
4114 continue | |
4115 | |
4116 if style & FNB_X_ON_TAB and cur == self.GetSelection(): | |
4117 # 'x' button exists on a tab | |
4118 if self._pagesInfoVec[cur].GetXRect().Contains(pt): | |
4119 return FNB_TAB_X, cur | |
4120 | |
4121 if style & FNB_VC8: | |
4122 | |
4123 if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y): | |
4124 if bFoundMatch or cur == self.GetSelection(): | |
4125 return FNB_TAB, cur | |
4126 | |
4127 tabIdx = cur | |
4128 bFoundMatch = True | |
4129 | |
4130 else: | |
4131 | |
4132 tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y, | |
4133 pgInfo.GetSize().x, pgInfo.GetSize().y) | |
4134 | |
4135 if tabRect.Contains(pt): | |
4136 # We have a match | |
4137 return FNB_TAB, cur | |
4138 | |
4139 if bFoundMatch: | |
4140 return FNB_TAB, tabIdx | |
4141 | |
4142 if self._isdragging: | |
4143 # We are doing DND, so check also the region outside the tabs | |
4144 # try before the first tab | |
4145 pgInfo = self._pagesInfoVec[0] | |
4146 tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y) | |
4147 if tabRect.Contains(pt): | |
4148 return FNB_TAB, 0 | |
4149 | |
4150 # try after the last tab | |
4151 pgInfo = self._pagesInfoVec[-1] | |
4152 startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x | |
4153 tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y) | |
4154 | |
4155 if tabRect.Contains(pt): | |
4156 return FNB_TAB, len(self._pagesInfoVec) | |
4157 | |
4158 # Default | |
4159 return FNB_NOWHERE, -1 | |
4160 | |
4161 | |
4162 def SetSelection(self, page): | |
4163 """ Sets the selected page. """ | |
4164 | |
4165 book = self.GetParent() | |
4166 book.SetSelection(page) | |
4167 self.DoSetSelection(page) | |
4168 | |
4169 | |
4170 def DoSetSelection(self, page): | |
4171 """ Does the actual selection of a page. """ | |
4172 | |
4173 if page < len(self._pagesInfoVec): | |
4174 #! fix for tabfocus | |
4175 da_page = self._pParent.GetPage(page) | |
4176 | |
4177 if da_page != None: | |
4178 da_page.SetFocus() | |
4179 | |
4180 if not self.IsTabVisible(page): | |
4181 # Try to remove one tab from start and try again | |
4182 | |
4183 if not self.CanFitToScreen(page): | |
4184 | |
4185 if self._nFrom > page: | |
4186 self._nFrom = page | |
4187 else: | |
4188 while self._nFrom < page: | |
4189 self._nFrom += 1 | |
4190 if self.CanFitToScreen(page): | |
4191 break | |
4192 | |
4193 self.Refresh() | |
4194 | |
4195 | |
4196 def DeletePage(self, page): | |
4197 """ Delete the specified page from L{FlatNotebook}. """ | |
4198 | |
4199 book = self.GetParent() | |
4200 book.DeletePage(page) | |
4201 book.Refresh() | |
4202 | |
4203 | |
4204 def IsTabVisible(self, page): | |
4205 """ Returns whether a tab is visible or not. """ | |
4206 | |
4207 iLastVisiblePage = self.GetLastVisibleTab() | |
4208 return page <= iLastVisiblePage and page >= self._nFrom | |
4209 | |
4210 | |
4211 def DoDeletePage(self, page): | |
4212 """ Does the actual page deletion. """ | |
4213 | |
4214 # Remove the page from the vector | |
4215 book = self.GetParent() | |
4216 self._pagesInfoVec.pop(page) | |
4217 | |
4218 # Thanks to Yiaanis AKA Mandrav | |
4219 if self._iActivePage >= page: | |
4220 self._iActivePage = self._iActivePage - 1 | |
4221 self._iPreviousActivePage = -1 | |
4222 | |
4223 # The delete page was the last first on the array, | |
4224 # but the book still has more pages, so we set the | |
4225 # active page to be the first one (0) | |
4226 if self._iActivePage < 0 and len(self._pagesInfoVec) > 0: | |
4227 self._iActivePage = 0 | |
4228 self._iPreviousActivePage = -1 | |
4229 | |
4230 # Refresh the tabs | |
4231 if self._iActivePage >= 0: | |
4232 | |
4233 book._bForceSelection = True | |
4234 | |
4235 # Check for selection and send event | |
4236 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId()) | |
4237 event.SetSelection(self._iActivePage) | |
4238 event.SetOldSelection(self._iPreviousActivePage) | |
4239 event.SetEventObject(self.GetParent()) | |
4240 | |
4241 book.SetSelection(self._iActivePage) | |
4242 book._bForceSelection = False | |
4243 | |
4244 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event | |
4245 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED) | |
4246 event.SetOldSelection(self._iPreviousActivePage) | |
4247 self.GetParent().GetEventHandler().ProcessEvent(event) | |
4248 | |
4249 if not self._pagesInfoVec: | |
4250 # Erase the page container drawings | |
4251 dc = wx.ClientDC(self) | |
4252 dc.Clear() | |
4253 | |
4254 | |
4255 def DeleteAllPages(self): | |
4256 """ Deletes all the pages. """ | |
4257 | |
4258 self._iActivePage = -1 | |
4259 self._iPreviousActivePage = -1 | |
4260 self._nFrom = 0 | |
4261 self._pagesInfoVec = [] | |
4262 | |
4263 # Erase the page container drawings | |
4264 dc = wx.ClientDC(self) | |
4265 dc.Clear() | |
4266 | |
4267 | |
4268 def OnMouseMove(self, event): | |
4269 """ Handles the wx.EVT_MOTION for L{PageContainer}. """ | |
4270 | |
4271 if self._pagesInfoVec and self.IsShown(): | |
4272 | |
4273 xButtonStatus = self._nXButtonStatus | |
4274 xTabButtonStatus = self._nTabXButtonStatus | |
4275 rightButtonStatus = self._nRightButtonStatus | |
4276 leftButtonStatus = self._nLeftButtonStatus | |
4277 dropDownButtonStatus = self._nArrowDownButtonStatus | |
4278 | |
4279 style = self.GetParent().GetWindowStyleFlag() | |
4280 | |
4281 self._nXButtonStatus = FNB_BTN_NONE | |
4282 self._nRightButtonStatus = FNB_BTN_NONE | |
4283 self._nLeftButtonStatus = FNB_BTN_NONE | |
4284 self._nTabXButtonStatus = FNB_BTN_NONE | |
4285 self._nArrowDownButtonStatus = FNB_BTN_NONE | |
4286 | |
4287 where, tabIdx = self.HitTest(event.GetPosition()) | |
4288 | |
4289 if where == FNB_X: | |
4290 if event.LeftIsDown(): | |
4291 | |
4292 self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0] | |
4293 | |
4294 else: | |
4295 | |
4296 self._nXButtonStatus = FNB_BTN_HOVER | |
4297 | |
4298 elif where == FNB_DROP_DOWN_ARROW: | |
4299 if event.LeftIsDown(): | |
4300 | |
4301 self._nArrowDownButtonStatus = (self._nLeftClickZone==FNB_DROP_DOWN_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0] | |
4302 | |
4303 else: | |
4304 | |
4305 self._nArrowDownButtonStatus = FNB_BTN_HOVER | |
4306 | |
4307 elif where == FNB_TAB_X: | |
4308 if event.LeftIsDown(): | |
4309 | |
4310 self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0] | |
4311 | |
4312 else: | |
4313 | |
4314 self._nTabXButtonStatus = FNB_BTN_HOVER | |
4315 | |
4316 elif where == FNB_RIGHT_ARROW: | |
4317 if event.LeftIsDown(): | |
4318 | |
4319 self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0] | |
4320 | |
4321 else: | |
4322 | |
4323 self._nRightButtonStatus = FNB_BTN_HOVER | |
4324 | |
4325 elif where == FNB_LEFT_ARROW: | |
4326 if event.LeftIsDown(): | |
4327 | |
4328 self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0] | |
4329 | |
4330 else: | |
4331 | |
4332 self._nLeftButtonStatus = FNB_BTN_HOVER | |
4333 | |
4334 elif where == FNB_TAB: | |
4335 # Call virtual method for showing tooltip | |
4336 self.ShowTabTooltip(tabIdx) | |
4337 | |
4338 if not self.GetEnabled(tabIdx): | |
4339 # Set the cursor to be 'No-entry' | |
4340 wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY)) | |
4341 | |
4342 # Support for drag and drop | |
4343 if event.Dragging() and not (style & FNB_NODRAG): | |
4344 | |
4345 self._isdragging = True | |
4346 draginfo = FNBDragInfo(self, tabIdx) | |
4347 drginfo = cPickle.dumps(draginfo) | |
4348 dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook")) | |
4349 dataobject.SetData(drginfo) | |
4350 dragSource = FNBDropSource(self) | |
4351 dragSource.SetData(dataobject) | |
4352 dragSource.DoDragDrop(wx.Drag_DefaultMove) | |
4353 | |
4354 bRedrawX = self._nXButtonStatus != xButtonStatus | |
4355 bRedrawRight = self._nRightButtonStatus != rightButtonStatus | |
4356 bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus | |
4357 bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus | |
4358 bRedrawDropArrow = self._nArrowDownButtonStatus != dropDownButtonStatus | |
4359 | |
4360 render = self._mgr.GetRenderer(style) | |
4361 | |
4362 if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX or bRedrawDropArrow): | |
4363 | |
4364 dc = wx.ClientDC(self) | |
4365 | |
4366 if bRedrawX: | |
4367 | |
4368 render.DrawX(self, dc) | |
4369 | |
4370 if bRedrawLeft: | |
4371 | |
4372 render.DrawLeftArrow(self, dc) | |
4373 | |
4374 if bRedrawRight: | |
4375 | |
4376 render.DrawRightArrow(self, dc) | |
4377 | |
4378 if bRedrawTabX: | |
4379 | |
4380 self.Refresh() | |
4381 | |
4382 if bRedrawDropArrow: | |
4383 | |
4384 render.DrawDropDownArrow(self, dc) | |
4385 | |
4386 event.Skip() | |
4387 | |
4388 | |
4389 def GetLastVisibleTab(self): | |
4390 """ Returns the last visible tab. """ | |
4391 | |
4392 if self._nFrom < 0: | |
4393 return -1 | |
4394 | |
4395 ii = 0 | |
4396 | |
4397 for ii in xrange(self._nFrom, len(self._pagesInfoVec)): | |
4398 | |
4399 if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1): | |
4400 break | |
4401 | |
4402 return ii-1 | |
4403 | |
4404 | |
4405 def GetNumTabsCanScrollLeft(self): | |
4406 """ Returns the number of tabs than can be scrolled left. """ | |
4407 | |
4408 if self._nFrom - 1 >= 0: | |
4409 return 1 | |
4410 | |
4411 return 0 | |
4412 | |
4413 | |
4414 def IsDefaultTabs(self): | |
4415 """ Returns whether a tab has a default style. """ | |
4416 | |
4417 style = self.GetParent().GetWindowStyleFlag() | |
4418 res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8) | |
4419 return not res | |
4420 | |
4421 | |
4422 def AdvanceSelection(self, bForward=True): | |
4423 """ | |
4424 Cycles through the tabs. | |
4425 The call to this function generates the page changing events. | |
4426 """ | |
4427 | |
4428 nSel = self.GetSelection() | |
4429 | |
4430 if nSel < 0: | |
4431 return | |
4432 | |
4433 nMax = self.GetPageCount() - 1 | |
4434 | |
4435 if bForward: | |
4436 newSelection = (nSel == nMax and [0] or [nSel + 1])[0] | |
4437 else: | |
4438 newSelection = (nSel == 0 and [nMax] or [nSel - 1])[0] | |
4439 | |
4440 if not self._pagesInfoVec[newSelection].GetEnabled(): | |
4441 return | |
4442 | |
4443 self.FireEvent(newSelection) | |
4444 | |
4445 | |
4446 def OnMouseLeave(self, event): | |
4447 """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """ | |
4448 | |
4449 self._nLeftButtonStatus = FNB_BTN_NONE | |
4450 self._nXButtonStatus = FNB_BTN_NONE | |
4451 self._nRightButtonStatus = FNB_BTN_NONE | |
4452 self._nTabXButtonStatus = FNB_BTN_NONE | |
4453 self._nArrowDownButtonStatus = FNB_BTN_NONE | |
4454 | |
4455 style = self.GetParent().GetWindowStyleFlag() | |
4456 render = self._mgr.GetRenderer(style) | |
4457 | |
4458 dc = wx.ClientDC(self) | |
4459 | |
4460 render.DrawX(self, dc) | |
4461 render.DrawLeftArrow(self, dc) | |
4462 render.DrawRightArrow(self, dc) | |
4463 | |
4464 selection = self.GetSelection() | |
4465 | |
4466 if selection == -1: | |
4467 event.Skip() | |
4468 return | |
4469 | |
4470 if not self.IsTabVisible(selection): | |
4471 if selection == len(self._pagesInfoVec) - 1: | |
4472 if not self.CanFitToScreen(selection): | |
4473 event.Skip() | |
4474 return | |
4475 else: | |
4476 event.Skip() | |
4477 return | |
4478 | |
4479 render.DrawTabX(self, dc, self._pagesInfoVec[selection].GetXRect(), selection, self._nTabXButtonStatus) | |
4480 render.DrawFocusRectangle(dc, self, self._pagesInfoVec[selection]) | |
4481 | |
4482 event.Skip() | |
4483 | |
4484 | |
4485 def OnMouseEnterWindow(self, event): | |
4486 """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """ | |
4487 | |
4488 self._nLeftButtonStatus = FNB_BTN_NONE | |
4489 self._nXButtonStatus = FNB_BTN_NONE | |
4490 self._nRightButtonStatus = FNB_BTN_NONE | |
4491 self._nLeftClickZone = FNB_BTN_NONE | |
4492 self._nArrowDownButtonStatus = FNB_BTN_NONE | |
4493 | |
4494 event.Skip() | |
4495 | |
4496 | |
4497 def ShowTabTooltip(self, tabIdx): | |
4498 """ Shows a tab tooltip. """ | |
4499 | |
4500 pWindow = self._pParent.GetPage(tabIdx) | |
4501 | |
4502 if pWindow: | |
4503 pToolTip = pWindow.GetToolTip() | |
4504 if pToolTip and pToolTip.GetWindow() == pWindow: | |
4505 self.SetToolTipString(pToolTip.GetTip()) | |
4506 | |
4507 | |
4508 def SetPageImage(self, page, imgindex): | |
4509 """ Sets the image index associated to a page. """ | |
4510 | |
4511 if page < len(self._pagesInfoVec): | |
4512 | |
4513 self._pagesInfoVec[page].SetImageIndex(imgindex) | |
4514 self.Refresh() | |
4515 | |
4516 | |
4517 def GetPageImage(self, page): | |
4518 """ Returns the image index associated to a page. """ | |
4519 | |
4520 if page < len(self._pagesInfoVec): | |
4521 | |
4522 return self._pagesInfoVec[page].GetImageIndex() | |
4523 | |
4524 return -1 | |
4525 | |
4526 | |
4527 def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer): | |
4528 """ Handles the drop action from a DND operation. """ | |
4529 | |
4530 # Disable drag'n'drop for disabled tab | |
4531 if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled(): | |
4532 return wx.DragCancel | |
4533 | |
4534 self._isdragging = True | |
4535 oldContainer = wnd_oldContainer | |
4536 nIndex = -1 | |
4537 | |
4538 where, nIndex = self.HitTest(wx.Point(x, y)) | |
4539 | |
4540 oldNotebook = oldContainer.GetParent() | |
4541 newNotebook = self.GetParent() | |
4542 | |
4543 if oldNotebook == newNotebook: | |
4544 | |
4545 if nTabPage >= 0: | |
4546 | |
4547 if where == FNB_TAB: | |
4548 self.MoveTabPage(nTabPage, nIndex) | |
4549 | |
4550 elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND: | |
4551 | |
4552 if wx.Platform in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]: | |
4553 if nTabPage >= 0: | |
4554 | |
4555 window = oldNotebook.GetPage(nTabPage) | |
4556 | |
4557 if window: | |
4558 where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y)) | |
4559 caption = oldContainer.GetPageText(nTabPage) | |
4560 imageindex = oldContainer.GetPageImage(nTabPage) | |
4561 oldNotebook.RemovePage(nTabPage) | |
4562 window.Reparent(newNotebook) | |
4563 | |
4564 if imageindex >= 0: | |
4565 | |
4566 bmp = oldNotebook.GetImageList().GetBitmap(imageindex) | |
4567 newImageList = newNotebook.GetImageList() | |
4568 | |
4569 if not newImageList: | |
4570 xbmp, ybmp = bmp.GetWidth(), bmp.GetHeight() | |
4571 newImageList = wx.ImageList(xbmp, ybmp) | |
4572 imageindex = 0 | |
4573 else: | |
4574 imageindex = newImageList.GetImageCount() | |
4575 | |
4576 newImageList.Add(bmp) | |
4577 newNotebook.SetImageList(newImageList) | |
4578 | |
4579 newNotebook.InsertPage(nIndex, window, caption, True, imageindex) | |
4580 | |
4581 self._isdragging = False | |
4582 | |
4583 return wx.DragMove | |
4584 | |
4585 | |
4586 def MoveTabPage(self, nMove, nMoveTo): | |
4587 """ Moves a tab inside the same L{FlatNotebook}. """ | |
4588 | |
4589 if nMove == nMoveTo: | |
4590 return | |
4591 | |
4592 elif nMoveTo < len(self._pParent._windows): | |
4593 nMoveTo = nMoveTo + 1 | |
4594 | |
4595 self._pParent.Freeze() | |
4596 | |
4597 # Remove the window from the main sizer | |
4598 nCurSel = self._pParent._pages.GetSelection() | |
4599 self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel]) | |
4600 self._pParent._windows[nCurSel].Hide() | |
4601 | |
4602 pWindow = self._pParent._windows[nMove] | |
4603 self._pParent._windows.pop(nMove) | |
4604 self._pParent._windows.insert(nMoveTo-1, pWindow) | |
4605 | |
4606 pgInfo = self._pagesInfoVec[nMove] | |
4607 | |
4608 self._pagesInfoVec.pop(nMove) | |
4609 self._pagesInfoVec.insert(nMoveTo - 1, pgInfo) | |
4610 | |
4611 # Add the page according to the style | |
4612 pSizer = self._pParent._mainSizer | |
4613 style = self.GetParent().GetWindowStyleFlag() | |
4614 | |
4615 if style & FNB_BOTTOM: | |
4616 | |
4617 pSizer.Insert(0, pWindow, 1, wx.EXPAND) | |
4618 | |
4619 else: | |
4620 | |
4621 # We leave a space of 1 pixel around the window | |
4622 pSizer.Add(pWindow, 1, wx.EXPAND) | |
4623 | |
4624 pWindow.Show() | |
4625 | |
4626 pSizer.Layout() | |
4627 self._iActivePage = nMoveTo - 1 | |
4628 self._iPreviousActivePage = -1 | |
4629 self.DoSetSelection(self._iActivePage) | |
4630 self.Refresh() | |
4631 self._pParent.Thaw() | |
4632 | |
4633 | |
4634 def CanFitToScreen(self, page): | |
4635 """ Returns wheter a tab can fit in the left space in the screen or not. """ | |
4636 | |
4637 # Incase the from is greater than page, | |
4638 # we need to reset the self._nFrom, so in order | |
4639 # to force the caller to do so, we return false | |
4640 if self._nFrom > page: | |
4641 return False | |
4642 | |
4643 style = self.GetParent().GetWindowStyleFlag() | |
4644 render = self._mgr.GetRenderer(style) | |
4645 | |
4646 vTabInfo = render.NumberTabsCanFit(self) | |
4647 | |
4648 if page - self._nFrom >= len(vTabInfo): | |
4649 return False | |
4650 | |
4651 return True | |
4652 | |
4653 | |
4654 def GetNumOfVisibleTabs(self): | |
4655 """ Returns the number of visible tabs. """ | |
4656 | |
4657 count = 0 | |
4658 for ii in xrange(self._nFrom, len(self._pagesInfoVec)): | |
4659 if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1): | |
4660 break | |
4661 count = count + 1 | |
4662 | |
4663 return count | |
4664 | |
4665 | |
4666 def GetEnabled(self, page): | |
4667 """ Returns whether a tab is enabled or not. """ | |
4668 | |
4669 if page >= len(self._pagesInfoVec): | |
4670 return True # Seems strange, but this is the default | |
4671 | |
4672 return self._pagesInfoVec[page].GetEnabled() | |
4673 | |
4674 | |
4675 def EnableTab(self, page, enabled=True): | |
4676 """ Enables or disables a tab. """ | |
4677 | |
4678 if page >= len(self._pagesInfoVec): | |
4679 return | |
4680 | |
4681 self._pagesInfoVec[page].EnableTab(enabled) | |
4682 | |
4683 | |
4684 def GetSingleLineBorderColour(self): | |
4685 """ Returns the colour for the single line border. """ | |
4686 | |
4687 if self.HasFlag(FNB_FANCY_TABS): | |
4688 return self._colorFrom | |
4689 | |
4690 return wx.WHITE | |
4691 | |
4692 | |
4693 def HasFlag(self, flag): | |
4694 """ Returns whether a flag is present in the L{FlatNotebook} style. """ | |
4695 | |
4696 style = self.GetParent().GetWindowStyleFlag() | |
4697 res = (style & flag and [True] or [False])[0] | |
4698 return res | |
4699 | |
4700 | |
4701 def ClearFlag(self, flag): | |
4702 """ Deletes a flag from the L{FlatNotebook} style. """ | |
4703 | |
4704 style = self.GetParent().GetWindowStyleFlag() | |
4705 style &= ~flag | |
4706 self.SetWindowStyleFlag(style) | |
4707 | |
4708 | |
4709 def TabHasImage(self, tabIdx): | |
4710 """ Returns whether a tab has an associated image index or not. """ | |
4711 | |
4712 if self._ImageList: | |
4713 return self._pagesInfoVec[tabIdx].GetImageIndex() != -1 | |
4714 | |
4715 return False | |
4716 | |
4717 | |
4718 def OnLeftDClick(self, event): | |
4719 """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """ | |
4720 | |
4721 where, tabIdx = self.HitTest(event.GetPosition()) | |
4722 | |
4723 if where == FNB_RIGHT_ARROW: | |
4724 self.RotateRight() | |
4725 | |
4726 elif where == FNB_LEFT_ARROW: | |
4727 self.RotateLeft() | |
4728 | |
4729 elif self.HasFlag(FNB_DCLICK_CLOSES_TABS): | |
4730 | |
4731 if where == FNB_TAB: | |
4732 self.DeletePage(tabIdx) | |
4733 | |
4734 else: | |
4735 | |
4736 event.Skip() | |
4737 | |
4738 | |
4739 def OnSetFocus(self, event): | |
4740 """ Handles the wx.EVT_SET_FOCUS event for L{PageContainer}. """ | |
4741 | |
4742 if self._iActivePage < 0: | |
4743 event.Skip() | |
4744 return | |
4745 | |
4746 self.SetFocusedPage(self._iActivePage) | |
4747 | |
4748 | |
4749 def OnKillFocus(self, event): | |
4750 """ Handles the wx.EVT_KILL_FOCUS event for L{PageContainer}. """ | |
4751 | |
4752 self.SetFocusedPage() | |
4753 | |
4754 | |
4755 def OnKeyDown(self, event): | |
4756 """ | |
4757 When the PageContainer has the focus tabs can be changed with | |
4758 the left/right arrow keys. | |
4759 """ | |
4760 key = event.GetKeyCode() | |
4761 if key == wx.WXK_LEFT: | |
4762 self.GetParent().AdvanceSelection(False) | |
4763 elif key == wx.WXK_RIGHT: | |
4764 self.GetParent().AdvanceSelection(True) | |
4765 elif key == wx.WXK_TAB and not event.ControlDown(): | |
4766 flags = 0 | |
4767 if not event.ShiftDown(): flags |= wx.NavigationKeyEvent.IsForward | |
4768 if event.CmdDown(): flags |= wx.NavigationKeyEvent.WinChange | |
4769 self.Navigate(flags) | |
4770 else: | |
4771 event.Skip() | |
4772 | |
4773 | |
4774 def SetFocusedPage(self, pageIndex=-1): | |
4775 """ | |
4776 Sets/Unsets the focus on the appropriate page. | |
4777 If pageIndex is defaulted, we have lost focus and no focus indicator is drawn. | |
4778 """ | |
4779 | |
4780 for indx, page in enumerate(self._pagesInfoVec): | |
4781 if indx == pageIndex: | |
4782 page._hasFocus = True | |
4783 else: | |
4784 page._hasFocus = False | |
4785 | |
4786 self.Refresh() | |
4787 | |
4788 | |
4789 def PopupTabsMenu(self): | |
4790 """ Pops up the menu activated with the drop down arrow in the navigation area. """ | |
4791 | |
4792 popupMenu = wx.Menu() | |
4793 | |
4794 for i in xrange(len(self._pagesInfoVec)): | |
4795 pi = self._pagesInfoVec[i] | |
4796 item = wx.MenuItem(popupMenu, i+1, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL) | |
4797 self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item) | |
4798 | |
4799 # There is an alignment problem with wx2.6.3 & Menus so only use | |
4800 # images for versions above 2.6.3 | |
4801 if wx.VERSION > (2, 6, 3, 0) and self.TabHasImage(i): | |
4802 item.SetBitmap(self.GetImageList().GetBitmap(pi.GetImageIndex())) | |
4803 | |
4804 popupMenu.AppendItem(item) | |
4805 item.Enable(pi.GetEnabled()) | |
4806 | |
4807 self.PopupMenu(popupMenu) | |
4808 | |
4809 | |
4810 def OnTabMenuSelection(self, event): | |
4811 """ Handles the wx.EVT_MENU event for L{PageContainer}. """ | |
4812 | |
4813 selection = event.GetId() - 1 | |
4814 self.FireEvent(selection) | |
4815 | |
4816 | |
4817 def FireEvent(self, selection): | |
4818 """ | |
4819 Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events | |
4820 called from other methods (from menu selection or Smart Tabbing). | |
4821 Utility function. | |
4822 """ | |
4823 | |
4824 if selection == self._iActivePage: | |
4825 # No events for the same selection | |
4826 return | |
4827 | |
4828 oldSelection = self._iActivePage | |
4829 | |
4830 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId()) | |
4831 event.SetSelection(selection) | |
4832 event.SetOldSelection(oldSelection) | |
4833 event.SetEventObject(self.GetParent()) | |
4834 | |
4835 if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed(): | |
4836 | |
4837 self.SetSelection(selection) | |
4838 | |
4839 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event | |
4840 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED) | |
4841 event.SetOldSelection(oldSelection) | |
4842 self.GetParent().GetEventHandler().ProcessEvent(event) | |
4843 self.SetFocus() | |
4844 | |
4845 | |
4846 def SetImageList(self, imglist): | |
4847 """ Sets the image list for the page control. """ | |
4848 | |
4849 self._ImageList = imglist | |
4850 | |
4851 | |
4852 def AssignImageList(self, imglist): | |
4853 """ Assigns the image list for the page control. """ | |
4854 | |
4855 self._ImageList = imglist | |
4856 | |
4857 | |
4858 def GetImageList(self): | |
4859 """ Returns the image list for the page control. """ | |
4860 | |
4861 return self._ImageList | |
4862 | |
4863 | |
4864 def GetSelection(self): | |
4865 """ Returns the current selected page. """ | |
4866 | |
4867 return self._iActivePage | |
4868 | |
4869 | |
4870 def GetPageCount(self): | |
4871 """ Returns the number of tabs in the L{FlatNotebook} control. """ | |
4872 | |
4873 return len(self._pagesInfoVec) | |
4874 | |
4875 | |
4876 def GetPageText(self, page): | |
4877 """ Returns the tab caption of the page. """ | |
4878 | |
4879 return self._pagesInfoVec[page].GetCaption() | |
4880 | |
4881 | |
4882 def SetPageText(self, page, text): | |
4883 """ Sets the tab caption of the page. """ | |
4884 | |
4885 self._pagesInfoVec[page].SetCaption(text) | |
4886 return True | |
4887 | |
4888 | |
4889 def DrawDragHint(self): | |
4890 """ Draws small arrow at the place that the tab will be placed. """ | |
4891 | |
4892 # get the index of tab that will be replaced with the dragged tab | |
4893 pt = wx.GetMousePosition() | |
4894 client_pt = self.ScreenToClient(pt) | |
4895 where, tabIdx = self.HitTest(client_pt) | |
4896 self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()).DrawDragHint(self, tabIdx) | |
4897 | |
4898 |