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