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