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