Compilation fix for wxCStrData handling.
[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
cbfc9df6
RD
201wxEVT_FLATNOTEBOOK_PAGE_CHANGED = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
202wxEVT_FLATNOTEBOOK_PAGE_CHANGING = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
6cb4f153
RD
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
cbfc9df6 211EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.EVT_NOTEBOOK_PAGE_CHANGED
6a64d551
RD
212"""Notify client objects when the active page in L{FlatNotebook}
213has changed."""
cbfc9df6 214EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.EVT_NOTEBOOK_PAGE_CHANGING
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):
cbfc9df6 2958 """ Sets the image list for the page control. """
6a64d551 2959
33113971 2960 self._pages.SetImageList(imageList)
6a64d551
RD
2961
2962
cbfc9df6
RD
2963 def AssignImageList(self, imageList):
2964 """ Assigns the image list for the page control. """
2965
2966 self._pages.AssignImageList(imageList)
2967
2968
6a64d551
RD
2969 def GetImageList(self):
2970 """ Returns the associated image list. """
2971
2972 return self._pages.GetImageList()
2973
2974
2975 def InsertPage(self, indx, page, text, select=True, imageId=-1):
2976 """
2977 Inserts a new page at the specified position.
2978
2979 @param indx: Specifies the position of the new page.
2980 @param page: Specifies the new page.
2981 @param text: Specifies the text for the new page.
2982 @param select: Specifies whether the page should be selected.
2983 @param imageId: Specifies the optional image index for the new page.
2984
2985 Return value:
2986 True if successful, False otherwise.
2987 """
2988
2989 # sanity check
2990 if not page:
2991 return False
6cb4f153 2992
6a64d551
RD
2993 # reparent the window to us
2994 page.Reparent(self)
6cb4f153 2995
6a64d551
RD
2996 if not self._windows:
2997
2998 self.AddPage(page, text, select, imageId)
2999 return True
6cb4f153 3000
6a64d551
RD
3001 # Insert tab
3002 bSelected = select or not self._windows
3003 curSel = self._pages.GetSelection()
3004
3005 indx = max(0, min(indx, len(self._windows)))
6cb4f153 3006
6a64d551
RD
3007 if indx <= len(self._windows):
3008
3009 self._windows.insert(indx, page)
3010
3011 else:
3012
3013 self._windows.append(page)
3014
3015 if bSelected:
3016
3017 bSelected = False
6cb4f153 3018
6a64d551
RD
3019 # Check for selection and send events
3020 oldSelection = self._pages._iActivePage
6cb4f153 3021
6a64d551
RD
3022 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
3023 event.SetSelection(indx)
3024 event.SetOldSelection(oldSelection)
3025 event.SetEventObject(self)
3026
33113971 3027 if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
6a64d551
RD
3028 bSelected = True
3029
3030 self._pages.InsertPage(indx, text, bSelected, imageId)
3031
3032 if indx <= curSel:
3033 curSel = curSel + 1
6cb4f153 3034
6a64d551 3035 self.Freeze()
6cb4f153 3036
6a64d551
RD
3037 # Check if a new selection was made
3038 if bSelected:
3039
3040 if curSel >= 0:
6cb4f153 3041
6a64d551
RD
3042 # Remove the window from the main sizer
3043 self._mainSizer.Detach(self._windows[curSel])
3044 self._windows[curSel].Hide()
6cb4f153 3045
6a64d551 3046 self._pages.SetSelection(indx)
6cb4f153 3047
6a64d551
RD
3048 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3049 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
3050 event.SetOldSelection(oldSelection)
3051 self.GetEventHandler().ProcessEvent(event)
3052
3053 else:
3054
3055 # Hide the page
3056 page.Hide()
33113971 3057
6a64d551 3058 self.Thaw()
33113971 3059 self._mainSizer.Layout()
6a64d551 3060 self.Refresh()
6cb4f153 3061
6a64d551 3062 return True
6cb4f153 3063
6a64d551
RD
3064
3065 def SetSelection(self, page):
6cb4f153 3066 """
6a64d551
RD
3067 Sets the selection for the given page.
3068 The call to this function generates the page changing events
6cb4f153
RD
3069 """
3070
6a64d551
RD
3071 if page >= len(self._windows) or not self._windows:
3072 return
6cb4f153 3073
6a64d551
RD
3074 # Support for disabed tabs
3075 if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection:
3076 return
3077
3078 curSel = self._pages.GetSelection()
3079
3080 # program allows the page change
3081 self.Freeze()
3082 if curSel >= 0:
6cb4f153 3083
6a64d551
RD
3084 # Remove the window from the main sizer
3085 self._mainSizer.Detach(self._windows[curSel])
3086 self._windows[curSel].Hide()
6cb4f153 3087
6a64d551 3088 if self.GetWindowStyleFlag() & FNB_BOTTOM:
6cb4f153 3089
6a64d551 3090 self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND)
6cb4f153 3091
6a64d551 3092 else:
6cb4f153 3093
6a64d551
RD
3094 # We leave a space of 1 pixel around the window
3095 self._mainSizer.Add(self._windows[page], 1, wx.EXPAND)
3096
3097 self._windows[page].Show()
3098 self.Thaw()
3099
3100 self._mainSizer.Layout()
3101
3102 if page != self._pages._iActivePage:
3103 # there is a real page changing
3104 self._pages._iPreviousActivePage = self._pages._iActivePage
6cb4f153 3105
6a64d551
RD
3106 self._pages._iActivePage = page
3107 self._pages.DoSetSelection(page)
6cb4f153 3108
6cb4f153 3109
6a64d551
RD
3110 def DeletePage(self, page):
3111 """
3112 Deletes the specified page, and the associated window.
3113 The call to this function generates the page changing events.
3114 """
6cb4f153 3115
6a64d551
RD
3116 if page >= len(self._windows) or page < 0:
3117 return
6cb4f153 3118
6a64d551
RD
3119 # Fire a closing event
3120 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
3121 event.SetSelection(page)
3122 event.SetEventObject(self)
3123 self.GetEventHandler().ProcessEvent(event)
6cb4f153 3124
6a64d551
RD
3125 # The event handler allows it?
3126 if not event.IsAllowed():
3127 return
6cb4f153 3128
6a64d551 3129 self.Freeze()
6cb4f153 3130
6a64d551
RD
3131 # Delete the requested page
3132 pageRemoved = self._windows[page]
6cb4f153 3133
6a64d551
RD
3134 # If the page is the current window, remove it from the sizer
3135 # as well
3136 if page == self._pages.GetSelection():
3137 self._mainSizer.Detach(pageRemoved)
6cb4f153 3138
6a64d551
RD
3139 # Remove it from the array as well
3140 self._windows.pop(page)
6cb4f153 3141
6a64d551
RD
3142 # Now we can destroy it in wxWidgets use Destroy instead of delete
3143 pageRemoved.Destroy()
3144
3145 self.Thaw()
3146
3147 self._pages.DoDeletePage(page)
3148 self.Refresh()
3149
3150 # Fire a closed event
3151 closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
3152 closedEvent.SetSelection(page)
3153 closedEvent.SetEventObject(self)
3154 self.GetEventHandler().ProcessEvent(closedEvent)
3155
3156
3157 def DeleteAllPages(self):
3158 """ Deletes all the pages. """
3159
3160 if not self._windows:
3161 return False
3162
3163 self.Freeze()
6cb4f153 3164
6a64d551
RD
3165 for page in self._windows:
3166 page.Destroy()
6cb4f153 3167
6a64d551
RD
3168 self._windows = []
3169 self.Thaw()
6cb4f153 3170
6a64d551
RD
3171 # Clear the container of the tabs as well
3172 self._pages.DeleteAllPages()
3173 return True
6cb4f153
RD
3174
3175
6a64d551
RD
3176 def GetCurrentPage(self):
3177 """ Returns the currently selected notebook page or None. """
3178
3179 sel = self._pages.GetSelection()
3180 if sel < 0:
3181 return None
6cb4f153 3182
6a64d551 3183 return self._windows[sel]
6cb4f153
RD
3184
3185
6a64d551
RD
3186 def GetPage(self, page):
3187 """ Returns the window at the given page position, or None. """
3188
3189 if page >= len(self._windows):
3190 return None
3191
3192 return self._windows[page]
3193
3194
3195 def GetPageIndex(self, win):
3196 """ Returns the index at which the window is found. """
3197
3198 try:
3199 return self._windows.index(win)
3200 except:
3201 return -1
3202
3203
3204 def GetSelection(self):
3205 """ Returns the currently selected page, or -1 if none was selected. """
3206
3207 return self._pages.GetSelection()
6cb4f153 3208
6cb4f153 3209
33113971 3210 def AdvanceSelection(self, forward=True):
6a64d551
RD
3211 """
3212 Cycles through the tabs.
3213 The call to this function generates the page changing events.
3214 """
6cb4f153 3215
33113971 3216 self._pages.AdvanceSelection(forward)
6cb4f153 3217
6cb4f153 3218
6a64d551
RD
3219 def GetPageCount(self):
3220 """ Returns the number of pages in the L{FlatNotebook} control. """
33113971 3221
6a64d551 3222 return self._pages.GetPageCount()
6cb4f153 3223
6cb4f153 3224
6a64d551
RD
3225 def OnNavigationKey(self, event):
3226 """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
6cb4f153 3227
6a64d551 3228 if event.IsWindowChange():
33113971
RD
3229 if len(self._windows) == 0:
3230 return
6a64d551
RD
3231 # change pages
3232 if self.HasFlag(FNB_SMART_TABS):
3233 if not self._popupWin:
3234 self._popupWin = TabNavigatorWindow(self)
3235 self._popupWin.SetReturnCode(wx.ID_OK)
3236 self._popupWin.ShowModal()
3237 self._popupWin.Destroy()
3238 self._popupWin = None
3239 else:
3240 # a dialog is already opened
3241 self._popupWin.OnNavigationKey(event)
3242 return
3243 else:
3244 # change pages
3245 self.AdvanceSelection(event.GetDirection())
3246 else:
3247 # pass to the parent
3248 if self.GetParent():
3249 event.SetCurrentFocus(self)
3250 self.GetParent().ProcessEvent(event)
3251
6cb4f153 3252
6a64d551
RD
3253 def GetPageShapeAngle(self, page_index):
3254 """ Returns the angle associated to a tab. """
6cb4f153 3255
6a64d551
RD
3256 if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
3257 return None, False
3258
3259 result = self._pages._pagesInfoVec[page_index].GetTabAngle()
3260 return result, True
6cb4f153
RD
3261
3262
6a64d551
RD
3263 def SetPageShapeAngle(self, page_index, angle):
3264 """ Sets the angle associated to a tab. """
6cb4f153 3265
6a64d551 3266 if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
6cb4f153
RD
3267 return
3268
6a64d551 3269 if angle > 15:
6cb4f153
RD
3270 return
3271
6a64d551 3272 self._pages._pagesInfoVec[page_index].SetTabAngle(angle)
6cb4f153 3273
6cb4f153 3274
6a64d551
RD
3275 def SetAllPagesShapeAngle(self, angle):
3276 """ Sets the angle associated to all the tab. """
6cb4f153 3277
6a64d551
RD
3278 if angle > 15:
3279 return
6cb4f153 3280
6a64d551
RD
3281 for ii in xrange(len(self._pages._pagesInfoVec)):
3282 self._pages._pagesInfoVec[ii].SetTabAngle(angle)
3283
3284 self.Refresh()
6cb4f153 3285
6cb4f153 3286
6a64d551
RD
3287 def GetPageBestSize(self):
3288 """ Return the page best size. """
6cb4f153 3289
6a64d551 3290 return self._pages.GetClientSize()
6cb4f153 3291
6cb4f153 3292
6a64d551
RD
3293 def SetPageText(self, page, text):
3294 """ Sets the text for the given page. """
6cb4f153 3295
6a64d551
RD
3296 bVal = self._pages.SetPageText(page, text)
3297 self._pages.Refresh()
6cb4f153 3298
6a64d551 3299 return bVal
6cb4f153
RD
3300
3301
6a64d551
RD
3302 def SetPadding(self, padding):
3303 """
3304 Sets the amount of space around each page's icon and label, in pixels.
3305 NB: only the horizontal padding is considered.
3306 """
6cb4f153 3307
6a64d551 3308 self._nPadding = padding.GetWidth()
6cb4f153 3309
6cb4f153 3310
6a64d551
RD
3311 def GetTabArea(self):
3312 """ Returns the associated page. """
6cb4f153 3313
6a64d551 3314 return self._pages
6cb4f153 3315
6cb4f153 3316
6a64d551
RD
3317 def GetPadding(self):
3318 """ Returns the amount of space around each page's icon and label, in pixels. """
3319
3320 return self._nPadding
6cb4f153
RD
3321
3322
6a64d551
RD
3323 def SetWindowStyleFlag(self, style):
3324 """ Sets the L{FlatNotebook} window style flags. """
3325
3326 wx.Panel.SetWindowStyleFlag(self, style)
33113971
RD
3327 renderer = self._pages._mgr.GetRenderer(self.GetWindowStyleFlag())
3328 renderer._tabHeight = None
6cb4f153 3329
6a64d551
RD
3330 if self._pages:
3331
3332 # For changing the tab position (i.e. placing them top/bottom)
3333 # refreshing the tab container is not enough
3334 self.SetSelection(self._pages._iActivePage)
6cb4f153 3335
37938059
RD
3336 if not self._pages.HasFlag(FNB_HIDE_ON_SINGLE_TAB):
3337 #For Redrawing the Tabs once you remove the Hide tyle
3338 self._pages._ReShow()
3339
6cb4f153 3340
6a64d551
RD
3341 def RemovePage(self, page):
3342 """ Deletes the specified page, without deleting the associated window. """
6cb4f153 3343
6a64d551
RD
3344 if page >= len(self._windows):
3345 return False
6cb4f153 3346
6a64d551
RD
3347 # Fire a closing event
3348 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
3349 event.SetSelection(page)
3350 event.SetEventObject(self)
3351 self.GetEventHandler().ProcessEvent(event)
6cb4f153 3352
6a64d551
RD
3353 # The event handler allows it?
3354 if not event.IsAllowed():
3355 return False
6cb4f153 3356
6a64d551 3357 self.Freeze()
6cb4f153 3358
6a64d551
RD
3359 # Remove the requested page
3360 pageRemoved = self._windows[page]
6cb4f153 3361
6a64d551
RD
3362 # If the page is the current window, remove it from the sizer
3363 # as well
3364 if page == self._pages.GetSelection():
3365 self._mainSizer.Detach(pageRemoved)
6cb4f153 3366
6a64d551
RD
3367 # Remove it from the array as well
3368 self._windows.pop(page)
3369 self.Thaw()
6cb4f153 3370
6a64d551 3371 self._pages.DoDeletePage(page)
6cb4f153 3372
6a64d551 3373 return True
6cb4f153 3374
6cb4f153 3375
6a64d551
RD
3376 def SetRightClickMenu(self, menu):
3377 """ Sets the popup menu associated to a right click on a tab. """
3378
3379 self._pages._pRightClickMenu = menu
6cb4f153 3380
6cb4f153 3381
33113971 3382 def GetPageText(self, nPage):
6a64d551 3383 """ Returns the tab caption. """
6cb4f153 3384
33113971 3385 return self._pages.GetPageText(nPage)
6cb4f153 3386
6cb4f153 3387
6a64d551
RD
3388 def SetGradientColours(self, fr, to, border):
3389 """ Sets the gradient colours for the tab. """
6cb4f153 3390
6a64d551
RD
3391 self._pages._colorFrom = fr
3392 self._pages._colorTo = to
3393 self._pages._colorBorder = border
6cb4f153 3394
6cb4f153 3395
6a64d551
RD
3396 def SetGradientColourFrom(self, fr):
3397 """ Sets the starting colour for the gradient. """
6cb4f153 3398
6a64d551 3399 self._pages._colorFrom = fr
6cb4f153 3400
6cb4f153 3401
6a64d551
RD
3402 def SetGradientColourTo(self, to):
3403 """ Sets the ending colour for the gradient. """
6cb4f153 3404
6a64d551 3405 self._pages._colorTo = to
6cb4f153 3406
6cb4f153 3407
6a64d551
RD
3408 def SetGradientColourBorder(self, border):
3409 """ Sets the tab border colour. """
6cb4f153 3410
6a64d551 3411 self._pages._colorBorder = border
6cb4f153 3412
6cb4f153 3413
6a64d551
RD
3414 def GetGradientColourFrom(self):
3415 """ Gets first gradient colour. """
6cb4f153 3416
6a64d551 3417 return self._pages._colorFrom
6cb4f153 3418
6cb4f153 3419
6a64d551
RD
3420 def GetGradientColourTo(self):
3421 """ Gets second gradient colour. """
6cb4f153 3422
6a64d551 3423 return self._pages._colorTo
6cb4f153 3424
6a64d551
RD
3425
3426 def GetGradientColourBorder(self):
3427 """ Gets the tab border colour. """
3428
3429 return self._pages._colorBorder
3430
3431
3432 def GetBorderColour(self):
3433 """ Returns the border colour. """
3434
3435 return self._pages._colorBorder
3436
3437
3438 def GetActiveTabTextColour(self):
3439 """ Get the active tab text colour. """
3440
3441 return self._pages._activeTextColor
3442
3443
33113971 3444 def SetPageImage(self, page, image):
6cb4f153 3445 """
6a64d551
RD
3446 Sets the image index for the given page. Image is an index into the
3447 image list which was set with SetImageList.
6cb4f153
RD
3448 """
3449
33113971 3450 self._pages.SetPageImage(page, image)
6cb4f153 3451
6cb4f153 3452
33113971 3453 def GetPageImage(self, nPage):
6a64d551
RD
3454 """
3455 Returns the image index for the given page. Image is an index into the
3456 image list which was set with SetImageList.
3457 """
6cb4f153 3458
33113971 3459 return self._pages.GetPageImage(nPage)
6cb4f153 3460
6cb4f153 3461
6a64d551
RD
3462 def GetEnabled(self, page):
3463 """ Returns whether a tab is enabled or not. """
6cb4f153 3464
6a64d551 3465 return self._pages.GetEnabled(page)
6cb4f153 3466
0a7f54ff 3467
6a64d551
RD
3468 def Enable(self, page, enabled=True):
3469 """ Enables or disables a tab. """
3470
3471 if page >= len(self._windows):
0a7f54ff 3472 return
6cb4f153 3473
6a64d551
RD
3474 self._windows[page].Enable(enabled)
3475 self._pages.Enable(page, enabled)
6cb4f153 3476
6cb4f153 3477
6a64d551
RD
3478 def GetNonActiveTabTextColour(self):
3479 """ Returns the non active tabs text colour. """
3480
3481 return self._pages._nonActiveTextColor
3482
3483
3484 def SetNonActiveTabTextColour(self, color):
3485 """ Sets the non active tabs text colour. """
3486
3487 self._pages._nonActiveTextColor = color
3488
3489
3490 def SetTabAreaColour(self, color):
3491 """ Sets the area behind the tabs colour. """
3492
3493 self._pages._tabAreaColor = color
3494
3495
3496 def GetTabAreaColour(self):
3497 """ Returns the area behind the tabs colour. """
3498
3499 return self._pages._tabAreaColor
3500
3501
3502 def SetActiveTabColour(self, color):
3503 """ Sets the active tab colour. """
3504
3505 self._pages._activeTabColor = color
3506
3507
3508 def GetActiveTabColour(self):
3509 """ Returns the active tab colour. """
3510
3511 return self._pages._activeTabColor
3512
3513
3514# ---------------------------------------------------------------------------- #
3515# Class PageContainer
3516# Acts as a container for the pages you add to FlatNotebook
3517# ---------------------------------------------------------------------------- #
3518
3519class PageContainer(wx.Panel):
3520 """
3521 This class acts as a container for the pages you add to L{FlatNotebook}.
3522 """
3523
3524 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
3525 size=wx.DefaultSize, style=0):
3526 """ Default class constructor. """
3527
3528 self._ImageList = None
3529 self._iActivePage = -1
3530 self._pDropTarget = None
3531 self._nLeftClickZone = FNB_NOWHERE
3532 self._iPreviousActivePage = -1
3533
3534 self._pRightClickMenu = None
6cb4f153 3535 self._nXButtonStatus = FNB_BTN_NONE
6a64d551
RD
3536 self._nArrowDownButtonStatus = FNB_BTN_NONE
3537 self._pParent = parent
6cb4f153 3538 self._nRightButtonStatus = FNB_BTN_NONE
6a64d551
RD
3539 self._nLeftButtonStatus = FNB_BTN_NONE
3540 self._nTabXButtonStatus = FNB_BTN_NONE
6cb4f153 3541
6a64d551 3542 self._pagesInfoVec = []
6cb4f153 3543
6a64d551
RD
3544 self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
3545 self._colorFrom = wx.WHITE
3546 self._activeTabColor = wx.WHITE
3547 self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
3548 self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
3549 self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
6cb4f153 3550
6a64d551
RD
3551 self._nFrom = 0
3552 self._isdragging = False
6cb4f153 3553
6a64d551
RD
3554 # Set default page height, this is done according to the system font
3555 memDc = wx.MemoryDC()
1c92f298 3556 memDc.SelectObject(wx.EmptyBitmap(1,1))
33113971
RD
3557
3558 if "__WXGTK__" in wx.PlatformInfo:
3559 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
3560 boldFont.SetWeight(wx.BOLD)
3561 memDc.SetFont(boldFont)
6a64d551
RD
3562
3563 height = memDc.GetCharHeight()
3564 tabHeight = height + FNB_HEIGHT_SPACER # We use 10 pixels as padding
3565
3566 wx.Panel.__init__(self, parent, id, pos, wx.Size(size.x, tabHeight),
3567 style|wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE)
6cb4f153 3568
6a64d551
RD
3569 self._pDropTarget = FNBDropTarget(self)
3570 self.SetDropTarget(self._pDropTarget)
3571 self._mgr = FNBRendererMgr()
3572
3573 self.Bind(wx.EVT_PAINT, self.OnPaint)
3574 self.Bind(wx.EVT_SIZE, self.OnSize)
3575 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
3576 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
3577 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
3578 self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
3579 self.Bind(wx.EVT_MOTION, self.OnMouseMove)
3580 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
3581 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
3582 self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
3583 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
6cb4f153 3584
6cb4f153 3585
6a64d551
RD
3586 def OnEraseBackground(self, event):
3587 """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
6cb4f153 3588
6a64d551 3589 pass
6cb4f153 3590
6a64d551 3591
37938059
RD
3592 def _ReShow(self):
3593 """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """
3594 self.Show()
3595 self.GetParent()._mainSizer.Layout()
3596 self.Refresh()
3597
3598
6a64d551
RD
3599 def OnPaint(self, event):
3600 """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
6cb4f153 3601
33113971 3602 dc = wx.BufferedPaintDC(self)
6a64d551
RD
3603 renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
3604 renderer.DrawTabs(self, dc)
6cb4f153 3605
37938059
RD
3606 if self.HasFlag(FNB_HIDE_ON_SINGLE_TAB) and len(self._pagesInfoVec) <= 1:
3607 self.Hide()
3608 self.GetParent()._mainSizer.Layout()
3609 self.Refresh()
3610
6cb4f153 3611
6a64d551
RD
3612 def AddPage(self, caption, selected=True, imgindex=-1):
3613 """
3614 Add a page to the L{FlatNotebook}.
6cb4f153 3615
6a64d551
RD
3616 @param window: Specifies the new page.
3617 @param caption: Specifies the text for the new page.
3618 @param selected: Specifies whether the page should be selected.
3619 @param imgindex: Specifies the optional image index for the new page.
6cb4f153 3620
6a64d551
RD
3621 Return value:
3622 True if successful, False otherwise.
3623 """
6cb4f153 3624
6a64d551 3625 if selected:
6cb4f153 3626
6a64d551
RD
3627 self._iPreviousActivePage = self._iActivePage
3628 self._iActivePage = len(self._pagesInfoVec)
3629
3630 # Create page info and add it to the vector
3631 pageInfo = PageInfo(caption, imgindex)
3632 self._pagesInfoVec.append(pageInfo)
3633 self.Refresh()
6cb4f153 3634
6cb4f153 3635
6a64d551
RD
3636 def InsertPage(self, indx, text, selected=True, imgindex=-1):
3637 """
3638 Inserts a new page at the specified position.
6cb4f153 3639
6a64d551
RD
3640 @param indx: Specifies the position of the new page.
3641 @param page: Specifies the new page.
3642 @param text: Specifies the text for the new page.
3643 @param select: Specifies whether the page should be selected.
3644 @param imgindex: Specifies the optional image index for the new page.
3645
3646 Return value:
3647 True if successful, False otherwise.
3648 """
6cb4f153 3649
6a64d551 3650 if selected:
6cb4f153 3651
6a64d551
RD
3652 self._iPreviousActivePage = self._iActivePage
3653 self._iActivePage = len(self._pagesInfoVec)
6cb4f153 3654
6a64d551 3655 self._pagesInfoVec.insert(indx, PageInfo(text, imgindex))
6cb4f153 3656
6a64d551
RD
3657 self.Refresh()
3658 return True
6cb4f153 3659
6cb4f153 3660
6a64d551
RD
3661 def OnSize(self, event):
3662 """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
6cb4f153 3663
6231770f
RD
3664 # When resizing the control, try to fit to screen as many tabs as we can
3665 style = self.GetParent().GetWindowStyleFlag()
3666 renderer = self._mgr.GetRenderer(style)
3667
3668 fr = 0
3669 page = self.GetSelection()
3670
3671 for fr in xrange(self._nFrom):
3672 vTabInfo = renderer.NumberTabsCanFit(self, fr)
3673 if page - fr >= len(vTabInfo):
3674 continue
3675 break
3676
3677 self._nFrom = fr
3678
6a64d551
RD
3679 self.Refresh() # Call on paint
3680 event.Skip()
6cb4f153
RD
3681
3682
6a64d551
RD
3683 def OnMiddleDown(self, event):
3684 """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
6cb4f153 3685
6a64d551
RD
3686 # Test if this style is enabled
3687 style = self.GetParent().GetWindowStyleFlag()
3688
3689 if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS:
6cb4f153
RD
3690 return
3691
6a64d551 3692 where, tabIdx = self.HitTest(event.GetPosition())
6cb4f153 3693
6a64d551
RD
3694 if where == FNB_TAB:
3695 self.DeletePage(tabIdx)
3696
3697 event.Skip()
6cb4f153 3698
6cb4f153 3699
6a64d551
RD
3700 def OnRightDown(self, event):
3701 """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
6cb4f153 3702
6231770f 3703 where, tabIdx = self.HitTest(event.GetPosition())
6cb4f153 3704
6231770f 3705 if where in [FNB_TAB, FNB_TAB_X]:
6cb4f153 3706
6231770f
RD
3707 if self._pagesInfoVec[tabIdx].GetEnabled():
3708 # Fire events and eventually (if allowed) change selection
3709 self.FireEvent(tabIdx)
3710
3711 # send a message to popup a custom menu
3712 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId())
3713 event.SetSelection(tabIdx)
3714 event.SetOldSelection(self._iActivePage)
3715 event.SetEventObject(self.GetParent())
3716 self.GetParent().GetEventHandler().ProcessEvent(event)
3717
3718 if self._pRightClickMenu:
3719 self.PopupMenu(self._pRightClickMenu)
3720
3721 event.Skip()
6cb4f153 3722
6cb4f153 3723
6a64d551
RD
3724 def OnLeftDown(self, event):
3725 """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
6cb4f153 3726
6a64d551
RD
3727 # Reset buttons status
3728 self._nXButtonStatus = FNB_BTN_NONE
3729 self._nLeftButtonStatus = FNB_BTN_NONE
3730 self._nRightButtonStatus = FNB_BTN_NONE
3731 self._nTabXButtonStatus = FNB_BTN_NONE
3732 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 3733
6a64d551 3734 self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition())
6cb4f153 3735
6a64d551
RD
3736 if self._nLeftClickZone == FNB_DROP_DOWN_ARROW:
3737 self._nArrowDownButtonStatus = FNB_BTN_PRESSED
3738 self.Refresh()
3739 elif self._nLeftClickZone == FNB_LEFT_ARROW:
3740 self._nLeftButtonStatus = FNB_BTN_PRESSED
3741 self.Refresh()
3742 elif self._nLeftClickZone == FNB_RIGHT_ARROW:
3743 self._nRightButtonStatus = FNB_BTN_PRESSED
3744 self.Refresh()
3745 elif self._nLeftClickZone == FNB_X:
3746 self._nXButtonStatus = FNB_BTN_PRESSED
3747 self.Refresh()
3748 elif self._nLeftClickZone == FNB_TAB_X:
3749 self._nTabXButtonStatus = FNB_BTN_PRESSED
3750 self.Refresh()
6cb4f153 3751
6a64d551
RD
3752 elif self._nLeftClickZone == FNB_TAB:
3753
3754 if self._iActivePage != tabIdx:
33113971 3755
6a64d551
RD
3756 # In case the tab is disabled, we dont allow to choose it
3757 if self._pagesInfoVec[tabIdx].GetEnabled():
33113971 3758 self.FireEvent(tabIdx)
6cb4f153 3759
6cb4f153 3760
6a64d551
RD
3761 def OnLeftUp(self, event):
3762 """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
6cb4f153 3763
6a64d551
RD
3764 # forget the zone that was initially clicked
3765 self._nLeftClickZone = FNB_NOWHERE
3766
3767 where, tabIdx = self.HitTest(event.GetPosition())
3768
3769 if where == FNB_LEFT_ARROW:
6cb4f153 3770
6a64d551
RD
3771 if self._nFrom == 0:
3772 return
6cb4f153 3773
6a64d551
RD
3774 # Make sure that the button was pressed before
3775 if self._nLeftButtonStatus != FNB_BTN_PRESSED:
3776 return
6cb4f153 3777
6a64d551 3778 self._nLeftButtonStatus = FNB_BTN_HOVER
6cb4f153 3779
6a64d551
RD
3780 # We scroll left with bulks of 5
3781 scrollLeft = self.GetNumTabsCanScrollLeft()
6cb4f153 3782
6a64d551
RD
3783 self._nFrom -= scrollLeft
3784 if self._nFrom < 0:
3785 self._nFrom = 0
6cb4f153 3786
6a64d551
RD
3787 self.Refresh()
3788
3789 elif where == FNB_RIGHT_ARROW:
3790
3791 if self._nFrom >= len(self._pagesInfoVec) - 1:
3792 return
6cb4f153 3793
6a64d551
RD
3794 # Make sure that the button was pressed before
3795 if self._nRightButtonStatus != FNB_BTN_PRESSED:
3796 return
3797
3798 self._nRightButtonStatus = FNB_BTN_HOVER
3799
3800 # Check if the right most tab is visible, if it is
3801 # don't rotate right anymore
3802 if self._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
3803 return
6cb4f153 3804
6a64d551
RD
3805 lastVisibleTab = self.GetLastVisibleTab()
3806 if lastVisibleTab < 0:
3807 # Probably the screen is too small for displaying even a single
3808 # tab, in this case we do nothing
3809 return
6cb4f153 3810
6a64d551
RD
3811 self._nFrom += self.GetNumOfVisibleTabs()
3812 self.Refresh()
3813
3814 elif where == FNB_X:
3815
3816 # Make sure that the button was pressed before
3817 if self._nXButtonStatus != FNB_BTN_PRESSED:
3818 return
6cb4f153 3819
6a64d551 3820 self._nXButtonStatus = FNB_BTN_HOVER
6cb4f153 3821
6a64d551
RD
3822 self.DeletePage(self._iActivePage)
3823
3824 elif where == FNB_TAB_X:
3825
3826 # Make sure that the button was pressed before
3827 if self._nTabXButtonStatus != FNB_BTN_PRESSED:
3828 return
6cb4f153 3829
6a64d551 3830 self._nTabXButtonStatus = FNB_BTN_HOVER
6cb4f153 3831
6a64d551 3832 self.DeletePage(self._iActivePage)
6cb4f153 3833
6a64d551 3834 elif where == FNB_DROP_DOWN_ARROW:
6cb4f153 3835
6a64d551
RD
3836 # Make sure that the button was pressed before
3837 if self._nArrowDownButtonStatus != FNB_BTN_PRESSED:
3838 return
6cb4f153 3839
6a64d551 3840 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 3841
6a64d551
RD
3842 # Refresh the button status
3843 renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
3844 dc = wx.ClientDC(self)
3845 renderer.DrawDropDownArrow(self, dc)
6cb4f153 3846
6a64d551 3847 self.PopupTabsMenu()
6cb4f153
RD
3848
3849
6a64d551
RD
3850 def HitTest(self, pt):
3851 """
3852 HitTest method for L{PageContainer}.
3853 Returns the flag (if any) and the hit page (if any).
3854 """
6cb4f153
RD
3855
3856 style = self.GetParent().GetWindowStyleFlag()
6a64d551 3857 render = self._mgr.GetRenderer(style)
6cb4f153 3858
6a64d551
RD
3859 fullrect = self.GetClientRect()
3860 btnLeftPos = render.GetLeftButtonPos(self)
3861 btnRightPos = render.GetRightButtonPos(self)
3862 btnXPos = render.GetXPos(self)
3863
3864 tabIdx = -1
3865
3866 if len(self._pagesInfoVec) == 0:
3867 return FNB_NOWHERE, tabIdx
6cb4f153 3868
6a64d551
RD
3869 rect = wx.Rect(btnXPos, 8, 16, 16)
3870 if rect.Contains(pt):
3871 return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], tabIdx
6cb4f153 3872
6a64d551
RD
3873 rect = wx.Rect(btnRightPos, 8, 16, 16)
3874 if style & FNB_DROPDOWN_TABS_LIST:
3875 rect = wx.Rect(render.GetDropArrowButtonPos(self), 8, 16, 16)
3876 if rect.Contains(pt):
3877 return FNB_DROP_DOWN_ARROW, tabIdx
6cb4f153 3878
6a64d551
RD
3879 if rect.Contains(pt):
3880 return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], tabIdx
6cb4f153 3881
6a64d551
RD
3882 rect = wx.Rect(btnLeftPos, 8, 16, 16)
3883 if rect.Contains(pt):
3884 return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], tabIdx
6cb4f153 3885
6a64d551
RD
3886 # Test whether a left click was made on a tab
3887 bFoundMatch = False
6cb4f153 3888
6a64d551 3889 for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
6cb4f153 3890
6a64d551 3891 pgInfo = self._pagesInfoVec[cur]
6cb4f153 3892
6a64d551
RD
3893 if pgInfo.GetPosition() == wx.Point(-1, -1):
3894 continue
6cb4f153 3895
6a64d551
RD
3896 if style & FNB_X_ON_TAB and cur == self.GetSelection():
3897 # 'x' button exists on a tab
3898 if self._pagesInfoVec[cur].GetXRect().Contains(pt):
3899 return FNB_TAB_X, cur
3900
3901 if style & FNB_VC8:
6cb4f153 3902
6a64d551
RD
3903 if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y):
3904 if bFoundMatch or cur == self.GetSelection():
3905 return FNB_TAB, cur
6cb4f153 3906
6a64d551
RD
3907 tabIdx = cur
3908 bFoundMatch = True
3909
6cb4f153 3910 else:
6a64d551
RD
3911
3912 tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y,
3913 pgInfo.GetSize().x, pgInfo.GetSize().y)
6cb4f153 3914
6a64d551
RD
3915 if tabRect.Contains(pt):
3916 # We have a match
3917 return FNB_TAB, cur
6cb4f153 3918
6a64d551
RD
3919 if bFoundMatch:
3920 return FNB_TAB, tabIdx
6cb4f153 3921
6a64d551
RD
3922 if self._isdragging:
3923 # We are doing DND, so check also the region outside the tabs
3924 # try before the first tab
3925 pgInfo = self._pagesInfoVec[0]
3926 tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
3927 if tabRect.Contains(pt):
3928 return FNB_TAB, 0
6cb4f153 3929
6a64d551
RD
3930 # try after the last tab
3931 pgInfo = self._pagesInfoVec[-1]
3932 startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
3933 tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
6cb4f153 3934
6a64d551
RD
3935 if tabRect.Contains(pt):
3936 return FNB_TAB, len(self._pagesInfoVec)
6cb4f153 3937
6a64d551
RD
3938 # Default
3939 return FNB_NOWHERE, -1
6cb4f153
RD
3940
3941
6a64d551
RD
3942 def SetSelection(self, page):
3943 """ Sets the selected page. """
6cb4f153 3944
6a64d551
RD
3945 book = self.GetParent()
3946 book.SetSelection(page)
3947 self.DoSetSelection(page)
6cb4f153
RD
3948
3949
6a64d551
RD
3950 def DoSetSelection(self, page):
3951 """ Does the actual selection of a page. """
6cb4f153 3952
6a64d551
RD
3953 if page < len(self._pagesInfoVec):
3954 #! fix for tabfocus
3955 da_page = self._pParent.GetPage(page)
3956
3957 if da_page != None:
3958 da_page.SetFocus()
6cb4f153 3959
6a64d551 3960 if not self.IsTabVisible(page):
6231770f
RD
3961 # Try to remove one tab from start and try again
3962
3963 if not self.CanFitToScreen(page):
6cb4f153 3964
6231770f 3965 if self._nFrom > page:
6a64d551 3966 self._nFrom = page
6231770f
RD
3967 else:
3968 while self._nFrom < page:
3969 self._nFrom += 1
3970 if self.CanFitToScreen(page):
3971 break
3972
6a64d551 3973 self.Refresh()
6cb4f153 3974
6cb4f153 3975
6a64d551
RD
3976 def DeletePage(self, page):
3977 """ Delete the specified page from L{FlatNotebook}. """
6cb4f153 3978
6a64d551
RD
3979 book = self.GetParent()
3980 book.DeletePage(page)
3981 book.Refresh()
6cb4f153 3982
6cb4f153 3983
6a64d551
RD
3984 def IsTabVisible(self, page):
3985 """ Returns whether a tab is visible or not. """
6cb4f153 3986
6a64d551
RD
3987 iLastVisiblePage = self.GetLastVisibleTab()
3988 return page <= iLastVisiblePage and page >= self._nFrom
6cb4f153 3989
6cb4f153 3990
6a64d551
RD
3991 def DoDeletePage(self, page):
3992 """ Does the actual page deletion. """
6cb4f153 3993
6a64d551
RD
3994 # Remove the page from the vector
3995 book = self.GetParent()
3996 self._pagesInfoVec.pop(page)
6cb4f153 3997
6a64d551
RD
3998 # Thanks to Yiaanis AKA Mandrav
3999 if self._iActivePage >= page:
4000 self._iActivePage = self._iActivePage - 1
4001 self._iPreviousActivePage = -1
6cb4f153 4002
6a64d551
RD
4003 # The delete page was the last first on the array,
4004 # but the book still has more pages, so we set the
4005 # active page to be the first one (0)
4006 if self._iActivePage < 0 and len(self._pagesInfoVec) > 0:
4007 self._iActivePage = 0
4008 self._iPreviousActivePage = -1
6cb4f153 4009
6a64d551
RD
4010 # Refresh the tabs
4011 if self._iActivePage >= 0:
6cb4f153 4012
6a64d551 4013 book._bForceSelection = True
6cb4f153 4014
6a64d551
RD
4015 # Check for selection and send event
4016 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
4017 event.SetSelection(self._iActivePage)
4018 event.SetOldSelection(self._iPreviousActivePage)
4019 event.SetEventObject(self.GetParent())
6cb4f153 4020
6a64d551
RD
4021 book.SetSelection(self._iActivePage)
4022 book._bForceSelection = False
6cb4f153 4023
6a64d551
RD
4024 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4025 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
4026 event.SetOldSelection(self._iPreviousActivePage)
4027 self.GetParent().GetEventHandler().ProcessEvent(event)
4028
4029 if not self._pagesInfoVec:
4030 # Erase the page container drawings
4031 dc = wx.ClientDC(self)
4032 dc.Clear()
6cb4f153 4033
6cb4f153 4034
6a64d551
RD
4035 def DeleteAllPages(self):
4036 """ Deletes all the pages. """
6cb4f153 4037
6a64d551
RD
4038 self._iActivePage = -1
4039 self._iPreviousActivePage = -1
4040 self._nFrom = 0
4041 self._pagesInfoVec = []
6cb4f153 4042
6a64d551
RD
4043 # Erase the page container drawings
4044 dc = wx.ClientDC(self)
4045 dc.Clear()
6cb4f153 4046
6cb4f153 4047
6a64d551
RD
4048 def OnMouseMove(self, event):
4049 """ Handles the wx.EVT_MOTION for L{PageContainer}. """
6cb4f153 4050
6a64d551 4051 if self._pagesInfoVec and self.IsShown():
6cb4f153 4052
6a64d551
RD
4053 xButtonStatus = self._nXButtonStatus
4054 xTabButtonStatus = self._nTabXButtonStatus
4055 rightButtonStatus = self._nRightButtonStatus
4056 leftButtonStatus = self._nLeftButtonStatus
4057 dropDownButtonStatus = self._nArrowDownButtonStatus
4058
4059 style = self.GetParent().GetWindowStyleFlag()
6cb4f153 4060
6a64d551
RD
4061 self._nXButtonStatus = FNB_BTN_NONE
4062 self._nRightButtonStatus = FNB_BTN_NONE
4063 self._nLeftButtonStatus = FNB_BTN_NONE
4064 self._nTabXButtonStatus = FNB_BTN_NONE
4065 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 4066
6a64d551
RD
4067 where, tabIdx = self.HitTest(event.GetPosition())
4068
4069 if where == FNB_X:
4070 if event.LeftIsDown():
4071
4072 self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4073
4074 else:
4075
4076 self._nXButtonStatus = FNB_BTN_HOVER
6cb4f153 4077
6a64d551
RD
4078 elif where == FNB_DROP_DOWN_ARROW:
4079 if event.LeftIsDown():
6cb4f153 4080
6a64d551 4081 self._nArrowDownButtonStatus = (self._nLeftClickZone==FNB_DROP_DOWN_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
6cb4f153 4082
6a64d551 4083 else:
6cb4f153 4084
6a64d551 4085 self._nArrowDownButtonStatus = FNB_BTN_HOVER
6cb4f153 4086
6a64d551
RD
4087 elif where == FNB_TAB_X:
4088 if event.LeftIsDown():
4089
4090 self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4091
4092 else:
6cb4f153 4093
6a64d551
RD
4094 self._nTabXButtonStatus = FNB_BTN_HOVER
4095
4096 elif where == FNB_RIGHT_ARROW:
4097 if event.LeftIsDown():
4098
4099 self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4100
4101 else:
4102
4103 self._nRightButtonStatus = FNB_BTN_HOVER
4104
4105 elif where == FNB_LEFT_ARROW:
4106 if event.LeftIsDown():
4107
4108 self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4109
4110 else:
4111
4112 self._nLeftButtonStatus = FNB_BTN_HOVER
4113
4114 elif where == FNB_TAB:
4115 # Call virtual method for showing tooltip
4116 self.ShowTabTooltip(tabIdx)
4117
4118 if not self.GetEnabled(tabIdx):
4119 # Set the cursor to be 'No-entry'
4120 wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
4121
4122 # Support for drag and drop
33113971 4123 if event.Dragging() and not (style & FNB_NODRAG):
6cb4f153 4124
6a64d551
RD
4125 self._isdragging = True
4126 draginfo = FNBDragInfo(self, tabIdx)
4127 drginfo = cPickle.dumps(draginfo)
4128 dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
4129 dataobject.SetData(drginfo)
33113971 4130 dragSource = FNBDropSource(self)
6a64d551
RD
4131 dragSource.SetData(dataobject)
4132 dragSource.DoDragDrop(wx.Drag_DefaultMove)
4133
4134 bRedrawX = self._nXButtonStatus != xButtonStatus
4135 bRedrawRight = self._nRightButtonStatus != rightButtonStatus
4136 bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus
4137 bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus
4138 bRedrawDropArrow = self._nArrowDownButtonStatus != dropDownButtonStatus
6cb4f153 4139
6a64d551 4140 render = self._mgr.GetRenderer(style)
6cb4f153 4141
6a64d551 4142 if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX or bRedrawDropArrow):
6cb4f153 4143
6a64d551
RD
4144 dc = wx.ClientDC(self)
4145
4146 if bRedrawX:
4147
4148 render.DrawX(self, dc)
4149
4150 if bRedrawLeft:
4151
4152 render.DrawLeftArrow(self, dc)
4153
4154 if bRedrawRight:
4155
4156 render.DrawRightArrow(self, dc)
4157
4158 if bRedrawTabX:
4159
4160 render.DrawTabX(self, dc, self._pagesInfoVec[tabIdx].GetXRect(), tabIdx, self._nTabXButtonStatus)
6cb4f153 4161
6a64d551 4162 if bRedrawDropArrow:
6cb4f153 4163
6a64d551 4164 render.DrawDropDownArrow(self, dc)
6cb4f153 4165
6a64d551 4166 event.Skip()
6cb4f153 4167
6cb4f153 4168
6a64d551
RD
4169 def GetLastVisibleTab(self):
4170 """ Returns the last visible tab. """
6cb4f153 4171
6231770f
RD
4172 if self._nFrom < 0:
4173 return -1
4174
6a64d551 4175 ii = 0
6cb4f153 4176
6a64d551 4177 for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
6cb4f153 4178
6a64d551 4179 if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
6cb4f153 4180 break
6cb4f153 4181
6a64d551
RD
4182 return ii-1
4183
6cb4f153
RD
4184
4185 def GetNumTabsCanScrollLeft(self):
4186 """ Returns the number of tabs than can be scrolled left. """
4187
4188 # Reserved area for the buttons (<>x)
4189 rect = self.GetClientRect()
4190 clientWidth = rect.width
6a64d551 4191 posx = self._pParent._nPadding
6cb4f153
RD
4192 numTabs = 0
4193 pom = 0
6a64d551
RD
4194
4195 # In case we have error prevent crash
6cb4f153
RD
4196 if self._nFrom < 0:
4197 return 0
4198
6a64d551
RD
4199 dc = wx.ClientDC(self)
4200
6cb4f153 4201 style = self.GetParent().GetWindowStyleFlag()
6a64d551 4202 render = self._mgr.GetRenderer(style)
6cb4f153 4203
6a64d551
RD
4204 for ii in xrange(self._nFrom, -1, -1):
4205
4206 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
6cb4f153
RD
4207 boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
4208 dc.SetFont(boldFont)
4209
6a64d551 4210 height = dc.GetCharHeight()
6cb4f153
RD
4211
4212 tabHeight = height + FNB_HEIGHT_SPACER # We use 6 pixels as padding
6cb4f153 4213 if style & FNB_VC71:
6a64d551 4214 tabHeight = (style & FNB_BOTTOM and [tabHeight - 4] or [tabHeight])[0]
6cb4f153 4215 elif style & FNB_FANCY_TABS:
6a64d551 4216 tabHeight = (style & FNB_BOTTOM and [tabHeight - 3] or [tabHeight])[0]
6cb4f153 4217
6a64d551 4218 width, pom = dc.GetTextExtent(self.GetPageText(ii))
6cb4f153 4219 if style != FNB_VC71:
6a64d551 4220 shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[ii].GetTabAngle())/180.0*math.pi))
6cb4f153
RD
4221 else:
4222 shapePoints = 0
4223
6a64d551
RD
4224 tabWidth = 2*self._pParent._nPadding + width
4225
4226 if not (style & FNB_VC71):
6cb4f153
RD
4227 # Default style
4228 tabWidth += 2*shapePoints
4229
6a64d551
RD
4230 hasImage = self._ImageList != None and self._pagesInfoVec[ii].GetImageIndex() != -1
4231
6cb4f153 4232 # For VC71 style, we only add the icon size (16 pixels)
6a64d551 4233 if hasImage:
6cb4f153
RD
4234
4235 if not self.IsDefaultTabs():
6a64d551 4236 tabWidth += 16 + self._pParent._nPadding
6cb4f153
RD
4237 else:
4238 # Default style
6a64d551 4239 tabWidth += 16 + self._pParent._nPadding + shapePoints/2
6cb4f153 4240
6a64d551
RD
4241 if posx + tabWidth + render.GetButtonsAreaLength(self) >= clientWidth:
4242 break
6cb4f153 4243
6a64d551
RD
4244 numTabs = numTabs + 1
4245 posx += tabWidth
6cb4f153 4246
6a64d551 4247 return numTabs
6cb4f153
RD
4248
4249
6a64d551
RD
4250 def IsDefaultTabs(self):
4251 """ Returns whether a tab has a default style. """
4252
4253 style = self.GetParent().GetWindowStyleFlag()
4254 res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8)
4255 return not res
4256
4257
4258 def AdvanceSelection(self, bForward=True):
6cb4f153 4259 """
6a64d551
RD
4260 Cycles through the tabs.
4261 The call to this function generates the page changing events.
6cb4f153
RD
4262 """
4263
6a64d551 4264 nSel = self.GetSelection()
6cb4f153 4265
6a64d551
RD
4266 if nSel < 0:
4267 return
6cb4f153 4268
6a64d551 4269 nMax = self.GetPageCount() - 1
6cb4f153 4270
6a64d551
RD
4271 if bForward:
4272 newSelection = (nSel == nMax and [0] or [nSel + 1])[0]
4273 else:
4274 newSelection = (nSel == 0 and [nMax] or [nSel - 1])[0]
6cb4f153 4275
6a64d551
RD
4276 if not self._pagesInfoVec[newSelection].GetEnabled():
4277 return
6cb4f153 4278
33113971 4279 self.FireEvent(newSelection)
6cb4f153 4280
6cb4f153 4281
6a64d551
RD
4282 def OnMouseLeave(self, event):
4283 """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
6cb4f153 4284
6a64d551
RD
4285 self._nLeftButtonStatus = FNB_BTN_NONE
4286 self._nXButtonStatus = FNB_BTN_NONE
4287 self._nRightButtonStatus = FNB_BTN_NONE
4288 self._nTabXButtonStatus = FNB_BTN_NONE
4289 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 4290
6a64d551
RD
4291 style = self.GetParent().GetWindowStyleFlag()
4292 render = self._mgr.GetRenderer(style)
6cb4f153 4293
6a64d551 4294 dc = wx.ClientDC(self)
6cb4f153 4295
6a64d551
RD
4296 render.DrawX(self, dc)
4297 render.DrawLeftArrow(self, dc)
4298 render.DrawRightArrow(self, dc)
6cb4f153 4299
6a64d551 4300 selection = self.GetSelection()
6cb4f153 4301
6a64d551
RD
4302 if selection == -1:
4303 event.Skip()
4304 return
6cb4f153 4305
6a64d551
RD
4306 if not self.IsTabVisible(selection):
4307 if selection == len(self._pagesInfoVec) - 1:
4308 if not self.CanFitToScreen(selection):
4309 event.Skip()
4310 return
4311 else:
4312 event.Skip()
4313 return
4314
4315 render.DrawTabX(self, dc, self._pagesInfoVec[selection].GetXRect(), selection, self._nTabXButtonStatus)
4316
4317 event.Skip()
6cb4f153 4318
6cb4f153 4319
6a64d551
RD
4320 def OnMouseEnterWindow(self, event):
4321 """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
6cb4f153 4322
6a64d551
RD
4323 self._nLeftButtonStatus = FNB_BTN_NONE
4324 self._nXButtonStatus = FNB_BTN_NONE
4325 self._nRightButtonStatus = FNB_BTN_NONE
4326 self._nLeftClickZone = FNB_BTN_NONE
4327 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 4328
6a64d551 4329 event.Skip()
6cb4f153 4330
6cb4f153 4331
6a64d551
RD
4332 def ShowTabTooltip(self, tabIdx):
4333 """ Shows a tab tooltip. """
6cb4f153 4334
6a64d551 4335 pWindow = self._pParent.GetPage(tabIdx)
6cb4f153 4336
6a64d551
RD
4337 if pWindow:
4338 pToolTip = pWindow.GetToolTip()
4339 if pToolTip and pToolTip.GetWindow() == pWindow:
4340 self.SetToolTipString(pToolTip.GetTip())
6cb4f153 4341
6cb4f153 4342
6a64d551
RD
4343 def SetPageImage(self, page, imgindex):
4344 """ Sets the image index associated to a page. """
6cb4f153 4345
6a64d551
RD
4346 if page < len(self._pagesInfoVec):
4347
4348 self._pagesInfoVec[page].SetImageIndex(imgindex)
4349 self.Refresh()
6cb4f153 4350
6cb4f153 4351
6a64d551
RD
4352 def GetPageImage(self, page):
4353 """ Returns the image index associated to a page. """
6cb4f153 4354
6a64d551
RD
4355 if page < len(self._pagesInfoVec):
4356
4357 return self._pagesInfoVec[page].GetImageIndex()
4358
4359 return -1
6cb4f153 4360
6cb4f153 4361
6a64d551
RD
4362 def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
4363 """ Handles the drop action from a DND operation. """
6cb4f153 4364
6a64d551
RD
4365 # Disable drag'n'drop for disabled tab
4366 if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled():
4367 return wx.DragCancel
6cb4f153 4368
6a64d551
RD
4369 self._isdragging = True
4370 oldContainer = wnd_oldContainer
4371 nIndex = -1
6cb4f153 4372
6a64d551 4373 where, nIndex = self.HitTest(wx.Point(x, y))
6cb4f153 4374
6a64d551
RD
4375 oldNotebook = oldContainer.GetParent()
4376 newNotebook = self.GetParent()
6cb4f153 4377
6a64d551
RD
4378 if oldNotebook == newNotebook:
4379
4380 if nTabPage >= 0:
6cb4f153 4381
6a64d551
RD
4382 if where == FNB_TAB:
4383 self.MoveTabPage(nTabPage, nIndex)
33113971 4384
6a64d551
RD
4385 elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND:
4386
cbfc9df6 4387 if wx.Platform in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]:
6a64d551
RD
4388 if nTabPage >= 0:
4389
4390 window = oldNotebook.GetPage(nTabPage)
6cb4f153 4391
6a64d551
RD
4392 if window:
4393 where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y))
4394 caption = oldContainer.GetPageText(nTabPage)
4395 imageindex = oldContainer.GetPageImage(nTabPage)
4396 oldNotebook.RemovePage(nTabPage)
4397 window.Reparent(newNotebook)
6cb4f153 4398
6a64d551
RD
4399 if imageindex >= 0:
4400
33113971 4401 bmp = oldNotebook.GetImageList().GetIcon(imageindex)
6a64d551
RD
4402 newImageList = newNotebook.GetImageList()
4403
4404 if not newImageList:
4405 xbmp, ybmp = bmp.GetWidth(), bmp.GetHeight()
4406 newImageList = wx.ImageList(xbmp, ybmp)
4407 imageindex = 0
4408 else:
4409 imageindex = newImageList.GetImageCount()
4410
33113971 4411 newImageList.AddIcon(bmp)
6a64d551
RD
4412 newNotebook.SetImageList(newImageList)
4413
4414 newNotebook.InsertPage(nIndex, window, caption, True, imageindex)
4415
4416 self._isdragging = False
6cb4f153 4417
6a64d551 4418 return wx.DragMove
6cb4f153 4419
6cb4f153 4420
6a64d551
RD
4421 def MoveTabPage(self, nMove, nMoveTo):
4422 """ Moves a tab inside the same L{FlatNotebook}. """
6cb4f153 4423
6a64d551
RD
4424 if nMove == nMoveTo:
4425 return
6cb4f153 4426
6a64d551
RD
4427 elif nMoveTo < len(self._pParent._windows):
4428 nMoveTo = nMoveTo + 1
6cb4f153 4429
6a64d551
RD
4430 self._pParent.Freeze()
4431
4432 # Remove the window from the main sizer
4433 nCurSel = self._pParent._pages.GetSelection()
4434 self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel])
4435 self._pParent._windows[nCurSel].Hide()
6cb4f153 4436
6a64d551
RD
4437 pWindow = self._pParent._windows[nMove]
4438 self._pParent._windows.pop(nMove)
4439 self._pParent._windows.insert(nMoveTo-1, pWindow)
6cb4f153 4440
6a64d551 4441 pgInfo = self._pagesInfoVec[nMove]
6cb4f153 4442
6a64d551
RD
4443 self._pagesInfoVec.pop(nMove)
4444 self._pagesInfoVec.insert(nMoveTo - 1, pgInfo)
6cb4f153 4445
6a64d551
RD
4446 # Add the page according to the style
4447 pSizer = self._pParent._mainSizer
4448 style = self.GetParent().GetWindowStyleFlag()
4449
4450 if style & FNB_BOTTOM:
6cb4f153 4451
6a64d551 4452 pSizer.Insert(0, pWindow, 1, wx.EXPAND)
6cb4f153 4453
6a64d551
RD
4454 else:
4455
4456 # We leave a space of 1 pixel around the window
4457 pSizer.Add(pWindow, 1, wx.EXPAND)
4458
4459 pWindow.Show()
4460
4461 pSizer.Layout()
4462 self._iActivePage = nMoveTo - 1
4463 self._iPreviousActivePage = -1
4464 self.DoSetSelection(self._iActivePage)
4465 self.Refresh()
4466 self._pParent.Thaw()
4467
4468
4469 def CanFitToScreen(self, page):
4470 """ Returns wheter a tab can fit in the left space in the screen or not. """
4471
4472 # Incase the from is greater than page,
4473 # we need to reset the self._nFrom, so in order
4474 # to force the caller to do so, we return false
4475 if self._nFrom > page:
4476 return False
6cb4f153 4477
6a64d551
RD
4478 style = self.GetParent().GetWindowStyleFlag()
4479 render = self._mgr.GetRenderer(style)
6cb4f153 4480
6231770f 4481 vTabInfo = render.NumberTabsCanFit(self)
6cb4f153 4482
6231770f
RD
4483 if page - self._nFrom >= len(vTabInfo):
4484 return False
4485
4486 return True
6cb4f153 4487
6cb4f153 4488
6a64d551
RD
4489 def GetNumOfVisibleTabs(self):
4490 """ Returns the number of visible tabs. """
6cb4f153 4491
6a64d551
RD
4492 count = 0
4493 for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
4494 if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
4495 break
4496 count = count + 1
6cb4f153 4497
6a64d551 4498 return count
6cb4f153 4499
6cb4f153 4500
6a64d551
RD
4501 def GetEnabled(self, page):
4502 """ Returns whether a tab is enabled or not. """
6cb4f153 4503
6a64d551
RD
4504 if page >= len(self._pagesInfoVec):
4505 return True # Seems strange, but this is the default
6cb4f153 4506
6a64d551 4507 return self._pagesInfoVec[page].GetEnabled()
6cb4f153 4508
6cb4f153 4509
6a64d551
RD
4510 def Enable(self, page, enabled=True):
4511 """ Enables or disables a tab. """
4512
4513 if page >= len(self._pagesInfoVec):
4514 return
6cb4f153 4515
6a64d551 4516 self._pagesInfoVec[page].Enable(enabled)
6cb4f153
RD
4517
4518
6a64d551
RD
4519 def GetSingleLineBorderColour(self):
4520 """ Returns the colour for the single line border. """
6cb4f153 4521
6a64d551
RD
4522 if self.HasFlag(FNB_FANCY_TABS):
4523 return self._colorFrom
6cb4f153 4524
6a64d551 4525 return wx.WHITE
6cb4f153 4526
6cb4f153 4527
6a64d551
RD
4528 def HasFlag(self, flag):
4529 """ Returns whether a flag is present in the L{FlatNotebook} style. """
6cb4f153 4530
6a64d551
RD
4531 style = self.GetParent().GetWindowStyleFlag()
4532 res = (style & flag and [True] or [False])[0]
4533 return res
6cb4f153 4534
6cb4f153 4535
6a64d551
RD
4536 def ClearFlag(self, flag):
4537 """ Deletes a flag from the L{FlatNotebook} style. """
6cb4f153 4538
6a64d551
RD
4539 style = self.GetParent().GetWindowStyleFlag()
4540 style &= ~flag
4541 self.SetWindowStyleFlag(style)
6cb4f153
RD
4542
4543
6a64d551
RD
4544 def TabHasImage(self, tabIdx):
4545 """ Returns whether a tab has an associated image index or not. """
6cb4f153 4546
6a64d551
RD
4547 if self._ImageList:
4548 return self._pagesInfoVec[tabIdx].GetImageIndex() != -1
4549
4550 return False
6cb4f153 4551
6cb4f153 4552
6a64d551
RD
4553 def OnLeftDClick(self, event):
4554 """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
4555
4556 if self.HasFlag(FNB_DCLICK_CLOSES_TABS):
6cb4f153 4557
6a64d551
RD
4558 where, tabIdx = self.HitTest(event.GetPosition())
4559
4560 if where == FNB_TAB:
4561 self.DeletePage(tabIdx)
6cb4f153 4562
6cb4f153 4563 else:
6a64d551
RD
4564
4565 event.Skip()
4566
6cb4f153 4567
6a64d551
RD
4568 def PopupTabsMenu(self):
4569 """ Pops up the menu activated with the drop down arrow in the navigation area. """
6cb4f153 4570
6a64d551 4571 popupMenu = wx.Menu()
6cb4f153 4572
6a64d551
RD
4573 for i in xrange(len(self._pagesInfoVec)):
4574 pi = self._pagesInfoVec[i]
4575 item = wx.MenuItem(popupMenu, i, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
4576 self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item)
6cb4f153 4577
6a64d551
RD
4578 # This code is commented, since there is an alignment problem with wx2.6.3 & Menus
4579 # if self.TabHasImage(ii):
4580 # item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] );
6cb4f153 4581
6a64d551 4582 popupMenu.AppendItem(item)
33113971 4583 item.Enable(pi.GetEnabled())
6a64d551
RD
4584
4585 self.PopupMenu(popupMenu)
6cb4f153 4586
6cb4f153 4587
6a64d551
RD
4588 def OnTabMenuSelection(self, event):
4589 """ Handles the wx.EVT_MENU event for L{PageContainer}. """
6cb4f153 4590
6a64d551 4591 selection = event.GetId()
33113971 4592 self.FireEvent(selection)
6cb4f153 4593
6cb4f153 4594
33113971
RD
4595 def FireEvent(self, selection):
4596 """
4597 Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
4598 called from other methods (from menu selection or Smart Tabbing).
4599 Utility function.
4600 """
4601
4602 if selection == self._iActivePage:
4603 # No events for the same selection
4604 return
4605
4606 oldSelection = self._iActivePage
4607
4608 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
4609 event.SetSelection(selection)
4610 event.SetOldSelection(oldSelection)
4611 event.SetEventObject(self.GetParent())
4612
4613 if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed():
4614
4615 self.SetSelection(selection)
4616
4617 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4618 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
4619 event.SetOldSelection(oldSelection)
4620 self.GetParent().GetEventHandler().ProcessEvent(event)
4621
4622
6a64d551
RD
4623 def SetImageList(self, imglist):
4624 """ Sets the image list for the page control. """
6cb4f153 4625
6a64d551 4626 self._ImageList = imglist
6cb4f153 4627
6cb4f153 4628
cbfc9df6
RD
4629 def AssignImageList(self, imglist):
4630 """ Assigns the image list for the page control. """
4631
4632 self._ImageList = imglist
4633
4634
6a64d551
RD
4635 def GetImageList(self):
4636 """ Returns the image list for the page control. """
6cb4f153 4637
6a64d551 4638 return self._ImageList
6cb4f153
RD
4639
4640
6a64d551
RD
4641 def GetSelection(self):
4642 """ Returns the current selected page. """
6cb4f153 4643
6a64d551 4644 return self._iActivePage
6cb4f153
RD
4645
4646
6a64d551
RD
4647 def GetPageCount(self):
4648 """ Returns the number of tabs in the L{FlatNotebook} control. """
6cb4f153 4649
6a64d551 4650 return len(self._pagesInfoVec)
6cb4f153
RD
4651
4652
6a64d551
RD
4653 def GetPageText(self, page):
4654 """ Returns the tab caption of the page. """
6cb4f153 4655
6a64d551 4656 return self._pagesInfoVec[page].GetCaption()
6cb4f153 4657
6cb4f153 4658
6a64d551
RD
4659 def SetPageText(self, page, text):
4660 """ Sets the tab caption of the page. """
6cb4f153 4661
6a64d551
RD
4662 self._pagesInfoVec[page].SetCaption(text)
4663 return True
6cb4f153
RD
4664
4665
33113971
RD
4666 def DrawDragHint(self):
4667 """ Draws small arrow at the place that the tab will be placed. """
4668
4669 # get the index of tab that will be replaced with the dragged tab
4670 pt = wx.GetMousePosition()
4671 client_pt = self.ScreenToClient(pt)
4672 where, tabIdx = self.HitTest(client_pt)
4673 self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()).DrawDragHint(self, tabIdx)
4674