]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/lib/flatnotebook.py
Test for KDE and GNOME using session manager vendor.
[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
6a64d551
RD
1791# ---------------------------------------------------------------------------- #
1792# Class FNBRendererMgr
1793# A manager that handles all the renderers defined below and calls the
1794# appropriate one when drawing is needed
1795# ---------------------------------------------------------------------------- #
6cb4f153 1796
6a64d551
RD
1797class FNBRendererMgr:
1798 """
1799 This class represents a manager that handles all the 4 renderers defined
1800 and calls the appropriate one when drawing is needed.
1801 """
6cb4f153 1802
6a64d551
RD
1803 def __init__(self):
1804 """ Default class constructor. """
1805
1806 # register renderers
6cb4f153 1807
6a64d551
RD
1808 self._renderers = {}
1809 self._renderers.update({-1: FNBRendererDefault()})
1810 self._renderers.update({FNB_VC71: FNBRendererVC71()})
1811 self._renderers.update({FNB_FANCY_TABS: FNBRendererFancy()})
1812 self._renderers.update({FNB_VC8: FNBRendererVC8()})
6cb4f153 1813
6cb4f153 1814
6a64d551
RD
1815 def GetRenderer(self, style):
1816 """ Returns the current renderer based on the style selected. """
6cb4f153 1817
6a64d551
RD
1818 # since we dont have a style for default tabs, we
1819 # test for all others - FIXME: add style for default tabs
1820 if not style & FNB_VC71 and not style & FNB_VC8 and not style & FNB_FANCY_TABS:
1821 return self._renderers[-1]
6cb4f153 1822
6a64d551
RD
1823 if style & FNB_VC71:
1824 return self._renderers[FNB_VC71]
6cb4f153 1825
6a64d551
RD
1826 if style & FNB_FANCY_TABS:
1827 return self._renderers[FNB_FANCY_TABS]
6cb4f153 1828
6a64d551
RD
1829 if style & FNB_VC8:
1830 return self._renderers[FNB_VC8]
6cb4f153 1831
6a64d551
RD
1832 # the default is to return the default renderer
1833 return self._renderers[-1]
6cb4f153 1834
6cb4f153 1835
6a64d551
RD
1836#------------------------------------------
1837# Default renderer
1838#------------------------------------------
6cb4f153 1839
6a64d551
RD
1840class FNBRendererDefault(FNBRenderer):
1841 """
1842 This class handles the drawing of tabs using the I{Standard} renderer.
1843 """
1844
1845 def __init__(self):
1846 """ Default class constructor. """
6cb4f153 1847
6a64d551
RD
1848 FNBRenderer.__init__(self)
1849
6cb4f153 1850
6a64d551
RD
1851 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
1852 """ Draws a tab using the I{Standard} style. """
6cb4f153 1853
6a64d551
RD
1854 # Default style
1855 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
1856 pc = pageContainer
6cb4f153 1857
6a64d551
RD
1858 tabPoints = [wx.Point() for ii in xrange(7)]
1859 tabPoints[0].x = posx
1860 tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
6cb4f153 1861
6a64d551
RD
1862 tabPoints[1].x = int(posx+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
1863 tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
6cb4f153 1864
6a64d551
RD
1865 tabPoints[2].x = tabPoints[1].x+2
1866 tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
6cb4f153 1867
6a64d551
RD
1868 tabPoints[3].x = int(posx+tabWidth-(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))-2
1869 tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
6cb4f153 1870
6a64d551
RD
1871 tabPoints[4].x = tabPoints[3].x+2
1872 tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
6cb4f153 1873
6a64d551
RD
1874 tabPoints[5].x = int(tabPoints[4].x+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
1875 tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
6cb4f153 1876
6a64d551
RD
1877 tabPoints[6].x = tabPoints[0].x
1878 tabPoints[6].y = tabPoints[0].y
1879
1880 if tabIdx == pc.GetSelection():
1881
1882 # Draw the tab as rounded rectangle
1883 dc.DrawPolygon(tabPoints)
1884
1885 else:
1886
1887 if tabIdx != pc.GetSelection() - 1:
1888
1889 # Draw a vertical line to the right of the text
1890 pt1x = tabPoints[5].x
1891 pt1y = (pc.HasFlag(FNB_BOTTOM) and [4] or [tabHeight - 6])[0]
1892 pt2x = tabPoints[5].x
1893 pt2y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 4] or [4])[0]
1894 dc.DrawLine(pt1x, pt1y, pt2x, pt2y)
6cb4f153 1895
6a64d551
RD
1896 if tabIdx == pc.GetSelection():
1897
1898 savePen = dc.GetPen()
1899 whitePen = wx.Pen(wx.WHITE)
1900 whitePen.SetWidth(1)
1901 dc.SetPen(whitePen)
6cb4f153 1902
6a64d551
RD
1903 secPt = wx.Point(tabPoints[5].x + 1, tabPoints[5].y)
1904 dc.DrawLine(tabPoints[0].x, tabPoints[0].y, secPt.x, secPt.y)
6cb4f153 1905
6a64d551
RD
1906 # Restore the pen
1907 dc.SetPen(savePen)
1908
1909 # -----------------------------------
1910 # Text and image drawing
1911 # -----------------------------------
6cb4f153 1912
6a64d551
RD
1913 # Text drawing offset from the left border of the
1914 # rectangle
1915
1916 # The width of the images are 16 pixels
1917 padding = pc.GetParent().GetPadding()
1918 shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
1919 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
1920 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
6cb4f153 1921
6a64d551
RD
1922 if hasImage:
1923 textOffset = 2*pc._pParent._nPadding + 16 + shapePoints/2
1924 else:
1925 textOffset = pc._pParent._nPadding + shapePoints/2
1926
1927 textOffset += 2
1928
1929 if tabIdx != pc.GetSelection():
1930
1931 # Set the text background to be like the vertical lines
1932 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
1933
1934 if hasImage:
1935
1936 imageXOffset = textOffset - 16 - padding
1937 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
1938 posx + imageXOffset, imageYCoord,
1939 wx.IMAGELIST_DRAW_TRANSPARENT, True)
1940
1941 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
1942
1943 # draw 'x' on tab (if enabled)
1944 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
1945
1946 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
1947 tabCloseButtonXCoord = posx + textOffset + textWidth + 1
1948
1949 # take a bitmap from the position of the 'x' button (the x on tab button)
1950 # this bitmap will be used later to delete old buttons
1951 tabCloseButtonYCoord = imageYCoord
1952 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
1953 self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
1954
1955 # Draw the tab
1956 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
1957
1958
1959#------------------------------------------------------------------
1960# Visual studio 7.1
1961#------------------------------------------------------------------
1962
1963class FNBRendererVC71(FNBRenderer):
1964 """
1965 This class handles the drawing of tabs using the I{VC71} renderer.
1966 """
1967
1968 def __init__(self):
6cb4f153 1969 """ Default class constructor. """
6a64d551
RD
1970
1971 FNBRenderer.__init__(self)
1972
1973
1974 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
1975 """ Draws a tab using the I{VC71} style. """
1976
1977 # Visual studio 7.1 style
1978 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
1979 pc = pageContainer
1980
1981 dc.SetPen((tabIdx == pc.GetSelection() and [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [borderPen])[0])
1982 dc.SetBrush((tabIdx == pc.GetSelection() and [wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [wx.Brush(wx.Colour(247, 243, 233))])[0])
1983
1984 if tabIdx == pc.GetSelection():
6cb4f153 1985
6a64d551 1986 posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
33113971
RD
1987 tabH = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 5] or [tabHeight - 3])[0]
1988 dc.DrawRectangle(posx, posy, tabWidth, tabH)
6cb4f153 1989
6a64d551
RD
1990 # Draw a black line on the left side of the
1991 # rectangle
1992 dc.SetPen(wx.BLACK_PEN)
6cb4f153 1993
6a64d551 1994 blackLineY1 = VERTICAL_BORDER_PADDING
33113971 1995 blackLineY2 = tabH
6a64d551 1996 dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
6cb4f153 1997
6a64d551
RD
1998 # To give the tab more 3D look we do the following
1999 # Incase the tab is on top,
2000 # Draw a thik white line on topof the rectangle
2001 # Otherwise, draw a thin (1 pixel) black line at the bottom
6cb4f153 2002
6a64d551
RD
2003 pen = wx.Pen((pc.HasFlag(FNB_BOTTOM) and [wx.BLACK] or [wx.WHITE])[0])
2004 dc.SetPen(pen)
2005 whiteLinePosY = (pc.HasFlag(FNB_BOTTOM) and [blackLineY2] or [VERTICAL_BORDER_PADDING ])[0]
2006 dc.DrawLine(posx , whiteLinePosY, posx + tabWidth + 1, whiteLinePosY)
2007
2008 # Draw a white vertical line to the left of the tab
2009 dc.SetPen(wx.WHITE_PEN)
2010 if not pc.HasFlag(FNB_BOTTOM):
2011 blackLineY2 += 1
2012
2013 dc.DrawLine(posx, blackLineY1, posx, blackLineY2)
2014
2015 else:
6cb4f153 2016
6a64d551
RD
2017 # We dont draw a rectangle for non selected tabs, but only
2018 # vertical line on the left
6cb4f153 2019
6a64d551
RD
2020 blackLineY1 = (pc.HasFlag(FNB_BOTTOM) and [VERTICAL_BORDER_PADDING + 2] or [VERTICAL_BORDER_PADDING + 1])[0]
2021 blackLineY2 = pc.GetSize().y - 5
2022 dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
2023
2024 # -----------------------------------
2025 # Text and image drawing
2026 # -----------------------------------
6cb4f153 2027
6a64d551
RD
2028 # Text drawing offset from the left border of the
2029 # rectangle
2030
2031 # The width of the images are 16 pixels
2032 padding = pc.GetParent().GetPadding()
2033 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
33113971 2034 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [5] or [8])[0]
6a64d551
RD
2035
2036 if hasImage:
2037 textOffset = 2*pc._pParent._nPadding + 16
2038 else:
2039 textOffset = pc._pParent._nPadding
2040
2041 if tabIdx != pc.GetSelection():
2042
2043 # Set the text background to be like the vertical lines
2044 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
2045
2046 if hasImage:
2047
2048 imageXOffset = textOffset - 16 - padding
2049 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
2050 posx + imageXOffset, imageYCoord,
2051 wx.IMAGELIST_DRAW_TRANSPARENT, True)
2052
2053 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
2054
2055 # draw 'x' on tab (if enabled)
2056 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
2057
2058 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
2059 tabCloseButtonXCoord = posx + textOffset + textWidth + 1
6cb4f153 2060
6a64d551
RD
2061 # take a bitmap from the position of the 'x' button (the x on tab button)
2062 # this bitmap will be used later to delete old buttons
2063 tabCloseButtonYCoord = imageYCoord
2064 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
2065 self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
6cb4f153 2066
6a64d551
RD
2067 # Draw the tab
2068 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
6cb4f153 2069
6cb4f153 2070
6a64d551
RD
2071#------------------------------------------------------------------
2072# Fancy style
2073#------------------------------------------------------------------
6cb4f153 2074
6a64d551
RD
2075class FNBRendererFancy(FNBRenderer):
2076 """
2077 This class handles the drawing of tabs using the I{Fancy} renderer.
2078 """
6cb4f153 2079
6a64d551
RD
2080 def __init__(self):
2081 """ Default class constructor. """
6cb4f153 2082
6a64d551 2083 FNBRenderer.__init__(self)
6cb4f153 2084
6cb4f153 2085
6a64d551
RD
2086 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
2087 """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
6cb4f153 2088
6a64d551
RD
2089 # Fancy tabs - like with VC71 but with the following differences:
2090 # - The Selected tab is colored with gradient color
2091 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
2092 pc = pageContainer
2093
2094 pen = (tabIdx == pc.GetSelection() and [wx.Pen(pc._pParent.GetBorderColour())] or [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))])[0]
2095
2096 if tabIdx == pc.GetSelection():
2097
2098 posy = (pc.HasFlag(FNB_BOTTOM) and [2] or [VERTICAL_BORDER_PADDING])[0]
33113971 2099 th = tabHeight - 5
6a64d551
RD
2100
2101 rect = wx.Rect(posx, posy, tabWidth, th)
2102
2103 col2 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourTo()] or [pc._pParent.GetGradientColourFrom()])[0]
2104 col1 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourFrom()] or [pc._pParent.GetGradientColourTo()])[0]
2105
2106 PaintStraightGradientBox(dc, rect, col1, col2)
2107 dc.SetBrush(wx.TRANSPARENT_BRUSH)
2108 dc.SetPen(pen)
2109 dc.DrawRectangleRect(rect)
2110
2111 # erase the bottom/top line of the rectangle
2112 dc.SetPen(wx.Pen(pc._pParent.GetGradientColourFrom()))
2113 if pc.HasFlag(FNB_BOTTOM):
2114 dc.DrawLine(rect.x, 2, rect.x + rect.width, 2)
2115 else:
2116 dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
2117
2118 else:
2119
2120 # We dont draw a rectangle for non selected tabs, but only
2121 # vertical line on the left
2122 dc.SetPen(borderPen)
2123 dc.DrawLine(posx + tabWidth, VERTICAL_BORDER_PADDING + 3, posx + tabWidth, tabHeight - 4)
2124
2125
2126 # -----------------------------------
2127 # Text and image drawing
2128 # -----------------------------------
2129
2130 # Text drawing offset from the left border of the
2131 # rectangle
2132
2133 # The width of the images are 16 pixels
2134 padding = pc.GetParent().GetPadding()
2135 hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
2136 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
2137
2138 if hasImage:
2139 textOffset = 2*pc._pParent._nPadding + 16
2140 else:
2141 textOffset = pc._pParent._nPadding
2142
2143 textOffset += 2
2144
2145 if tabIdx != pc.GetSelection():
2146
2147 # Set the text background to be like the vertical lines
2148 dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
2149
2150 if hasImage:
2151
2152 imageXOffset = textOffset - 16 - padding
2153 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
2154 posx + imageXOffset, imageYCoord,
2155 wx.IMAGELIST_DRAW_TRANSPARENT, True)
2156
2157 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
2158
2159 # draw 'x' on tab (if enabled)
2160 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
2161
2162 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
2163 tabCloseButtonXCoord = posx + textOffset + textWidth + 1
2164
2165 # take a bitmap from the position of the 'x' button (the x on tab button)
2166 # this bitmap will be used later to delete old buttons
2167 tabCloseButtonYCoord = imageYCoord
2168 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
2169 self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
2170
2171 # Draw the tab
2172 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
2173
2174
2175#------------------------------------------------------------------
2176# Visual studio 2005 (VS8)
2177#------------------------------------------------------------------
2178class FNBRendererVC8(FNBRenderer):
2179 """
2180 This class handles the drawing of tabs using the I{VC8} renderer.
2181 """
2182
2183 def __init__(self):
2184 """ Default class constructor. """
2185
2186 FNBRenderer.__init__(self)
2187 self._first = True
2188 self._factor = 1
2189
2190
2191 def DrawTabs(self, pageContainer, dc):
2192 """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
6cb4f153 2193
6a64d551 2194 pc = pageContainer
6cb4f153
RD
2195
2196 if "__WXMAC__" in wx.PlatformInfo:
2197 # Works well on MSW & GTK, however this lines should be skipped on MAC
6a64d551
RD
2198 if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
2199 pc.Hide()
6cb4f153 2200 return
6a64d551 2201
6cb4f153 2202 # Get the text hight
6a64d551 2203 tabHeight = self.CalcTabHeight(pageContainer)
6cb4f153 2204
6a64d551
RD
2205 # Set the font for measuring the tab height
2206 normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
33113971 2207 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
6cb4f153 2208 boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
6cb4f153
RD
2209
2210 # Calculate the number of rows required for drawing the tabs
6a64d551 2211 rect = pc.GetClientRect()
6cb4f153
RD
2212
2213 # Set the maximum client size
6a64d551
RD
2214 pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
2215 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
6cb4f153 2216
6a64d551
RD
2217 # Create brushes
2218 backBrush = wx.Brush(pc._tabAreaColor)
2219 noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
2220 selBrush = wx.Brush(pc._activeTabColor)
2221 size = pc.GetSize()
6cb4f153
RD
2222
2223 # Background
6a64d551
RD
2224 dc.SetTextBackground(pc.GetBackgroundColour())
2225 dc.SetTextForeground(pc._activeTextColor)
2226
6cb4f153 2227 # If border style is set, set the pen to be border pen
6a64d551 2228 if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
6cb4f153
RD
2229 dc.SetPen(borderPen)
2230 else:
6a64d551
RD
2231 dc.SetPen(wx.TRANSPARENT_PEN)
2232
2233 lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
6cb4f153 2234
6a64d551
RD
2235 # For VC8 style, we color the tab area in gradient coloring
2236 lightcolour = LightColour(pc._tabAreaColor, lightFactor)
2237 PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, lightcolour)
2238
2239 dc.SetBrush(wx.TRANSPARENT_BRUSH)
6cb4f153
RD
2240 dc.DrawRectangle(0, 0, size.x, size.y)
2241
2242 # Take 3 bitmaps for the background for the buttons
2243
2244 mem_dc = wx.MemoryDC()
6cb4f153
RD
2245 #---------------------------------------
2246 # X button
2247 #---------------------------------------
6a64d551 2248 rect = wx.Rect(self.GetXPos(pc), 6, 16, 14)
6cb4f153
RD
2249 mem_dc.SelectObject(self._xBgBmp)
2250 mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
2251 mem_dc.SelectObject(wx.NullBitmap)
2252
2253 #---------------------------------------
2254 # Right button
2255 #---------------------------------------
6a64d551 2256 rect = wx.Rect(self.GetRightButtonPos(pc), 6, 16, 14)
6cb4f153
RD
2257 mem_dc.SelectObject(self._rightBgBmp)
2258 mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
2259 mem_dc.SelectObject(wx.NullBitmap)
2260
2261 #---------------------------------------
2262 # Left button
2263 #---------------------------------------
6a64d551 2264 rect = wx.Rect(self.GetLeftButtonPos(pc), 6, 16, 14)
6cb4f153
RD
2265 mem_dc.SelectObject(self._leftBgBmp)
2266 mem_dc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y)
2267 mem_dc.SelectObject(wx.NullBitmap)
6a64d551 2268
6cb4f153
RD
2269 # We always draw the bottom/upper line of the tabs
2270 # regradless the style
2271 dc.SetPen(borderPen)
6a64d551 2272 self.DrawTabsLine(pc, dc)
6cb4f153
RD
2273
2274 # Restore the pen
2275 dc.SetPen(borderPen)
2276
6a64d551
RD
2277 # Draw labels
2278 dc.SetFont(boldFont)
6cb4f153 2279
6a64d551
RD
2280 # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
2281 for i in xrange(pc._nFrom):
2282
2283 pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
2284 pc._pagesInfoVec[i].GetRegion().Clear()
2285
2286 # Draw the visible tabs, in VC8 style, we draw them from right to left
2287 vTabsInfo = self.NumberTabsCanFit(pc)
6cb4f153 2288
6a64d551
RD
2289 activeTabPosx = 0
2290 activeTabWidth = 0
2291 activeTabHeight = 0
6cb4f153 2292
6a64d551 2293 for cur in xrange(len(vTabsInfo)-1, -1, -1):
6cb4f153 2294
6a64d551
RD
2295 # 'i' points to the index of the currently drawn tab
2296 # in pc.GetPageInfoVector() vector
2297 i = pc._nFrom + cur
2298 dc.SetPen(borderPen)
2299 dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
6cb4f153 2300
6a64d551
RD
2301 # Now set the font to the correct font
2302 dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
6cb4f153 2303
6a64d551
RD
2304 # Add the padding to the tab width
2305 # Tab width:
2306 # +-----------------------------------------------------------+
2307 # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
2308 # +-----------------------------------------------------------+
6cb4f153 2309
6a64d551
RD
2310 tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
2311 posx = vTabsInfo[cur].x
6cb4f153
RD
2312
2313 # By default we clean the tab region
6a64d551
RD
2314 # incase we use the VC8 style which requires
2315 # the region, it will be filled by the function
2316 # drawVc8Tab
2317 pc._pagesInfoVec[i].GetRegion().Clear()
2318
2319 # Clean the 'x' buttn on the tab
6cb4f153
RD
2320 # 'Clean' rectanlge is a rectangle with width or height
2321 # with values lower than or equal to 0
6a64d551 2322 pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
6cb4f153
RD
2323
2324 # Draw the tab
6a64d551
RD
2325 # Incase we are drawing the active tab
2326 # we need to redraw so it will appear on top
2327 # of all other tabs
6cb4f153 2328
6a64d551
RD
2329 # when using the vc8 style, we keep the position of the active tab so we will draw it again later
2330 if i == pc.GetSelection() and pc.HasFlag(FNB_VC8):
6cb4f153 2331
6a64d551
RD
2332 activeTabPosx = posx
2333 activeTabWidth = tabWidth
2334 activeTabHeight = tabHeight
6cb4f153 2335
6a64d551 2336 else:
6cb4f153 2337
6a64d551 2338 self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
6cb4f153
RD
2339
2340 # Restore the text forground
6a64d551 2341 dc.SetTextForeground(pc._activeTextColor)
6cb4f153
RD
2342
2343 # Update the tab position & size
6a64d551
RD
2344 pc._pagesInfoVec[i].SetPosition(wx.Point(posx, VERTICAL_BORDER_PADDING))
2345 pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
6cb4f153 2346
6a64d551
RD
2347 # Incase we are in VC8 style, redraw the active tab (incase it is visible)
2348 if pc.GetSelection() >= pc._nFrom and pc.GetSelection() < pc._nFrom + len(vTabsInfo):
6cb4f153 2349
6a64d551 2350 self.DrawTab(pc, dc, activeTabPosx, pc.GetSelection(), activeTabWidth, activeTabHeight, pc._nTabXButtonStatus)
6cb4f153 2351
6a64d551
RD
2352 # Update all tabs that can not fit into the screen as non-visible
2353 for xx in xrange(pc._nFrom + len(vTabsInfo), len(pc._pagesInfoVec)):
6cb4f153 2354
6a64d551
RD
2355 pc._pagesInfoVec[xx].SetPosition(wx.Point(-1, -1))
2356 pc._pagesInfoVec[xx].GetRegion().Clear()
6cb4f153 2357
6a64d551
RD
2358 # Draw the left/right/close buttons
2359 # Left arrow
2360 self.DrawLeftArrow(pc, dc)
2361 self.DrawRightArrow(pc, dc)
2362 self.DrawX(pc, dc)
2363 self.DrawDropDownArrow(pc, dc)
6cb4f153 2364
6cb4f153 2365
6a64d551
RD
2366 def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
2367 """ Draws a tab using VC8 style. """
6cb4f153 2368
6a64d551
RD
2369 pc = pageContainer
2370 borderPen = wx.Pen(pc._pParent.GetBorderColour())
2371 tabPoints = [wx.Point() for ii in xrange(8)]
6cb4f153 2372
6a64d551
RD
2373 # If we draw the first tab or the active tab,
2374 # we draw a full tab, else we draw a truncated tab
2375 #
2376 # X(2) X(3)
2377 # X(1) X(4)
2378 #
2379 # X(5)
2380 #
2381 # X(0),(7) X(6)
2382 #
2383 #
6cb4f153 2384
6a64d551
RD
2385 tabPoints[0].x = (pc.HasFlag(FNB_BOTTOM) and [posx] or [posx+self._factor])[0]
2386 tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 3])[0]
6cb4f153 2387
6a64d551
RD
2388 tabPoints[1].x = tabPoints[0].x + tabHeight - VERTICAL_BORDER_PADDING - 3 - self._factor
2389 tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
6cb4f153 2390
6a64d551
RD
2391 tabPoints[2].x = tabPoints[1].x + 4
2392 tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
6cb4f153 2393
6a64d551
RD
2394 tabPoints[3].x = tabPoints[2].x + tabWidth - 2
2395 tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
6cb4f153 2396
6a64d551
RD
2397 tabPoints[4].x = tabPoints[3].x + 1
2398 tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
6cb4f153 2399
6a64d551
RD
2400 tabPoints[5].x = tabPoints[4].x + 1
2401 tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
6cb4f153 2402
6a64d551
RD
2403 tabPoints[6].x = tabPoints[2].x + tabWidth
2404 tabPoints[6].y = tabPoints[0].y
6cb4f153 2405
6a64d551
RD
2406 tabPoints[7].x = tabPoints[0].x
2407 tabPoints[7].y = tabPoints[0].y
6cb4f153 2408
6a64d551 2409 pc._pagesInfoVec[tabIdx].SetRegion(tabPoints)
6cb4f153 2410
6a64d551
RD
2411 # Draw the polygon
2412 br = dc.GetBrush()
2413 dc.SetBrush(wx.Brush((tabIdx == pc.GetSelection() and [pc._activeTabColor] or [pc._colorTo])[0]))
2414 dc.SetPen(wx.Pen((tabIdx == pc.GetSelection() and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
2415 dc.DrawPolygon(tabPoints)
6cb4f153 2416
6a64d551
RD
2417 # Restore the brush
2418 dc.SetBrush(br)
2419 rect = pc.GetClientRect()
6cb4f153 2420
6a64d551 2421 if tabIdx != pc.GetSelection() and not pc.HasFlag(FNB_BOTTOM):
6cb4f153 2422
6a64d551
RD
2423 # Top default tabs
2424 dc.SetPen(wx.Pen(pc._pParent.GetBorderColour()))
2425 lineY = rect.height
2426 curPen = dc.GetPen()
2427 curPen.SetWidth(1)
2428 dc.SetPen(curPen)
2429 dc.DrawLine(posx, lineY, posx+rect.width, lineY)
6cb4f153 2430
6a64d551
RD
2431 # Incase we are drawing the selected tab, we draw the border of it as well
2432 # but without the bottom (upper line incase of wxBOTTOM)
2433 if tabIdx == pc.GetSelection():
6cb4f153 2434
6a64d551
RD
2435 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
2436 dc.SetPen(borderPen)
2437 dc.SetBrush(wx.TRANSPARENT_BRUSH)
2438 dc.DrawPolygon(tabPoints)
6cb4f153 2439
6a64d551
RD
2440 # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
2441 dc.SetPen(wx.WHITE_PEN)
2442 dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y)
6cb4f153 2443
6a64d551 2444 self.FillVC8GradientColour(pc, dc, tabPoints, tabIdx == pc.GetSelection(), tabIdx)
6cb4f153 2445
6a64d551
RD
2446 # Draw a thin line to the right of the non-selected tab
2447 if tabIdx != pc.GetSelection():
6cb4f153 2448
6a64d551
RD
2449 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
2450 dc.DrawLine(tabPoints[4].x-1, tabPoints[4].y, tabPoints[5].x-1, tabPoints[5].y)
2451 dc.DrawLine(tabPoints[5].x-1, tabPoints[5].y, tabPoints[6].x-1, tabPoints[6].y)
6cb4f153 2452
6a64d551
RD
2453 # Text drawing offset from the left border of the
2454 # rectangle
6cb4f153 2455
6a64d551
RD
2456 # The width of the images are 16 pixels
2457 vc8ShapeLen = tabHeight - VERTICAL_BORDER_PADDING - 2
2458 if pc.TabHasImage(tabIdx):
2459 textOffset = 2*pc._pParent.GetPadding() + 16 + vc8ShapeLen
2460 else:
2461 textOffset = pc._pParent.GetPadding() + vc8ShapeLen
6cb4f153 2462
6a64d551
RD
2463 # Draw the image for the tab if any
2464 imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
6cb4f153 2465
6a64d551 2466 if pc.TabHasImage(tabIdx):
6cb4f153 2467
6a64d551
RD
2468 imageXOffset = textOffset - 16 - pc._pParent.GetPadding()
2469 pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
2470 posx + imageXOffset, imageYCoord,
2471 wx.IMAGELIST_DRAW_TRANSPARENT, True)
6cb4f153 2472
6a64d551
RD
2473 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
2474
2475 # if selected tab, draw text in bold
2476 if tabIdx == pc.GetSelection():
2477 boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
6cb4f153 2478
6a64d551
RD
2479 dc.SetFont(boldFont)
2480 dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
6cb4f153 2481
6a64d551
RD
2482 # draw 'x' on tab (if enabled)
2483 if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
6cb4f153 2484
6a64d551
RD
2485 textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
2486 tabCloseButtonXCoord = posx + textOffset + textWidth + 1
6cb4f153 2487
6a64d551
RD
2488 # take a bitmap from the position of the 'x' button (the x on tab button)
2489 # this bitmap will be used later to delete old buttons
2490 tabCloseButtonYCoord = imageYCoord
2491 x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
2492 self._tabXBgBmp = self._GetBitmap(dc, x_rect, self._tabXBgBmp)
2493 # Draw the tab
2494 self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
6cb4f153
RD
2495
2496
6a64d551
RD
2497 def FillVC8GradientColour(self, pageContainer, dc, tabPoints, bSelectedTab, tabIdx):
2498 """ Fills a tab with a gradient shading. """
6cb4f153 2499
6a64d551
RD
2500 # calculate gradient coefficients
2501 pc = pageContainer
6cb4f153 2502
6a64d551
RD
2503 if self._first:
2504 self._first = False
2505 pc._colorTo = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 0)
2506 pc._colorFrom = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 60)
6cb4f153 2507
6a64d551
RD
2508 col2 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourTo()] or [pc._pParent.GetGradientColourFrom()])[0]
2509 col1 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourFrom()] or [pc._pParent.GetGradientColourTo()])[0]
6cb4f153 2510
6a64d551
RD
2511 # If colorful tabs style is set, override the tab color
2512 if pc.HasFlag(FNB_COLORFUL_TABS):
6cb4f153 2513
6a64d551
RD
2514 if not pc._pagesInfoVec[tabIdx].GetColour():
2515
2516 # First time, generate color, and keep it in the vector
2517 tabColor = RandomColour()
2518 pc._pagesInfoVec[tabIdx].SetColour(tabColor)
2519
2520 if pc.HasFlag(FNB_BOTTOM):
2521
2522 col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
2523 col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
2524
2525 else:
2526
2527 col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
2528 col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
2529
2530 size = abs(tabPoints[2].y - tabPoints[0].y) - 1
6cb4f153 2531
6a64d551
RD
2532 rf, gf, bf = 0, 0, 0
2533 rstep = float(col2.Red() - col1.Red())/float(size)
2534 gstep = float(col2.Green() - col1.Green())/float(size)
2535 bstep = float(col2.Blue() - col1.Blue())/float(size)
2536
2537 y = tabPoints[0].y
6cb4f153 2538
6a64d551
RD
2539 # If we are drawing the selected tab, we need also to draw a line
2540 # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
2541 # by drawing the rectangle with transparent brush
2542 # the line under the selected tab will be deleted by the drwaing loop
2543 if bSelectedTab:
2544 self.DrawTabsLine(pc, dc)
6cb4f153 2545
6a64d551
RD
2546 while 1:
2547
2548 if pc.HasFlag(FNB_BOTTOM):
2549
2550 if y > tabPoints[0].y + size:
2551 break
2552
2553 else:
2554
2555 if y < tabPoints[0].y - size:
2556 break
2557
2558 currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
2559
2560 dc.SetPen((bSelectedTab and [wx.Pen(pc._activeTabColor)] or [wx.Pen(currCol)])[0])
2561 startX = self.GetStartX(tabPoints, y, pc.GetParent().GetWindowStyleFlag())
2562 endX = self.GetEndX(tabPoints, y, pc.GetParent().GetWindowStyleFlag())
2563 dc.DrawLine(startX, y, endX, y)
2564
2565 # Draw the border using the 'edge' point
2566 dc.SetPen(wx.Pen((bSelectedTab and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
2567
2568 dc.DrawPoint(startX, y)
2569 dc.DrawPoint(endX, y)
2570
2571 # Progress the color
2572 rf += rstep
2573 gf += gstep
2574 bf += bstep
2575
2576 if pc.HasFlag(FNB_BOTTOM):
2577 y = y + 1
2578 else:
2579 y = y - 1
2580
2581
2582 def GetStartX(self, tabPoints, y, style):
2583 """ Returns the x start position of a tab. """
2584
2585 x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
2586
2587 # We check the 3 points to the left
2588
2589 bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
2590 match = False
2591
2592 if bBottomStyle:
2593
2594 for i in xrange(3):
6cb4f153 2595
6a64d551
RD
2596 if y >= tabPoints[i].y and y < tabPoints[i+1].y:
2597
2598 x1 = tabPoints[i].x
2599 x2 = tabPoints[i+1].x
2600 y1 = tabPoints[i].y
2601 y2 = tabPoints[i+1].y
2602 match = True
2603 break
2604
2605 else:
2606
2607 for i in xrange(3):
2608
2609 if y <= tabPoints[i].y and y > tabPoints[i+1].y:
2610
2611 x1 = tabPoints[i].x
2612 x2 = tabPoints[i+1].x
2613 y1 = tabPoints[i].y
2614 y2 = tabPoints[i+1].y
2615 match = True
2616 break
2617
2618 if not match:
2619 return tabPoints[2].x
6cb4f153 2620
6a64d551
RD
2621 # According to the equation y = ax + b => x = (y-b)/a
2622 # We know the first 2 points
6cb4f153 2623
6a64d551
RD
2624 if x2 == x1:
2625 return x2
2626 else:
2627 a = (y2 - y1)/(x2 - x1)
6cb4f153 2628
6a64d551 2629 b = y1 - ((y2 - y1)/(x2 - x1))*x1
6cb4f153 2630
6a64d551
RD
2631 if a == 0:
2632 return int(x1)
6cb4f153 2633
6a64d551
RD
2634 x = (y - b)/a
2635
2636 return int(x)
6cb4f153 2637
6cb4f153 2638
6a64d551
RD
2639 def GetEndX(self, tabPoints, y, style):
2640 """ Returns the x end position of a tab. """
6cb4f153 2641
6a64d551 2642 x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
6cb4f153 2643
6a64d551
RD
2644 # We check the 3 points to the left
2645 bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
2646 match = False
6cb4f153 2647
6a64d551 2648 if bBottomStyle:
6cb4f153 2649
6a64d551
RD
2650 for i in xrange(7, 3, -1):
2651
2652 if y >= tabPoints[i].y and y < tabPoints[i-1].y:
2653
2654 x1 = tabPoints[i].x
2655 x2 = tabPoints[i-1].x
2656 y1 = tabPoints[i].y
2657 y2 = tabPoints[i-1].y
2658 match = True
2659 break
2660
2661 else:
2662
2663 for i in xrange(7, 3, -1):
2664
2665 if y <= tabPoints[i].y and y > tabPoints[i-1].y:
2666
2667 x1 = tabPoints[i].x
2668 x2 = tabPoints[i-1].x
2669 y1 = tabPoints[i].y
2670 y2 = tabPoints[i-1].y
2671 match = True
2672 break
6cb4f153 2673
6a64d551
RD
2674 if not match:
2675 return tabPoints[3].x
6cb4f153 2676
6a64d551
RD
2677 # According to the equation y = ax + b => x = (y-b)/a
2678 # We know the first 2 points
2679
2680 # Vertical line
2681 if x1 == x2:
2682 return int(x1)
6cb4f153 2683
6a64d551
RD
2684 a = (y2 - y1)/(x2 - x1)
2685 b = y1 - ((y2 - y1)/(x2 - x1))*x1
2686
2687 if a == 0:
2688 return int(x1)
2689
2690 x = (y - b)/a
2691
2692 return int(x)
2693
2694
2695 def NumberTabsCanFit(self, pageContainer, fr=-1):
2696 """ Returns the number of tabs that can fit in the visible area. """
2697
2698 pc = pageContainer
2699
2700 rect = pc.GetClientRect()
2701 clientWidth = rect.width
2702
2703 # Empty results
2704 vTabInfo = []
2705 tabHeight = self.CalcTabHeight(pageContainer)
2706
2707 # The drawing starts from posx
2708 posx = pc._pParent.GetPadding()
2709
2710 if fr < 0:
2711 fr = pc._nFrom
2712
2713 for i in xrange(fr, len(pc._pagesInfoVec)):
2714
2715 vc8glitch = tabHeight + FNB_HEIGHT_SPACER
2716 tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
2717
2718 if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength(pc) >= clientWidth:
2719 break
2720
2721 # Add a result to the returned vector
2722 tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth, tabHeight)
2723 vTabInfo.append(tabRect)
2724
2725 # Advance posx
2726 posx += tabWidth + FNB_HEIGHT_SPACER
2727
2728 return vTabInfo
2729
2730
2731# ---------------------------------------------------------------------------- #
2732# Class FlatNotebook
2733# ---------------------------------------------------------------------------- #
2734
2735class FlatNotebook(wx.Panel):
2736 """
2737 Display one or more windows in a notebook.
2738
2739 B{Events}:
2740 - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active
2741 page in the notebook is changing
2742 - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active
2743 page in the notebook has changed
2744 - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the
2745 notebook is closing
2746 - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the
2747 notebook has been closed
2748 - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
2749 clicks a tab in the notebook with the right mouse
2750 button
2751 """
2752
2753 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
2754 style=0, name="FlatNotebook"):
2755 """
2756 Default class constructor.
2757
2758 All the parameters are as in wxPython class construction, except the
2759 'style': this can be assigned to whatever combination of FNB_* styles.
2760
2761 """
2762
2763 self._bForceSelection = False
2764 self._nPadding = 6
2765 self._nFrom = 0
2766 style |= wx.TAB_TRAVERSAL
2767 self._pages = None
2768 self._windows = []
2769 self._popupWin = None
2770
2771 wx.Panel.__init__(self, parent, id, pos, size, style)
2772
2773 self._pages = PageContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style)
2774
2775 self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
2776
2777 self.Init()
2778
2779
2780 def Init(self):
2781 """ Initializes all the class attributes. """
2782
2783 self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
2784
2785 self._mainSizer = wx.BoxSizer(wx.VERTICAL)
2786 self.SetSizer(self._mainSizer)
2787
2788 # The child panels will inherit this bg color, so leave it at the default value
2789 #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
2790
2791 # Set default page height
2792 dc = wx.ClientDC(self)
6a64d551 2793
33113971
RD
2794 if "__WXGTK__" in wx.PlatformInfo:
2795 # For GTK it seems that we must do this steps in order
2796 # for the tabs will get the proper height on initialization
2797 # on MSW, preforming these steps yields wierd results
2798 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
2799 boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
2800 dc.SetFont(boldFont)
2801
2802 height = dc.GetCharHeight()
2803
6a64d551
RD
2804 tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding
2805
2806 if "__WXGTK__" in wx.PlatformInfo:
2807 tabHeight += 6
6cb4f153 2808
6a64d551
RD
2809 self._pages.SetSizeHints(-1, tabHeight)
2810 # Add the tab container to the sizer
2811 self._mainSizer.Insert(0, self._pages, 0, wx.EXPAND)
2812 self._mainSizer.Layout()
6cb4f153 2813
6a64d551
RD
2814 self._pages._nFrom = self._nFrom
2815 self._pDropTarget = FNBDropTarget(self)
2816 self.SetDropTarget(self._pDropTarget)
6cb4f153 2817
6cb4f153 2818
6a64d551
RD
2819 def SetActiveTabTextColour(self, textColour):
2820 """ Sets the text colour for the active tab. """
6cb4f153 2821
6a64d551 2822 self._pages._activeTextColor = textColour
6cb4f153 2823
6a64d551
RD
2824
2825 def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
2826 """ Handles the drop action from a DND operation. """
2827
2828 return self._pages.OnDropTarget(x, y, nTabPage, wnd_oldContainer)
2829
2830
2831 def GetPreviousSelection(self):
2832 """ Returns the previous selection. """
2833
2834 return self._pages._iPreviousActivePage
2835
2836
2837 def AddPage(self, page, text, select=True, imageId=-1):
2838 """
2839 Add a page to the L{FlatNotebook}.
2840
2841 @param page: Specifies the new page.
2842 @param text: Specifies the text for the new page.
2843 @param select: Specifies whether the page should be selected.
2844 @param imageId: Specifies the optional image index for the new page.
2845
2846 Return value:
2847 True if successful, False otherwise.
2848 """
2849
2850 # sanity check
2851 if not page:
2852 return False
2853
2854 # reparent the window to us
2855 page.Reparent(self)
2856
2857 # Add tab
2858 bSelected = select or len(self._windows) == 0
2859
2860 if bSelected:
6cb4f153 2861
6a64d551 2862 bSelected = False
6cb4f153 2863
6a64d551
RD
2864 # Check for selection and send events
2865 oldSelection = self._pages._iActivePage
2866 tabIdx = len(self._windows)
2867
2868 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
2869 event.SetSelection(tabIdx)
2870 event.SetOldSelection(oldSelection)
2871 event.SetEventObject(self)
2872
33113971 2873 if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
6a64d551
RD
2874 bSelected = True
2875
2876 curSel = self._pages.GetSelection()
6cb4f153 2877
6a64d551
RD
2878 if not self._pages.IsShown():
2879 self._pages.Show()
2880
2881 self._pages.AddPage(text, bSelected, imageId)
2882 self._windows.append(page)
2883
2884 self.Freeze()
2885
2886 # Check if a new selection was made
2887 if bSelected:
2888
2889 if curSel >= 0:
2890
2891 # Remove the window from the main sizer
2892 self._mainSizer.Detach(self._windows[curSel])
2893 self._windows[curSel].Hide()
2894
2895 if self.GetWindowStyleFlag() & FNB_BOTTOM:
2896
2897 self._mainSizer.Insert(0, page, 1, wx.EXPAND)
2898
2899 else:
2900
2901 # We leave a space of 1 pixel around the window
2902 self._mainSizer.Add(page, 1, wx.EXPAND)
2903
2904 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
2905 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
2906 event.SetOldSelection(oldSelection)
2907 self.GetEventHandler().ProcessEvent(event)
2908
2909 else:
2910
2911 # Hide the page
2912 page.Hide()
33113971
RD
2913
2914 self.Thaw()
6a64d551 2915 self._mainSizer.Layout()
6a64d551
RD
2916 self.Refresh()
2917
2918 return True
2919
2920
33113971 2921 def SetImageList(self, imageList):
6a64d551
RD
2922 """
2923 Sets the image list for the page control. It does not take ownership
2924 of the image list, you must delete it yourself.
2925 """
2926
33113971 2927 self._pages.SetImageList(imageList)
6a64d551
RD
2928
2929
2930 def GetImageList(self):
2931 """ Returns the associated image list. """
2932
2933 return self._pages.GetImageList()
2934
2935
2936 def InsertPage(self, indx, page, text, select=True, imageId=-1):
2937 """
2938 Inserts a new page at the specified position.
2939
2940 @param indx: Specifies the position of the new page.
2941 @param page: Specifies the new page.
2942 @param text: Specifies the text for the new page.
2943 @param select: Specifies whether the page should be selected.
2944 @param imageId: Specifies the optional image index for the new page.
2945
2946 Return value:
2947 True if successful, False otherwise.
2948 """
2949
2950 # sanity check
2951 if not page:
2952 return False
6cb4f153 2953
6a64d551
RD
2954 # reparent the window to us
2955 page.Reparent(self)
6cb4f153 2956
6a64d551
RD
2957 if not self._windows:
2958
2959 self.AddPage(page, text, select, imageId)
2960 return True
6cb4f153 2961
6a64d551
RD
2962 # Insert tab
2963 bSelected = select or not self._windows
2964 curSel = self._pages.GetSelection()
2965
2966 indx = max(0, min(indx, len(self._windows)))
6cb4f153 2967
6a64d551
RD
2968 if indx <= len(self._windows):
2969
2970 self._windows.insert(indx, page)
2971
2972 else:
2973
2974 self._windows.append(page)
2975
2976 if bSelected:
2977
2978 bSelected = False
6cb4f153 2979
6a64d551
RD
2980 # Check for selection and send events
2981 oldSelection = self._pages._iActivePage
6cb4f153 2982
6a64d551
RD
2983 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
2984 event.SetSelection(indx)
2985 event.SetOldSelection(oldSelection)
2986 event.SetEventObject(self)
2987
33113971 2988 if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
6a64d551
RD
2989 bSelected = True
2990
2991 self._pages.InsertPage(indx, text, bSelected, imageId)
2992
2993 if indx <= curSel:
2994 curSel = curSel + 1
6cb4f153 2995
6a64d551 2996 self.Freeze()
6cb4f153 2997
6a64d551
RD
2998 # Check if a new selection was made
2999 if bSelected:
3000
3001 if curSel >= 0:
6cb4f153 3002
6a64d551
RD
3003 # Remove the window from the main sizer
3004 self._mainSizer.Detach(self._windows[curSel])
3005 self._windows[curSel].Hide()
6cb4f153 3006
6a64d551 3007 self._pages.SetSelection(indx)
6cb4f153 3008
6a64d551
RD
3009 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3010 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
3011 event.SetOldSelection(oldSelection)
3012 self.GetEventHandler().ProcessEvent(event)
3013
3014 else:
3015
3016 # Hide the page
3017 page.Hide()
33113971 3018
6a64d551 3019 self.Thaw()
33113971 3020 self._mainSizer.Layout()
6a64d551 3021 self.Refresh()
6cb4f153 3022
6a64d551 3023 return True
6cb4f153 3024
6a64d551
RD
3025
3026 def SetSelection(self, page):
6cb4f153 3027 """
6a64d551
RD
3028 Sets the selection for the given page.
3029 The call to this function generates the page changing events
6cb4f153
RD
3030 """
3031
6a64d551
RD
3032 if page >= len(self._windows) or not self._windows:
3033 return
6cb4f153 3034
6a64d551
RD
3035 # Support for disabed tabs
3036 if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection:
3037 return
3038
3039 curSel = self._pages.GetSelection()
3040
3041 # program allows the page change
3042 self.Freeze()
3043 if curSel >= 0:
6cb4f153 3044
6a64d551
RD
3045 # Remove the window from the main sizer
3046 self._mainSizer.Detach(self._windows[curSel])
3047 self._windows[curSel].Hide()
6cb4f153 3048
6a64d551 3049 if self.GetWindowStyleFlag() & FNB_BOTTOM:
6cb4f153 3050
6a64d551 3051 self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND)
6cb4f153 3052
6a64d551 3053 else:
6cb4f153 3054
6a64d551
RD
3055 # We leave a space of 1 pixel around the window
3056 self._mainSizer.Add(self._windows[page], 1, wx.EXPAND)
3057
3058 self._windows[page].Show()
3059 self.Thaw()
3060
3061 self._mainSizer.Layout()
3062
3063 if page != self._pages._iActivePage:
3064 # there is a real page changing
3065 self._pages._iPreviousActivePage = self._pages._iActivePage
6cb4f153 3066
6a64d551
RD
3067 self._pages._iActivePage = page
3068 self._pages.DoSetSelection(page)
6cb4f153 3069
6cb4f153 3070
6a64d551
RD
3071 def DeletePage(self, page):
3072 """
3073 Deletes the specified page, and the associated window.
3074 The call to this function generates the page changing events.
3075 """
6cb4f153 3076
6a64d551
RD
3077 if page >= len(self._windows) or page < 0:
3078 return
6cb4f153 3079
6a64d551
RD
3080 # Fire a closing event
3081 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
3082 event.SetSelection(page)
3083 event.SetEventObject(self)
3084 self.GetEventHandler().ProcessEvent(event)
6cb4f153 3085
6a64d551
RD
3086 # The event handler allows it?
3087 if not event.IsAllowed():
3088 return
6cb4f153 3089
6a64d551 3090 self.Freeze()
6cb4f153 3091
6a64d551
RD
3092 # Delete the requested page
3093 pageRemoved = self._windows[page]
6cb4f153 3094
6a64d551
RD
3095 # If the page is the current window, remove it from the sizer
3096 # as well
3097 if page == self._pages.GetSelection():
3098 self._mainSizer.Detach(pageRemoved)
6cb4f153 3099
6a64d551
RD
3100 # Remove it from the array as well
3101 self._windows.pop(page)
6cb4f153 3102
6a64d551
RD
3103 # Now we can destroy it in wxWidgets use Destroy instead of delete
3104 pageRemoved.Destroy()
3105
3106 self.Thaw()
3107
3108 self._pages.DoDeletePage(page)
3109 self.Refresh()
3110
3111 # Fire a closed event
3112 closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
3113 closedEvent.SetSelection(page)
3114 closedEvent.SetEventObject(self)
3115 self.GetEventHandler().ProcessEvent(closedEvent)
3116
3117
3118 def DeleteAllPages(self):
3119 """ Deletes all the pages. """
3120
3121 if not self._windows:
3122 return False
3123
3124 self.Freeze()
6cb4f153 3125
6a64d551
RD
3126 for page in self._windows:
3127 page.Destroy()
6cb4f153 3128
6a64d551
RD
3129 self._windows = []
3130 self.Thaw()
6cb4f153 3131
6a64d551
RD
3132 # Clear the container of the tabs as well
3133 self._pages.DeleteAllPages()
3134 return True
6cb4f153
RD
3135
3136
6a64d551
RD
3137 def GetCurrentPage(self):
3138 """ Returns the currently selected notebook page or None. """
3139
3140 sel = self._pages.GetSelection()
3141 if sel < 0:
3142 return None
6cb4f153 3143
6a64d551 3144 return self._windows[sel]
6cb4f153
RD
3145
3146
6a64d551
RD
3147 def GetPage(self, page):
3148 """ Returns the window at the given page position, or None. """
3149
3150 if page >= len(self._windows):
3151 return None
3152
3153 return self._windows[page]
3154
3155
3156 def GetPageIndex(self, win):
3157 """ Returns the index at which the window is found. """
3158
3159 try:
3160 return self._windows.index(win)
3161 except:
3162 return -1
3163
3164
3165 def GetSelection(self):
3166 """ Returns the currently selected page, or -1 if none was selected. """
3167
3168 return self._pages.GetSelection()
6cb4f153 3169
6cb4f153 3170
33113971 3171 def AdvanceSelection(self, forward=True):
6a64d551
RD
3172 """
3173 Cycles through the tabs.
3174 The call to this function generates the page changing events.
3175 """
6cb4f153 3176
33113971 3177 self._pages.AdvanceSelection(forward)
6cb4f153 3178
6cb4f153 3179
6a64d551
RD
3180 def GetPageCount(self):
3181 """ Returns the number of pages in the L{FlatNotebook} control. """
33113971 3182
6a64d551 3183 return self._pages.GetPageCount()
6cb4f153 3184
6cb4f153 3185
6a64d551
RD
3186 def OnNavigationKey(self, event):
3187 """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
6cb4f153 3188
6a64d551 3189 if event.IsWindowChange():
33113971
RD
3190 if len(self._windows) == 0:
3191 return
6a64d551
RD
3192 # change pages
3193 if self.HasFlag(FNB_SMART_TABS):
3194 if not self._popupWin:
3195 self._popupWin = TabNavigatorWindow(self)
3196 self._popupWin.SetReturnCode(wx.ID_OK)
3197 self._popupWin.ShowModal()
3198 self._popupWin.Destroy()
3199 self._popupWin = None
3200 else:
3201 # a dialog is already opened
3202 self._popupWin.OnNavigationKey(event)
3203 return
3204 else:
3205 # change pages
3206 self.AdvanceSelection(event.GetDirection())
3207 else:
3208 # pass to the parent
3209 if self.GetParent():
3210 event.SetCurrentFocus(self)
3211 self.GetParent().ProcessEvent(event)
3212
6cb4f153 3213
6a64d551
RD
3214 def GetPageShapeAngle(self, page_index):
3215 """ Returns the angle associated to a tab. """
6cb4f153 3216
6a64d551
RD
3217 if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
3218 return None, False
3219
3220 result = self._pages._pagesInfoVec[page_index].GetTabAngle()
3221 return result, True
6cb4f153
RD
3222
3223
6a64d551
RD
3224 def SetPageShapeAngle(self, page_index, angle):
3225 """ Sets the angle associated to a tab. """
6cb4f153 3226
6a64d551 3227 if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
6cb4f153
RD
3228 return
3229
6a64d551 3230 if angle > 15:
6cb4f153
RD
3231 return
3232
6a64d551 3233 self._pages._pagesInfoVec[page_index].SetTabAngle(angle)
6cb4f153 3234
6cb4f153 3235
6a64d551
RD
3236 def SetAllPagesShapeAngle(self, angle):
3237 """ Sets the angle associated to all the tab. """
6cb4f153 3238
6a64d551
RD
3239 if angle > 15:
3240 return
6cb4f153 3241
6a64d551
RD
3242 for ii in xrange(len(self._pages._pagesInfoVec)):
3243 self._pages._pagesInfoVec[ii].SetTabAngle(angle)
3244
3245 self.Refresh()
6cb4f153 3246
6cb4f153 3247
6a64d551
RD
3248 def GetPageBestSize(self):
3249 """ Return the page best size. """
6cb4f153 3250
6a64d551 3251 return self._pages.GetClientSize()
6cb4f153 3252
6cb4f153 3253
6a64d551
RD
3254 def SetPageText(self, page, text):
3255 """ Sets the text for the given page. """
6cb4f153 3256
6a64d551
RD
3257 bVal = self._pages.SetPageText(page, text)
3258 self._pages.Refresh()
6cb4f153 3259
6a64d551 3260 return bVal
6cb4f153
RD
3261
3262
6a64d551
RD
3263 def SetPadding(self, padding):
3264 """
3265 Sets the amount of space around each page's icon and label, in pixels.
3266 NB: only the horizontal padding is considered.
3267 """
6cb4f153 3268
6a64d551 3269 self._nPadding = padding.GetWidth()
6cb4f153 3270
6cb4f153 3271
6a64d551
RD
3272 def GetTabArea(self):
3273 """ Returns the associated page. """
6cb4f153 3274
6a64d551 3275 return self._pages
6cb4f153 3276
6cb4f153 3277
6a64d551
RD
3278 def GetPadding(self):
3279 """ Returns the amount of space around each page's icon and label, in pixels. """
3280
3281 return self._nPadding
6cb4f153
RD
3282
3283
6a64d551
RD
3284 def SetWindowStyleFlag(self, style):
3285 """ Sets the L{FlatNotebook} window style flags. """
3286
3287 wx.Panel.SetWindowStyleFlag(self, style)
33113971
RD
3288 renderer = self._pages._mgr.GetRenderer(self.GetWindowStyleFlag())
3289 renderer._tabHeight = None
6cb4f153 3290
6a64d551
RD
3291 if self._pages:
3292
3293 # For changing the tab position (i.e. placing them top/bottom)
3294 # refreshing the tab container is not enough
3295 self.SetSelection(self._pages._iActivePage)
6cb4f153 3296
6cb4f153 3297
6a64d551
RD
3298 def RemovePage(self, page):
3299 """ Deletes the specified page, without deleting the associated window. """
6cb4f153 3300
6a64d551
RD
3301 if page >= len(self._windows):
3302 return False
6cb4f153 3303
6a64d551
RD
3304 # Fire a closing event
3305 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
3306 event.SetSelection(page)
3307 event.SetEventObject(self)
3308 self.GetEventHandler().ProcessEvent(event)
6cb4f153 3309
6a64d551
RD
3310 # The event handler allows it?
3311 if not event.IsAllowed():
3312 return False
6cb4f153 3313
6a64d551 3314 self.Freeze()
6cb4f153 3315
6a64d551
RD
3316 # Remove the requested page
3317 pageRemoved = self._windows[page]
6cb4f153 3318
6a64d551
RD
3319 # If the page is the current window, remove it from the sizer
3320 # as well
3321 if page == self._pages.GetSelection():
3322 self._mainSizer.Detach(pageRemoved)
6cb4f153 3323
6a64d551
RD
3324 # Remove it from the array as well
3325 self._windows.pop(page)
3326 self.Thaw()
6cb4f153 3327
6a64d551 3328 self._pages.DoDeletePage(page)
6cb4f153 3329
6a64d551 3330 return True
6cb4f153 3331
6cb4f153 3332
6a64d551
RD
3333 def SetRightClickMenu(self, menu):
3334 """ Sets the popup menu associated to a right click on a tab. """
3335
3336 self._pages._pRightClickMenu = menu
6cb4f153 3337
6cb4f153 3338
33113971 3339 def GetPageText(self, nPage):
6a64d551 3340 """ Returns the tab caption. """
6cb4f153 3341
33113971 3342 return self._pages.GetPageText(nPage)
6cb4f153 3343
6cb4f153 3344
6a64d551
RD
3345 def SetGradientColours(self, fr, to, border):
3346 """ Sets the gradient colours for the tab. """
6cb4f153 3347
6a64d551
RD
3348 self._pages._colorFrom = fr
3349 self._pages._colorTo = to
3350 self._pages._colorBorder = border
6cb4f153 3351
6cb4f153 3352
6a64d551
RD
3353 def SetGradientColourFrom(self, fr):
3354 """ Sets the starting colour for the gradient. """
6cb4f153 3355
6a64d551 3356 self._pages._colorFrom = fr
6cb4f153 3357
6cb4f153 3358
6a64d551
RD
3359 def SetGradientColourTo(self, to):
3360 """ Sets the ending colour for the gradient. """
6cb4f153 3361
6a64d551 3362 self._pages._colorTo = to
6cb4f153 3363
6cb4f153 3364
6a64d551
RD
3365 def SetGradientColourBorder(self, border):
3366 """ Sets the tab border colour. """
6cb4f153 3367
6a64d551 3368 self._pages._colorBorder = border
6cb4f153 3369
6cb4f153 3370
6a64d551
RD
3371 def GetGradientColourFrom(self):
3372 """ Gets first gradient colour. """
6cb4f153 3373
6a64d551 3374 return self._pages._colorFrom
6cb4f153 3375
6cb4f153 3376
6a64d551
RD
3377 def GetGradientColourTo(self):
3378 """ Gets second gradient colour. """
6cb4f153 3379
6a64d551 3380 return self._pages._colorTo
6cb4f153 3381
6a64d551
RD
3382
3383 def GetGradientColourBorder(self):
3384 """ Gets the tab border colour. """
3385
3386 return self._pages._colorBorder
3387
3388
3389 def GetBorderColour(self):
3390 """ Returns the border colour. """
3391
3392 return self._pages._colorBorder
3393
3394
3395 def GetActiveTabTextColour(self):
3396 """ Get the active tab text colour. """
3397
3398 return self._pages._activeTextColor
3399
3400
33113971 3401 def SetPageImage(self, page, image):
6cb4f153 3402 """
6a64d551
RD
3403 Sets the image index for the given page. Image is an index into the
3404 image list which was set with SetImageList.
6cb4f153
RD
3405 """
3406
33113971 3407 self._pages.SetPageImage(page, image)
6cb4f153 3408
6cb4f153 3409
33113971 3410 def GetPageImage(self, nPage):
6a64d551
RD
3411 """
3412 Returns the image index for the given page. Image is an index into the
3413 image list which was set with SetImageList.
3414 """
6cb4f153 3415
33113971 3416 return self._pages.GetPageImage(nPage)
6cb4f153 3417
6cb4f153 3418
6a64d551
RD
3419 def GetEnabled(self, page):
3420 """ Returns whether a tab is enabled or not. """
6cb4f153 3421
6a64d551 3422 return self._pages.GetEnabled(page)
6cb4f153 3423
0a7f54ff 3424
6a64d551
RD
3425 def Enable(self, page, enabled=True):
3426 """ Enables or disables a tab. """
3427
3428 if page >= len(self._windows):
0a7f54ff 3429 return
6cb4f153 3430
6a64d551
RD
3431 self._windows[page].Enable(enabled)
3432 self._pages.Enable(page, enabled)
6cb4f153 3433
6cb4f153 3434
6a64d551
RD
3435 def GetNonActiveTabTextColour(self):
3436 """ Returns the non active tabs text colour. """
3437
3438 return self._pages._nonActiveTextColor
3439
3440
3441 def SetNonActiveTabTextColour(self, color):
3442 """ Sets the non active tabs text colour. """
3443
3444 self._pages._nonActiveTextColor = color
3445
3446
3447 def SetTabAreaColour(self, color):
3448 """ Sets the area behind the tabs colour. """
3449
3450 self._pages._tabAreaColor = color
3451
3452
3453 def GetTabAreaColour(self):
3454 """ Returns the area behind the tabs colour. """
3455
3456 return self._pages._tabAreaColor
3457
3458
3459 def SetActiveTabColour(self, color):
3460 """ Sets the active tab colour. """
3461
3462 self._pages._activeTabColor = color
3463
3464
3465 def GetActiveTabColour(self):
3466 """ Returns the active tab colour. """
3467
3468 return self._pages._activeTabColor
3469
3470
3471# ---------------------------------------------------------------------------- #
3472# Class PageContainer
3473# Acts as a container for the pages you add to FlatNotebook
3474# ---------------------------------------------------------------------------- #
3475
3476class PageContainer(wx.Panel):
3477 """
3478 This class acts as a container for the pages you add to L{FlatNotebook}.
3479 """
3480
3481 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
3482 size=wx.DefaultSize, style=0):
3483 """ Default class constructor. """
3484
3485 self._ImageList = None
3486 self._iActivePage = -1
3487 self._pDropTarget = None
3488 self._nLeftClickZone = FNB_NOWHERE
3489 self._iPreviousActivePage = -1
3490
3491 self._pRightClickMenu = None
6cb4f153 3492 self._nXButtonStatus = FNB_BTN_NONE
6a64d551
RD
3493 self._nArrowDownButtonStatus = FNB_BTN_NONE
3494 self._pParent = parent
6cb4f153 3495 self._nRightButtonStatus = FNB_BTN_NONE
6a64d551
RD
3496 self._nLeftButtonStatus = FNB_BTN_NONE
3497 self._nTabXButtonStatus = FNB_BTN_NONE
6cb4f153 3498
6a64d551 3499 self._pagesInfoVec = []
6cb4f153 3500
6a64d551
RD
3501 self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
3502 self._colorFrom = wx.WHITE
3503 self._activeTabColor = wx.WHITE
3504 self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
3505 self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
3506 self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
6cb4f153 3507
6a64d551
RD
3508 self._nFrom = 0
3509 self._isdragging = False
6cb4f153 3510
6a64d551
RD
3511 # Set default page height, this is done according to the system font
3512 memDc = wx.MemoryDC()
1c92f298 3513 memDc.SelectObject(wx.EmptyBitmap(1,1))
33113971
RD
3514
3515 if "__WXGTK__" in wx.PlatformInfo:
3516 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
3517 boldFont.SetWeight(wx.BOLD)
3518 memDc.SetFont(boldFont)
6a64d551
RD
3519
3520 height = memDc.GetCharHeight()
3521 tabHeight = height + FNB_HEIGHT_SPACER # We use 10 pixels as padding
3522
3523 wx.Panel.__init__(self, parent, id, pos, wx.Size(size.x, tabHeight),
3524 style|wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE)
6cb4f153 3525
6a64d551
RD
3526 self._pDropTarget = FNBDropTarget(self)
3527 self.SetDropTarget(self._pDropTarget)
3528 self._mgr = FNBRendererMgr()
3529
3530 self.Bind(wx.EVT_PAINT, self.OnPaint)
3531 self.Bind(wx.EVT_SIZE, self.OnSize)
3532 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
3533 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
3534 self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
3535 self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
3536 self.Bind(wx.EVT_MOTION, self.OnMouseMove)
3537 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
3538 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
3539 self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
3540 self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
6cb4f153 3541
6cb4f153 3542
6a64d551
RD
3543 def OnEraseBackground(self, event):
3544 """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
6cb4f153 3545
6a64d551 3546 pass
6cb4f153 3547
6a64d551
RD
3548
3549 def OnPaint(self, event):
3550 """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
6cb4f153 3551
33113971 3552 dc = wx.BufferedPaintDC(self)
6a64d551
RD
3553 renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
3554 renderer.DrawTabs(self, dc)
6cb4f153 3555
6cb4f153 3556
6a64d551
RD
3557 def AddPage(self, caption, selected=True, imgindex=-1):
3558 """
3559 Add a page to the L{FlatNotebook}.
6cb4f153 3560
6a64d551
RD
3561 @param window: Specifies the new page.
3562 @param caption: Specifies the text for the new page.
3563 @param selected: Specifies whether the page should be selected.
3564 @param imgindex: Specifies the optional image index for the new page.
6cb4f153 3565
6a64d551
RD
3566 Return value:
3567 True if successful, False otherwise.
3568 """
6cb4f153 3569
6a64d551 3570 if selected:
6cb4f153 3571
6a64d551
RD
3572 self._iPreviousActivePage = self._iActivePage
3573 self._iActivePage = len(self._pagesInfoVec)
3574
3575 # Create page info and add it to the vector
3576 pageInfo = PageInfo(caption, imgindex)
3577 self._pagesInfoVec.append(pageInfo)
3578 self.Refresh()
6cb4f153 3579
6cb4f153 3580
6a64d551
RD
3581 def InsertPage(self, indx, text, selected=True, imgindex=-1):
3582 """
3583 Inserts a new page at the specified position.
6cb4f153 3584
6a64d551
RD
3585 @param indx: Specifies the position of the new page.
3586 @param page: Specifies the new page.
3587 @param text: Specifies the text for the new page.
3588 @param select: Specifies whether the page should be selected.
3589 @param imgindex: Specifies the optional image index for the new page.
3590
3591 Return value:
3592 True if successful, False otherwise.
3593 """
6cb4f153 3594
6a64d551 3595 if selected:
6cb4f153 3596
6a64d551
RD
3597 self._iPreviousActivePage = self._iActivePage
3598 self._iActivePage = len(self._pagesInfoVec)
6cb4f153 3599
6a64d551 3600 self._pagesInfoVec.insert(indx, PageInfo(text, imgindex))
6cb4f153 3601
6a64d551
RD
3602 self.Refresh()
3603 return True
6cb4f153 3604
6cb4f153 3605
6a64d551
RD
3606 def OnSize(self, event):
3607 """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
6cb4f153 3608
6a64d551
RD
3609 self.Refresh() # Call on paint
3610 event.Skip()
6cb4f153
RD
3611
3612
6a64d551
RD
3613 def OnMiddleDown(self, event):
3614 """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
6cb4f153 3615
6a64d551
RD
3616 # Test if this style is enabled
3617 style = self.GetParent().GetWindowStyleFlag()
3618
3619 if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS:
6cb4f153
RD
3620 return
3621
6a64d551 3622 where, tabIdx = self.HitTest(event.GetPosition())
6cb4f153 3623
6a64d551
RD
3624 if where == FNB_TAB:
3625 self.DeletePage(tabIdx)
3626
3627 event.Skip()
6cb4f153 3628
6cb4f153 3629
6a64d551
RD
3630 def OnRightDown(self, event):
3631 """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
6cb4f153 3632
6a64d551 3633 if self._pRightClickMenu:
6cb4f153 3634
6a64d551 3635 where, tabIdx = self.HitTest(event.GetPosition())
6cb4f153 3636
6a64d551 3637 if where in [FNB_TAB, FNB_TAB_X]:
6cb4f153 3638
6a64d551
RD
3639 if self._pagesInfoVec[tabIdx].GetEnabled():
3640 # Set the current tab to be active
3641 self.SetSelection(tabIdx)
6cb4f153 3642
6a64d551
RD
3643 # If the owner has defined a context menu for the tabs,
3644 # popup the right click menu
3645 if self._pRightClickMenu:
3646 self.PopupMenu(self._pRightClickMenu)
3647 else:
3648 # send a message to popup a custom menu
3649 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId())
3650 event.SetSelection(tabIdx)
3651 event.SetOldSelection(self._iActivePage)
3652 event.SetEventObject(self.GetParent())
3653 self.GetParent().GetEventHandler().ProcessEvent(event)
3654
3655 event.Skip()
6cb4f153 3656
6cb4f153 3657
6a64d551
RD
3658 def OnLeftDown(self, event):
3659 """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
6cb4f153 3660
6a64d551
RD
3661 # Reset buttons status
3662 self._nXButtonStatus = FNB_BTN_NONE
3663 self._nLeftButtonStatus = FNB_BTN_NONE
3664 self._nRightButtonStatus = FNB_BTN_NONE
3665 self._nTabXButtonStatus = FNB_BTN_NONE
3666 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 3667
6a64d551 3668 self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition())
6cb4f153 3669
6a64d551
RD
3670 if self._nLeftClickZone == FNB_DROP_DOWN_ARROW:
3671 self._nArrowDownButtonStatus = FNB_BTN_PRESSED
3672 self.Refresh()
3673 elif self._nLeftClickZone == FNB_LEFT_ARROW:
3674 self._nLeftButtonStatus = FNB_BTN_PRESSED
3675 self.Refresh()
3676 elif self._nLeftClickZone == FNB_RIGHT_ARROW:
3677 self._nRightButtonStatus = FNB_BTN_PRESSED
3678 self.Refresh()
3679 elif self._nLeftClickZone == FNB_X:
3680 self._nXButtonStatus = FNB_BTN_PRESSED
3681 self.Refresh()
3682 elif self._nLeftClickZone == FNB_TAB_X:
3683 self._nTabXButtonStatus = FNB_BTN_PRESSED
3684 self.Refresh()
6cb4f153 3685
6a64d551
RD
3686 elif self._nLeftClickZone == FNB_TAB:
3687
3688 if self._iActivePage != tabIdx:
33113971 3689
6a64d551
RD
3690 # In case the tab is disabled, we dont allow to choose it
3691 if self._pagesInfoVec[tabIdx].GetEnabled():
33113971 3692 self.FireEvent(tabIdx)
6cb4f153 3693
6cb4f153 3694
6a64d551
RD
3695 def OnLeftUp(self, event):
3696 """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
6cb4f153 3697
6a64d551
RD
3698 # forget the zone that was initially clicked
3699 self._nLeftClickZone = FNB_NOWHERE
3700
3701 where, tabIdx = self.HitTest(event.GetPosition())
3702
3703 if where == FNB_LEFT_ARROW:
6cb4f153 3704
6a64d551
RD
3705 if self._nFrom == 0:
3706 return
6cb4f153 3707
6a64d551
RD
3708 # Make sure that the button was pressed before
3709 if self._nLeftButtonStatus != FNB_BTN_PRESSED:
3710 return
6cb4f153 3711
6a64d551 3712 self._nLeftButtonStatus = FNB_BTN_HOVER
6cb4f153 3713
6a64d551
RD
3714 # We scroll left with bulks of 5
3715 scrollLeft = self.GetNumTabsCanScrollLeft()
6cb4f153 3716
6a64d551
RD
3717 self._nFrom -= scrollLeft
3718 if self._nFrom < 0:
3719 self._nFrom = 0
6cb4f153 3720
6a64d551
RD
3721 self.Refresh()
3722
3723 elif where == FNB_RIGHT_ARROW:
3724
3725 if self._nFrom >= len(self._pagesInfoVec) - 1:
3726 return
6cb4f153 3727
6a64d551
RD
3728 # Make sure that the button was pressed before
3729 if self._nRightButtonStatus != FNB_BTN_PRESSED:
3730 return
3731
3732 self._nRightButtonStatus = FNB_BTN_HOVER
3733
3734 # Check if the right most tab is visible, if it is
3735 # don't rotate right anymore
3736 if self._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
3737 return
6cb4f153 3738
6a64d551
RD
3739 lastVisibleTab = self.GetLastVisibleTab()
3740 if lastVisibleTab < 0:
3741 # Probably the screen is too small for displaying even a single
3742 # tab, in this case we do nothing
3743 return
6cb4f153 3744
6a64d551
RD
3745 self._nFrom += self.GetNumOfVisibleTabs()
3746 self.Refresh()
3747
3748 elif where == FNB_X:
3749
3750 # Make sure that the button was pressed before
3751 if self._nXButtonStatus != FNB_BTN_PRESSED:
3752 return
6cb4f153 3753
6a64d551 3754 self._nXButtonStatus = FNB_BTN_HOVER
6cb4f153 3755
6a64d551
RD
3756 self.DeletePage(self._iActivePage)
3757
3758 elif where == FNB_TAB_X:
3759
3760 # Make sure that the button was pressed before
3761 if self._nTabXButtonStatus != FNB_BTN_PRESSED:
3762 return
6cb4f153 3763
6a64d551 3764 self._nTabXButtonStatus = FNB_BTN_HOVER
6cb4f153 3765
6a64d551 3766 self.DeletePage(self._iActivePage)
6cb4f153 3767
6a64d551 3768 elif where == FNB_DROP_DOWN_ARROW:
6cb4f153 3769
6a64d551
RD
3770 # Make sure that the button was pressed before
3771 if self._nArrowDownButtonStatus != FNB_BTN_PRESSED:
3772 return
6cb4f153 3773
6a64d551 3774 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 3775
6a64d551
RD
3776 # Refresh the button status
3777 renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
3778 dc = wx.ClientDC(self)
3779 renderer.DrawDropDownArrow(self, dc)
6cb4f153 3780
6a64d551 3781 self.PopupTabsMenu()
6cb4f153
RD
3782
3783
6a64d551
RD
3784 def HitTest(self, pt):
3785 """
3786 HitTest method for L{PageContainer}.
3787 Returns the flag (if any) and the hit page (if any).
3788 """
6cb4f153
RD
3789
3790 style = self.GetParent().GetWindowStyleFlag()
6a64d551 3791 render = self._mgr.GetRenderer(style)
6cb4f153 3792
6a64d551
RD
3793 fullrect = self.GetClientRect()
3794 btnLeftPos = render.GetLeftButtonPos(self)
3795 btnRightPos = render.GetRightButtonPos(self)
3796 btnXPos = render.GetXPos(self)
3797
3798 tabIdx = -1
3799
3800 if len(self._pagesInfoVec) == 0:
3801 return FNB_NOWHERE, tabIdx
6cb4f153 3802
6a64d551
RD
3803 rect = wx.Rect(btnXPos, 8, 16, 16)
3804 if rect.Contains(pt):
3805 return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], tabIdx
6cb4f153 3806
6a64d551
RD
3807 rect = wx.Rect(btnRightPos, 8, 16, 16)
3808 if style & FNB_DROPDOWN_TABS_LIST:
3809 rect = wx.Rect(render.GetDropArrowButtonPos(self), 8, 16, 16)
3810 if rect.Contains(pt):
3811 return FNB_DROP_DOWN_ARROW, tabIdx
6cb4f153 3812
6a64d551
RD
3813 if rect.Contains(pt):
3814 return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], tabIdx
6cb4f153 3815
6a64d551
RD
3816 rect = wx.Rect(btnLeftPos, 8, 16, 16)
3817 if rect.Contains(pt):
3818 return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], tabIdx
6cb4f153 3819
6a64d551
RD
3820 # Test whether a left click was made on a tab
3821 bFoundMatch = False
6cb4f153 3822
6a64d551 3823 for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
6cb4f153 3824
6a64d551 3825 pgInfo = self._pagesInfoVec[cur]
6cb4f153 3826
6a64d551
RD
3827 if pgInfo.GetPosition() == wx.Point(-1, -1):
3828 continue
6cb4f153 3829
6a64d551
RD
3830 if style & FNB_X_ON_TAB and cur == self.GetSelection():
3831 # 'x' button exists on a tab
3832 if self._pagesInfoVec[cur].GetXRect().Contains(pt):
3833 return FNB_TAB_X, cur
3834
3835 if style & FNB_VC8:
6cb4f153 3836
6a64d551
RD
3837 if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y):
3838 if bFoundMatch or cur == self.GetSelection():
3839 return FNB_TAB, cur
6cb4f153 3840
6a64d551
RD
3841 tabIdx = cur
3842 bFoundMatch = True
3843
6cb4f153 3844 else:
6a64d551
RD
3845
3846 tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y,
3847 pgInfo.GetSize().x, pgInfo.GetSize().y)
6cb4f153 3848
6a64d551
RD
3849 if tabRect.Contains(pt):
3850 # We have a match
3851 return FNB_TAB, cur
6cb4f153 3852
6a64d551
RD
3853 if bFoundMatch:
3854 return FNB_TAB, tabIdx
6cb4f153 3855
6a64d551
RD
3856 if self._isdragging:
3857 # We are doing DND, so check also the region outside the tabs
3858 # try before the first tab
3859 pgInfo = self._pagesInfoVec[0]
3860 tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
3861 if tabRect.Contains(pt):
3862 return FNB_TAB, 0
6cb4f153 3863
6a64d551
RD
3864 # try after the last tab
3865 pgInfo = self._pagesInfoVec[-1]
3866 startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
3867 tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
6cb4f153 3868
6a64d551
RD
3869 if tabRect.Contains(pt):
3870 return FNB_TAB, len(self._pagesInfoVec)
6cb4f153 3871
6a64d551
RD
3872 # Default
3873 return FNB_NOWHERE, -1
6cb4f153
RD
3874
3875
6a64d551
RD
3876 def SetSelection(self, page):
3877 """ Sets the selected page. """
6cb4f153 3878
6a64d551
RD
3879 book = self.GetParent()
3880 book.SetSelection(page)
3881 self.DoSetSelection(page)
6cb4f153
RD
3882
3883
6a64d551
RD
3884 def DoSetSelection(self, page):
3885 """ Does the actual selection of a page. """
6cb4f153 3886
6a64d551
RD
3887 if page < len(self._pagesInfoVec):
3888 #! fix for tabfocus
3889 da_page = self._pParent.GetPage(page)
3890
3891 if da_page != None:
3892 da_page.SetFocus()
6cb4f153 3893
6a64d551 3894 if not self.IsTabVisible(page):
6cb4f153 3895
6a64d551
RD
3896 if page == len(self._pagesInfoVec) - 1:
3897 # Incase the added tab is last,
3898 # the function IsTabVisible() will always return False
3899 # and thus will cause an evil behaviour that the new
3900 # tab will hide all other tabs, we need to check if the
3901 # new selected tab can fit to the current screen
3902 if not self.CanFitToScreen(page):
3903 self._nFrom = page
3904
3905 else:
6cb4f153 3906
6a64d551
RD
3907 if not self.CanFitToScreen(page):
3908 # Redraw the tabs starting from page
3909 self._nFrom = page
3910
3911 self.Refresh()
6cb4f153 3912
6cb4f153 3913
6a64d551
RD
3914 def DeletePage(self, page):
3915 """ Delete the specified page from L{FlatNotebook}. """
6cb4f153 3916
6a64d551
RD
3917 book = self.GetParent()
3918 book.DeletePage(page)
3919 book.Refresh()
6cb4f153 3920
6cb4f153 3921
6a64d551
RD
3922 def IsTabVisible(self, page):
3923 """ Returns whether a tab is visible or not. """
6cb4f153 3924
6a64d551
RD
3925 iLastVisiblePage = self.GetLastVisibleTab()
3926 return page <= iLastVisiblePage and page >= self._nFrom
6cb4f153 3927
6cb4f153 3928
6a64d551
RD
3929 def DoDeletePage(self, page):
3930 """ Does the actual page deletion. """
6cb4f153 3931
6a64d551
RD
3932 # Remove the page from the vector
3933 book = self.GetParent()
3934 self._pagesInfoVec.pop(page)
6cb4f153 3935
6a64d551
RD
3936 # Thanks to Yiaanis AKA Mandrav
3937 if self._iActivePage >= page:
3938 self._iActivePage = self._iActivePage - 1
3939 self._iPreviousActivePage = -1
6cb4f153 3940
6a64d551
RD
3941 # The delete page was the last first on the array,
3942 # but the book still has more pages, so we set the
3943 # active page to be the first one (0)
3944 if self._iActivePage < 0 and len(self._pagesInfoVec) > 0:
3945 self._iActivePage = 0
3946 self._iPreviousActivePage = -1
6cb4f153 3947
6a64d551
RD
3948 # Refresh the tabs
3949 if self._iActivePage >= 0:
6cb4f153 3950
6a64d551 3951 book._bForceSelection = True
6cb4f153 3952
6a64d551
RD
3953 # Check for selection and send event
3954 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
3955 event.SetSelection(self._iActivePage)
3956 event.SetOldSelection(self._iPreviousActivePage)
3957 event.SetEventObject(self.GetParent())
6cb4f153 3958
6a64d551
RD
3959 book.SetSelection(self._iActivePage)
3960 book._bForceSelection = False
6cb4f153 3961
6a64d551
RD
3962 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
3963 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
3964 event.SetOldSelection(self._iPreviousActivePage)
3965 self.GetParent().GetEventHandler().ProcessEvent(event)
3966
3967 if not self._pagesInfoVec:
3968 # Erase the page container drawings
3969 dc = wx.ClientDC(self)
3970 dc.Clear()
6cb4f153 3971
6cb4f153 3972
6a64d551
RD
3973 def DeleteAllPages(self):
3974 """ Deletes all the pages. """
6cb4f153 3975
6a64d551
RD
3976 self._iActivePage = -1
3977 self._iPreviousActivePage = -1
3978 self._nFrom = 0
3979 self._pagesInfoVec = []
6cb4f153 3980
6a64d551
RD
3981 # Erase the page container drawings
3982 dc = wx.ClientDC(self)
3983 dc.Clear()
6cb4f153 3984
6cb4f153 3985
6a64d551
RD
3986 def OnMouseMove(self, event):
3987 """ Handles the wx.EVT_MOTION for L{PageContainer}. """
6cb4f153 3988
6a64d551 3989 if self._pagesInfoVec and self.IsShown():
6cb4f153 3990
6a64d551
RD
3991 xButtonStatus = self._nXButtonStatus
3992 xTabButtonStatus = self._nTabXButtonStatus
3993 rightButtonStatus = self._nRightButtonStatus
3994 leftButtonStatus = self._nLeftButtonStatus
3995 dropDownButtonStatus = self._nArrowDownButtonStatus
3996
3997 style = self.GetParent().GetWindowStyleFlag()
6cb4f153 3998
6a64d551
RD
3999 self._nXButtonStatus = FNB_BTN_NONE
4000 self._nRightButtonStatus = FNB_BTN_NONE
4001 self._nLeftButtonStatus = FNB_BTN_NONE
4002 self._nTabXButtonStatus = FNB_BTN_NONE
4003 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 4004
6a64d551
RD
4005 where, tabIdx = self.HitTest(event.GetPosition())
4006
4007 if where == FNB_X:
4008 if event.LeftIsDown():
4009
4010 self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4011
4012 else:
4013
4014 self._nXButtonStatus = FNB_BTN_HOVER
6cb4f153 4015
6a64d551
RD
4016 elif where == FNB_DROP_DOWN_ARROW:
4017 if event.LeftIsDown():
6cb4f153 4018
6a64d551 4019 self._nArrowDownButtonStatus = (self._nLeftClickZone==FNB_DROP_DOWN_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
6cb4f153 4020
6a64d551 4021 else:
6cb4f153 4022
6a64d551 4023 self._nArrowDownButtonStatus = FNB_BTN_HOVER
6cb4f153 4024
6a64d551
RD
4025 elif where == FNB_TAB_X:
4026 if event.LeftIsDown():
4027
4028 self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4029
4030 else:
6cb4f153 4031
6a64d551
RD
4032 self._nTabXButtonStatus = FNB_BTN_HOVER
4033
4034 elif where == FNB_RIGHT_ARROW:
4035 if event.LeftIsDown():
4036
4037 self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4038
4039 else:
4040
4041 self._nRightButtonStatus = FNB_BTN_HOVER
4042
4043 elif where == FNB_LEFT_ARROW:
4044 if event.LeftIsDown():
4045
4046 self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
4047
4048 else:
4049
4050 self._nLeftButtonStatus = FNB_BTN_HOVER
4051
4052 elif where == FNB_TAB:
4053 # Call virtual method for showing tooltip
4054 self.ShowTabTooltip(tabIdx)
4055
4056 if not self.GetEnabled(tabIdx):
4057 # Set the cursor to be 'No-entry'
4058 wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
4059
4060 # Support for drag and drop
33113971 4061 if event.Dragging() and not (style & FNB_NODRAG):
6cb4f153 4062
6a64d551
RD
4063 self._isdragging = True
4064 draginfo = FNBDragInfo(self, tabIdx)
4065 drginfo = cPickle.dumps(draginfo)
4066 dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
4067 dataobject.SetData(drginfo)
33113971 4068 dragSource = FNBDropSource(self)
6a64d551
RD
4069 dragSource.SetData(dataobject)
4070 dragSource.DoDragDrop(wx.Drag_DefaultMove)
4071
4072 bRedrawX = self._nXButtonStatus != xButtonStatus
4073 bRedrawRight = self._nRightButtonStatus != rightButtonStatus
4074 bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus
4075 bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus
4076 bRedrawDropArrow = self._nArrowDownButtonStatus != dropDownButtonStatus
6cb4f153 4077
6a64d551 4078 render = self._mgr.GetRenderer(style)
6cb4f153 4079
6a64d551 4080 if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX or bRedrawDropArrow):
6cb4f153 4081
6a64d551
RD
4082 dc = wx.ClientDC(self)
4083
4084 if bRedrawX:
4085
4086 render.DrawX(self, dc)
4087
4088 if bRedrawLeft:
4089
4090 render.DrawLeftArrow(self, dc)
4091
4092 if bRedrawRight:
4093
4094 render.DrawRightArrow(self, dc)
4095
4096 if bRedrawTabX:
4097
4098 render.DrawTabX(self, dc, self._pagesInfoVec[tabIdx].GetXRect(), tabIdx, self._nTabXButtonStatus)
6cb4f153 4099
6a64d551 4100 if bRedrawDropArrow:
6cb4f153 4101
6a64d551 4102 render.DrawDropDownArrow(self, dc)
6cb4f153 4103
6a64d551 4104 event.Skip()
6cb4f153 4105
6cb4f153 4106
6a64d551
RD
4107 def GetLastVisibleTab(self):
4108 """ Returns the last visible tab. """
6cb4f153 4109
6a64d551 4110 ii = 0
6cb4f153 4111
6a64d551 4112 for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
6cb4f153 4113
6a64d551 4114 if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
6cb4f153 4115 break
6cb4f153 4116
6a64d551
RD
4117 return ii-1
4118
6cb4f153
RD
4119
4120 def GetNumTabsCanScrollLeft(self):
4121 """ Returns the number of tabs than can be scrolled left. """
4122
4123 # Reserved area for the buttons (<>x)
4124 rect = self.GetClientRect()
4125 clientWidth = rect.width
6a64d551 4126 posx = self._pParent._nPadding
6cb4f153
RD
4127 numTabs = 0
4128 pom = 0
6a64d551
RD
4129
4130 # In case we have error prevent crash
6cb4f153
RD
4131 if self._nFrom < 0:
4132 return 0
4133
6a64d551
RD
4134 dc = wx.ClientDC(self)
4135
6cb4f153 4136 style = self.GetParent().GetWindowStyleFlag()
6a64d551 4137 render = self._mgr.GetRenderer(style)
6cb4f153 4138
6a64d551
RD
4139 for ii in xrange(self._nFrom, -1, -1):
4140
4141 boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
6cb4f153
RD
4142 boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
4143 dc.SetFont(boldFont)
4144
6a64d551 4145 height = dc.GetCharHeight()
6cb4f153
RD
4146
4147 tabHeight = height + FNB_HEIGHT_SPACER # We use 6 pixels as padding
6cb4f153 4148 if style & FNB_VC71:
6a64d551 4149 tabHeight = (style & FNB_BOTTOM and [tabHeight - 4] or [tabHeight])[0]
6cb4f153 4150 elif style & FNB_FANCY_TABS:
6a64d551 4151 tabHeight = (style & FNB_BOTTOM and [tabHeight - 3] or [tabHeight])[0]
6cb4f153 4152
6a64d551 4153 width, pom = dc.GetTextExtent(self.GetPageText(ii))
6cb4f153 4154 if style != FNB_VC71:
6a64d551 4155 shapePoints = int(tabHeight*math.tan(float(self._pagesInfoVec[ii].GetTabAngle())/180.0*math.pi))
6cb4f153
RD
4156 else:
4157 shapePoints = 0
4158
6a64d551
RD
4159 tabWidth = 2*self._pParent._nPadding + width
4160
4161 if not (style & FNB_VC71):
6cb4f153
RD
4162 # Default style
4163 tabWidth += 2*shapePoints
4164
6a64d551
RD
4165 hasImage = self._ImageList != None and self._pagesInfoVec[ii].GetImageIndex() != -1
4166
6cb4f153 4167 # For VC71 style, we only add the icon size (16 pixels)
6a64d551 4168 if hasImage:
6cb4f153
RD
4169
4170 if not self.IsDefaultTabs():
6a64d551 4171 tabWidth += 16 + self._pParent._nPadding
6cb4f153
RD
4172 else:
4173 # Default style
6a64d551 4174 tabWidth += 16 + self._pParent._nPadding + shapePoints/2
6cb4f153 4175
6a64d551
RD
4176 if posx + tabWidth + render.GetButtonsAreaLength(self) >= clientWidth:
4177 break
6cb4f153 4178
6a64d551
RD
4179 numTabs = numTabs + 1
4180 posx += tabWidth
6cb4f153 4181
6a64d551 4182 return numTabs
6cb4f153
RD
4183
4184
6a64d551
RD
4185 def IsDefaultTabs(self):
4186 """ Returns whether a tab has a default style. """
4187
4188 style = self.GetParent().GetWindowStyleFlag()
4189 res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8)
4190 return not res
4191
4192
4193 def AdvanceSelection(self, bForward=True):
6cb4f153 4194 """
6a64d551
RD
4195 Cycles through the tabs.
4196 The call to this function generates the page changing events.
6cb4f153
RD
4197 """
4198
6a64d551 4199 nSel = self.GetSelection()
6cb4f153 4200
6a64d551
RD
4201 if nSel < 0:
4202 return
6cb4f153 4203
6a64d551 4204 nMax = self.GetPageCount() - 1
6cb4f153 4205
6a64d551
RD
4206 if bForward:
4207 newSelection = (nSel == nMax and [0] or [nSel + 1])[0]
4208 else:
4209 newSelection = (nSel == 0 and [nMax] or [nSel - 1])[0]
6cb4f153 4210
6a64d551
RD
4211 if not self._pagesInfoVec[newSelection].GetEnabled():
4212 return
6cb4f153 4213
33113971 4214 self.FireEvent(newSelection)
6cb4f153 4215
6cb4f153 4216
6a64d551
RD
4217 def OnMouseLeave(self, event):
4218 """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
6cb4f153 4219
6a64d551
RD
4220 self._nLeftButtonStatus = FNB_BTN_NONE
4221 self._nXButtonStatus = FNB_BTN_NONE
4222 self._nRightButtonStatus = FNB_BTN_NONE
4223 self._nTabXButtonStatus = FNB_BTN_NONE
4224 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 4225
6a64d551
RD
4226 style = self.GetParent().GetWindowStyleFlag()
4227 render = self._mgr.GetRenderer(style)
6cb4f153 4228
6a64d551 4229 dc = wx.ClientDC(self)
6cb4f153 4230
6a64d551
RD
4231 render.DrawX(self, dc)
4232 render.DrawLeftArrow(self, dc)
4233 render.DrawRightArrow(self, dc)
6cb4f153 4234
6a64d551 4235 selection = self.GetSelection()
6cb4f153 4236
6a64d551
RD
4237 if selection == -1:
4238 event.Skip()
4239 return
6cb4f153 4240
6a64d551
RD
4241 if not self.IsTabVisible(selection):
4242 if selection == len(self._pagesInfoVec) - 1:
4243 if not self.CanFitToScreen(selection):
4244 event.Skip()
4245 return
4246 else:
4247 event.Skip()
4248 return
4249
4250 render.DrawTabX(self, dc, self._pagesInfoVec[selection].GetXRect(), selection, self._nTabXButtonStatus)
4251
4252 event.Skip()
6cb4f153 4253
6cb4f153 4254
6a64d551
RD
4255 def OnMouseEnterWindow(self, event):
4256 """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
6cb4f153 4257
6a64d551
RD
4258 self._nLeftButtonStatus = FNB_BTN_NONE
4259 self._nXButtonStatus = FNB_BTN_NONE
4260 self._nRightButtonStatus = FNB_BTN_NONE
4261 self._nLeftClickZone = FNB_BTN_NONE
4262 self._nArrowDownButtonStatus = FNB_BTN_NONE
6cb4f153 4263
6a64d551 4264 event.Skip()
6cb4f153 4265
6cb4f153 4266
6a64d551
RD
4267 def ShowTabTooltip(self, tabIdx):
4268 """ Shows a tab tooltip. """
6cb4f153 4269
6a64d551 4270 pWindow = self._pParent.GetPage(tabIdx)
6cb4f153 4271
6a64d551
RD
4272 if pWindow:
4273 pToolTip = pWindow.GetToolTip()
4274 if pToolTip and pToolTip.GetWindow() == pWindow:
4275 self.SetToolTipString(pToolTip.GetTip())
6cb4f153 4276
6cb4f153 4277
6a64d551
RD
4278 def SetPageImage(self, page, imgindex):
4279 """ Sets the image index associated to a page. """
6cb4f153 4280
6a64d551
RD
4281 if page < len(self._pagesInfoVec):
4282
4283 self._pagesInfoVec[page].SetImageIndex(imgindex)
4284 self.Refresh()
6cb4f153 4285
6cb4f153 4286
6a64d551
RD
4287 def GetPageImage(self, page):
4288 """ Returns the image index associated to a page. """
6cb4f153 4289
6a64d551
RD
4290 if page < len(self._pagesInfoVec):
4291
4292 return self._pagesInfoVec[page].GetImageIndex()
4293
4294 return -1
6cb4f153 4295
6cb4f153 4296
6a64d551
RD
4297 def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
4298 """ Handles the drop action from a DND operation. """
6cb4f153 4299
6a64d551
RD
4300 # Disable drag'n'drop for disabled tab
4301 if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled():
4302 return wx.DragCancel
6cb4f153 4303
6a64d551
RD
4304 self._isdragging = True
4305 oldContainer = wnd_oldContainer
4306 nIndex = -1
6cb4f153 4307
6a64d551 4308 where, nIndex = self.HitTest(wx.Point(x, y))
6cb4f153 4309
6a64d551
RD
4310 oldNotebook = oldContainer.GetParent()
4311 newNotebook = self.GetParent()
6cb4f153 4312
6a64d551
RD
4313 if oldNotebook == newNotebook:
4314
4315 if nTabPage >= 0:
6cb4f153 4316
6a64d551
RD
4317 if where == FNB_TAB:
4318 self.MoveTabPage(nTabPage, nIndex)
33113971 4319
6a64d551
RD
4320 elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND:
4321
4322 if wx.Platform in ["__WXMSW__", "__WXGTK__"]:
4323 if nTabPage >= 0:
4324
4325 window = oldNotebook.GetPage(nTabPage)
6cb4f153 4326
6a64d551
RD
4327 if window:
4328 where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y))
4329 caption = oldContainer.GetPageText(nTabPage)
4330 imageindex = oldContainer.GetPageImage(nTabPage)
4331 oldNotebook.RemovePage(nTabPage)
4332 window.Reparent(newNotebook)
6cb4f153 4333
6a64d551
RD
4334 if imageindex >= 0:
4335
33113971 4336 bmp = oldNotebook.GetImageList().GetIcon(imageindex)
6a64d551
RD
4337 newImageList = newNotebook.GetImageList()
4338
4339 if not newImageList:
4340 xbmp, ybmp = bmp.GetWidth(), bmp.GetHeight()
4341 newImageList = wx.ImageList(xbmp, ybmp)
4342 imageindex = 0
4343 else:
4344 imageindex = newImageList.GetImageCount()
4345
33113971 4346 newImageList.AddIcon(bmp)
6a64d551
RD
4347 newNotebook.SetImageList(newImageList)
4348
4349 newNotebook.InsertPage(nIndex, window, caption, True, imageindex)
4350
4351 self._isdragging = False
6cb4f153 4352
6a64d551 4353 return wx.DragMove
6cb4f153 4354
6cb4f153 4355
6a64d551
RD
4356 def MoveTabPage(self, nMove, nMoveTo):
4357 """ Moves a tab inside the same L{FlatNotebook}. """
6cb4f153 4358
6a64d551
RD
4359 if nMove == nMoveTo:
4360 return
6cb4f153 4361
6a64d551
RD
4362 elif nMoveTo < len(self._pParent._windows):
4363 nMoveTo = nMoveTo + 1
6cb4f153 4364
6a64d551
RD
4365 self._pParent.Freeze()
4366
4367 # Remove the window from the main sizer
4368 nCurSel = self._pParent._pages.GetSelection()
4369 self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel])
4370 self._pParent._windows[nCurSel].Hide()
6cb4f153 4371
6a64d551
RD
4372 pWindow = self._pParent._windows[nMove]
4373 self._pParent._windows.pop(nMove)
4374 self._pParent._windows.insert(nMoveTo-1, pWindow)
6cb4f153 4375
6a64d551 4376 pgInfo = self._pagesInfoVec[nMove]
6cb4f153 4377
6a64d551
RD
4378 self._pagesInfoVec.pop(nMove)
4379 self._pagesInfoVec.insert(nMoveTo - 1, pgInfo)
6cb4f153 4380
6a64d551
RD
4381 # Add the page according to the style
4382 pSizer = self._pParent._mainSizer
4383 style = self.GetParent().GetWindowStyleFlag()
4384
4385 if style & FNB_BOTTOM:
6cb4f153 4386
6a64d551 4387 pSizer.Insert(0, pWindow, 1, wx.EXPAND)
6cb4f153 4388
6a64d551
RD
4389 else:
4390
4391 # We leave a space of 1 pixel around the window
4392 pSizer.Add(pWindow, 1, wx.EXPAND)
4393
4394 pWindow.Show()
4395
4396 pSizer.Layout()
4397 self._iActivePage = nMoveTo - 1
4398 self._iPreviousActivePage = -1
4399 self.DoSetSelection(self._iActivePage)
4400 self.Refresh()
4401 self._pParent.Thaw()
4402
4403
4404 def CanFitToScreen(self, page):
4405 """ Returns wheter a tab can fit in the left space in the screen or not. """
4406
4407 # Incase the from is greater than page,
4408 # we need to reset the self._nFrom, so in order
4409 # to force the caller to do so, we return false
4410 if self._nFrom > page:
4411 return False
6cb4f153 4412
6a64d551
RD
4413 style = self.GetParent().GetWindowStyleFlag()
4414 render = self._mgr.GetRenderer(style)
6cb4f153 4415
6a64d551
RD
4416 if not self.HasFlag(FNB_VC8):
4417 rect = self.GetClientRect();
4418 clientWidth = rect.width;
4419 tabHeight = render.CalcTabHeight(self)
4420 tabWidth = render.CalcTabWidth(self, page, tabHeight)
6cb4f153 4421
6a64d551 4422 posx = self._pParent._nPadding
6cb4f153 4423
6a64d551 4424 if self._nFrom >= 0:
6cb4f153 4425
6a64d551 4426 for i in xrange(self._nFrom, len(self._pagesInfoVec)):
6cb4f153 4427
6a64d551
RD
4428 if self._pagesInfoVec[i].GetPosition() == wx.Point(-1, -1):
4429 break
4430
4431 posx += self._pagesInfoVec[i].GetSize().x
6cb4f153 4432
6a64d551
RD
4433 if posx + tabWidth + render.GetButtonsAreaLength(self) >= clientWidth:
4434 return False
6cb4f153 4435
6a64d551 4436 return True
6cb4f153 4437
6a64d551 4438 else:
6cb4f153 4439
6a64d551
RD
4440 # TODO:: this is ugly and should be improved, we should *never* access the
4441 # raw pointer directly like we do here (render.Get())
4442 vc8_render = render
4443 vTabInfo = vc8_render.NumberTabsCanFit(self)
6cb4f153 4444
6a64d551
RD
4445 if page - self._nFrom >= len(vTabInfo):
4446 return False
4447
4448 return True
6cb4f153 4449
6cb4f153 4450
6a64d551
RD
4451 def GetNumOfVisibleTabs(self):
4452 """ Returns the number of visible tabs. """
6cb4f153 4453
6a64d551
RD
4454 count = 0
4455 for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
4456 if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
4457 break
4458 count = count + 1
6cb4f153 4459
6a64d551 4460 return count
6cb4f153 4461
6cb4f153 4462
6a64d551
RD
4463 def GetEnabled(self, page):
4464 """ Returns whether a tab is enabled or not. """
6cb4f153 4465
6a64d551
RD
4466 if page >= len(self._pagesInfoVec):
4467 return True # Seems strange, but this is the default
6cb4f153 4468
6a64d551 4469 return self._pagesInfoVec[page].GetEnabled()
6cb4f153 4470
6cb4f153 4471
6a64d551
RD
4472 def Enable(self, page, enabled=True):
4473 """ Enables or disables a tab. """
4474
4475 if page >= len(self._pagesInfoVec):
4476 return
6cb4f153 4477
6a64d551 4478 self._pagesInfoVec[page].Enable(enabled)
6cb4f153
RD
4479
4480
6a64d551
RD
4481 def GetSingleLineBorderColour(self):
4482 """ Returns the colour for the single line border. """
6cb4f153 4483
6a64d551
RD
4484 if self.HasFlag(FNB_FANCY_TABS):
4485 return self._colorFrom
6cb4f153 4486
6a64d551 4487 return wx.WHITE
6cb4f153 4488
6cb4f153 4489
6a64d551
RD
4490 def HasFlag(self, flag):
4491 """ Returns whether a flag is present in the L{FlatNotebook} style. """
6cb4f153 4492
6a64d551
RD
4493 style = self.GetParent().GetWindowStyleFlag()
4494 res = (style & flag and [True] or [False])[0]
4495 return res
6cb4f153 4496
6cb4f153 4497
6a64d551
RD
4498 def ClearFlag(self, flag):
4499 """ Deletes a flag from the L{FlatNotebook} style. """
6cb4f153 4500
6a64d551
RD
4501 style = self.GetParent().GetWindowStyleFlag()
4502 style &= ~flag
4503 self.SetWindowStyleFlag(style)
6cb4f153
RD
4504
4505
6a64d551
RD
4506 def TabHasImage(self, tabIdx):
4507 """ Returns whether a tab has an associated image index or not. """
6cb4f153 4508
6a64d551
RD
4509 if self._ImageList:
4510 return self._pagesInfoVec[tabIdx].GetImageIndex() != -1
4511
4512 return False
6cb4f153 4513
6cb4f153 4514
6a64d551
RD
4515 def OnLeftDClick(self, event):
4516 """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
4517
4518 if self.HasFlag(FNB_DCLICK_CLOSES_TABS):
6cb4f153 4519
6a64d551
RD
4520 where, tabIdx = self.HitTest(event.GetPosition())
4521
4522 if where == FNB_TAB:
4523 self.DeletePage(tabIdx)
6cb4f153 4524
6cb4f153 4525 else:
6a64d551
RD
4526
4527 event.Skip()
4528
6cb4f153 4529
6a64d551
RD
4530 def PopupTabsMenu(self):
4531 """ Pops up the menu activated with the drop down arrow in the navigation area. """
6cb4f153 4532
6a64d551 4533 popupMenu = wx.Menu()
6cb4f153 4534
6a64d551
RD
4535 for i in xrange(len(self._pagesInfoVec)):
4536 pi = self._pagesInfoVec[i]
4537 item = wx.MenuItem(popupMenu, i, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
4538 self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item)
6cb4f153 4539
6a64d551
RD
4540 # This code is commented, since there is an alignment problem with wx2.6.3 & Menus
4541 # if self.TabHasImage(ii):
4542 # item.SetBitmaps( (*m_ImageList)[pi.GetImageIndex()] );
6cb4f153 4543
6a64d551 4544 popupMenu.AppendItem(item)
33113971 4545 item.Enable(pi.GetEnabled())
6a64d551
RD
4546
4547 self.PopupMenu(popupMenu)
6cb4f153 4548
6cb4f153 4549
6a64d551
RD
4550 def OnTabMenuSelection(self, event):
4551 """ Handles the wx.EVT_MENU event for L{PageContainer}. """
6cb4f153 4552
6a64d551 4553 selection = event.GetId()
33113971 4554 self.FireEvent(selection)
6cb4f153 4555
6cb4f153 4556
33113971
RD
4557 def FireEvent(self, selection):
4558 """
4559 Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
4560 called from other methods (from menu selection or Smart Tabbing).
4561 Utility function.
4562 """
4563
4564 if selection == self._iActivePage:
4565 # No events for the same selection
4566 return
4567
4568 oldSelection = self._iActivePage
4569
4570 event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
4571 event.SetSelection(selection)
4572 event.SetOldSelection(oldSelection)
4573 event.SetEventObject(self.GetParent())
4574
4575 if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed():
4576
4577 self.SetSelection(selection)
4578
4579 # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
4580 event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
4581 event.SetOldSelection(oldSelection)
4582 self.GetParent().GetEventHandler().ProcessEvent(event)
4583
4584
6a64d551
RD
4585 def SetImageList(self, imglist):
4586 """ Sets the image list for the page control. """
6cb4f153 4587
6a64d551 4588 self._ImageList = imglist
6cb4f153 4589
6cb4f153 4590
6a64d551
RD
4591 def GetImageList(self):
4592 """ Returns the image list for the page control. """
6cb4f153 4593
6a64d551 4594 return self._ImageList
6cb4f153
RD
4595
4596
6a64d551
RD
4597 def GetSelection(self):
4598 """ Returns the current selected page. """
6cb4f153 4599
6a64d551 4600 return self._iActivePage
6cb4f153
RD
4601
4602
6a64d551
RD
4603 def GetPageCount(self):
4604 """ Returns the number of tabs in the L{FlatNotebook} control. """
6cb4f153 4605
6a64d551 4606 return len(self._pagesInfoVec)
6cb4f153
RD
4607
4608
6a64d551
RD
4609 def GetPageText(self, page):
4610 """ Returns the tab caption of the page. """
6cb4f153 4611
6a64d551 4612 return self._pagesInfoVec[page].GetCaption()
6cb4f153 4613
6cb4f153 4614
6a64d551
RD
4615 def SetPageText(self, page, text):
4616 """ Sets the tab caption of the page. """
6cb4f153 4617
6a64d551
RD
4618 self._pagesInfoVec[page].SetCaption(text)
4619 return True
6cb4f153
RD
4620
4621
33113971
RD
4622 def DrawDragHint(self):
4623 """ Draws small arrow at the place that the tab will be placed. """
4624
4625 # get the index of tab that will be replaced with the dragged tab
4626 pt = wx.GetMousePosition()
4627 client_pt = self.ScreenToClient(pt)
4628 where, tabIdx = self.HitTest(client_pt)
4629 self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()).DrawDragHint(self, tabIdx)
4630