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