Mercurial > traipse
comparison orpg/tools/NotebookCtrl.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4385a7d0efd1 |
---|---|
1 # --------------------------------------------------------------------------- # | |
2 # NOTEBOOKCTRL Control wxPython IMPLEMENTATION | |
3 # Python Code By: | |
4 # | |
5 # Andrea Gavana, @ 11 Nov 2005 | |
6 # Latest Revision: 06 Oct 2006, 18.10 GMT | |
7 # | |
8 # | |
9 # AKNOWLEDGEMENTS | |
10 # | |
11 # A big load of thanks goes to Julianne Sharer that has implemented the new | |
12 # features of left/right tabs, rotated or horizontal, with the ability to | |
13 # switch between the two views by a single mouse click. Moreover, all the | |
14 # work done to refactor NotebookCtrl in a more readable way has been done | |
15 # by Julianne Sharer. Thanks Julianne. | |
16 # | |
17 # | |
18 # TODO List/Caveats | |
19 # | |
20 # 1. Ay Idea? | |
21 # | |
22 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please | |
23 # Write To Me At: | |
24 # | |
25 # andrea.gavana@gmail.com | |
26 # gavana@kpo.kz | |
27 # | |
28 # Or, Obviously, To The wxPython Mailing List!!! | |
29 # | |
30 # | |
31 # End Of Comments | |
32 # --------------------------------------------------------------------------- # | |
33 | |
34 | |
35 """ | |
36 A full-featured notebook control, worked out by Andrea Gavana And Julianne Sharer. | |
37 | |
38 Description: | |
39 | |
40 NotebookCtrl Mimics The Behavior Of wx.Notebook, And Most Of Its Functionalities | |
41 Are Implemented In NotebookCtrl. However, NotebookCtrl Has A Lot Of Options That | |
42 wx.Notebook Does Not Have, And It Is Therefore Quite Customizable. | |
43 wx.Notebook Styles Not Implemented in NotebookCtrl Are: | |
44 | |
45 - wx.NB_MULTILINE (But NotebookCtrl Has A SpinButton To Navigate | |
46 Through Tabs). | |
47 | |
48 Supported Customizations For NotebookCtrl Include: | |
49 | |
50 - Setting Individual Tab Font And Text Colour; | |
51 - Images On Tabs (Line wx.Notebook); | |
52 - Setting Individual Tab Colours; | |
53 - Disabling/Enabling Individual Tabs (Also Visually Effective); | |
54 Now Supports Grayed Out Icons When A Page Is Disabled; | |
55 - Drawing Of A Small Closing "X" At The Right Of Every Tab, That Enable The User | |
56 To Close A Tab With A Mouse Click (Like eMule Tab Style); | |
57 - Enabling Highlighted Tabs On Selection; | |
58 - Drawing Focus Indicator In Each Tab (Like wx.Notebook); | |
59 - Ctrl-Tab Keyboard Navigation Between Pages; | |
60 - Tab With Animated Icons (Animation On Tabs); | |
61 - Drag And Drop Tabs In NotebookCtrl (Plus A Visual Arrow Effect | |
62 To Indicate Dropping Position); | |
63 - Drag And Drop Event; | |
64 - ToolTips On Individual Tabs, With Customizable ToolTip Time | |
65 Popup And ToolTip Window Size For Individual Tabs; | |
66 - Possibility To Hide The TabCtrl There Is Only One Tab (Thus | |
67 Maximizing The Corresponding Window); | |
68 - Possibility To Convert The Tab Image Into A Close Button While | |
69 Mouse Is Hovering On The Tab Image; | |
70 - Popup Menus On Tabs (Popup Menus Specific To Each Tab); | |
71 - Showing Pages In "Column/Row Mode", Which Means That All Pages | |
72 Will Be Shown In NotebookCtrl While The Tabs Are Hidden. They | |
73 Can Be Shown In Columns (Default) Or In Rows; | |
74 - Possibility To Hide Tabs On User Request, Thus Showing Only The | |
75 Current Panel; | |
76 - Multiple Tabs Selection (Hold Ctrl Key Down And Left Mouse | |
77 Click), Useful When You Use The Show All The Panels In | |
78 Columns/Rows. In This Case, Only The Selected Tabs Are Shown In | |
79 Columns/Rows; | |
80 - Events For Mouse Events (Left Double Click, Middle Click, Right Click); | |
81 - Possibility To Reparent A NotebookCtrl Page To A Freshly Created | |
82 Frame As A Simple Panel Or To A New NotebookCtrl Created Inside | |
83 That New Frame. | |
84 - Possibility To Add A Custom Panel To Show A Logo Or HTML | |
85 Information Or Whatever You Like When There Are No Tabs In | |
86 NotebookCtrl; | |
87 - Possibility To Change The ToolTip Window Background Colour; | |
88 - Possibility To Draw Vertical Or Horizontal Gradient Coloured Tabs | |
89 (2 Colours); | |
90 - Themes On Tabs: Built-In Themes Are KDE (Unix/Linux), Metal, | |
91 Aqua Light And Aqua Dark (MacOS), Windows Silver (Windows) Or | |
92 Generic Gradient Coloured Tabs. It's Also Possible To Define A | |
93 Separate Theme For Selected Tabs And Control Background (The | |
94 Last Two Are Work In Progress); | |
95 - Contour Line Colour Around Tabs Is Customizable; | |
96 - Highlight Colour Of Selected Tab Is Customizable; | |
97 - Each Tab Can Have Its Own Gradient Colouring (2 Colours For Every Tab); | |
98 - Custom Images May Be Drawn As A "X" Close Buttons On Tabs; | |
99 - Possibility To Hide A Particular Tab Using A wx.PopupMenu That | |
100 Is Shown If You Call EnableHiding(True). Look At The Top Right | |
101 Of NotebookCtrl; | |
102 - Allows Drag And Drop Of Tabs/Pages Between Different | |
103 NotebookCtrls In The Same Application. | |
104 - Draw tabs on the left or right side, rotated or horizontal | |
105 - Allow user to switch between rotated and horizontal displays of | |
106 tabs on the left or right side. | |
107 | |
108 | |
109 Usage: | |
110 | |
111 NotebookCtrl Construction Is Quite Similar To wx.Notebook:: | |
112 | |
113 NotebookCtrl.__init__(self, parent, id, pos=wx.DefaultPosition, | |
114 size=wx.DefaultSize, style=style, sizer=nbsizer) | |
115 | |
116 See L{NotebookCtrl.__init__} Method For The Definition Of Non Standard (Non | |
117 wxPython) Parameters. | |
118 | |
119 NotebookCtrl Control Is Freeware And Distributed Under The wxPython License. | |
120 | |
121 Latest Revision: Andrea Gavana @ 06 Oct 2006, 18.10 GMT | |
122 | |
123 @undocumented: NC_MAC*, topaqua*, botaqua*, distaqua*, disbaqua*, | |
124 kdetheme, silvertheme*, wxEVT*, attrs, GetMenuButton*, NCDragInfo, | |
125 NCDropTarget, TabbedPage, TabCtrl, TransientTipWindow, | |
126 macPopupWindow, macTransientTipWindow, NCFrame, DEFAULT_SIZE, | |
127 NotebookSpinButton, NotebookMenuButton | |
128 """ | |
129 | |
130 __docformat__ = "epytext" | |
131 | |
132 | |
133 #---------------------------------------------------------------------- | |
134 # Beginning Of NOTEBOOKCTRL wxPython Code | |
135 #---------------------------------------------------------------------- | |
136 | |
137 from orpg.orpg_wx import * | |
138 from wx.lib.buttons import GenBitmapButton as BitmapButton | |
139 import wx.xrc as xrc | |
140 | |
141 import cStringIO, zlib | |
142 import cPickle | |
143 import weakref | |
144 | |
145 # HitTest Results | |
146 NC_HITTEST_NOWHERE = 0 # Not On Tab | |
147 """Indicates mouse coordinates not on any tab of the notebook""" | |
148 NC_HITTEST_ONICON = 1 # On Icon | |
149 """Indicates mouse coordinates on an icon in a tab of the notebook""" | |
150 NC_HITTEST_ONLABEL = 2 # On Label | |
151 """Indicates mouse coordinates on a label in a tab of the notebook""" | |
152 NC_HITTEST_ONITEM = 4 # Generic, On Item | |
153 """Indicates mouse coordinates on a tab of the notebook""" | |
154 NC_HITTEST_ONX = 8 # On Small Square On Every Page | |
155 """Indicates mouse coordinates on the closing I{X} in a tab of the notebook""" | |
156 | |
157 # NotebookCtrl Styles | |
158 # NotebookCtrl Placed On Top (Default) | |
159 NC_TOP = 1 | |
160 """Specify tabs at the top of the notebook control.""" | |
161 # NotebookCtrl Placed At The Bottom | |
162 NC_BOTTOM = 2 | |
163 """Specify tabs at the bottom of the notebook control.""" | |
164 # NotebookCtrl With Fixed Width Tabs | |
165 NC_FIXED_WIDTH = 4 | |
166 """Specify tabs of a fixed width in the notebook control.""" | |
167 # NotebookCtrl Placed At The Left | |
168 NC_LEFT = 8 | |
169 """Specify tabs on the left side of the notebook control.""" | |
170 # NotebookCtrl Placed At The Right | |
171 NC_RIGHT = 16 | |
172 """Specify tabs on the right side of the notebook control.""" | |
173 # NotebookCtrl tab rotated | |
174 NC_ROTATE = 32 | |
175 """Specify rotated tabs (with vertical text) in the notebook control.""" | |
176 # NotebookCtrl switchable between compact and expanded sizes | |
177 NC_EXPANDABLE = 64 | |
178 """Specify that the notebook control includes a toggle button to | |
179 switch between compact tabs (rotated on the left or right side) | |
180 expanded tabs (horizontal on the left or right side).""" | |
181 | |
182 NC_DEFAULT_STYLE = NC_TOP | wx.NO_BORDER | |
183 """The default style for the notebook control (tabs on top with no border)""" | |
184 # Also wx.STATIC_BORDER Is Supported | |
185 | |
186 # NotebookCtrl theme styles | |
187 NC_GRADIENT_VERTICAL = 1 | |
188 """Specify tabs rendered with a vertical gradient background.""" | |
189 NC_GRADIENT_HORIZONTAL = 2 | |
190 """Specify tabs rendered with a horizontal gradient background.""" | |
191 NC_GRADIENT_SELECTION = 4 | |
192 NC_AQUA_LIGHT = 8 | |
193 """Specify tabs rendered with a Mac I{Light Aqua}-like background.""" | |
194 NC_AQUA_DARK = 16 | |
195 """Specify tabs rendered with a Mac I{Dark Aqua}-like background.""" | |
196 NC_AQUA = NC_AQUA_LIGHT | |
197 """Specify tabs rendered with a Mac I{Light Aqua}-like background.""" | |
198 NC_METAL = 32 | |
199 """Specify tabs rendered with a Mac I{Metal}-like background.""" | |
200 NC_SILVER = 64 | |
201 """Specify tabs rendered with a Windows I{Silver}-like background.""" | |
202 NC_KDE = 128 | |
203 """Specify tabs rendered with a KDE-style background.""" | |
204 | |
205 # Patch To Make NotebookCtrl Working Also On MacOS: Thanks To Stani ;-) | |
206 if wx.Platform == '__WXMAC__': | |
207 DEFAULT_SIZE = wx.Size(26, 26) | |
208 else: | |
209 DEFAULT_SIZE = wx.DefaultSize | |
210 | |
211 # Themes On Mac... This May Slow Down The Paint Event If You Turn It On! | |
212 NC_MAC_LIGHT = (240, 236) | |
213 NC_MAC_DARK = (232, 228) | |
214 | |
215 topaqua1 = [wx.Colour(106, 152, 231), wx.Colour(124, 173, 236)] | |
216 botaqua1 = [wx.Colour(54, 128, 213), wx.Colour(130, 225, 249)] | |
217 | |
218 topaqua2 = [wx.Colour(176, 222, 251), wx.Colour(166, 211, 245)] | |
219 botaqua2 = [wx.Colour(120, 182, 244), wx.Colour(162, 230, 245)] | |
220 | |
221 distaqua = [wx.Colour(248, 248, 248), wx.Colour(243, 243, 243)] | |
222 disbaqua = [wx.Colour(219, 219, 219), wx.Colour(248, 248, 248)] | |
223 | |
224 # Themes On KDE... This May Slow Down The Paint Event If You Turn It On! | |
225 kdetheme = [wx.Colour(0xf3,0xf7,0xf9), wx.Colour(0xf3,0xf7,0xf9), | |
226 wx.Colour(0xee,0xf3,0xf7), wx.Colour(0xee,0xf3,0xf7), | |
227 wx.Colour(0xea,0xf0,0xf4), wx.Colour(0xea,0xf0,0xf4), | |
228 wx.Colour(0xe6,0xec,0xf1), wx.Colour(0xe6,0xec,0xf1), | |
229 wx.Colour(0xe2,0xe9,0xef), wx.Colour(0xe2,0xe9,0xef), | |
230 wx.Colour(0xdd,0xe5,0xec), wx.Colour(0xdd,0xe5,0xec), | |
231 wx.Colour(0xd9,0xe2,0xea), wx.Colour(0xd9,0xe2,0xea)] | |
232 | |
233 # Themes On Windows... This May Slow Down The Paint Event If You Turn It On! | |
234 silvertheme2 = [wx.Colour(255, 255, 255), wx.Colour(190, 190, 216), | |
235 wx.Colour(180, 180, 200)] | |
236 silvertheme1 = [wx.Colour(252, 252, 254), wx.Colour(252, 252, 254)] | |
237 | |
238 # NotebookCtrl Events: | |
239 # wxEVT_NOTEBOOKCTRL_PAGE_CHANGED: Event Fired When You Switch Page; | |
240 # wxEVT_NOTEBOOKCTRL_PAGE_CHANGING: Event Fired When You Are About To Switch | |
241 # Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call | |
242 # event.Skip() In Your Event Handler; | |
243 # wxEVT_NOTEBOOKCTRL_PAGE_CLOSING: Event Fired When A Page Is Closing, But | |
244 # You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip() | |
245 # In Your Event Handler; | |
246 # wxEVT_NOTEBOOKCTRL_PAGE_DND: Event Fired When A Drag And Drop Action On | |
247 # Tabs Ends. | |
248 wxEVT_NOTEBOOKCTRL_PAGE_CHANGED = wx.NewEventType() | |
249 wxEVT_NOTEBOOKCTRL_PAGE_CHANGING = wx.NewEventType() | |
250 wxEVT_NOTEBOOKCTRL_PAGE_CLOSING = wx.NewEventType() | |
251 wxEVT_NOTEBOOKCTRL_PAGE_DND = wx.NewEventType() | |
252 wxEVT_NOTEBOOKCTRL_PAGE_DCLICK = wx.NewEventType() | |
253 wxEVT_NOTEBOOKCTRL_PAGE_RIGHT = wx.NewEventType() | |
254 wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE = wx.NewEventType() | |
255 | |
256 #-----------------------------------# | |
257 # NotebookCtrlEvent | |
258 #-----------------------------------# | |
259 | |
260 EVT_NOTEBOOKCTRL_PAGE_CHANGED = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED, 1) | |
261 """Notify client objects when the active page in the notebook control | |
262 has changed.""" | |
263 | |
264 EVT_NOTEBOOKCTRL_PAGE_CHANGING = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, 1) | |
265 """Notify client objects when the active page in the notebook control | |
266 is changing.""" | |
267 | |
268 EVT_NOTEBOOKCTRL_PAGE_CLOSING = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_CLOSING, 1) | |
269 """Notify client objects when a page in the notebook control is closing.""" | |
270 | |
271 EVT_NOTEBOOKCTRL_PAGE_DND = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_DND, 1) | |
272 """Enable client objects to override the behavior of the notebook control | |
273 when a dragged tab is dropped onto it.""" | |
274 | |
275 EVT_NOTEBOOKCTRL_PAGE_DCLICK = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_DCLICK, 1) | |
276 """Notify client objects when the user double-clicks a tab | |
277 in the notebook control.""" | |
278 | |
279 EVT_NOTEBOOKCTRL_PAGE_RIGHT = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_RIGHT, 1) | |
280 """Notify client objects when the user right-clicks a tab | |
281 in the notebook control.""" | |
282 | |
283 EVT_NOTEBOOKCTRL_PAGE_MIDDLE = wx.PyEventBinder(wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE, 1) | |
284 """Notify client objects when the user clicks with the | |
285 middle mouse button on a tab in the notebook control.""" | |
286 | |
287 attrs = ["_backstyle", "_backtooltip", "_borderpen", "_convertimage", "_drawx", | |
288 "_drawxstyle", "_enabledragging", "_focusindpen", "_hideonsingletab", | |
289 "_highlight", "_padding", "_selectioncolour", "_selstyle", "_tabstyle", | |
290 "_upperhigh", "_usefocus", "_usegradients"] | |
291 | |
292 | |
293 # Check for the new method in 2.7 (not present in 2.6.3.3) | |
294 if wx.VERSION_STRING < "2.7": | |
295 wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point) | |
296 | |
297 | |
298 # ---------------------------------------------------------------------------- # | |
299 def GetMenuButtonData(): | |
300 | |
301 return zlib.decompress( | |
302 "x\xda\xeb\x0c\xf0s\xe7\xe5\x92\xe2b``\xe0\xf5\xf4p\t\x02\xd2\x9c \xcc\xc1\ | |
303 \x06$\x1fLd\x13\x00R,\xc5N\x9e!\x1c@P\xc3\x91\xd2\x01\xe4[x\xba8\x86HL\xed\ | |
304 \xbd`\xc8\xc7\xa0\xc0\xe1|q\xdb\x9d\xff'\xba\xb4\x1d\x05v\xff}\xe2\xab\x9a:c\ | |
305 \x99\xc4\xbe\xe9\xfd+\x9a\xc5W%t\x1a\xe5\x08\xa6\xd6,\xe2\xf0\x9a\xc2\xc8\ | |
306 \xf0\xe1\xf9r\xe6\xa3\xc9\x02b\xd9\x0c35\x80f0x\xba\xfa\xb9\xacsJh\x02\x00\ | |
307 \xcd-%1") | |
308 | |
309 | |
310 def GetMenuButtonBitmap(): | |
311 | |
312 return wx.BitmapFromImage(GetMenuButtonImage()) | |
313 | |
314 | |
315 def GetMenuButtonImage(): | |
316 | |
317 stream = cStringIO.StringIO(GetMenuButtonData()) | |
318 return wx.ImageFromStream(stream) | |
319 | |
320 # ---------------------------------------------------------------------------- # | |
321 | |
322 def GrayOut(anImage): | |
323 """ | |
324 Convert The Given Image (In Place) To A Grayed-Out Version, | |
325 Appropriate For A 'Disabled' Appearance. | |
326 """ | |
327 | |
328 factor = 0.7 # 0 < f < 1. Higher Is Grayer | |
329 | |
330 if anImage.HasMask(): | |
331 maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue()) | |
332 else: | |
333 maskColor = None | |
334 | |
335 data = map(ord, list(anImage.GetData())) | |
336 | |
337 for i in range(0, len(data), 3): | |
338 | |
339 pixel = (data[i], data[i+1], data[i+2]) | |
340 pixel = MakeGray(pixel, factor, maskColor) | |
341 | |
342 for x in range(3): | |
343 data[i+x] = pixel[x] | |
344 | |
345 anImage.SetData(''.join(map(chr, data))) | |
346 | |
347 return anImage | |
348 | |
349 | |
350 def MakeGray((r,g,b), factor, maskColor): | |
351 """ | |
352 Make A Pixel Grayed-Out. If The Pixel Matches The MaskColor, It Won't Be | |
353 Changed. | |
354 """ | |
355 | |
356 if (r,g,b) != maskColor: | |
357 return map(lambda x: int((230 - x) * factor) + x, (r,g,b)) | |
358 else: | |
359 return (r,g,b) | |
360 | |
361 def GetDefaultTabStyle(): | |
362 tabstyle = ThemeStyle() | |
363 | |
364 # Draw Mac Themes On Tabs? | |
365 if wx.Platform == "__WXMAC__" or wx.Platform == "__WXCOCOA__": | |
366 tabstyle.EnableAquaTheme(True, 2) | |
367 # Draw Windows Silver Theme On Tabs? | |
368 elif wx.Platform == "__WXMSW__": | |
369 tabstyle.EnableSilverTheme(True) | |
370 else: | |
371 tabstyle.EnableKDETheme(True) | |
372 | |
373 return tabstyle | |
374 | |
375 # ---------------------------------------------------------------------------- # | |
376 # Class NotebookCtrlEvent | |
377 # ---------------------------------------------------------------------------- # | |
378 | |
379 class NotebookCtrlEvent(wx.PyCommandEvent): | |
380 """ | |
381 Represent details of the events that the L{NotebookCtrl} object sends. | |
382 """ | |
383 | |
384 def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1): | |
385 """ Default Class Constructor. """ | |
386 | |
387 wx.PyCommandEvent.__init__(self, eventType, id) | |
388 self._eventType = eventType | |
389 | |
390 | |
391 def SetSelection(self, nSel): | |
392 """ Sets Event Selection. """ | |
393 | |
394 self._selection = nSel | |
395 | |
396 | |
397 def SetOldSelection(self, nOldSel): | |
398 """ Sets Old Event Selection. """ | |
399 | |
400 self._oldselection = nOldSel | |
401 | |
402 | |
403 def GetSelection(self): | |
404 """ Returns Event Selection. """ | |
405 | |
406 return self._selection | |
407 | |
408 | |
409 def GetOldSelection(self): | |
410 """ Returns Old Event Selection """ | |
411 | |
412 return self._oldselection | |
413 | |
414 | |
415 def SetOldPosition(self, pos): | |
416 """ Sets Old Event Position. """ | |
417 | |
418 self._oldposition = pos | |
419 | |
420 | |
421 def SetNewPosition(self, pos): | |
422 """ Sets New Event Position. """ | |
423 | |
424 self._newposition = pos | |
425 | |
426 | |
427 def GetOldPosition(self): | |
428 """ Returns Old Event Position. """ | |
429 | |
430 return self._oldposition | |
431 | |
432 | |
433 def GetNewPosition(self): | |
434 """ Returns New Event Position. """ | |
435 | |
436 return self._newposition | |
437 | |
438 | |
439 # ---------------------------------------------------------------------------- # | |
440 # Class NCDragInfo | |
441 # Stores All The Information To Allow Drag And Drop Between Different | |
442 # NotebookCtrls In The Same Application. | |
443 # ---------------------------------------------------------------------------- # | |
444 | |
445 class NCDragInfo: | |
446 | |
447 _map = weakref.WeakValueDictionary() | |
448 | |
449 def __init__(self, container, pageindex): | |
450 """ Default Class Constructor. """ | |
451 | |
452 self._id = id(container) | |
453 NCDragInfo._map[self._id] = container | |
454 self._pageindex = pageindex | |
455 | |
456 | |
457 def GetContainer(self): | |
458 """ Returns The NotebookCtrl Page (Usually A Panel). """ | |
459 | |
460 return NCDragInfo._map.get(self._id, None) | |
461 | |
462 | |
463 def GetPageIndex(self): | |
464 """ Returns The Page Index Associated With A Page. """ | |
465 | |
466 return self._pageindex | |
467 | |
468 | |
469 # ---------------------------------------------------------------------------- # | |
470 # Class NCDropTarget | |
471 # Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between | |
472 # Different NotebookCtrls. | |
473 # ---------------------------------------------------------------------------- # | |
474 | |
475 class NCDropTarget(wx.DropTarget): | |
476 | |
477 def __init__(self, parent): | |
478 """ Default Class Constructor. """ | |
479 | |
480 wx.DropTarget.__init__(self) | |
481 | |
482 self._parent = parent | |
483 self._dataobject = wx.CustomDataObject(wx.CustomDataFormat("NotebookCtrl")) | |
484 self.SetDataObject(self._dataobject) | |
485 | |
486 | |
487 def OnData(self, x, y, dragres): | |
488 """ Handles The OnData() Method TO Call The Real DnD Routine. """ | |
489 | |
490 if not self.GetData(): | |
491 return wx.DragNone | |
492 | |
493 draginfo = self._dataobject.GetData() | |
494 drginfo = cPickle.loads(draginfo) | |
495 | |
496 return self._parent.OnDropTarget(x, y, drginfo.GetPageIndex(), drginfo.GetContainer()) | |
497 | |
498 | |
499 # ---------------------------------------------------------------------------- # | |
500 # Class ThemeStyle. Used To Define A Custom Style For Tabs And Control | |
501 # Background Colour. | |
502 # ---------------------------------------------------------------------------- # | |
503 | |
504 class ThemeStyle: | |
505 """ | |
506 Represent the style for rendering a notebook tab. | |
507 """ | |
508 | |
509 GRADIENT_VERTICAL = 1 | |
510 GRADIENT_HORIZONTAL = 2 | |
511 DIFFERENT_GRADIENT_FOR_SELECTED = 4 | |
512 | |
513 def __init__(self): | |
514 """ Default Constructor For This Class.""" | |
515 | |
516 self.ResetDefaults() | |
517 | |
518 | |
519 def ResetDefaults(self): | |
520 """ Resets Default Theme. """ | |
521 | |
522 self._normal = True | |
523 self._aqua = False | |
524 self._metal = False | |
525 self._macstyle = False | |
526 self._kdetheme = False | |
527 self._silver = False | |
528 self._gradient = False | |
529 self._firstcolour = wx.WHITE | |
530 self._secondcolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) | |
531 self._firstcolourselected = wx.WHITE | |
532 self._secondcolourselected = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) | |
533 | |
534 | |
535 def EnableMacTheme(self, enable=True, style=1): | |
536 """ | |
537 Enables/Disables Mac Themes. style=1 Is The Light Style, While style=2 | |
538 Is The Dark Style. Mainly Used For Control Background Colour, Not For Tabs. | |
539 """ | |
540 | |
541 if enable: | |
542 self._normal = False | |
543 self._macstyle = style | |
544 self._kdetheme = False | |
545 self._metal = False | |
546 self._aqua = False | |
547 self._silver = False | |
548 self._gradient = False | |
549 else: | |
550 self._macstyle = 0 | |
551 | |
552 | |
553 def EnableKDETheme(self, enable=True): | |
554 """ Globally Enables/Disables Unix-Like KDE Theme For Tabs. """ | |
555 | |
556 self._kdetheme = enable | |
557 | |
558 if enable: | |
559 self._normal = False | |
560 self._macstyle = False | |
561 self._metal = False | |
562 self._aqua = False | |
563 self._silver = False | |
564 self._gradient = False | |
565 | |
566 | |
567 def EnableMetalTheme(self, enable=True): | |
568 """ Globally Enables/Disables Mac-Like Metal Theme For Tabs. """ | |
569 | |
570 self._metal = enable | |
571 | |
572 if enable: | |
573 self._normal = False | |
574 self._macstyle = False | |
575 self._kdetheme = False | |
576 self._aqua = False | |
577 self._silver = False | |
578 self._gradient = False | |
579 | |
580 | |
581 def EnableAquaTheme(self, enable=True, style=1): | |
582 """ Globally Enables/Disables Mac-Like Aqua Theme For Tabs. """ | |
583 | |
584 if enable: | |
585 self._aqua = style | |
586 self._normal = False | |
587 self._macstyle = False | |
588 self._kdetheme = False | |
589 self._metal = False | |
590 self._silver = False | |
591 self._gradient = False | |
592 else: | |
593 self._aqua = 0 | |
594 | |
595 | |
596 def EnableSilverTheme(self, enable=True): | |
597 """ Globally Enables/Disables Windows Silver Theme For Tabs. """ | |
598 | |
599 self._silver = enable | |
600 | |
601 if enable: | |
602 self._normal = False | |
603 self._macstyle = False | |
604 self._kdetheme = False | |
605 self._metal = False | |
606 self._aqua = False | |
607 self._gradient = False | |
608 | |
609 | |
610 def EnableGradientStyle(self, enable=True, style=1): | |
611 """ | |
612 Enables/Disables Gradient Drawing On Tabs. style=1 Is The Vertical Gradient, | |
613 While style=2 Is The Horizontal Gradient. | |
614 If style flag 4 is set, the style has a separate set of colors for the | |
615 selected tab. | |
616 """ | |
617 | |
618 if enable: | |
619 self._normal = False | |
620 if style & self.GRADIENT_VERTICAL == 0 and style & self.GRADIENT_HORIZONTAL == 0: | |
621 style |= self.GRADIENT_VERTICAL | |
622 self._gradient = style | |
623 self._macstyle = False | |
624 self._kdetheme = False | |
625 self._metal = False | |
626 self._aqua = False | |
627 self._silver = False | |
628 else: | |
629 self._gradient = 0 | |
630 | |
631 | |
632 def SetFirstGradientColour(self, colour=None): | |
633 """ Sets The First Gradient Colour. """ | |
634 | |
635 if colour is None: | |
636 colour = wx.WHITE | |
637 | |
638 self._firstcolour = colour | |
639 | |
640 def SetFirstGradientColourSelected(self, colour=None): | |
641 """Sets The First Gradient Colour For The Selected Tab.""" | |
642 if colour is None: | |
643 colour = wx.WHITE | |
644 | |
645 self._firstcolourselected = colour | |
646 | |
647 def SetSecondGradientColour(self, colour=None): | |
648 """ Sets The Second Gradient Colour. """ | |
649 | |
650 if colour is None: | |
651 color = self.GetBackgroundColour() | |
652 r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) | |
653 color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) | |
654 colour = wx.Colour(color[0], color[1], color[2]) | |
655 | |
656 self._secondcolour = colour | |
657 | |
658 def SetSecondGradientColourSelected(self, colour=None): | |
659 """ Sets The Second Gradient Colour For The Selected Tab. """ | |
660 | |
661 if colour is None: | |
662 color = self.GetBackgroundColour() | |
663 r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) | |
664 color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) | |
665 colour = wx.Colour(color[0], color[1], color[2]) | |
666 | |
667 self._secondcolourselected = colour | |
668 | |
669 def GetFirstGradientColour(self, selected=False): | |
670 """ Returns The First Gradient Colour. """ | |
671 | |
672 if selected and self._gradient & self.DIFFERENT_GRADIENT_FOR_SELECTED: | |
673 return self._firstcolourselected | |
674 else: | |
675 return self._firstcolour | |
676 | |
677 def GetSecondGradientColour(self, selected=False): | |
678 """ Returns The Second Gradient Colour. """ | |
679 | |
680 if selected and self._gradient & self.DIFFERENT_GRADIENT_FOR_SELECTED: | |
681 return self._secondcolourselected | |
682 else: | |
683 return self._secondcolour | |
684 | |
685 | |
686 # ---------------------------------------------------------------------------- # | |
687 # Class TabbedPage | |
688 # This Is Just A Container Class That Initialize All The Default Settings For | |
689 # Every Tab. | |
690 # ---------------------------------------------------------------------------- # | |
691 | |
692 class TabbedPage: | |
693 | |
694 def __init__(self, text="", image=-1, hidden=False): | |
695 """ Default Class Constructor. """ | |
696 | |
697 self._text = text | |
698 self._image = image | |
699 self._font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
700 self._secondaryfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
701 self._pagetextcolour = wx.BLACK | |
702 self._pagecolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) | |
703 self._enable = True | |
704 self._animationimages = [] | |
705 self._tooltip = "" | |
706 self._tooltiptime = 500 | |
707 self._winsize = 400 | |
708 self._menu = None | |
709 self._ishidden = hidden | |
710 self._firstcolour = color = wx.WHITE | |
711 r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) | |
712 color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) | |
713 colour = wx.Colour(color[0], color[1], color[2]) | |
714 self._secondcolour = colour | |
715 | |
716 | |
717 # ---------------------------------------------------------------------------- # | |
718 # Class NotebookSpinButton | |
719 # This SpinButton Is Created/Shown Only When The Total Tabs Size Exceed The | |
720 # Client Size, Allowing The User To Navigate Between Tabs By Clicking On The | |
721 # SpinButton. It Is Very Similar To The wx.Notebook SpinButton | |
722 # ---------------------------------------------------------------------------- # | |
723 | |
724 class NotebookSpinButton(wx.SpinButton): | |
725 | |
726 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, | |
727 size=wx.DefaultSize, style=wx.SP_HORIZONTAL): | |
728 """ Default Class Constructor. """ | |
729 | |
730 wx.SpinButton.__init__(self, parent, id, pos, size, style) | |
731 self._nb = parent | |
732 self._oldvalue = 0 | |
733 self._style = style | |
734 self.Bind(wx.EVT_SPIN, self.OnSpin) | |
735 | |
736 def GetValue(self): | |
737 result = super(NotebookSpinButton, self).GetValue() | |
738 if self._style & wx.SP_VERTICAL: | |
739 result = -result | |
740 return result | |
741 | |
742 def OnSpin(self, event): | |
743 """ Handles The User's Clicks On The SpinButton. """ | |
744 | |
745 if type(event) != type(1): | |
746 pos = event.GetPosition() | |
747 else: | |
748 pos = event | |
749 | |
750 if pos < self.GetMin(): | |
751 self.SetValue(self.GetMin()) | |
752 return | |
753 | |
754 if type(event) != type(1): | |
755 if self._nb._enablehiding: | |
756 if pos < self._oldvalue: | |
757 incr = -1 | |
758 else: | |
759 incr = 1 | |
760 while self._nb._pages[pos]._ishidden: | |
761 pos = pos + incr | |
762 | |
763 self.SetValue(pos) | |
764 | |
765 if self._nb.IsLastVisible(): | |
766 if (self._style & wx.SP_HORIZONTAL and self._oldvalue < pos) or \ | |
767 (self._style & wx.SP_VERTICAL and self._oldvalue > pos): | |
768 self.SetValue(self._oldvalue) | |
769 return | |
770 | |
771 self._oldvalue = pos | |
772 | |
773 self._nb.Refresh() | |
774 | |
775 | |
776 # ---------------------------------------------------------------------------- # | |
777 # Class NotebookMenuButton | |
778 # This MenuButton Is Created/Shown Only When You Activate The Option EnableHiding | |
779 # Of NotebookCtrl. This Small Button Will Be Shown Right Above The Spin Button | |
780 # (If Present), Or In The Position Of The Spin Button. | |
781 # ---------------------------------------------------------------------------- # | |
782 | |
783 class NotebookMenuButton(BitmapButton): | |
784 | |
785 def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=(15, 11), | |
786 style=0): | |
787 """ Default Class Constructor. """ | |
788 | |
789 bmp = GetMenuButtonBitmap() | |
790 | |
791 BitmapButton.__init__(self, parent, id, bmp, pos, size, style) | |
792 | |
793 self.SetUseFocusIndicator(False) | |
794 self.SetBezelWidth(1) | |
795 | |
796 self._originalcolour = self.GetBackgroundColour() | |
797 self._nb = parent | |
798 | |
799 self.Bind(wx.EVT_BUTTON, self.OnButton) | |
800 self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow) | |
801 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) | |
802 self.Bind(wx.EVT_MENU, self.OnMenu) | |
803 | |
804 | |
805 def OnButton(self, event): | |
806 """ Handles The wx.EVT_BUTTON For NotebookMenuButton (Opens The wx.PopupMenu) """ | |
807 | |
808 count = self._nb.GetPageCount() | |
809 | |
810 if count <= 0: | |
811 return | |
812 | |
813 menu = wx.Menu() | |
814 id = wx.NewId() | |
815 myids = [] | |
816 | |
817 for ii in xrange(count): | |
818 | |
819 id = id + 1 | |
820 myids.append(id) | |
821 name = self._nb.GetPageText(ii) | |
822 | |
823 if self._nb._pages[ii]._ishidden: | |
824 msg = "Page Hidden" | |
825 check = False | |
826 else: | |
827 msg = "Page Shown" | |
828 check = True | |
829 | |
830 item = wx.MenuItem(menu, id, name, msg, wx.ITEM_CHECK) | |
831 menu.AppendItem(item) | |
832 | |
833 if not self._nb._pages[ii]._ishidden: | |
834 item.Check() | |
835 | |
836 menu.SetHelpString(id, msg) | |
837 | |
838 self._myids = myids | |
839 | |
840 self.PopupMenu(menu) | |
841 | |
842 event.Skip() | |
843 | |
844 | |
845 def OnMenu(self, event): | |
846 """ Handles The wx.EVT_MENU For NotebookMenuButton. Calls HideTab(). """ | |
847 | |
848 indx = self._myids.index(event.GetId()) | |
849 checked = not event.GetEventObject().IsChecked(event.GetId()) | |
850 | |
851 self._nb.HideTab(indx, not checked) | |
852 | |
853 event.Skip() | |
854 | |
855 | |
856 def OnEnterWindow(self, event): | |
857 """ | |
858 Changes The NotebookMenuButton Background Colour When The Mouse | |
859 Enters The Button Region. | |
860 """ | |
861 | |
862 entercolour = self.GetBackgroundColour() | |
863 firstcolour = entercolour.Red() | |
864 secondcolour = entercolour.Green() | |
865 thirdcolour = entercolour.Blue() | |
866 | |
867 if entercolour.Red() > 235: | |
868 firstcolour = entercolour.Red() - 40 | |
869 if entercolour.Green() > 235: | |
870 secondcolour = entercolour.Green() - 40 | |
871 if entercolour.Blue() > 235: | |
872 thirdcolour = entercolour.Blue() - 40 | |
873 | |
874 entercolour = wx.Colour(firstcolour+20, secondcolour+20, thirdcolour+20) | |
875 | |
876 self.SetBackgroundColour(entercolour) | |
877 self.Refresh() | |
878 | |
879 event.Skip() | |
880 | |
881 | |
882 def OnLeaveWindow(self, event): | |
883 """ | |
884 Restore The NotebookMenuButton Background Colour When The Mouse | |
885 Leaves The Button Region. | |
886 """ | |
887 | |
888 self.SetBackgroundColour(self._originalcolour) | |
889 self.Refresh() | |
890 | |
891 event.Skip() | |
892 | |
893 class _TabCtrlPaintTools(object): | |
894 # Structure-like object for passing data among | |
895 # private rendering methods | |
896 def __init__(self, backBrush, backPen, borderPen, highlightPen, | |
897 shadowPen, upperHighlightPen, selectionPen, selectionEdgePen, | |
898 xPen, focusPen): | |
899 self.BackBrush = backBrush | |
900 self.BackPen = backPen | |
901 self.BorderPen = borderPen | |
902 self.HighlightPen = highlightPen | |
903 self.ShadowPen = shadowPen | |
904 self.UpperHighlightPen = upperHighlightPen | |
905 self.SelectionPen = selectionPen | |
906 self.SelectionEdgePen = selectionEdgePen | |
907 self.XPen = xPen | |
908 self.FocusPen = focusPen | |
909 | |
910 | |
911 # ---------------------------------------------------------------------------- # | |
912 # Class TabCtrl | |
913 # This Class Handles The Drawing Of Every Tab In The NotebookCtrl, And Also | |
914 # All Settings/Methods For Every Tab. | |
915 # ---------------------------------------------------------------------------- # | |
916 | |
917 class TabCtrl(wx.PyControl): | |
918 | |
919 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, | |
920 size=DEFAULT_SIZE, style=NC_DEFAULT_STYLE, | |
921 validator=wx.DefaultValidator, name="TabCtrl"): | |
922 """ | |
923 Default Class Constructor. | |
924 Used Internally. Do Not Call It Explicitely! | |
925 """ | |
926 | |
927 wx.PyControl.__init__(self, parent, id, pos, size, wx.NO_BORDER | wx.WANTS_CHARS, | |
928 validator, name) | |
929 | |
930 # Set All The Default Parameters For TabCtrl | |
931 self._selection = -1 | |
932 self._imglist = 0 | |
933 self._style = style | |
934 self._expanded = False | |
935 self._pages = [] | |
936 self._enabledpages = [] | |
937 | |
938 self._padding = wx.Point(8, 4) | |
939 self._spacetabs = 2 | |
940 self._xrect = [] | |
941 self._xrefreshed = False | |
942 self._imageconverted = False | |
943 self._convertimage = False | |
944 self._disabledcolour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT) | |
945 | |
946 self._hover = False | |
947 self._parent = parent | |
948 self._firsttime = True | |
949 self._somethingchanged = True | |
950 self._isdragging = False | |
951 self._tabID = -1 | |
952 self._enabledragging = False | |
953 self._olddragpos = -1 | |
954 self._fromdnd = False | |
955 self._isleaving = False | |
956 self._highlight = False | |
957 self._usefocus = True | |
958 self._hideonsingletab = False | |
959 self._selectioncolour = wx.Colour(255, 200, 60) | |
960 self._selectionedgecolour = wx.Colour(230, 139, 44) | |
961 | |
962 self._tabstyle = ThemeStyle() | |
963 self._backstyle = ThemeStyle() | |
964 self._selstyle = ThemeStyle() | |
965 self._usegradients = False | |
966 | |
967 self._insidetab = -1 | |
968 self._showtooltip = False | |
969 self._istooltipshown = False | |
970 self._tipwindow = None | |
971 self._tiptimer = wx.PyTimer(self.OnShowToolTip) | |
972 self._backtooltip = wx.Colour(255, 255, 230) | |
973 self._xvideo = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) | |
974 self._yvideo = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) | |
975 | |
976 self._selectedtabs = [] | |
977 | |
978 self._timers = [] | |
979 | |
980 self._dragcursor = wx.StockCursor(wx.CURSOR_HAND) | |
981 self._dragstartpos = wx.Point() | |
982 | |
983 self._drawx = False | |
984 self._drawxstyle = 1 | |
985 | |
986 self._pmenu = None | |
987 | |
988 self._enablehiding = False | |
989 if (style & NC_LEFT or style & NC_RIGHT) and style & NC_EXPANDABLE: | |
990 self._InitExpandableStyles(style) | |
991 self._InitExpandableTabStyles(self._style, self._expanded, self._tabstyle) | |
992 self._CreateSizeToggleButton() | |
993 else: | |
994 self._sizeToggleButton = None | |
995 | |
996 self.SetDefaultPage() | |
997 | |
998 if style & NC_TOP or style & NC_BOTTOM: | |
999 self.SetBestSize((-1, 28)) | |
1000 self._firsttabpos = wx.Point(3, 0) | |
1001 else: | |
1002 self.SetBestSize((28, -1)) | |
1003 self._firsttabpos = wx.Point(0, 3 + self._CalcSizeToggleBestSize()[1]) | |
1004 | |
1005 self._borderpen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)) | |
1006 self._highlightpen2 = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) | |
1007 self._highlightpen = wx.Pen((145, 167, 180)) | |
1008 self._upperhigh = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) | |
1009 self._shadowpen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DDKSHADOW), 2) | |
1010 self._shadowpen.SetCap(wx.CAP_BUTT) | |
1011 self._highlightpen.SetCap(wx.CAP_BUTT) | |
1012 self._highlightpen2.SetCap(wx.CAP_BUTT) | |
1013 | |
1014 if wx.Platform == "__WXMAC__": | |
1015 self._focusindpen = wx.Pen(wx.BLACK, 1, wx.SOLID) | |
1016 else: | |
1017 self._focusindpen = wx.Pen(wx.BLACK, 1, wx.USER_DASH) | |
1018 self._focusindpen.SetDashes([1,1]) | |
1019 self._focusindpen.SetCap(wx.CAP_BUTT) | |
1020 | |
1021 self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) | |
1022 self.Bind(wx.EVT_LEFT_DCLICK, self.OnMouseLeftDClick) | |
1023 self.Bind(wx.EVT_MOTION, self.OnMouseMotion) | |
1024 self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) | |
1025 self.Bind(wx.EVT_RIGHT_UP, self.OnMouseRightUp) | |
1026 self.Bind(wx.EVT_RIGHT_DOWN, self.OnMouseRightDown) | |
1027 self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMouseMiddleDown) | |
1028 self.Bind(wx.EVT_SIZE, self.OnSize) | |
1029 | |
1030 self.Bind(wx.EVT_PAINT, self.OnPaint) | |
1031 self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: None) | |
1032 | |
1033 self.Bind(wx.EVT_TIMER, self.AnimateTab) | |
1034 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) | |
1035 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) | |
1036 | |
1037 self._droptarget = NCDropTarget(self) | |
1038 self.SetDropTarget(self._droptarget) | |
1039 | |
1040 def Contract(self): | |
1041 if self._style & NC_EXPANDABLE and self._expanded: | |
1042 self._ToggleSize() | |
1043 | |
1044 def Expand(self): | |
1045 if self._style & NC_EXPANDABLE and not self._expanded: | |
1046 self._ToggleSize() | |
1047 | |
1048 def _ToggleSize(self, event=None): | |
1049 if self._style & NC_EXPANDABLE and not self._expanded: | |
1050 # contract | |
1051 self._style = self._expandedstyle | |
1052 self._tabstyle = self._expandedtabstyle | |
1053 self._expanded = True | |
1054 self._sizeToggleButton.SetLabel("<<") | |
1055 elif self._style & NC_EXPANDABLE and self._expanded: | |
1056 # expand | |
1057 self._style = self._contractedstyle | |
1058 self._tabstyle = self._contractedtabstyle | |
1059 self._expanded = False | |
1060 self._sizeToggleButton.SetLabel(">>") | |
1061 self._OnStyleChange() | |
1062 | |
1063 | |
1064 def OnDropTarget(self, x, y, nPage, oldcont): | |
1065 """ Handles The OnDrop Action For Drag And Drop Between Different NotebookCtrl. """ | |
1066 | |
1067 where = self.HitTest(wx.Point(x, y)) | |
1068 | |
1069 oldNotebook = oldcont.GetParent() | |
1070 newNotebook = self.GetParent() | |
1071 | |
1072 if oldNotebook == newNotebook: | |
1073 if where >= 0 and where != self._tabID: | |
1074 | |
1075 self._isdragging = False | |
1076 self._olddragpos = -1 | |
1077 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, self.GetId()) | |
1078 eventOut.SetOldPosition(self._tabID) | |
1079 eventOut.SetNewPosition(where) | |
1080 eventOut.SetEventObject(self) | |
1081 | |
1082 if self.GetEventHandler().ProcessEvent(eventOut): | |
1083 self._tabID = -1 | |
1084 self._olddragpos = -1 | |
1085 self.SetCursor(wx.STANDARD_CURSOR) | |
1086 self.Refresh() | |
1087 return | |
1088 | |
1089 self._parent.Freeze() | |
1090 | |
1091 try: | |
1092 text = self.GetPageText(self._tabID) | |
1093 image = self.GetPageImage(self._tabID) | |
1094 font1 = self.GetPageTextFont(self._tabID) | |
1095 font2 = self.GetPageTextSecondaryFont(self._tabID) | |
1096 fontcolour = self.GetPageTextColour(self._tabID) | |
1097 pagecolour = self.GetPageColour(self._tabID) | |
1098 enabled = self.IsPageEnabled(self._tabID) | |
1099 tooltip, ontime, winsize = self.GetPageToolTip(self._tabID) | |
1100 menu = self.GetPagePopupMenu(self._tabID) | |
1101 firstcol = self.GetPageFirstGradientColour(self._tabID) | |
1102 secondcol = self.GetPageSecondGradientColour(self._tabID) | |
1103 ishidden = self._pages[self._tabID]._ishidden | |
1104 except: | |
1105 self._parent.Thaw() | |
1106 self._tabID = -1 | |
1107 self.SetCursor(wx.STANDARD_CURSOR) | |
1108 return | |
1109 | |
1110 isanimated = 0 | |
1111 if self._timers[self._tabID].IsRunning(): | |
1112 isanimated = 1 | |
1113 timer = self._timers[self._tabID].GetInterval() | |
1114 | |
1115 self.StopAnimation(self._tabID) | |
1116 animatedimages = self.GetAnimationImages(self._tabID) | |
1117 | |
1118 pagerange = range(self.GetPageCount()) | |
1119 | |
1120 newrange = pagerange[:] | |
1121 newrange.remove(self._tabID) | |
1122 newrange.insert(where, self._tabID) | |
1123 | |
1124 newpages = [] | |
1125 counter = self.GetPageCount() - 1 | |
1126 | |
1127 for ii in xrange(self.GetPageCount()): | |
1128 newpages.append(self._parent.GetPage(ii)) | |
1129 self._parent.bsizer.Detach(counter-ii) | |
1130 | |
1131 cc = 0 | |
1132 | |
1133 self._parent._notebookpages = [] | |
1134 | |
1135 for jj in newrange: | |
1136 self._parent.bsizer.Add(newpages[jj], 1, wx.EXPAND | wx.ALL, 2) | |
1137 self._parent.bsizer.Show(cc, False) | |
1138 self._parent._notebookpages.append(newpages[jj]) | |
1139 cc = cc + 1 | |
1140 | |
1141 self.DeletePage(self._tabID) | |
1142 | |
1143 if enabled: | |
1144 if id == self.GetPageCount(): | |
1145 self.AddPage(text, True, image) | |
1146 else: | |
1147 self.InsertPage(where, text, True, image) | |
1148 else: | |
1149 if id == self.GetPageCount(): | |
1150 self.AddPage(text, False, image) | |
1151 else: | |
1152 self.InsertPage(where, text, False, image) | |
1153 | |
1154 self.SetPageImage(where, image) | |
1155 self.SetPageText(where, text) | |
1156 self.SetPageTextFont(where, font1) | |
1157 self.SetPageTextSecondaryFont(where, font2) | |
1158 self.SetPageTextColour(where, fontcolour) | |
1159 self.SetPageColour(where, pagecolour) | |
1160 self.EnablePage(where, enabled) | |
1161 self.SetPageToolTip(where, tooltip, ontime, winsize) | |
1162 self.SetPagePopupMenu(where, menu) | |
1163 self.SetPageFirstGradientColour(where, firstcol) | |
1164 self.SetPageSecondGradientColour(where, secondcol) | |
1165 self._pages[where]._ishidden = ishidden | |
1166 | |
1167 if isanimated and len(animatedimages) > 1: | |
1168 self.SetAnimationImages(where, animatedimages) | |
1169 self.StartAnimation(where, timer) | |
1170 | |
1171 if enabled: | |
1172 self._parent.bsizer.Show(where, True) | |
1173 else: | |
1174 sel = self.GetSelection() | |
1175 | |
1176 if sel == -1: | |
1177 sel = 0 | |
1178 self._parent.bsizer.Show(where, False) | |
1179 self._parent.SetSelection(sel) | |
1180 self._parent.bsizer.Show(sel, True) | |
1181 | |
1182 self._parent.bsizer.Layout() | |
1183 | |
1184 self._parent.Thaw() | |
1185 | |
1186 self._isdragging = False | |
1187 self._olddragpos = -1 | |
1188 self._fromdnd = True | |
1189 self.Refresh() | |
1190 self._tabID = -1 | |
1191 self.SetCursor(wx.STANDARD_CURSOR) | |
1192 | |
1193 return | |
1194 | |
1195 if nPage >= 0 and where >= 0: | |
1196 panel = oldNotebook.GetPage(nPage) | |
1197 | |
1198 if panel: | |
1199 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, oldNotebook.GetId()) | |
1200 eventOut.SetOldPosition(nPage) | |
1201 eventOut.SetNewPosition(where) | |
1202 eventOut.SetEventObject(oldNotebook) | |
1203 | |
1204 if oldNotebook.GetEventHandler().ProcessEvent(eventOut): | |
1205 oldNotebook.nb._tabID = -1 | |
1206 oldNotebook.nb._olddragpos = -1 | |
1207 oldNotebook.SetCursor(wx.STANDARD_CURSOR) | |
1208 oldNotebook.Refresh() | |
1209 return | |
1210 | |
1211 oldNotebook.Freeze() | |
1212 infos = oldNotebook.GetPageInfo(nPage) | |
1213 | |
1214 text = infos["text"] | |
1215 image = infos["image"] | |
1216 hidden = infos["ishidden"] | |
1217 | |
1218 panel.Reparent(newNotebook) | |
1219 newNotebook.InsertPage(where, panel, text, True, image, hidden) | |
1220 newNotebook.SetPageInfo(where, infos) | |
1221 | |
1222 oldNotebook.nb.DeletePage(nPage) | |
1223 | |
1224 oldNotebook.bsizer.Detach(nPage) | |
1225 oldNotebook.bsizer.Layout() | |
1226 oldNotebook.sizer.Layout() | |
1227 | |
1228 oldNotebook._notebookpages.pop(nPage) | |
1229 | |
1230 oldNotebook.AdvanceSelection() | |
1231 | |
1232 if oldNotebook.GetPageCount() == 0: | |
1233 if oldNotebook._style & NC_TOP: | |
1234 oldNotebook.sizer.Show(0, False) | |
1235 oldNotebook.sizer.Show(1, False) | |
1236 else: | |
1237 oldNotebook.sizer.Show(1, False) | |
1238 oldNotebook.sizer.Show(2, False) | |
1239 | |
1240 oldNotebook.sizer.Layout() | |
1241 | |
1242 oldNotebook.Thaw() | |
1243 newNotebook.Refresh() | |
1244 | |
1245 return wx.DragMove | |
1246 | |
1247 def OnLeaveWindow(self, event): | |
1248 """ Handles The wx.EVT_LEAVE_WINDOW Events For TabCtrl. """ | |
1249 | |
1250 if self._enabledragging: | |
1251 if self._isdragging: | |
1252 | |
1253 page = self._parent.GetPage(self._tabID) | |
1254 draginfo = NCDragInfo(page, self._tabID) | |
1255 drginfo = cPickle.dumps(draginfo) | |
1256 dataobject = wx.CustomDataObject(wx.CustomDataFormat("NotebookCtrl")) | |
1257 dataobject.SetData(drginfo) | |
1258 dragSource = wx.DropSource(self) | |
1259 dragSource.SetData(dataobject) | |
1260 dragSource.DoDragDrop(wx.Drag_DefaultMove) | |
1261 | |
1262 self._isleaving = True | |
1263 self.Refresh() | |
1264 | |
1265 if self._istooltipshown: | |
1266 self._tipwindow.Destroy() | |
1267 self._istooltipshown = False | |
1268 self.Refresh() | |
1269 | |
1270 event.Skip() | |
1271 | |
1272 | |
1273 def OnKeyDown(self, event): | |
1274 """ | |
1275 Handles The wx.EVT_KEY_DOWN Event For TabCtrl. This Is Only Processed If | |
1276 The User Navigate Through Tabs With Ctrl-Tab Keyboard Navigation. | |
1277 """ | |
1278 | |
1279 if event.GetKeyCode == wx.WXK_TAB: | |
1280 if event.ControlDown(): | |
1281 sel = self.GetSelection() | |
1282 if sel == self.GetPageCount() - 1: | |
1283 sel = 0 | |
1284 else: | |
1285 sel = sel + 1 | |
1286 | |
1287 while not self.IsPageEnabled(sel): | |
1288 sel = sel + 1 | |
1289 if sel == self.GetPageCount() - 1: | |
1290 sel = 0 | |
1291 | |
1292 self._parent.SetSelection(sel) | |
1293 | |
1294 event.Skip() | |
1295 | |
1296 | |
1297 def AddPage(self, text, select=False, img=-1, hidden=False): | |
1298 """ | |
1299 Add A Page To The Notebook. | |
1300 | |
1301 @param text: The Tab Text; | |
1302 @param select: Whether The Page Should Be Selected Or Not; | |
1303 @param img: Specifies The Optional Image Index For The New Page. | |
1304 """ | |
1305 | |
1306 self._pages.append(TabbedPage(text, img, hidden)) | |
1307 self._somethingchanged = True | |
1308 | |
1309 self._firsttime = True | |
1310 self._timers.append(wx.Timer(self)) | |
1311 | |
1312 # JS: The following two lines caused this control not to fire | |
1313 # the EVT_NOTEBOOKCTRL_PAGE_CHANGING/CHANGED events for the | |
1314 # first page. The NotebookCtrl sets the selection later anyway, | |
1315 # and without these two lines, the events fire. | |
1316 ## if select or self.GetSelection() == -1: | |
1317 ## self._selection = self.GetPageCount() - 1 | |
1318 | |
1319 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
1320 self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) | |
1321 | |
1322 self.Refresh() | |
1323 | |
1324 | |
1325 def InsertPage(self, nPage, text, select=False, img=-1, hidden=False): | |
1326 """ | |
1327 Insert A Page Into The Notebook. | |
1328 | |
1329 @param nPage: Specifies The Position For The New Page; | |
1330 @param text: The Tab Text; | |
1331 @param select: Whether The Page Should Be Selected Or Not; | |
1332 @param img: Specifies The Optional Image Index For The New Page. | |
1333 """ | |
1334 | |
1335 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
1336 raise "\nERROR: Invalid Notebook Page In InsertPage: (" + str(nPage) + ")" | |
1337 | |
1338 oldselection = self.GetSelection() | |
1339 | |
1340 self._pages.insert(nPage, TabbedPage(text, img, hidden)) | |
1341 self._timers.insert(nPage, wx.Timer(self)) | |
1342 | |
1343 self._somethingchanged = True | |
1344 self._firsttime = True | |
1345 | |
1346 if select or self.GetSelection() == -1: | |
1347 self._selection = nPage | |
1348 self.SetSelection(nPage) | |
1349 else: | |
1350 if nPage <= oldselection: | |
1351 self._selection = self._selection + 1 | |
1352 | |
1353 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
1354 self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) | |
1355 | |
1356 self.Refresh() | |
1357 | |
1358 | |
1359 def DeleteAllPages(self): | |
1360 """ Deletes All NotebookCtrl Pages. """ | |
1361 | |
1362 for tims in self._timers: | |
1363 if tims.IsRunning(): | |
1364 tims.Stop() | |
1365 | |
1366 tims.Destroy() | |
1367 | |
1368 self._timers = [] | |
1369 self._pages = [] | |
1370 self._selection = -1 | |
1371 self._somethingchanged = True | |
1372 self._firsttime = True | |
1373 self.Refresh() | |
1374 | |
1375 | |
1376 def DeletePage(self, nPage, oncontinue=True): | |
1377 """ Deletes The Page nPage, And The Associated Window. """ | |
1378 | |
1379 if nPage < 0 or nPage >= self.GetPageCount(): | |
1380 raise "\nERROR: Invalid Notebook Page In DeletePage: (" + str(nPage) + ")" | |
1381 | |
1382 oldselection = self.GetSelection() | |
1383 | |
1384 self._pages.pop(nPage) | |
1385 | |
1386 if self._timers[nPage].IsRunning(): | |
1387 self._timers[nPage].Stop() | |
1388 | |
1389 self._timers[nPage].Destroy() | |
1390 | |
1391 if self._istooltipshown: | |
1392 self._tipwindow.Destroy() | |
1393 self._istooltipshown = False | |
1394 | |
1395 if not oncontinue: | |
1396 self._somethingchanged = True | |
1397 self._firsttime = True | |
1398 self.Refresh() | |
1399 return | |
1400 | |
1401 if nPage < self._selection: | |
1402 self._selection = self._selection - 1 | |
1403 elif self._selection == nPage and self._selection == self.GetPageCount(): | |
1404 self._selection = self._selection - 1 | |
1405 else: | |
1406 self._selection = oldselection | |
1407 | |
1408 self._somethingchanged = True | |
1409 self._firsttime = True | |
1410 self.Refresh() | |
1411 | |
1412 | |
1413 def SetSelection(self, nPage): | |
1414 """ | |
1415 Sets The Current Tab Selection To The Given nPage. This Call Generates The | |
1416 EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. | |
1417 """ | |
1418 | |
1419 if nPage < 0 or nPage >= self.GetPageCount(): | |
1420 raise "\nERROR: Invalid Notebook Page In SetSelection: (" + str(nPage) + ")" | |
1421 | |
1422 oldselection = self._selection | |
1423 | |
1424 if nPage != self._selection: | |
1425 | |
1426 if not self.IsPageEnabled(nPage): | |
1427 return | |
1428 | |
1429 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, self.GetId()) | |
1430 eventOut.SetSelection(nPage) | |
1431 eventOut.SetOldSelection(self._selection) | |
1432 eventOut.SetEventObject(self) | |
1433 | |
1434 if not self.GetEventHandler().ProcessEvent(eventOut): | |
1435 | |
1436 # Prevent full paint unless never fully painted | |
1437 if hasattr(self, "_initrect"): | |
1438 self._firsttime = False | |
1439 # Program Allows The Page Change | |
1440 self._selection = nPage | |
1441 eventOut.SetEventType(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED) | |
1442 eventOut.SetOldSelection(self._selection) | |
1443 self.GetEventHandler().ProcessEvent(eventOut) | |
1444 | |
1445 if oldselection != -1: | |
1446 self._parent.bsizer.Show(oldselection, False) | |
1447 | |
1448 self.EnsureVisible(self._selection) | |
1449 self._parent.bsizer.Show(self._selection, True) | |
1450 self._parent.bsizer.Layout() | |
1451 | |
1452 self.Refresh() | |
1453 | |
1454 self._shown = nPage | |
1455 | |
1456 | |
1457 def EnsureVisible(self, selection): | |
1458 | |
1459 if self.GetPageCount() < 2: | |
1460 return | |
1461 | |
1462 if not self.HasSpinButton(): | |
1463 return | |
1464 | |
1465 fullrect = self.GetClientSize() | |
1466 count = self._tabvisible[0:selection].count(0) | |
1467 currect = self._tabrect[selection-self._firstvisible-count] | |
1468 | |
1469 spinval = self._spinbutton.GetValue() | |
1470 firstrect = self._initrect[spinval] | |
1471 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
1472 pos = currect.y | |
1473 size = currect.height | |
1474 posIndex = 1 | |
1475 else: | |
1476 pos = currect.x | |
1477 size = currect.width | |
1478 posIndex = 0 | |
1479 torefresh = 0 | |
1480 | |
1481 while pos + size > fullrect[posIndex] - self._spinbutton.GetSize()[posIndex]: | |
1482 | |
1483 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
1484 pos -= firstrect.height | |
1485 else: | |
1486 pos -= firstrect.width | |
1487 | |
1488 if not self._enablehiding: | |
1489 spinval = spinval + 1 | |
1490 else: | |
1491 oldspinval = spinval | |
1492 spinval = spinval + self._tabvisible[0:selection].count(0) | |
1493 if spinval == oldspinval: | |
1494 spinval = spinval + 1 | |
1495 | |
1496 if spinval >= len(self._initrect): | |
1497 spinval = spinval - 1 | |
1498 | |
1499 firstrect = self._initrect[spinval] | |
1500 | |
1501 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
1502 self._spinbutton.OnSpin(-spinval) | |
1503 self._spinbutton.SetValue(-spinval) | |
1504 else: | |
1505 self._spinbutton.OnSpin(spinval) | |
1506 self._spinbutton.SetValue(spinval) | |
1507 | |
1508 torefresh = 1 | |
1509 | |
1510 if torefresh: | |
1511 self.Refresh() | |
1512 | |
1513 | |
1514 def GetPageCount(self): | |
1515 """ Returns The Number Of Pages In NotebookCtrl. """ | |
1516 | |
1517 return len(self._pages) | |
1518 | |
1519 | |
1520 def GetSelection(self): | |
1521 """ Returns The Current Selection. """ | |
1522 | |
1523 return self._selection | |
1524 | |
1525 | |
1526 def GetImageList(self): | |
1527 """ Returns The Image List Associated With The NotebookCtrl. """ | |
1528 | |
1529 return self._imglist | |
1530 | |
1531 | |
1532 def SetImageList(self, imagelist): | |
1533 """ Associate An Image List To NotebookCtrl. """ | |
1534 | |
1535 self._imglist = imagelist | |
1536 self._grayedlist = wx.ImageList(16, 16, True, 0) | |
1537 | |
1538 for ii in xrange(imagelist.GetImageCount()): | |
1539 | |
1540 bmp = imagelist.GetBitmap(ii) | |
1541 image = wx.ImageFromBitmap(bmp) | |
1542 image = GrayOut(image) | |
1543 newbmp = wx.BitmapFromImage(image) | |
1544 self._grayedlist.Add(newbmp) | |
1545 | |
1546 | |
1547 def AssignImageList(self, imagelist): | |
1548 """ Associate An Image List To NotebookCtrl. """ | |
1549 | |
1550 self._imglist = imagelist | |
1551 self._grayedlist = wx.ImageList(16, 16, True, 0) | |
1552 | |
1553 for ii in xrange(imagelist.GetImageCount()): | |
1554 | |
1555 bmp = imagelist.GetBitmap(ii) | |
1556 image = wx.ImageFromBitmap(bmp) | |
1557 image = GrayOut(image) | |
1558 newbmp = wx.BitmapFromImage(image) | |
1559 self._grayedlist.Add(newbmp) | |
1560 | |
1561 | |
1562 def GetPadding(self): | |
1563 """ Returns The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ | |
1564 | |
1565 return self._padding | |
1566 | |
1567 | |
1568 def SetPadding(self, padding): | |
1569 """ Sets The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ | |
1570 | |
1571 self._padding = padding | |
1572 self._somethingchanged = True | |
1573 self._firsttime = True | |
1574 self.Refresh() | |
1575 | |
1576 | |
1577 def GetPageText(self, nPage): | |
1578 """ Returns The String For The Given Page nPage. """ | |
1579 | |
1580 if nPage < 0 or nPage >= self.GetPageCount(): | |
1581 raise "\nERROR: Invalid Notebook Page In GetPageText: (" + str(nPage) + ")" | |
1582 | |
1583 return self._pages[nPage]._text | |
1584 | |
1585 | |
1586 def SetPageText(self, nPage, text): | |
1587 """ Sets The String For The Given Page nPage. """ | |
1588 | |
1589 if nPage < 0 or nPage >= self.GetPageCount(): | |
1590 raise "\nERROR: Invalid Notebook Page In SetPageText: (" + str(nPage) + ")" | |
1591 | |
1592 if self._pages[nPage]._text != text: | |
1593 self._pages[nPage]._text = text | |
1594 self._somethingchanged = True | |
1595 self._firsttime = True | |
1596 self.Refresh() | |
1597 | |
1598 | |
1599 def GetPageImage(self, nPage): | |
1600 """ Returns The Image Index For The Given Page nPage. """ | |
1601 | |
1602 if nPage < 0 or nPage >= self.GetPageCount(): | |
1603 raise "\nERROR: Invalid Notebook Page In GetPageImage: (" + str(nPage) + ")" | |
1604 | |
1605 return self._pages[nPage]._image | |
1606 | |
1607 | |
1608 def SetPageImage(self, nPage, img): | |
1609 """ Sets The Image Index For The Given Page nPage. """ | |
1610 | |
1611 if nPage < 0 or nPage >= self.GetPageCount(): | |
1612 raise "\nERROR: Invalid Notebook Page In SetPageImage: (" + str(nPage) + ")" | |
1613 | |
1614 if self._pages[nPage]._image != img: | |
1615 self._pages[nPage]._image = img | |
1616 self._somethingchanged = True | |
1617 self._firsttime = True | |
1618 | |
1619 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
1620 self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) | |
1621 self._parent.GetSizer().Layout() | |
1622 | |
1623 self.Refresh() | |
1624 | |
1625 | |
1626 def SetPageTextFont(self, nPage, font=None): | |
1627 """ Sets The Primary Font For The Given Page nPage. """ | |
1628 | |
1629 if nPage < 0 or nPage >= self.GetPageCount(): | |
1630 raise "\nERROR: Invalid Notebook Page In SetPageTextFont: (" + str(nPage) + ")" | |
1631 | |
1632 if font is None: | |
1633 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1634 | |
1635 normalfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1636 | |
1637 self._pages[nPage]._font = font | |
1638 | |
1639 if font == normalfont: | |
1640 self._parent.GetSizer().Layout() | |
1641 self._somethingchanged = True | |
1642 self._firsttime = True | |
1643 self.Refresh() | |
1644 return | |
1645 | |
1646 dc = wx.ClientDC(self) | |
1647 dc.SetFont(font) | |
1648 w1, h1 = dc.GetTextExtent("Aq") | |
1649 dc.SetFont(normalfont) | |
1650 wn, hn = dc.GetTextExtent("Aq") | |
1651 w2, h2 = (0, 0) | |
1652 | |
1653 if hasattr(self._pages[nPage], "_secondaryfont"): | |
1654 dc.SetFont(self._pages[nPage]._secondaryfont) | |
1655 w2, h2 = dc.GetTextExtent("Aq") | |
1656 | |
1657 h = max(h1, h2) | |
1658 | |
1659 if h < hn: | |
1660 self._somethingchanged = True | |
1661 self._firsttime = True | |
1662 self.Refresh() | |
1663 return | |
1664 | |
1665 if h + 2*self._padding.y < 24: | |
1666 newheight = 24 | |
1667 else: | |
1668 newheight = h + 2*self._padding.y | |
1669 | |
1670 oldsize = self.GetSize() | |
1671 | |
1672 if newheight < oldsize[1]: | |
1673 newheight = oldsize[1] | |
1674 | |
1675 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
1676 self.SetBestSize((-1, newheight)) | |
1677 else: | |
1678 self.SetBestSize((self._CalcBestWidth(dc), -1)) | |
1679 self._parent.GetSizer().Layout() | |
1680 self._somethingchanged = True | |
1681 self._firsttime = True | |
1682 self.Refresh() | |
1683 | |
1684 def SetTabHeight(self, height=28): | |
1685 """ Sets The Tabs Height. """ | |
1686 | |
1687 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
1688 self.SetBestSize((-1, height)) | |
1689 self._bestsize = height | |
1690 | |
1691 | |
1692 def SetControlBackgroundColour(self, colour=None): | |
1693 """ Sets The TabCtrl Background Colour (Behind The Tabs). """ | |
1694 | |
1695 if colour is None: | |
1696 colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) | |
1697 | |
1698 self.SetBackgroundColour(colour) | |
1699 self.Refresh() | |
1700 | |
1701 | |
1702 def GetPageTextFont(self, nPage): | |
1703 """ Returns The Primary Font For The Given Page nPage. """ | |
1704 | |
1705 if nPage < 0 or nPage >= self.GetPageCount(): | |
1706 raise "\nERROR: Invalid Notebook Page In GetPageTextFont: (" + str(nPage) + ")" | |
1707 | |
1708 return self._pages[nPage]._font | |
1709 | |
1710 | |
1711 def SetPageTextSecondaryFont(self, nPage, font=None): | |
1712 """ Sets The Secondary Font For The Given Page nPage. """ | |
1713 | |
1714 if nPage < 0 or nPage >= self.GetPageCount(): | |
1715 raise "\nERROR: Invalid Notebook Page In SetPageTextSecondaryFont: (" + str(nPage) + ")" | |
1716 | |
1717 if font is None: | |
1718 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1719 | |
1720 normalfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
1721 | |
1722 self._pages[nPage]._secondaryfont = font | |
1723 | |
1724 if font == normalfont: | |
1725 self._somethingchanged = True | |
1726 self._firsttime = True | |
1727 self.Refresh() | |
1728 return | |
1729 | |
1730 dc = wx.ClientDC(self) | |
1731 dc.SetFont(font) | |
1732 w1, h1 = dc.GetTextExtent("Aq") | |
1733 dc.SetFont(normalfont) | |
1734 wn, hn = dc.GetTextExtent("Aq") | |
1735 w2, h2 = (0, 0) | |
1736 | |
1737 if hasattr(self._pages[nPage], "_font"): | |
1738 dc.SetFont(self._pages[nPage]._font) | |
1739 w2, h2 = dc.GetTextExtent("Aq") | |
1740 | |
1741 h = max(h1, h2) | |
1742 | |
1743 if h < hn: | |
1744 self._somethingchanged = True | |
1745 self._firsttime = True | |
1746 self.Refresh() | |
1747 return | |
1748 | |
1749 if h + 2*self._padding.y < 24: | |
1750 newheight = 24 | |
1751 else: | |
1752 newheight = h + 2*self._padding.y | |
1753 | |
1754 oldsize = self.GetSize() | |
1755 | |
1756 if newheight < oldsize[-1]: | |
1757 newheight = oldsize[-1] | |
1758 | |
1759 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
1760 self.SetBestSize((-1, newheight)) | |
1761 else: | |
1762 self.SetBestSize((self._CalcBestWidth(dc), -1)) | |
1763 self._parent.GetSizer().Layout() | |
1764 | |
1765 self._somethingchanged = True | |
1766 self._firsttime = True | |
1767 self.Refresh() | |
1768 | |
1769 | |
1770 def GetPageTextSecondaryFont(self, nPage): | |
1771 """ Returns The Secondary Font For The Given Page nPage. """ | |
1772 | |
1773 if nPage < 0 or nPage >= self.GetPageCount(): | |
1774 raise "\nERROR: Invalid Notebook Page In GetPageTextSecondaryFont: (" + str(nPage) + ")" | |
1775 | |
1776 return self._pages[nPage]._secondaryfont | |
1777 | |
1778 | |
1779 def SetPageTextColour(self, nPage, colour=None): | |
1780 """ Sets The Text Colour For The Given Page nPage. """ | |
1781 | |
1782 if nPage < 0 or nPage >= self.GetPageCount(): | |
1783 raise "\nERROR: Invalid Notebook Page In SetPageTextColour: (" + str(nPage) + ")" | |
1784 | |
1785 if colour is None: | |
1786 colour = wx.BLACK | |
1787 | |
1788 self._pages[nPage]._pagetextcolour = colour | |
1789 self._somethingchanged = True | |
1790 self.Refresh() | |
1791 | |
1792 | |
1793 def GetPageTextColour(self, nPage): | |
1794 """ Returns The Text Colour For The Given Page nPage. """ | |
1795 | |
1796 if nPage < 0 or nPage >= self.GetPageCount(): | |
1797 raise "\nERROR: Invalid Notebook Page In GetPageTextColour: (" + str(nPage) + ")" | |
1798 | |
1799 return self._pages[nPage]._pagetextcolour | |
1800 | |
1801 | |
1802 def SetPageColour(self, nPage, colour=None): | |
1803 """ Sets The Tab Background Colour For The Given Page nPage. """ | |
1804 | |
1805 if nPage < 0 or nPage >= self.GetPageCount(): | |
1806 raise "\nERROR: Invalid Notebook Page In SetPageColour: (" + str(nPage) + ")" | |
1807 | |
1808 if colour is None: | |
1809 colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) | |
1810 | |
1811 self._pages[nPage]._pagecolour = colour | |
1812 self._somethingchanged = True | |
1813 self.Refresh() | |
1814 | |
1815 | |
1816 def GetPageColour(self, nPage): | |
1817 """ Returns The Tab Background Colour For The Given Page nPage. """ | |
1818 | |
1819 if nPage < 0 or nPage >= self.GetPageCount(): | |
1820 raise "\nERROR: Invalid Notebook Page In GetPageColour: (" + str(nPage) + ")" | |
1821 | |
1822 if not self._tabstyle._normal or self._usegradients: | |
1823 if self._usegradients: | |
1824 return self._tabstyle._firstcolour | |
1825 else: | |
1826 return self._GetThemePageColour(nPage) | |
1827 else: | |
1828 return self._pages[nPage]._pagecolour | |
1829 | |
1830 | |
1831 def EnablePage(self, nPage, enable=True): | |
1832 """ Enable/Disable The Given Page nPage. """ | |
1833 | |
1834 if nPage < 0 or nPage >= self.GetPageCount(): | |
1835 raise "\nERROR: Invalid Notebook Page In EnablePage: (" + str(nPage) + ")" | |
1836 | |
1837 self._pages[nPage]._enable = enable | |
1838 | |
1839 if not enable and self.GetSelection() == nPage: | |
1840 defpage = self.GetDefaultPage() | |
1841 if defpage < 0: | |
1842 self.AdvanceSelection() | |
1843 else: | |
1844 if defpage >= self.GetPageCount(): | |
1845 self.AdvanceSelection() | |
1846 else: | |
1847 if defpage == nPage: | |
1848 self.AdvanceSelection() | |
1849 else: | |
1850 self.SetSelection(defpage) | |
1851 | |
1852 self.Refresh() | |
1853 | |
1854 | |
1855 def IsPageEnabled(self, nPage): | |
1856 """ Returns Whether A Page Is Enabled Or Not. """ | |
1857 | |
1858 if nPage < 0 or nPage >= self.GetPageCount(): | |
1859 raise "\nERROR: Invalid Notebook Page In IsPageEnabled: (" + str(nPage) + ")" | |
1860 | |
1861 return self._pages[nPage]._enable | |
1862 | |
1863 | |
1864 def SetHighlightSelection(self, highlight=True): | |
1865 """ Globally Enables/Disables Tab Highlighting On Tab Selection. """ | |
1866 | |
1867 self._highlight = highlight | |
1868 self.Refresh() | |
1869 | |
1870 | |
1871 def GetHighlightSelection(self): | |
1872 """ Returns Globally Enable/Disable State For Tab Highlighting On Tab Selection. """ | |
1873 | |
1874 return self._highlight | |
1875 | |
1876 | |
1877 def SetUseFocusIndicator(self, focus=True): | |
1878 """ Globally Enables/Disables Tab Focus Indicator. """ | |
1879 | |
1880 self._usefocus = focus | |
1881 self.Refresh() | |
1882 | |
1883 | |
1884 def GetUseFocusIndicator(self): | |
1885 """ Returns Globally Enable/Disable State For Tab Focus Indicator. """ | |
1886 | |
1887 return self._usefocus | |
1888 | |
1889 | |
1890 def SetPageToolTip(self, nPage, tooltip="", timer=500, winsize=400): | |
1891 """ | |
1892 Sets A ToolTip For The Given Page nPage. | |
1893 | |
1894 @param nPage: The Given Page; | |
1895 @param tooltip: The ToolTip String; | |
1896 @param timer: The Timer After Which The Tip Window Is Popped Up; | |
1897 @param winsize: The Maximum Width Of The Tip Window. | |
1898 """ | |
1899 | |
1900 if nPage < 0 or nPage >= self.GetPageCount(): | |
1901 raise "\nERROR: Invalid Notebook Page In SetPageToolTip: (" + str(nPage) + ")" | |
1902 | |
1903 self._pages[nPage]._tooltip = tooltip | |
1904 self._pages[nPage]._tooltiptime = timer | |
1905 self._pages[nPage]._winsize = winsize | |
1906 | |
1907 | |
1908 def GetPageToolTip(self, nPage): | |
1909 """ Returns A Tuple With All Page ToolTip Parameters. """ | |
1910 | |
1911 if nPage < 0 or nPage >= self.GetPageCount(): | |
1912 raise "\nERROR: Invalid Notebook Page In GetPageToolTip: (" + str(nPage) + ")" | |
1913 | |
1914 return self._pages[nPage]._tooltip, self._pages[nPage]._tooltiptime, \ | |
1915 self._pages[nPage]._winsize | |
1916 | |
1917 | |
1918 def EnableToolTip(self, show=True): | |
1919 """ Globally Enables/Disables Tab ToolTips. """ | |
1920 | |
1921 self._showtooltip = show | |
1922 | |
1923 if show: | |
1924 try: | |
1925 wx.PopupWindow(self) | |
1926 self.TransientTipWindow = TransientTipWindow | |
1927 | |
1928 except NotImplementedError: | |
1929 | |
1930 self.TransientTipWindow = macTransientTipWindow | |
1931 | |
1932 else: | |
1933 if self._istooltipshown: | |
1934 self._tipwindow.Destroy() | |
1935 self._istooltipshown = False | |
1936 self.Refresh() | |
1937 | |
1938 if self._tiptimer.IsRunning(): | |
1939 self._tiptimer.Stop() | |
1940 | |
1941 | |
1942 def GetToolTipBackgroundColour(self): | |
1943 """ Returns The ToolTip Window Background Colour. """ | |
1944 | |
1945 return self._backtooltip | |
1946 | |
1947 | |
1948 def SetToolTipBackgroundColour(self, colour=None): | |
1949 """ Sets The ToolTip Window Background Colour. """ | |
1950 | |
1951 if colour is None: | |
1952 colour = wx.Colour(255, 255, 230) | |
1953 | |
1954 self._backtooltip = colour | |
1955 | |
1956 | |
1957 def EnableTabGradients(self, enable=True): | |
1958 """ Globally Enables/Disables Drawing Of Gradient Coloured Tabs For Each Tab. """ | |
1959 | |
1960 self._usegradients = enable | |
1961 | |
1962 if enable: | |
1963 self._tabstyle.ResetDefaults() | |
1964 self._selstyle.ResetDefaults() | |
1965 | |
1966 self.Refresh() | |
1967 | |
1968 | |
1969 def SetPageFirstGradientColour(self, nPage, colour=None): | |
1970 """ Sets The Single Tab First Gradient Colour. """ | |
1971 | |
1972 if nPage < 0 or nPage >= self.GetPageCount(): | |
1973 raise "\nERROR: Invalid Notebook Page In SetPageFirstGradientColour: (" + str(nPage) + ")" | |
1974 | |
1975 if colour is None: | |
1976 colour = wx.WHITE | |
1977 | |
1978 self._pages[nPage]._firstcolour = colour | |
1979 self.Refresh() | |
1980 | |
1981 | |
1982 def SetPageSecondGradientColour(self, nPage, colour=None): | |
1983 """ Sets The Single Tab Second Gradient Colour. """ | |
1984 | |
1985 if nPage < 0 or nPage >= self.GetPageCount(): | |
1986 raise "\nERROR: Invalid Notebook Page In SetPageSecondGradientColour: (" + str(nPage) + ")" | |
1987 | |
1988 if colour is None: | |
1989 color = self._pages[nPage]._firstcolour | |
1990 r, g, b = int(color.Red()), int(color.Green()), int(color.Blue()) | |
1991 color = ((r >> 1) + 20, (g >> 1) + 20, (b >> 1) + 20) | |
1992 colour = wx.Colour(color[0], color[1], color[2]) | |
1993 | |
1994 self._pages[nPage]._secondcolour = colour | |
1995 self.Refresh() | |
1996 | |
1997 | |
1998 def GetPageFirstGradientColour(self, nPage): | |
1999 """ Returns The Single Tab First Gradient Colour. """ | |
2000 | |
2001 if nPage < 0 or nPage >= self.GetPageCount(): | |
2002 raise "\nERROR: Invalid Notebook Page In GetPageFirstGradientColour: (" + str(nPage) + ")" | |
2003 | |
2004 return self._pages[nPage]._firstcolour | |
2005 | |
2006 | |
2007 def GetPageSecondGradientColour(self, nPage): | |
2008 """ Returns The Single Tab Second Gradient Colour. """ | |
2009 | |
2010 if nPage < 0 or nPage >= self.GetPageCount(): | |
2011 raise "\nERROR: Invalid Notebook Page In GetPageSecondGradientColour: (" + str(nPage) + ")" | |
2012 | |
2013 return self._pages[nPage]._secondcolour | |
2014 | |
2015 | |
2016 def CancelTip(self): | |
2017 """ Destroys The Tip Window (Probably You Won't Need This One). """ | |
2018 | |
2019 if self._istooltipshown: | |
2020 self._istooltipshown = False | |
2021 self._tipwindow.Destroy() | |
2022 self.Refresh() | |
2023 | |
2024 | |
2025 def AdvanceSelection(self, forward=True): | |
2026 """ | |
2027 Cycles Through The Tabs. The Call To This Function Generates The | |
2028 EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. | |
2029 """ | |
2030 | |
2031 if self.GetPageCount() <= 1: | |
2032 return | |
2033 | |
2034 sel = self.GetSelection() | |
2035 count = 0 | |
2036 | |
2037 if forward: | |
2038 if sel == self.GetPageCount() - 1: | |
2039 sel = 0 | |
2040 else: | |
2041 sel = sel + 1 | |
2042 | |
2043 while not self.IsPageEnabled(sel) or \ | |
2044 (self._enablehiding and self._pages[sel]._ishidden): | |
2045 | |
2046 count = count + 1 | |
2047 sel = sel + 1 | |
2048 | |
2049 if self._enablehiding and self._pages[sel]._ishidden: | |
2050 count = count + 1 | |
2051 sel = sel + 1 | |
2052 | |
2053 if sel == self.GetPageCount() - 1: | |
2054 sel = 0 | |
2055 | |
2056 if count > self.GetPageCount() + 1: | |
2057 return None | |
2058 | |
2059 else: | |
2060 if sel == 0: | |
2061 sel = self.GetPageCount() - 1 | |
2062 else: | |
2063 sel = sel - 1 | |
2064 | |
2065 while not self.IsPageEnabled(sel): | |
2066 count = count + 1 | |
2067 sel = sel - 1 | |
2068 if sel == 0: | |
2069 sel = self.GetPageCount() - 1 | |
2070 | |
2071 if count > self.GetPageCount() + 1: | |
2072 return None | |
2073 | |
2074 self._parent.SetSelection(sel) | |
2075 | |
2076 | |
2077 def SetDefaultPage(self, defaultpage=-1): | |
2078 """ | |
2079 Sets The Default Page That Will Be Selected When An Active And Selected | |
2080 Tab Is Made Inactive. | |
2081 """ | |
2082 | |
2083 if defaultpage >= self.GetPageCount(): | |
2084 raise "\nERROR: Invalid Notebook Page In SetDefaultPage: (" + str(defaultpage) + ")" | |
2085 | |
2086 self._defaultpage = defaultpage | |
2087 | |
2088 | |
2089 def GetDefaultPage(self): | |
2090 """ Returns The Default Page. """ | |
2091 | |
2092 return self._defaultpage | |
2093 | |
2094 | |
2095 def UpdateSpinButton(self): | |
2096 """ Update The NotebookSpinButton. Used Internally. """ | |
2097 | |
2098 count = self.GetPageCount() | |
2099 | |
2100 if count == 0: | |
2101 return | |
2102 | |
2103 nbsize = [] | |
2104 nbsize.append(self._initrect[-1][0] + self._initrect[-1][2]) | |
2105 nbsize.append(self._initrect[-1][1] + self._initrect[-1][3]) | |
2106 clsize = self.GetClientSize() | |
2107 | |
2108 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
2109 spinstyle = wx.SP_HORIZONTAL | |
2110 showspin = nbsize[0] > clsize[0] | |
2111 else: | |
2112 spinstyle = wx.SP_VERTICAL | |
2113 showspin = nbsize[1] > clsize[1] | |
2114 | |
2115 if showspin: | |
2116 if not hasattr(self, "_spinbutton"): | |
2117 self._spinbutton = NotebookSpinButton(self, pos=(10000,10000), | |
2118 style=spinstyle) | |
2119 self._spinbutton.SetValue(0) | |
2120 self._originalspinsize = self._spinbutton.GetSize() | |
2121 | |
2122 sbsize = self._spinbutton.GetSize() | |
2123 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
2124 ypos = clsize[1] - sbsize[1] | |
2125 if self._style & NC_LEFT: | |
2126 xpos = nbsize[0] - (2 + sbsize[0]) | |
2127 else: | |
2128 xpos = 2 | |
2129 else: | |
2130 xpos = clsize[0] - sbsize[0] | |
2131 if self._style & NC_BOTTOM: | |
2132 ypos = 2 | |
2133 else: | |
2134 ypos = clsize[1] - sbsize[1] | |
2135 | |
2136 if self.HasMenuButton(): | |
2137 self._spinbutton.SetSize((-1, 16)) | |
2138 else: | |
2139 self._spinbutton.SetSize(self._originalspinsize) | |
2140 | |
2141 self._spinbutton.Move((xpos, ypos)) | |
2142 self._spinbutton.Show() | |
2143 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
2144 self._spinbutton.SetRange(-(count-1), 0) | |
2145 else: | |
2146 self._spinbutton.SetRange(0, count-1) | |
2147 | |
2148 else: | |
2149 | |
2150 if hasattr(self, "_spinbutton") and self._spinbutton.IsShown(): | |
2151 self._spinbutton.Hide() | |
2152 self._spinbutton.SetValue(0) | |
2153 | |
2154 | |
2155 def HasSpinButton(self): | |
2156 """ Returns Wheter The NotebookSpinButton Exists And Is Shown. """ | |
2157 | |
2158 return hasattr(self, "_spinbutton") and self._spinbutton.IsShown() | |
2159 | |
2160 | |
2161 def IsLastVisible(self): | |
2162 """ Returns Whether The Last Tab Is Visible Or Not. """ | |
2163 | |
2164 if self.HasSpinButton(): | |
2165 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
2166 pos, size = (1, 3) | |
2167 else: | |
2168 pos, size = (0, 2) | |
2169 lastpos = self._tabrect[-1][pos] + self._tabrect[-1][size] | |
2170 if lastpos < self._spinbutton.GetPosition()[pos]: | |
2171 return True | |
2172 | |
2173 return False | |
2174 | |
2175 | |
2176 def UpdateMenuButton(self, show): | |
2177 """ Updates The Notebook Menu Button To Show/Hide Tabs. Used Internally. """ | |
2178 | |
2179 count = self.GetPageCount() | |
2180 | |
2181 if count == 0: | |
2182 return | |
2183 | |
2184 if not hasattr(self, "_initrect"): | |
2185 return | |
2186 | |
2187 if not show and not hasattr(self, "_menubutton"): | |
2188 return | |
2189 | |
2190 if not hasattr(self, "_menubutton"): | |
2191 self._menubutton = NotebookMenuButton(self, pos=(10000,10000)) | |
2192 | |
2193 sbsize = self._menubutton.GetSize() | |
2194 nbsize = [] | |
2195 nbsize.append(self._initrect[-1][0] + self._initrect[-1][2]) | |
2196 nbsize.append(self._initrect[-1][1] + self._initrect[-1][3]) | |
2197 clsize = self.GetClientSize() | |
2198 | |
2199 xpos = clsize[0] - sbsize[0] | |
2200 ypos = clsize[1] - sbsize[1] | |
2201 | |
2202 if self.HasSpinButton(): | |
2203 self._menubutton.Move((xpos-1, ypos-16)) | |
2204 else: | |
2205 self._menubutton.Move((xpos-1, ypos-1)) | |
2206 | |
2207 self._menubutton.Show(show) | |
2208 | |
2209 | |
2210 def HasMenuButton(self): | |
2211 """ Returns Wheter The NotebookMenuButton Exists And Is Shown. """ | |
2212 | |
2213 return hasattr(self, "_menubutton") and self._menubutton.IsShown() | |
2214 | |
2215 | |
2216 def HideTab(self, nPage, hide=True): | |
2217 """ Hides A Tab In The NotebookCtrl. """ | |
2218 | |
2219 if hide: | |
2220 self._pages[nPage]._ishidden = True | |
2221 else: | |
2222 self._pages[nPage]._ishidden = False | |
2223 | |
2224 if nPage == self.GetSelection(): | |
2225 self.AdvanceSelection() | |
2226 | |
2227 self._firsttime = True | |
2228 self.Refresh() | |
2229 | |
2230 | |
2231 def HitTest(self, point, flags=0): | |
2232 """ | |
2233 Standard NotebookCtrl HitTest() Method. If Called With 2 Outputs, It | |
2234 Returns The Page Clicked (If Any) And One Of These Flags: | |
2235 | |
2236 NC_HITTEST_NOWHERE = 0 ==> Hit Not On Tab | |
2237 NC_HITTEST_ONICON = 1 ==> Hit On Icon | |
2238 NC_HITTEST_ONLABEL = 2 ==> Hit On Label | |
2239 NC_HITTEST_ONITEM = 4 ==> Hit Generic, On Item | |
2240 NC_HITTEST_ONX = 8 ==> Hit On Closing "X" On Every Page | |
2241 """ | |
2242 | |
2243 mirror = self._style & NC_BOTTOM | |
2244 size = self.GetSize() | |
2245 dc = wx.ClientDC(self) | |
2246 | |
2247 height = self._tabrect[0].height | |
2248 | |
2249 if flags: | |
2250 flags = wx.NB_HITTEST_NOWHERE | |
2251 | |
2252 if point.x <= 0 or point.x >= size.x: | |
2253 if flags: | |
2254 return wx.NOT_FOUND, flags | |
2255 else: | |
2256 return wx.NOT_FOUND | |
2257 | |
2258 if not point.y >= self._tabrect[0].y and point.y < self._tabrect[0].y + height: | |
2259 if flags: | |
2260 return wx.NOT_FOUND, flags | |
2261 else: | |
2262 return wx.NOT_FOUND | |
2263 | |
2264 posx = self._firsttabpos.x | |
2265 posy = self._firsttabpos.y | |
2266 maxwidth = max(self._maxtabwidths) | |
2267 | |
2268 for ii in xrange(self._firstvisible, self.GetPageCount()): | |
2269 | |
2270 if not self._enablehiding or not self._pages[ii]._ishidden: | |
2271 | |
2272 width = self._CalcTabTextWidth(dc, ii) | |
2273 | |
2274 bmpWidth, bmpHeight = self._CalcTabBitmapSize(ii) | |
2275 | |
2276 tabrect = self._CalcTabRect(ii, posx, posy, width, bmpWidth, bmpHeight) | |
2277 | |
2278 if tabrect.Contains(point): | |
2279 | |
2280 if flags: | |
2281 flags = NC_HITTEST_ONITEM | |
2282 | |
2283 #onx attempt | |
2284 if self.GetDrawX()[0]: | |
2285 count = self._tabvisible[0:ii].count(0) | |
2286 if flags and self._xrect[ii-self._firstvisible-count].Contains(point): | |
2287 flags = NC_HITTEST_ONX | |
2288 | |
2289 #onicon attempt | |
2290 if flags and bmpWidth > 0 and \ | |
2291 wx.RectPS(wx.Point(*self._CalcTabBitmapPosition(ii, | |
2292 bmpWidth, bmpHeight, tabrect)), | |
2293 wx.Size(bmpWidth, bmpHeight)).Contains(point): | |
2294 flags = NC_HITTEST_ONICON | |
2295 | |
2296 #onlabel attempt | |
2297 elif flags and wx.RectPS(wx.Point(*self._CalcTabTextPosition(ii, | |
2298 tabrect, self._CalcTabBitmapSpace(bmpWidth, bmpHeight))), | |
2299 wx.Size(width, height)).Contains(point): | |
2300 flags = NC_HITTEST_ONLABEL | |
2301 | |
2302 if flags: | |
2303 return ii, flags | |
2304 else: | |
2305 return ii | |
2306 | |
2307 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
2308 posx += tabrect.width | |
2309 else: | |
2310 posy += tabrect.height | |
2311 | |
2312 if flags: | |
2313 return wx.NOT_FOUND, flags | |
2314 else: | |
2315 return wx.NOT_FOUND | |
2316 | |
2317 | |
2318 def EnableDragAndDrop(self, enable=True): | |
2319 """ Globall Enables/Disables Tabs Drag And Drop. """ | |
2320 | |
2321 self._enabledragging = enable | |
2322 | |
2323 | |
2324 def EnableHiding(self, enable=True): | |
2325 """ Globally Enables/Disables Hiding On Tabs In Runtime. """ | |
2326 | |
2327 self._enablehiding = enable | |
2328 self.UpdateMenuButton(enable) | |
2329 | |
2330 wx.FutureCall(1000, self.UpdateMenuButton, enable) | |
2331 | |
2332 | |
2333 def SetAnimationImages(self, nPage, imgarray): | |
2334 """ | |
2335 Sets An Animation List Associated To The Given Page nPage. | |
2336 | |
2337 @param nPage: The Given Page | |
2338 @param imgarray: A List Of Image Indexes Of Images Inside The | |
2339 ImageList Associated To NotebookCtrl. | |
2340 """ | |
2341 | |
2342 if nPage < 0 or nPage >= self.GetPageCount(): | |
2343 raise "\nERROR: Invalid Notebook Page In SetAnimationImages: (" + str(nPage) + ")" | |
2344 | |
2345 if not imgarray: | |
2346 raise "\nERROR: Invalid Image Array In SetAnimationImages: (" + repr(imgarray) + ")" | |
2347 | |
2348 if min(imgarray) < 0: | |
2349 raise "\nERROR: Invalid Image Array In SetAnimationImages: (Min(ImgArray) = " + \ | |
2350 str(min(imgarray)) + " < 0)" | |
2351 | |
2352 if max(imgarray) > self.GetImageList().GetImageCount() - 1: | |
2353 raise "\nERROR: Invalid Image Array In SetAnimationImages: (Max(ImgArray) = " + \ | |
2354 str(max(imgarray)) + " > " + str(self.GetImageList().GetImageCount()-1) + ")" | |
2355 | |
2356 self._pages[nPage]._animationimages = imgarray | |
2357 | |
2358 | |
2359 def GetAnimationImages(self, nPage): | |
2360 """ Returns The Animation Images List Associated To The Given Page nPage. """ | |
2361 | |
2362 if nPage < 0 or nPage >= self.GetPageCount(): | |
2363 raise "\nERROR: Invalid Notebook Page In GetAnimationImages: (" + str(nPage) + ")" | |
2364 | |
2365 return self._pages[nPage]._animationimages | |
2366 | |
2367 | |
2368 def AnimateTab(self, event): | |
2369 """ Called When The Refreshing Animation Timer Expires. Used Internally""" | |
2370 | |
2371 obj = event.GetEventObject() | |
2372 nPage = self._timers.index(obj) | |
2373 | |
2374 if not self.IsPageEnabled(nPage): | |
2375 return | |
2376 | |
2377 indx = self.GetPageImage(nPage) | |
2378 images = self.GetAnimationImages(nPage) | |
2379 myindx = images.index(indx) | |
2380 | |
2381 if indx == images[-1]: | |
2382 myindx = -1 | |
2383 | |
2384 myindx = myindx + 1 | |
2385 | |
2386 self.SetPageImage(nPage, images[myindx]) | |
2387 | |
2388 | |
2389 def StartAnimation(self, nPage, timer=500): | |
2390 """ Starts The Animation On The Given Page, With Refreshing Time Rate "timer". """ | |
2391 | |
2392 if nPage < 0 or nPage >= self.GetPageCount(): | |
2393 raise "\nERROR: Invalid Notebook Page In StartAnimation: (" + str(nPage) + ")" | |
2394 | |
2395 images = self.GetAnimationImages(nPage) | |
2396 | |
2397 if not images: | |
2398 raise "\nERROR: No Images Array Defined For Page: (" + str(nPage) + ")" | |
2399 | |
2400 if len(images) == 1: | |
2401 raise "\nERROR: Impossible To Animate Tab: " + str(nPage) + " With Only One Image" | |
2402 | |
2403 self._timers[nPage].Start(timer) | |
2404 | |
2405 | |
2406 def StopAnimation(self, nPage): | |
2407 """ Stops The Animation On The Given Page nPage. """ | |
2408 | |
2409 if nPage < 0 or nPage >= self.GetPageCount(): | |
2410 raise "\nERROR: Invalid Notebook Page In StopAnimation: (" + str(nPage) + ")" | |
2411 | |
2412 if self._timers[nPage].IsRunning(): | |
2413 self._timers[nPage].Stop() | |
2414 | |
2415 | |
2416 def SetDrawX(self, drawx=True, style=1, image1=None, image2=None): | |
2417 """ | |
2418 Globally Enables/Disables The Drawing Of A Closing "X" In The Tab. | |
2419 | |
2420 @param drawx: C{True} to enable drawing a closing "X"; C{False} to | |
2421 disable it | |
2422 @param style: the style of the X to draw when C{drawx} is C{True}; | |
2423 possible values are: | |
2424 - C{1}: Small "X" At The Top-Right Of The Tab; | |
2425 - C{2}: Bigger "X" In The Middle Vertical Of The Tab (Like Opera Notebook); | |
2426 - C{3}: Custom "X" Image Is Drawn On Tabs. | |
2427 @param image1: if C{style} is C{3}, the image to use when drawing | |
2428 the X on an unhighlighted tab | |
2429 @param image2: if C{style} is C{3}, the image to use when drawing | |
2430 the X on a highlighted tab | |
2431 """ | |
2432 | |
2433 self._drawx = drawx | |
2434 self._drawxstyle = style | |
2435 | |
2436 if style == 3: | |
2437 self._imglist2 = wx.ImageList(16, 16, True, 0) | |
2438 self._imglist2.Add(image1) | |
2439 self._imglist2.Add(image2) | |
2440 | |
2441 if self._style & NC_LEFT or self._style & NC_RIGHT: | |
2442 self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) | |
2443 self._parent.GetSizer().Layout() | |
2444 | |
2445 self.Refresh() | |
2446 | |
2447 | |
2448 def GetDrawX(self): | |
2449 """ | |
2450 Returns The Enable/Disable State Of Drawing Of A Small "X" At The Top-Right Of | |
2451 Every Page. | |
2452 """ | |
2453 | |
2454 return self._drawx, self._drawxstyle | |
2455 | |
2456 | |
2457 def GetInsideTab(self, pt): | |
2458 """ Returns The Tab On Which The Mouse Is Hovering On. """ | |
2459 | |
2460 count = 0 | |
2461 | |
2462 for tabs in self._tabrect: | |
2463 if tabs.Contains(pt): | |
2464 return count | |
2465 | |
2466 count = count + 1 | |
2467 | |
2468 return -1 | |
2469 | |
2470 | |
2471 def GetInsideX(self, pt): | |
2472 """ Returns The Tab On Which The Mouse Is Hovering On The "X" Button. """ | |
2473 | |
2474 count = 0 | |
2475 | |
2476 for rects in self._xrect: | |
2477 if rects.Contains(pt): | |
2478 return count | |
2479 | |
2480 count = count + 1 | |
2481 | |
2482 return -1 | |
2483 | |
2484 | |
2485 def SetImageToCloseButton(self, convert=True): | |
2486 """ Set Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ | |
2487 | |
2488 self._convertimage = convert | |
2489 | |
2490 | |
2491 def GetImageToCloseButton(self): | |
2492 """ Get Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ | |
2493 | |
2494 return self._convertimage | |
2495 | |
2496 | |
2497 def ConvertImageToCloseButton(self, page): | |
2498 """ Globally Converts The Page Image To The "Opera" Style Close Button. """ | |
2499 | |
2500 bmpindex = self.GetPageImage(page) | |
2501 if bmpindex < 0: | |
2502 return | |
2503 | |
2504 tabrect = self._tabrect[page] | |
2505 size = self.GetSize() | |
2506 | |
2507 maxfont = self._maxfont | |
2508 | |
2509 dc = wx.ClientDC(self) | |
2510 | |
2511 dc.SetFont(maxfont) | |
2512 pom, height = dc.GetTextExtent("Aq") | |
2513 | |
2514 bmp = self._imglist.GetBitmap(bmpindex) | |
2515 | |
2516 bmpposx = tabrect.x + self._padding.x | |
2517 bmpposy = size.y - (height + 2*self._padding.y + bmp.GetHeight())/2 - 1 | |
2518 | |
2519 ypos = size.y - height - self._padding.y*2 | |
2520 ysize = height + self._padding.y*2 + 3 | |
2521 | |
2522 if page == self.GetSelection(): | |
2523 bmpposx = bmpposx + 1 | |
2524 bmpposy = bmpposy - 1 | |
2525 ypos = ypos - 3 | |
2526 ysize = ysize + 2 | |
2527 | |
2528 colour = self.GetPageColour(page) | |
2529 bmprect = wx.Rect(bmpposx, bmpposy, bmp.GetWidth()+self._padding.x, bmp.GetHeight()) | |
2530 | |
2531 dc.SetBrush(wx.Brush(colour)) | |
2532 dc.SetPen(wx.TRANSPARENT_PEN) | |
2533 dc.DrawRectangleRect(bmprect) | |
2534 | |
2535 colour = self.GetPageTextColour(page) | |
2536 | |
2537 r = colour.Red() | |
2538 g = colour.Green() | |
2539 b = colour.Blue() | |
2540 | |
2541 hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64) | |
2542 | |
2543 colour = wx.Colour(hr, hg, hb) | |
2544 back_colour = wx.WHITE | |
2545 | |
2546 yypos = ypos+(ysize-height-self._padding.y/2)/2 | |
2547 | |
2548 xrect = wx.Rect(bmprect.x+(bmprect.width - self._padding.x - height)/2, | |
2549 yypos, height, height) | |
2550 | |
2551 # Opera Style | |
2552 dc.SetPen(wx.Pen(colour, 1)) | |
2553 dc.SetBrush(wx.Brush(colour)) | |
2554 dc.DrawRoundedRectangleRect(xrect, 2) | |
2555 dc.SetPen(wx.Pen(back_colour, 2)) | |
2556 dc.DrawLine(xrect[0]+2, xrect[1]+2, xrect[0]+xrect[2]-3, xrect[1]+xrect[3]-3) | |
2557 dc.DrawLine(xrect[0]+2, xrect[1]+xrect[3]-3, xrect[0]+xrect[2]-3, xrect[1]+2) | |
2558 | |
2559 | |
2560 def RedrawClosingX(self, pt, insidex, drawx, highlight=False): | |
2561 """ Redraw The Closing "X" Accordingly To The Mouse "Hovering" Position. """ | |
2562 | |
2563 colour = self.GetPageTextColour(insidex) | |
2564 back_colour = self.GetBackgroundColour() | |
2565 imagelist = 0 | |
2566 | |
2567 if highlight: | |
2568 r = colour.Red() | |
2569 g = colour.Green() | |
2570 b = colour.Blue() | |
2571 | |
2572 hr, hg, hb = min(255,r+64), min(255,g+64), min(255,b+64) | |
2573 | |
2574 colour = wx.Colour(hr, hg, hb) | |
2575 back_colour = wx.WHITE | |
2576 imagelist = 1 | |
2577 | |
2578 dc = wx.ClientDC(self) | |
2579 xrect = self._xrect[insidex] | |
2580 | |
2581 if drawx == 1: | |
2582 # Emule Style | |
2583 dc.SetPen(wx.Pen(colour, 1)) | |
2584 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
2585 dc.DrawRectangleRect(xrect) | |
2586 elif drawx == 2: | |
2587 # Opera Style | |
2588 dc.SetPen(wx.Pen(colour, 1)) | |
2589 dc.SetBrush(wx.Brush(colour)) | |
2590 dc.DrawRoundedRectangleRect(xrect, 2) | |
2591 dc.SetPen(wx.Pen(back_colour, 2)) | |
2592 dc.DrawLine(xrect[0]+2, xrect[1]+2, xrect[0]+xrect[2]-3, xrect[1]+xrect[3]-3) | |
2593 dc.DrawLine(xrect[0]+2, xrect[1]+xrect[3]-3, xrect[0]+xrect[2]-3, xrect[1]+2) | |
2594 else: | |
2595 self._imglist2.Draw(imagelist, dc, xrect[0], xrect[1], | |
2596 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
2597 | |
2598 | |
2599 def HideOnSingleTab(self, hide=True): | |
2600 """ Hides The TabCtrl When There Is Only One Tab In NotebookCtrl. """ | |
2601 | |
2602 self._hideonsingletab = hide | |
2603 | |
2604 | |
2605 def SetPagePopupMenu(self, nPage, menu): | |
2606 """ Sets A Popup Menu Specific To A Single Tab. """ | |
2607 | |
2608 if nPage < 0 or nPage >= self.GetPageCount(): | |
2609 raise "\nERROR: Invalid Notebook Page In SetPagePopupMenu: (" + str(nPage) + ")" | |
2610 | |
2611 self._pages[nPage]._menu = menu | |
2612 | |
2613 | |
2614 def GetPagePopupMenu(self, nPage): | |
2615 """ Returns The Popup Menu Associated To A Single Tab. """ | |
2616 | |
2617 if nPage < 0 or nPage >= self.GetPageCount(): | |
2618 raise "\nERROR: Invalid Notebook Page In GetPagePopupMenu: (" + str(nPage) + ")" | |
2619 | |
2620 return self._pages[nPage]._menu | |
2621 | |
2622 | |
2623 def DrawInsertionMark(self, dc, nPage): | |
2624 """ | |
2625 Draw An Insertion Arrow To Let The User Understand Where A Dragged Tab Will | |
2626 Be Dropped (Between Which Tabs). | |
2627 """ | |
2628 | |
2629 if not self._enablehiding: | |
2630 if nPage < 0 or nPage >= len(self._tabrect): | |
2631 return | |
2632 else: | |
2633 if nPage < 0 or nPage >= len(self._tabrect) + self._tabvisible.count(0): | |
2634 return | |
2635 | |
2636 colour = wx.BLACK | |
2637 somehidden = False | |
2638 | |
2639 if self._enablehiding: | |
2640 for ii in xrange(nPage): | |
2641 if self._pages[ii]._ishidden: | |
2642 nPage = nPage - 1 | |
2643 somehidden = True | |
2644 | |
2645 rect = self._tabrect[nPage] | |
2646 | |
2647 x1 = rect.x - 4 | |
2648 y1 = rect.y - 1 | |
2649 x2 = rect.x | |
2650 y2 = y1 + 5 | |
2651 x3 = rect.x + 3 | |
2652 y3 = y1 | |
2653 | |
2654 mybrush = wx.Brush(self.GetPageTextColour(nPage)) | |
2655 | |
2656 if not self._enablehiding: | |
2657 if nPage > self._tabID: | |
2658 x1 = x1 + rect.width | |
2659 x2 = x2 + rect.width | |
2660 x3 = x3 + rect.width | |
2661 else: | |
2662 mybrush = wx.Brush(self.GetPageTextColour(nPage)) | |
2663 if nPage >= self._tabID: | |
2664 x1 = x1 + rect.width | |
2665 x2 = x2 + rect.width | |
2666 x3 = x3 + rect.width | |
2667 | |
2668 dc.SetPen(wx.Pen(wx.BLACK, 1)) | |
2669 dc.SetBrush(mybrush) | |
2670 dc.DrawPolygon([(x1, y1), (x2, y2), (x3, y3)]) | |
2671 | |
2672 | |
2673 def OnMouseMotion(self, event): | |
2674 """ Handles The wx.EVT_MOTION Event For TabCtrl. """ | |
2675 | |
2676 pt = event.GetPosition() | |
2677 | |
2678 if self._enabledragging: | |
2679 | |
2680 if event.Dragging() and not event.RightIsDown() and not event.MiddleIsDown(): | |
2681 | |
2682 tolerance = 2 | |
2683 | |
2684 dx = abs(pt.x - self._dragstartpos.x) | |
2685 dy = abs(pt.y - self._dragstartpos.y) | |
2686 | |
2687 if dx <= tolerance and dy <= tolerance: | |
2688 self.SetCursor(wx.STANDARD_CURSOR) | |
2689 return | |
2690 | |
2691 self.SetCursor(self._dragcursor) | |
2692 self._isdragging = True | |
2693 self._isleaving = False | |
2694 newpos = self.HitTest(pt) | |
2695 | |
2696 if newpos >= 0 and newpos != self._olddragpos: | |
2697 self._olddragpos = newpos | |
2698 self.Refresh() | |
2699 | |
2700 else: | |
2701 | |
2702 self._isdragging = False | |
2703 self.SetCursor(wx.STANDARD_CURSOR) | |
2704 | |
2705 if not event.Dragging(): | |
2706 drawx = self.GetDrawX() | |
2707 | |
2708 if drawx[0]: | |
2709 insidex = self.GetInsideX(pt) | |
2710 if insidex >= 0: | |
2711 if self.IsPageEnabled(insidex): | |
2712 self.RedrawClosingX(pt, insidex, drawx[1], True) | |
2713 self._xrefreshed = False | |
2714 else: | |
2715 if not self._xrefreshed: | |
2716 insidetab = self.GetInsideTab(pt) | |
2717 if insidetab >= 0: | |
2718 if self.IsPageEnabled(insidetab): | |
2719 self.RedrawClosingX(pt, insidetab, drawx[1]) | |
2720 self._xrefreshed = True | |
2721 else: | |
2722 if self.GetImageToCloseButton(): | |
2723 page, flags = self.HitTest(pt, 1) | |
2724 if page >= 0: | |
2725 if self.IsPageEnabled(page): | |
2726 if flags == NC_HITTEST_ONICON: | |
2727 if not self._imageconverted: | |
2728 self.ConvertImageToCloseButton(page) | |
2729 self._imageconverted = True | |
2730 else: | |
2731 if self._imageconverted: | |
2732 self.Refresh() | |
2733 self._imageconverted = False | |
2734 | |
2735 if self._showtooltip: | |
2736 if not event.Dragging(): | |
2737 if not event.LeftDown(): | |
2738 | |
2739 oldinside = self._insidetab | |
2740 self._insidetab = self.GetInsideTab(pt) | |
2741 | |
2742 if self._insidetab >= 0: | |
2743 if oldinside != self._insidetab: | |
2744 | |
2745 if self._istooltipshown: | |
2746 self._tipwindow.Destroy() | |
2747 self._istooltipshown = False | |
2748 self.Refresh() | |
2749 | |
2750 if self._tiptimer.IsRunning(): | |
2751 self._tiptimer.Stop() | |
2752 | |
2753 tip, ontime, winsize= self.GetPageToolTip(self._insidetab) | |
2754 | |
2755 if tip.strip() != "": | |
2756 self._currenttip = tip | |
2757 self._currentwinsize = winsize | |
2758 self._tiptimer.Start(ontime, wx.TIMER_ONE_SHOT) | |
2759 | |
2760 else: | |
2761 if self._istooltipshown: | |
2762 self._tipwindow.Destroy() | |
2763 self._istooltipshown = False | |
2764 self.Refresh() | |
2765 | |
2766 self._mousepos = pt | |
2767 | |
2768 event.Skip() | |
2769 | |
2770 | |
2771 def OnShowToolTip(self): | |
2772 """ Called When The Timer For The ToolTip Expires. Used Internally. """ | |
2773 | |
2774 pt = self.ScreenToClient(wx.GetMousePosition()) | |
2775 | |
2776 oldinside = self._insidetab | |
2777 self._insidetab = self.GetInsideTab(pt) | |
2778 | |
2779 if self._insidetab != oldinside or self._insidetab < 0: | |
2780 return | |
2781 | |
2782 self._istooltipshown = True | |
2783 self._tipwindow = self.TransientTipWindow(self, self._currenttip, | |
2784 self._currentwinsize) | |
2785 | |
2786 xsize, ysize = self._tipwindow.GetSize() | |
2787 xpos, ypos = self.ClientToScreen(self._mousepos) | |
2788 | |
2789 if xpos + xsize > self._xvideo - 10: | |
2790 if ypos + ysize > self._yvideo - 10: # SW Tip Positioning | |
2791 posx = xpos - xsize | |
2792 posy = ypos - ysize | |
2793 else: # NE Tip Positioning | |
2794 posx = xpos - xsize | |
2795 posy = ypos | |
2796 else: | |
2797 if ypos + ysize > self._yvideo - 10: # SE Tip Positioning | |
2798 posx = xpos + 10 | |
2799 posy = ypos - ysize | |
2800 else: # NW Tip Positioning | |
2801 posx = xpos + 10 | |
2802 posy = ypos | |
2803 | |
2804 if posy < 0: | |
2805 posy = ypos | |
2806 | |
2807 if posx < 0: | |
2808 posx = xpos | |
2809 | |
2810 self._tipwindow.SetPosition((posx, posy)) | |
2811 self._tipwindow.Show() | |
2812 | |
2813 | |
2814 def OnMouseLeftDown(self, event): | |
2815 """ Handles The wx.EVT_LEFT_DOWN Event For TabCtrl. """ | |
2816 | |
2817 pos = event.GetPosition() | |
2818 page, flags = self.HitTest(pos, 1) | |
2819 self._dragstartpos = pos | |
2820 | |
2821 if page != wx.NOT_FOUND: | |
2822 | |
2823 if self.IsPageEnabled(page): | |
2824 | |
2825 if event.m_controlDown: | |
2826 if page in self._selectedtabs: | |
2827 self._selectedtabs.remove(page) | |
2828 else: | |
2829 self._selectedtabs.append(page) | |
2830 self.Refresh() | |
2831 else: | |
2832 self._selectedtabs = [] | |
2833 if flags == NC_HITTEST_ONX or (flags == NC_HITTEST_ONICON and self.GetImageToCloseButton()): | |
2834 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CLOSING, self.GetId()) | |
2835 eventOut.SetOldSelection(self._selection) | |
2836 eventOut.SetSelection(page) | |
2837 eventOut.SetEventObject(self) | |
2838 | |
2839 if not self.GetEventHandler().ProcessEvent(eventOut): | |
2840 self._parent.DeletePage(page) | |
2841 self._parent.bsizer.Layout() | |
2842 | |
2843 else: | |
2844 self.SetSelection(page) | |
2845 self._tabID = page | |
2846 | |
2847 event.Skip() | |
2848 | |
2849 | |
2850 def OnMouseLeftDClick(self, event): | |
2851 """ Handles The wx.EVT_LEFT_DCLICK Event For TabCtrl. """ | |
2852 | |
2853 pos = event.GetPosition() | |
2854 page = self.HitTest(pos) | |
2855 self._selectedtabs = [] | |
2856 | |
2857 if page == wx.NOT_FOUND: | |
2858 return | |
2859 | |
2860 if not self.IsPageEnabled(page): | |
2861 return | |
2862 | |
2863 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DCLICK, self.GetId()) | |
2864 eventOut.SetOldSelection(self._selection) | |
2865 eventOut.SetSelection(page) | |
2866 eventOut.SetEventObject(self) | |
2867 | |
2868 if not self.GetEventHandler().ProcessEvent(eventOut): | |
2869 return | |
2870 | |
2871 event.Skip() | |
2872 | |
2873 | |
2874 def OnMouseLeftUp(self, event): | |
2875 """ Handles The wx.EVT_LEFT_UP Event For TabCtrl. """ | |
2876 | |
2877 if not self._enabledragging: | |
2878 event.Skip() | |
2879 return | |
2880 | |
2881 if not self._isdragging: | |
2882 self.SetCursor(wx.STANDARD_CURSOR) | |
2883 event.Skip() | |
2884 return | |
2885 | |
2886 id = self.HitTest(wx.Point(event.GetX(), event.GetY())) | |
2887 | |
2888 if id >= 0 and id != self._tabID: | |
2889 | |
2890 self._isdragging = False | |
2891 self._olddragpos = -1 | |
2892 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_DND, self.GetId()) | |
2893 eventOut.SetOldPosition(self._tabID) | |
2894 eventOut.SetNewPosition(id) | |
2895 eventOut.SetEventObject(self) | |
2896 | |
2897 if self.GetEventHandler().ProcessEvent(eventOut): | |
2898 self._tabID = -1 | |
2899 self._olddragpos = -1 | |
2900 self.SetCursor(wx.STANDARD_CURSOR) | |
2901 self.Refresh() | |
2902 return | |
2903 | |
2904 self._parent.Freeze() | |
2905 | |
2906 try: | |
2907 text = self.GetPageText(self._tabID) | |
2908 image = self.GetPageImage(self._tabID) | |
2909 font1 = self.GetPageTextFont(self._tabID) | |
2910 font2 = self.GetPageTextSecondaryFont(self._tabID) | |
2911 fontcolour = self.GetPageTextColour(self._tabID) | |
2912 pagecolour = self.GetPageColour(self._tabID) | |
2913 enabled = self.IsPageEnabled(self._tabID) | |
2914 tooltip, ontime, winsize = self.GetPageToolTip(self._tabID) | |
2915 menu = self.GetPagePopupMenu(self._tabID) | |
2916 firstcol = self.GetPageFirstGradientColour(self._tabID) | |
2917 secondcol = self.GetPageSecondGradientColour(self._tabID) | |
2918 ishidden = self._pages[self._tabID]._ishidden | |
2919 except: | |
2920 self._parent.Thaw() | |
2921 self._tabID = -1 | |
2922 self.SetCursor(wx.STANDARD_CURSOR) | |
2923 return | |
2924 | |
2925 isanimated = 0 | |
2926 if self._timers[self._tabID].IsRunning(): | |
2927 isanimated = 1 | |
2928 timer = self._timers[self._tabID].GetInterval() | |
2929 | |
2930 self.StopAnimation(self._tabID) | |
2931 animatedimages = self.GetAnimationImages(self._tabID) | |
2932 | |
2933 pagerange = range(self.GetPageCount()) | |
2934 | |
2935 newrange = pagerange[:] | |
2936 newrange.remove(self._tabID) | |
2937 newrange.insert(id, self._tabID) | |
2938 | |
2939 newpages = [] | |
2940 counter = self.GetPageCount() - 1 | |
2941 | |
2942 for ii in xrange(self.GetPageCount()): | |
2943 newpages.append(self._parent.GetPage(ii)) | |
2944 self._parent.bsizer.Detach(counter-ii) | |
2945 | |
2946 cc = 0 | |
2947 | |
2948 self._parent._notebookpages = [] | |
2949 | |
2950 for jj in newrange: | |
2951 self._parent.bsizer.Add(newpages[jj], 1, wx.EXPAND | wx.ALL, 2) | |
2952 self._parent.bsizer.Show(cc, False) | |
2953 self._parent._notebookpages.append(newpages[jj]) | |
2954 cc = cc + 1 | |
2955 | |
2956 self.DeletePage(self._tabID) | |
2957 | |
2958 if enabled: | |
2959 if id == self.GetPageCount(): | |
2960 self.AddPage(text, True, image) | |
2961 else: | |
2962 self.InsertPage(id, text, True, image) | |
2963 else: | |
2964 if id == self.GetPageCount(): | |
2965 self.AddPage(text, False, image) | |
2966 else: | |
2967 self.InsertPage(id, text, False, image) | |
2968 | |
2969 self.SetPageImage(id, image) | |
2970 self.SetPageText(id, text) | |
2971 self.SetPageTextFont(id, font1) | |
2972 self.SetPageTextSecondaryFont(id, font2) | |
2973 self.SetPageTextColour(id, fontcolour) | |
2974 self.SetPageColour(id, pagecolour) | |
2975 self.EnablePage(id, enabled) | |
2976 self.SetPageToolTip(id, tooltip, ontime, winsize) | |
2977 self.SetPagePopupMenu(id, menu) | |
2978 self.SetPageFirstGradientColour(id, firstcol) | |
2979 self.SetPageSecondGradientColour(id, secondcol) | |
2980 self._pages[id]._ishidden = ishidden | |
2981 | |
2982 if isanimated and len(animatedimages) > 1: | |
2983 self.SetAnimationImages(id, animatedimages) | |
2984 self.StartAnimation(id, timer) | |
2985 | |
2986 if enabled: | |
2987 self._parent.bsizer.Show(id, True) | |
2988 else: | |
2989 sel = self.GetSelection() | |
2990 | |
2991 if sel == -1: | |
2992 sel = 0 | |
2993 self._parent.bsizer.Show(id, False) | |
2994 self._parent.SetSelection(sel) | |
2995 self._parent.bsizer.Show(sel, True) | |
2996 | |
2997 self._parent.bsizer.Layout() | |
2998 | |
2999 self._parent.Thaw() | |
3000 | |
3001 self._isdragging = False | |
3002 self._olddragpos = -1 | |
3003 self._fromdnd = True | |
3004 self.Refresh() | |
3005 self._tabID = -1 | |
3006 self.SetCursor(wx.STANDARD_CURSOR) | |
3007 | |
3008 event.Skip() | |
3009 | |
3010 | |
3011 def OnSize(self, event=None): | |
3012 """ Handles The wx.EVT_SIZE Event For TabCtrl. """ | |
3013 | |
3014 if self._sizeToggleButton: | |
3015 width = self.GetSize()[0] | |
3016 height = self._CalcSizeToggleBestSize()[1] | |
3017 self._sizeToggleButton.SetSize(wx.Size(width, height)) | |
3018 self.Refresh() | |
3019 | |
3020 if event is not None: | |
3021 event.Skip() | |
3022 | |
3023 | |
3024 def OnMouseRightUp(self, event): | |
3025 """ Handles The wx.EVT_RIGHT_UP Event For TabCtrl. """ | |
3026 | |
3027 pt = event.GetPosition() | |
3028 id = self.HitTest(pt) | |
3029 | |
3030 self._selectedtabs = [] | |
3031 | |
3032 if id >= 0: | |
3033 if self.IsPageEnabled(id): | |
3034 menu = self.GetPagePopupMenu(id) | |
3035 if menu: | |
3036 self.PopupMenu(menu) | |
3037 | |
3038 event.Skip() | |
3039 | |
3040 | |
3041 def OnMouseRightDown(self, event): | |
3042 """ Handles The wx.EVT_RIGHT_DOWN Event For TabCtrl. """ | |
3043 | |
3044 pos = event.GetPosition() | |
3045 page = self.HitTest(pos) | |
3046 | |
3047 self._selectedtabs = [] | |
3048 | |
3049 if page == wx.NOT_FOUND: | |
3050 return | |
3051 | |
3052 if not self.IsPageEnabled(page): | |
3053 return | |
3054 | |
3055 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_RIGHT, self.GetId()) | |
3056 eventOut.SetOldSelection(self._selection) | |
3057 eventOut.SetSelection(page) | |
3058 eventOut.SetEventObject(self) | |
3059 | |
3060 if not self.GetEventHandler().ProcessEvent(eventOut): | |
3061 return | |
3062 | |
3063 event.Skip() | |
3064 | |
3065 | |
3066 def OnMouseMiddleDown(self, event): | |
3067 """ Handles The wx.EVT_MIDDLE_DOWN Event For TabCtrl. """ | |
3068 | |
3069 pos = event.GetPosition() | |
3070 page = self.HitTest(pos) | |
3071 | |
3072 self._selectedtabs = [] | |
3073 | |
3074 if page == wx.NOT_FOUND: | |
3075 return | |
3076 | |
3077 if not self.IsPageEnabled(page): | |
3078 return | |
3079 | |
3080 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_MIDDLE, self.GetId()) | |
3081 eventOut.SetOldSelection(self._selection) | |
3082 eventOut.SetSelection(page) | |
3083 eventOut.SetEventObject(self) | |
3084 | |
3085 if not self.GetEventHandler().ProcessEvent(eventOut): | |
3086 return | |
3087 | |
3088 event.Skip() | |
3089 | |
3090 | |
3091 def SetSelectionColour(self, colour=None): | |
3092 """ Sets The Tab Selection Colour (Thin Line Above The Selected Tab). """ | |
3093 | |
3094 if colour is None: | |
3095 colour = wx.Colour(255, 180, 0) | |
3096 | |
3097 self._selectioncolour = colour | |
3098 | |
3099 | |
3100 def SetContourLineColour(self, colour=None): | |
3101 """ Sets The Contour Line Colour (Controur Line Around Tabs). """ | |
3102 | |
3103 if colour is None: | |
3104 if not self._tabstyle._normal or self._usegradients: | |
3105 colour = wx.Colour(145, 167, 180) | |
3106 else: | |
3107 colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW) | |
3108 | |
3109 if not self._tabstyle._normal or self._usegradients: | |
3110 self._highlightpen = wx.Pen(colour) | |
3111 self._highlightpen.SetCap(wx.CAP_BUTT) | |
3112 else: | |
3113 self._highlightpen2 = wx.Pen(colour) | |
3114 self._highlightpen2.SetCap(wx.CAP_BUTT) | |
3115 | |
3116 self.Refresh() | |
3117 | |
3118 | |
3119 def ApplyTabTheme(self, theme=None): | |
3120 """ Applies A Particular Theme To Be Drawn On Tabs. """ | |
3121 | |
3122 if theme is None: | |
3123 theme = ThemeStyle() | |
3124 | |
3125 self._tabstyle = theme | |
3126 if self._style & NC_EXPANDABLE: | |
3127 self._InitExpandableTabStyles(self._style, self._expanded, theme) | |
3128 self.Refresh() | |
3129 | |
3130 def DrawMacTheme(self, dc, tabrect, theme): | |
3131 """ Draws The Mac Theme On Tabs, If It Is Enabled. """ | |
3132 | |
3133 if theme == 1: | |
3134 col1, col2 = NC_MAC_LIGHT | |
3135 else: | |
3136 col1, col2 = NC_MAC_DARK | |
3137 | |
3138 colour1 = wx.Colour(col1, col1, col1) | |
3139 colour2 = wx.Colour(col2, col2, col2) | |
3140 | |
3141 x, y, w, h = tabrect | |
3142 endrange = self._style & NC_ROTATE and w or h | |
3143 | |
3144 index = 0 | |
3145 | |
3146 for ii in xrange(0, endrange, 2): | |
3147 if index%2 == 0: | |
3148 colour = colour1 | |
3149 else: | |
3150 colour = colour2 | |
3151 | |
3152 dc.SetBrush(wx.Brush(colour)) | |
3153 dc.SetPen(wx.Pen(colour)) | |
3154 if self._style & NC_ROTATE: | |
3155 if ii > 3: | |
3156 dc.DrawRectangle(x+ii, y, 2, w) | |
3157 else: | |
3158 dc.DrawRoundedRectangle(x+ii, y, 3, 3) | |
3159 else: | |
3160 if ii > 3: | |
3161 dc.DrawRectangle(x, y+ii, w, 2) | |
3162 else: | |
3163 dc.DrawRoundedRectangle(x, y+ii, w, 3, 3) | |
3164 | |
3165 index = index + 1 | |
3166 | |
3167 self._lastcolour = colour | |
3168 | |
3169 | |
3170 def DrawKDETheme(self, dc, rect): | |
3171 """ Draws Unix-Style KDE Theme On Tabs. """ | |
3172 | |
3173 x, y, w, h = rect | |
3174 | |
3175 if self._style & NC_ROTATE and self._style & NC_RIGHT: | |
3176 bandrange = xrange(13, -1, -1) | |
3177 self._lastcolour = kdetheme[13] | |
3178 brush = wx.Brush(kdetheme[0], wx.SOLID) | |
3179 else: | |
3180 bandrange = xrange(14) | |
3181 self._lastcolour = kdetheme[0] | |
3182 brush = wx.Brush(kdetheme[13], wx.SOLID) | |
3183 | |
3184 dc.SetBackground(brush) | |
3185 for band in bandrange: | |
3186 pen = wx.Pen(kdetheme[band]) | |
3187 dc.SetPen(pen) | |
3188 if self._style & NC_ROTATE: | |
3189 if self._style & NC_RIGHT: | |
3190 dc.DrawLine(x+1+band, y+1, x+1+band, y+h-1) | |
3191 dc.DrawLine(x+w-(1+band), y+1, x+w-(1+band), y+h-2) | |
3192 else: | |
3193 dc.DrawLine(x+1+band, y+1, x+1+band, y+h-1) | |
3194 dc.DrawLine(x+w-(2+band), y+1, x+w-(2+band), y+h-2) | |
3195 else: | |
3196 dc.DrawLine(x+1, y+band, x+w-1, y+band) | |
3197 dc.DrawLine(x+1, y+h-1-band, x+w-2, y+h-1-band) | |
3198 | |
3199 | |
3200 def DrawSilverTheme(self, dc, rect, selected): | |
3201 """ Draws Windows XP Silver-Like Theme. """ | |
3202 | |
3203 x, y, w, h = rect | |
3204 | |
3205 if selected: | |
3206 r1 = silvertheme1[0].Red() | |
3207 g1 = silvertheme1[0].Green() | |
3208 b1 = silvertheme1[0].Blue() | |
3209 r2 = silvertheme1[1].Red() | |
3210 g2 = silvertheme1[1].Green() | |
3211 b2 = silvertheme1[1].Blue() | |
3212 else: | |
3213 r1 = silvertheme2[0].Red() | |
3214 g1 = silvertheme2[0].Green() | |
3215 b1 = silvertheme2[0].Blue() | |
3216 r2 = silvertheme2[1].Red() | |
3217 g2 = silvertheme2[1].Green() | |
3218 b2 = silvertheme2[1].Blue() | |
3219 rend = silvertheme2[2].Red() | |
3220 gend = silvertheme2[2].Green() | |
3221 bend = silvertheme2[2].Blue() | |
3222 | |
3223 if self._style & NC_ROTATE: | |
3224 flrect = float(w-2) | |
3225 else: | |
3226 flrect = float(h-2) | |
3227 | |
3228 rstep = float((r2 - r1)) / flrect | |
3229 gstep = float((g2 - g1)) / flrect | |
3230 bstep = float((b2 - b1)) / flrect | |
3231 | |
3232 rf, gf, bf = 0, 0, 0 | |
3233 | |
3234 counter = 0 | |
3235 | |
3236 if self._style & NC_ROTATE: | |
3237 if self._style & NC_RIGHT: | |
3238 bandrange = xrange(x+w-2, x, -1) | |
3239 else: | |
3240 bandrange = xrange(x+1, x+w-1) | |
3241 else: | |
3242 bandrange = xrange(y+1, y+h) | |
3243 | |
3244 for band in bandrange: | |
3245 currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) | |
3246 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
3247 dc.SetPen(wx.Pen(currCol)) | |
3248 if self._style & NC_ROTATE: | |
3249 if counter == 0: | |
3250 ypos = y + 2 | |
3251 yend = h - 4 | |
3252 elif counter == 1: | |
3253 ypos = y + 1 | |
3254 yend = h - 2 | |
3255 else: | |
3256 ypos = y + 1 | |
3257 yend = h - 2 | |
3258 | |
3259 dc.DrawRectangle(band, ypos, 1, yend) | |
3260 | |
3261 else: | |
3262 if counter == 0: | |
3263 xpos = x + 2 | |
3264 xend = w - 4 | |
3265 elif counter == 1: | |
3266 xpos = x + 1 | |
3267 xend = w - 2 | |
3268 else: | |
3269 xpos = x + 1 | |
3270 xend = w - 2 | |
3271 | |
3272 dc.DrawRectangle(xpos, band, xend, 1) | |
3273 | |
3274 counter = counter + 1 | |
3275 rf = rf + rstep | |
3276 gf = gf + gstep | |
3277 bf = bf + bstep | |
3278 self._lastcolour = currCol | |
3279 | |
3280 if not selected and self._style & NC_TOP: | |
3281 dc.SetBrush(wx.Brush((rend, gend, bend))) | |
3282 dc.SetPen(wx.Pen((rend, gend, bend))) | |
3283 if self._style & NC_ROTATE: | |
3284 if self._style & NC_LEFT: | |
3285 xpos = x + w - 4 | |
3286 else: | |
3287 xpos = x | |
3288 | |
3289 dc.DrawRectangle(xpos, ypos, 3, yend) | |
3290 else: | |
3291 dc.DrawRectangle(xpos, y+h-3, xend, 3) | |
3292 self._lastcolour = wx.Colour(rend, gend, bend) | |
3293 | |
3294 | |
3295 def DrawAquaTheme(self, dc, rect, style, selected): | |
3296 """ Draws Mac-Style Aqua Theme On Tabs. """ | |
3297 | |
3298 x, y, w, h = rect | |
3299 | |
3300 if selected: | |
3301 if style == 1: # Dark Aqua | |
3302 r1 = topaqua1[0].Red() | |
3303 g1 = topaqua1[0].Green() | |
3304 b1 = topaqua1[0].Blue() | |
3305 | |
3306 r2 = topaqua1[1].Red() | |
3307 g2 = topaqua1[1].Green() | |
3308 b2 = topaqua1[1].Blue() | |
3309 else: | |
3310 r1 = topaqua2[0].Red() | |
3311 g1 = topaqua2[0].Green() | |
3312 b1 = topaqua2[0].Blue() | |
3313 | |
3314 r2 = topaqua2[1].Red() | |
3315 g2 = topaqua2[1].Green() | |
3316 b2 = topaqua2[1].Blue() | |
3317 | |
3318 else: | |
3319 r1 = distaqua[0].Red() | |
3320 g1 = distaqua[0].Green() | |
3321 b1 = distaqua[0].Blue() | |
3322 | |
3323 r2 = distaqua[1].Red() | |
3324 g2 = distaqua[1].Green() | |
3325 b2 = distaqua[1].Blue() | |
3326 | |
3327 flrect = float((h-2)/2) | |
3328 | |
3329 rstep = float((r2 - r1)) / flrect | |
3330 gstep = float((g2 - g1)) / flrect | |
3331 bstep = float((b2 - b1)) / flrect | |
3332 | |
3333 rf, gf, bf = 0, 0, 0 | |
3334 | |
3335 counter = 0 | |
3336 dc.SetPen(wx.TRANSPARENT_PEN) | |
3337 | |
3338 if self._style & NC_ROTATE: | |
3339 startrange, endrange = (x, w) | |
3340 else: | |
3341 startrange, endrange = (y, h) | |
3342 if self._style & NC_ROTATE and self._style & NC_RIGHT: | |
3343 bandrange = xrange(startrange+endrange, startrange+endrange/2, -1) | |
3344 else: | |
3345 bandrange = xrange(startrange+1, startrange+endrange/2) | |
3346 | |
3347 for band in bandrange: | |
3348 currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) | |
3349 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
3350 if self._style & NC_ROTATE: | |
3351 if counter == 0: | |
3352 ypos = y + 2 | |
3353 yend = h - 4 | |
3354 elif counter == 1: | |
3355 ypos = y + 1 | |
3356 yend = h - 2 | |
3357 else: | |
3358 ypos = y + 1 | |
3359 yend = h - 2 | |
3360 | |
3361 dc.DrawRectangle(band, ypos, 1, yend) | |
3362 else: | |
3363 if counter == 0: | |
3364 xpos = x + 2 | |
3365 xend = w - 4 | |
3366 elif counter == 1: | |
3367 xpos = x + 1 | |
3368 xend = w - 2 | |
3369 else: | |
3370 xpos = x + 1 | |
3371 xend = w - 2 | |
3372 | |
3373 dc.DrawRectangle(xpos, band, xend, 1) | |
3374 | |
3375 counter = counter + 1 | |
3376 | |
3377 rf = rf + rstep | |
3378 gf = gf + gstep | |
3379 bf = bf + bstep | |
3380 | |
3381 if selected: | |
3382 if style == 1: # Dark Aqua | |
3383 r1 = botaqua1[0].Red() | |
3384 g1 = botaqua1[0].Green() | |
3385 b1 = botaqua1[0].Blue() | |
3386 | |
3387 r2 = botaqua1[1].Red() | |
3388 g2 = botaqua1[1].Green() | |
3389 b2 = botaqua1[1].Blue() | |
3390 else: | |
3391 r1 = botaqua2[0].Red() | |
3392 g1 = botaqua2[0].Green() | |
3393 b1 = botaqua2[0].Blue() | |
3394 | |
3395 r2 = botaqua2[1].Red() | |
3396 g2 = botaqua2[1].Green() | |
3397 b2 = botaqua2[1].Blue() | |
3398 else: | |
3399 r1 = disbaqua[0].Red() | |
3400 g1 = disbaqua[0].Green() | |
3401 b1 = disbaqua[0].Blue() | |
3402 | |
3403 r2 = disbaqua[1].Red() | |
3404 g2 = disbaqua[1].Green() | |
3405 b2 = disbaqua[1].Blue() | |
3406 | |
3407 flrect = float((h-2)/2) | |
3408 | |
3409 rstep = float((r2 - r1)) / flrect | |
3410 gstep = float((g2 - g1)) / flrect | |
3411 bstep = float((b2 - b1)) / flrect | |
3412 | |
3413 rf, gf, bf = 0, 0, 0 | |
3414 | |
3415 counter = 0 | |
3416 | |
3417 if self._style & NC_ROTATE and self._style & NC_RIGHT: | |
3418 bandrange = xrange(startrange+endrange/2, startrange+1, -1) | |
3419 else: | |
3420 bandrange = xrange(startrange+endrange/2, startrange+endrange) | |
3421 for band in bandrange: | |
3422 currCol = (int(round(r1 + rf)), int(round(g1 + gf)), int(round(b1 + bf))) | |
3423 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
3424 if self._style & NC_ROTATE: | |
3425 dc.DrawRectangle(band, y + 1, 1, h-2) | |
3426 else: | |
3427 dc.DrawRectangle(x+1, band, w-2, 1) | |
3428 rf = rf + rstep | |
3429 gf = gf + gstep | |
3430 bf = bf + bstep | |
3431 | |
3432 self._lastcolour = currCol | |
3433 | |
3434 | |
3435 def DrawMetalTheme(self, dc, rect): | |
3436 """ Draws Mac-Style Metal Gradient On Tabs. """ | |
3437 | |
3438 x, y, w, h = rect | |
3439 | |
3440 dc.SetPen(wx.TRANSPARENT_PEN) | |
3441 counter = 0 | |
3442 | |
3443 if self._style & NC_ROTATE: | |
3444 bandrange = xrange(x+1, x+w) | |
3445 else: | |
3446 bandrange = xrange(y+1, h+y) | |
3447 for band in bandrange: | |
3448 if self._style & NC_ROTATE: | |
3449 intens = (230 + 80 * (x-band)/w) | |
3450 else: | |
3451 intens = (230 + 80 * (y-band)/h) | |
3452 | |
3453 colour = wx.Colour(intens, intens, intens) | |
3454 dc.SetBrush(wx.Brush(colour)) | |
3455 | |
3456 if self._style & NC_ROTATE: | |
3457 if counter == 0: | |
3458 ypos = y + 2 | |
3459 yend = h - 4 | |
3460 elif counter == 1: | |
3461 ypos = y + 1 | |
3462 yend = h - 2 | |
3463 else: | |
3464 ypos = y + 1 | |
3465 yend = h - 2 | |
3466 if self._style & NC_RIGHT: | |
3467 dc.DrawRectangle(x+w-band, ypos, 1, yend) | |
3468 else: | |
3469 dc.DrawRectangle(x+band, ypos, 1, yend) | |
3470 | |
3471 else: | |
3472 if counter == 0: | |
3473 xpos = x + 2 | |
3474 xend = w - 4 | |
3475 elif counter == 1: | |
3476 xpos = x + 1 | |
3477 xend = w - 2 | |
3478 else: | |
3479 xpos = x + 1 | |
3480 xend = w - 2 | |
3481 dc.DrawRectangle(xpos, band, xend, 1) | |
3482 | |
3483 counter = counter + 1 | |
3484 | |
3485 self._lastcolour = colour | |
3486 | |
3487 | |
3488 def DrawVerticalGradient(self, dc, rect, index): | |
3489 """ Gradient Fill From Colour 1 To Colour 2 From Top To Bottom. """ | |
3490 | |
3491 dc.SetPen(wx.TRANSPARENT_PEN) | |
3492 | |
3493 # calculate gradient coefficients | |
3494 col2 = self._tabstyle.GetSecondGradientColour(index == self.GetSelection()) | |
3495 col1 = self._tabstyle.GetFirstGradientColour(index == self.GetSelection()) | |
3496 | |
3497 r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) | |
3498 r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) | |
3499 | |
3500 flrect = float(rect.height) | |
3501 | |
3502 rstep = float((r2 - r1)) / flrect | |
3503 gstep = float((g2 - g1)) / flrect | |
3504 bstep = float((b2 - b1)) / flrect | |
3505 | |
3506 rf, gf, bf = 0, 0, 0 | |
3507 | |
3508 counter = 0 | |
3509 | |
3510 bandrange = xrange(rect.y+1, rect.y + rect.height-1) | |
3511 lenc = len(bandrange) | |
3512 | |
3513 for y in bandrange: | |
3514 currCol = (r1 + rf, g1 + gf, b1 + bf) | |
3515 | |
3516 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
3517 | |
3518 # adjust along x-axis to preserve the curved tab edge | |
3519 def GetXAdjust(counter): | |
3520 if counter >=2 or counter <=lenc-2: | |
3521 return 1 | |
3522 if self._style & NC_LEFT or self._style & NC_RIGHT and not self._style & NC_ROTATE: | |
3523 if counter == 0 and self._style & NC_RIGHT or \ | |
3524 counter == lenc - 1 and self._style & NC_LEFT: | |
3525 return 3 | |
3526 elif counter == 1 and self._style & NC_RIGHT or \ | |
3527 counter == lend - 2 and self._style & NC_LEFT: | |
3528 return 2 | |
3529 else: | |
3530 return 1 | |
3531 else: | |
3532 if counter == lenc - 2: | |
3533 return 2 | |
3534 elif counter == lenc - 1: | |
3535 return 3 | |
3536 else: | |
3537 return 1 | |
3538 | |
3539 xadjust = GetXAdjust(counter) | |
3540 xpos = rect.x + xadjust | |
3541 xend = rect.width - xadjust | |
3542 | |
3543 | |
3544 counter = counter + 1 | |
3545 | |
3546 dc.DrawRectangle(xpos, y, xend, 1) | |
3547 rf = rf + rstep | |
3548 gf = gf + gstep | |
3549 bf = bf + bstep | |
3550 | |
3551 self._lastcolour = currCol | |
3552 | |
3553 | |
3554 def DrawHorizontalGradient(self, dc, rect, index): | |
3555 """ Gradient Fill From Colour 1 To Colour 2 From Left To Right. """ | |
3556 | |
3557 dc.SetPen(wx.TRANSPARENT_PEN) | |
3558 | |
3559 # calculate gradient coefficients | |
3560 col2 = self._tabstyle.GetSecondGradientColour(index == self.GetSelection()) | |
3561 col1 = self._tabstyle.GetFirstGradientColour(index == self.GetSelection()) | |
3562 | |
3563 r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) | |
3564 r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) | |
3565 | |
3566 flrect = float(rect.width) | |
3567 | |
3568 rstep = float((r2 - r1)) / flrect | |
3569 gstep = float((g2 - g1)) / flrect | |
3570 bstep = float((b2 - b1)) / flrect | |
3571 | |
3572 rf, gf, bf = 0, 0, 0 | |
3573 counter = 0 | |
3574 | |
3575 bandrange = xrange(rect.x + 1, rect.x + rect.width - 1) | |
3576 lenc = len(bandrange) | |
3577 | |
3578 for x in bandrange: | |
3579 currCol = (r1 + rf, g1 + gf, b1 + bf) | |
3580 | |
3581 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
3582 # adjust along y-axis to preserve the curved tab edge | |
3583 def GetYAdjust(counter): | |
3584 if counter >=2 or counter <=lenc-2: | |
3585 return 1 | |
3586 if self._style & NC_TOP or self._style & NC_BOTTOM or \ | |
3587 (self._style & NC_LEFT and self._style & NC_ROTATE): | |
3588 if counter == 0 or counter == lenc - 1 and not self._style & NC_LEFT: | |
3589 return 3 | |
3590 elif counter == 1 or counter == lenc - 2 and not self._style & NC_LEFT: | |
3591 return 2 | |
3592 else: | |
3593 return 1 | |
3594 else: | |
3595 if counter == lenc - 2: | |
3596 return 2 | |
3597 elif counter == lenc - 1: | |
3598 return 3 | |
3599 else: | |
3600 return 1 | |
3601 | |
3602 yadjust = GetYAdjust(counter) | |
3603 ypos = rect.y + yadjust | |
3604 yend = rect.height - yadjust | |
3605 | |
3606 counter = counter + 1 | |
3607 | |
3608 dc.DrawRectangle(x, ypos, 1, yend) | |
3609 rf = rf + rstep | |
3610 gf = gf + gstep | |
3611 bf = bf + bstep | |
3612 | |
3613 self._lastcolour = currCol | |
3614 | |
3615 | |
3616 def GetAllTextExtents(self, dc): | |
3617 """ Returns All Tabs Text Extents. Used Internally. """ | |
3618 | |
3619 self._mintabwidths = [] | |
3620 self._maxtabwidths = [] | |
3621 self._mintabheights = [] | |
3622 self._maxtabheights = [] | |
3623 self._incrtext = [] | |
3624 minheight = 0 | |
3625 | |
3626 for ii in xrange(self.GetPageCount()): | |
3627 | |
3628 txts = self.GetPageText(ii) | |
3629 font1 = self.GetPageTextFont(ii) | |
3630 dc.SetFont(font1) | |
3631 w1, h1 = dc.GetTextExtent(txts) | |
3632 minheight = max(minheight, h1) | |
3633 self._mintabwidths.append(w1) | |
3634 self._mintabheights.append(h1) | |
3635 font2 = self.GetPageTextSecondaryFont(ii) | |
3636 dc.SetFont(font2) | |
3637 w2, h2 = dc.GetTextExtent(txts) | |
3638 minheight = max(minheight, h2) | |
3639 | |
3640 self._maxtabwidths.append(w2) | |
3641 self._maxtabheights.append(h2) | |
3642 self._incrtext.append(abs(self._mintabwidths[ii] - self._maxtabwidths[ii])) | |
3643 | |
3644 mh1 = max(self._mintabheights) | |
3645 font1 = self.GetPageTextFont(self._mintabheights.index(mh1)) | |
3646 mh2 = max(self._maxtabheights) | |
3647 font2 = self.GetPageTextSecondaryFont(self._maxtabheights.index(mh2)) | |
3648 | |
3649 mhend = max(mh1, mh2) | |
3650 | |
3651 if mhend == mh1: | |
3652 maxfont = font1 | |
3653 else: | |
3654 maxfont = font2 | |
3655 | |
3656 minheight = self.GetSize()[1] | |
3657 | |
3658 return minheight, maxfont | |
3659 | |
3660 | |
3661 def DrawBuiltinStyle(self, dc, style, rect, index, selection): | |
3662 """ Methods That Holds All The Theme Styles. """ | |
3663 | |
3664 if style._aqua: | |
3665 if self._selstyle._normal: | |
3666 self.DrawAquaTheme(dc, rect, style._aqua, index==selection) | |
3667 else: | |
3668 oldselstyle = self._selstyle[:] | |
3669 self._selstyle._normal = True | |
3670 self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) | |
3671 self._selstyle = oldselstyle | |
3672 | |
3673 elif style._metal: | |
3674 if self._selstyle._normal: | |
3675 self.DrawMetalTheme(dc, rect) | |
3676 else: | |
3677 oldselstyle = self._selstyle[:] | |
3678 self._selstyle._normal = True | |
3679 self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) | |
3680 self._selstyle = oldselstyle | |
3681 | |
3682 elif style._kdetheme: | |
3683 if self._selstyle._normal: | |
3684 self.DrawKDETheme(dc, rect) | |
3685 else: | |
3686 oldselstyle = self._selstyle[:] | |
3687 self._selstyle._normal = True | |
3688 self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) | |
3689 self._selstyle = oldselstyle | |
3690 | |
3691 elif style._macstyle: | |
3692 if self._selstyle._normal: | |
3693 self.DrawMacTheme(dc, rect, style._macstyle) | |
3694 else: | |
3695 oldselstyle = self._selstyle[:] | |
3696 self._selstyle._normal = True | |
3697 self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) | |
3698 self._selstyle = oldselstyle | |
3699 | |
3700 elif style._gradient: | |
3701 if self._selstyle._normal: | |
3702 if style._gradient & ThemeStyle.GRADIENT_VERTICAL: | |
3703 self.DrawVerticalGradient(dc, rect, index) | |
3704 else: | |
3705 self.DrawHorizontalGradient(dc, rect, index) | |
3706 else: | |
3707 oldselstyle = self._selstyle[:] | |
3708 self._selstyle._normal = True | |
3709 self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) | |
3710 self._selstyle = oldselstyle | |
3711 | |
3712 elif style._silver: | |
3713 if self._selstyle._normal: | |
3714 self.DrawSilverTheme(dc, rect, index==selection) | |
3715 else: | |
3716 oldselstyle = self._selstyle[:] | |
3717 self._selstyle._normal = True | |
3718 self.DrawBuiltinStyle(dc, self._selstyle, rect, index, selection) | |
3719 self._selstyle = oldselstyle | |
3720 | |
3721 | |
3722 def DrawGradientOnTab(self, dc, rect, col1, col2): | |
3723 """ Draw A Gradient Coloured Tab. """ | |
3724 | |
3725 dc.SetPen(wx.TRANSPARENT_PEN) | |
3726 | |
3727 r1, g1, b1 = int(col1.Red()), int(col1.Green()), int(col1.Blue()) | |
3728 r2, g2, b2 = int(col2.Red()), int(col2.Green()), int(col2.Blue()) | |
3729 | |
3730 flrect = float(rect.height) | |
3731 | |
3732 rstep = float((r2 - r1)) / flrect | |
3733 gstep = float((g2 - g1)) / flrect | |
3734 bstep = float((b2 - b1)) / flrect | |
3735 | |
3736 rf, gf, bf = 0, 0, 0 | |
3737 | |
3738 counter = 0 | |
3739 | |
3740 for y in xrange(rect.y+1, rect.y + rect.height): | |
3741 currCol = (r1 + rf, g1 + gf, b1 + bf) | |
3742 | |
3743 dc.SetBrush(wx.Brush(currCol, wx.SOLID)) | |
3744 if counter == 0: | |
3745 xpos = rect.x + 2 | |
3746 xend = rect.width - 4 | |
3747 elif counter == 1: | |
3748 xpos = rect.x + 1 | |
3749 xend = rect.width - 2 | |
3750 else: | |
3751 xpos = rect.x | |
3752 xend = rect.width | |
3753 | |
3754 counter = counter + 1 | |
3755 | |
3756 dc.DrawRectangle(xpos, y, xend, 1) | |
3757 rf = rf + rstep | |
3758 gf = gf + gstep | |
3759 bf = bf + bstep | |
3760 | |
3761 self._lastcolour = currCol | |
3762 | |
3763 def _CalcBestWidth(self, dc): | |
3764 return max(self._CalcMaxTabWidth(dc), self._CalcSizeToggleBestSize()[0]) | |
3765 | |
3766 def _CalcMaxTabWidth(self, dc): | |
3767 self._CalcMaxTextHeight(dc) | |
3768 textWidth = max(self._maxtabwidths) | |
3769 tabIndex = self._maxtabwidths.index(textWidth) | |
3770 bmpWidth, bmpHeight = self._CalcTabBitmapSize(tabIndex) | |
3771 tabrect = self._CalcTabRect(tabIndex, 0, 0, textWidth, bmpWidth, bmpHeight) | |
3772 # return the width based on the longest label, plus 3 for | |
3773 # the additional width of the selected tab | |
3774 return tabrect.width + 3 | |
3775 | |
3776 def _CalcMaxTextHeight(self, dc): | |
3777 if self._somethingchanged: | |
3778 minheight, maxfont = self.GetAllTextExtents(dc) | |
3779 self._minheight = minheight | |
3780 self._maxfont = maxfont | |
3781 else: | |
3782 minheight = self._minheight | |
3783 maxfont = self._maxfont | |
3784 | |
3785 dc.SetFont(maxfont) | |
3786 _, height = dc.GetTextExtent("Aq") | |
3787 self._maxtextheight = height | |
3788 | |
3789 def _CalcSizeToggleBestSize(self): | |
3790 if self._sizeToggleButton: | |
3791 return self._sizeToggleButton.GetBestSize() | |
3792 else: | |
3793 return wx.Size(0,0) | |
3794 | |
3795 def _CalcTabBitmapPosition(self, tabIndex, bmpWidth, bmpHeight, tabrect): | |
3796 | |
3797 if self._style & NC_ROTATE: | |
3798 bmpposx = tabrect.x + (tabrect.width - bmpWidth) / 2 | |
3799 yoffset = self._padding.x | |
3800 if self._style & NC_LEFT: | |
3801 bmpposx += 1 | |
3802 bmpposy = tabrect.y + tabrect.height - (yoffset + bmpHeight) | |
3803 else: | |
3804 bmpposy = tabrect.y + yoffset | |
3805 if tabIndex == self.GetSelection(): | |
3806 bmpposx += self._style & NC_LEFT and -1 or 1 | |
3807 else: | |
3808 bmpposx = tabrect.x + self._padding.x | |
3809 bmpposy = tabrect.y + (tabrect.height - bmpHeight) / 2 | |
3810 if tabIndex == self.GetSelection() and self._style & NC_TOP: | |
3811 bmpposy -= 1 | |
3812 | |
3813 return (bmpposx, bmpposy) | |
3814 | |
3815 def _CalcTabBitmapSize(self, tabIndex): | |
3816 result = (0, 0) | |
3817 bmp = self._GetTabBitmap(tabIndex) | |
3818 bmpOk = bmp.Ok() | |
3819 if bmpOk: | |
3820 result = (bmp.GetWidth(), bmp.GetHeight()) | |
3821 return result | |
3822 | |
3823 def _CalcTabBitmapSpace(self, bmpWidth, bmpHeight): | |
3824 space = self._padding.x | |
3825 bmpSpace = self._style & NC_ROTATE and bmpHeight or bmpWidth | |
3826 if bmpSpace: | |
3827 space = space + self._padding.x + bmpSpace | |
3828 return space | |
3829 | |
3830 def _CalcTabRect(self, tabIndex, posx, posy, textWidth, bmpWidth, bmpHeight): | |
3831 | |
3832 xpos = posx | |
3833 if self._style & NC_BOTTOM: | |
3834 ypos = 1 | |
3835 elif self._style & NC_TOP: | |
3836 ypos = self.GetSize().y - self._maxtextheight - self._padding.y*2 | |
3837 else: | |
3838 ypos = posy | |
3839 | |
3840 xsize = textWidth + self._CalcTabBitmapSpace(bmpWidth, bmpHeight) + \ | |
3841 self._padding.x + self._incrtext[tabIndex] + \ | |
3842 self._CalcXWidth() | |
3843 | |
3844 ysize = self._maxtextheight + self._padding.y*2 | |
3845 if self._style & NC_TOP: | |
3846 ysize += 3 | |
3847 | |
3848 if self._style & NC_ROTATE: | |
3849 xsize, ysize = (ysize, xsize) | |
3850 | |
3851 if tabIndex == self.GetSelection(): | |
3852 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
3853 xsize = xsize + self._spacetabs | |
3854 if tabIndex > 0: | |
3855 xpos = xpos - self._spacetabs | |
3856 xsize = xsize + self._spacetabs | |
3857 if self._style & NC_TOP: | |
3858 ypos -= 3 | |
3859 ysize = ysize + 2 | |
3860 else: | |
3861 xsize += 3 | |
3862 | |
3863 if self._style & NC_LEFT: | |
3864 xpos = self.GetSize().width - xsize | |
3865 return wx.Rect(xpos, ypos, xsize, ysize) | |
3866 | |
3867 def _CalcTabTextPosition(self, tabIndex, tabrect, space): | |
3868 xtextpos = tabrect.x + space + self._incrtext[tabIndex]/2 | |
3869 | |
3870 if self._style & NC_BOTTOM: | |
3871 ytextpos = self._padding.y | |
3872 else: | |
3873 ytextpos = tabrect.y + self._padding.y + 1 | |
3874 if tabIndex == self.GetSelection(): | |
3875 if tabIndex == 0 and self._style & NC_TOP or self._style & NC_BOTTOM: | |
3876 xtextpos = xtextpos + self._spacetabs/2.0 + 1 | |
3877 if self._style & NC_BOTTOM: | |
3878 ytextpos += 2 | |
3879 elif self._style & NC_TOP: | |
3880 ytextpos -= 2 | |
3881 | |
3882 if self._style & NC_ROTATE: | |
3883 xoffset = ytextpos - tabrect.y | |
3884 yoffset = xtextpos - tabrect.x | |
3885 if self._style & NC_LEFT: | |
3886 xtextpos, ytextpos = (tabrect.x + xoffset - 1, | |
3887 tabrect.y + tabrect.height - yoffset) | |
3888 else: | |
3889 yoffset += self._CalcXWidth() | |
3890 xtextpos, ytextpos = (tabrect.x + tabrect.width - xoffset, | |
3891 tabrect.y + yoffset) | |
3892 | |
3893 return (xtextpos, ytextpos) | |
3894 | |
3895 def _CalcTabTextWidth(self, dc, tabIndex): | |
3896 if self._style & NC_FIXED_WIDTH: | |
3897 result = max(self._maxtabwidths) | |
3898 else: | |
3899 dc.SetFont(self.GetPageTextFont(tabIndex)) | |
3900 result, _ = dc.GetTextExtent(self.GetPageText(tabIndex)) | |
3901 return result | |
3902 | |
3903 def _CalcXRect(self, tabrect): | |
3904 result = None | |
3905 drawx, dxstyle = self.GetDrawX() | |
3906 if drawx: | |
3907 if dxstyle == 1: | |
3908 mins = min(self._padding.x, self._padding.y) + 1 | |
3909 mins = min(mins, 6) | |
3910 xoffset = tabrect.width-mins-3 | |
3911 yoffset = 2 | |
3912 xsize = ysize = mins+1 | |
3913 else: | |
3914 if self._style & NC_ROTATE: | |
3915 xoffset = (tabrect.width-self._maxtextheight-self._padding.y/2)/2 | |
3916 yoffset = self._padding.x/2 | |
3917 else: | |
3918 xoffset = tabrect.width-self._maxtextheight-self._padding.x | |
3919 yoffset = (tabrect.height-self._maxtextheight-self._padding.y/2)/2 | |
3920 xsize = ysize = self._maxtextheight | |
3921 result = wx.Rect(tabrect.x+xoffset, tabrect.y+yoffset, xsize, ysize) | |
3922 return result | |
3923 | |
3924 def _CalcXWidth(self): | |
3925 drawx, dxstyle = self.GetDrawX() | |
3926 if drawx: | |
3927 if dxstyle == 1: | |
3928 xxspace = self._padding.x/2 | |
3929 else: | |
3930 xxspace = self._padding.x + self._maxtextheight | |
3931 else: | |
3932 xxspace = 0 | |
3933 return xxspace | |
3934 | |
3935 def _ClipAtPaperEdge(self, dc, tabrect, tabIndex): | |
3936 selected = tabIndex == self.GetSelection() | |
3937 if self._style & NC_TOP: | |
3938 cliprect = (tabrect.x, tabrect.y, tabrect.width, | |
3939 selected and tabrect.height - 2 or tabrect.height-3) | |
3940 elif self._style & NC_LEFT: | |
3941 cliprect = (tabrect.x, tabrect.y, tabrect.width - 2, tabrect.height) | |
3942 elif self._style & NC_BOTTOM: | |
3943 cliprect = (tabrect.x, tabrect.y + 2, tabrect.width, tabrect.height - 2) | |
3944 else: | |
3945 cliprect = (tabrect.x + 2, tabrect.y, tabrect.width - 2, tabrect.height) | |
3946 dc.SetClippingRegion(*cliprect) | |
3947 | |
3948 def _CreateSizeToggleButton(self): | |
3949 buttonlabel = self._expanded and "<<" or ">>" | |
3950 self._sizeToggleButton = wx.Button(self, wx.NewId(), | |
3951 pos = wx.Point(0,0,), label = buttonlabel, style=wx.BU_EXACTFIT) | |
3952 font = self._sizeToggleButton.GetFont() | |
3953 if font.GetPointSize() > 6: | |
3954 font.SetPointSize(6) | |
3955 self._sizeToggleButton.SetFont(font) | |
3956 self.Bind(wx.EVT_BUTTON, self._ToggleSize, self._sizeToggleButton) | |
3957 | |
3958 | |
3959 def _DrawBackground(self, dc, paintTools): | |
3960 #background | |
3961 size = self.GetSize() | |
3962 dc.SetBrush(paintTools.BackBrush) | |
3963 | |
3964 if not (self._style & wx.NO_BORDER): | |
3965 # full border | |
3966 dc.SetPen(paintTools.BorderPen) | |
3967 dc.SetPen(paintTools.HighlightPen) | |
3968 dc.DrawRectangle(0, 0, size.x, size.y) | |
3969 | |
3970 else: | |
3971 dc.SetPen(paintTools.BackPen) | |
3972 dc.DrawRectangle(0, 0, size.x, size.y) | |
3973 self._DrawPageEdge(dc, paintTools) | |
3974 | |
3975 def _DrawFocusIndicator(self, dc, paintTools, tabrect): | |
3976 if self.GetUseFocusIndicator(): | |
3977 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
3978 dc.SetPen(paintTools.FocusPen) | |
3979 dc.DrawRoundedRectangle(tabrect.x+self._padding.x/2, tabrect.y+self._padding.y/2, | |
3980 tabrect.width-self._padding.x, | |
3981 tabrect.height-self._padding.y-2, 2) | |
3982 | |
3983 def _DrawPageEdge(self, dc, paintTools): | |
3984 if self._style & NC_TOP: | |
3985 dc.SetPen(paintTools.HighlightPen) | |
3986 dc.DrawLine(0, self.GetSize().y-1, self.GetSize().x, self.GetSize().y-1) | |
3987 else: | |
3988 if not self._tabstyle._normal or self._usegradients: | |
3989 dc.SetPen(paintTools.HighlightPen) | |
3990 else: | |
3991 dc.SetPen(paintTools.BorderPen) | |
3992 if self._style & NC_BOTTOM: | |
3993 dc.DrawLine(0, 1, self.GetSize().x, 1) | |
3994 elif self._style & NC_LEFT: | |
3995 dc.DrawLine(self.GetSize().width - 1, 0, self.GetSize().width - 1, self.GetSize().height) | |
3996 elif self._style & NC_RIGHT: | |
3997 dc.DrawLine(0, 0, 0, self.GetSize().height) | |
3998 | |
3999 def _DrawTab(self, dc, paintTools, tabrect, tabIndex): | |
4000 size = self.GetSize() | |
4001 self._DrawTabGradientOutline(dc, paintTools, tabrect, tabIndex) | |
4002 self._FillTab(dc, paintTools, tabrect, tabIndex) | |
4003 self._DrawTabOutline(dc, paintTools, tabrect, tabIndex) | |
4004 self._DrawTabPageEdge(dc, paintTools, tabrect, tabIndex) | |
4005 self._HighlightTabEdge(dc, paintTools, tabrect) | |
4006 self._ShadowTabEdge(dc, paintTools, tabrect) | |
4007 | |
4008 def _DrawTabBitmap(self, dc, tabIndex, bmpposx, bmpposy): | |
4009 bmpindex = self.GetPageImage(tabIndex) | |
4010 if self.IsPageEnabled(tabIndex): | |
4011 self._imglist.Draw(bmpindex, dc, bmpposx, bmpposy, | |
4012 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
4013 else: | |
4014 self._grayedlist.Draw(bmpindex, dc, bmpposx, bmpposy, | |
4015 wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
4016 | |
4017 def _DrawTabGradientOutline(self, dc, paintTools, tabrect, tabIndex): | |
4018 if not self._tabstyle._normal or self._usegradients: | |
4019 if tabIndex != self.GetSelection() and self._style & NC_TOP: | |
4020 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
4021 dc.SetPen(paintTools.ShadowPen) | |
4022 dc.DrawRoundedRectangle(tabrect.x+1, tabrect.y+1, tabrect.width, tabrect.height-1, 3) | |
4023 | |
4024 def _DrawTabOutline(self, dc, paintTools, tabrect, tabIndex): | |
4025 if not self._tabstyle._normal or self._usegradients: | |
4026 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
4027 dc.SetPen(paintTools.HighlightPen) | |
4028 else: | |
4029 dc.SetBrush(wx.Brush(self.GetPageColour(tabIndex))) | |
4030 if self._style & NC_TOP: | |
4031 dc.SetPen(paintTools.HighlightPen) | |
4032 else: | |
4033 dc.SetPen(paintTools.BorderPen) | |
4034 self._ClipAtPaperEdge(dc, tabrect, tabIndex) | |
4035 dc.DrawRoundedRectangle(tabrect.x, tabrect.y, tabrect.width, tabrect.height, 3) | |
4036 dc.DestroyClippingRegion() | |
4037 | |
4038 def _DrawTabPageEdge(self, dc, paintTools, tabrect, tabIndex): | |
4039 if not self._tabstyle._normal or self._usegradients: | |
4040 edgePen = paintTools.HighlightPen | |
4041 else: | |
4042 if self._style & NC_TOP: | |
4043 edgePen = paintTools.HighlightPen | |
4044 else: | |
4045 edgePen = paintTools.BorderPen | |
4046 | |
4047 if tabIndex == self.GetSelection(): | |
4048 # un-paint the line at the paper edge | |
4049 cancelPen = wx.Pen(self.GetPageColour(tabIndex)) | |
4050 dc.SetPen(cancelPen) | |
4051 if self._style & NC_BOTTOM: | |
4052 dc.DrawLine(tabrect.x+1, tabrect.y, tabrect.x + tabrect.width, tabrect.y) | |
4053 elif self._style & NC_LEFT: | |
4054 dc.DrawLine(tabrect.x + tabrect.width-1, tabrect.y, tabrect.x + tabrect.width-1, tabrect.y + tabrect.height) | |
4055 elif self._style & NC_RIGHT: | |
4056 dc.DrawLine(tabrect.x, tabrect.y, tabrect.x, tabrect.y + tabrect.height) | |
4057 | |
4058 if tabIndex != self.GetSelection(): | |
4059 if self._style & NC_TOP: | |
4060 dc.DrawLine(tabrect.x, self.GetSize().y-1, tabrect.x + tabrect.width, self.GetSize().y-1) | |
4061 | |
4062 # draw sharp corners at the paper edge | |
4063 dc.SetPen(edgePen) | |
4064 if self._style & NC_BOTTOM: | |
4065 dc.DrawLine(tabrect.x, tabrect.y, tabrect.x, tabrect.y + 2) | |
4066 dc.DrawLine((tabrect.x + tabrect.width)-1, tabrect.y, | |
4067 (tabrect.x + tabrect.width)-1, tabrect.y + 2) | |
4068 elif self._style & NC_LEFT: | |
4069 dc.DrawLine(self.GetSize().width - 2, tabrect.y, self.GetSize().width, tabrect.y) | |
4070 dc.DrawLine(self.GetSize().width - 2, tabrect.y + tabrect.height - 1, self.GetSize().width, tabrect.y + tabrect.height - 1) | |
4071 elif self._style & NC_RIGHT: | |
4072 dc.DrawLine(tabrect.x, tabrect.y, tabrect.x + 2, tabrect.y) | |
4073 dc.DrawLine(tabrect.x, tabrect.y + tabrect.height - 1, tabrect.x + 2, tabrect.y + tabrect.height - 1) | |
4074 | |
4075 def _DrawTabText(self, dc, tabIndex, xtextpos, ytextpos): | |
4076 dc.SetFont(self.GetPageTextFont(tabIndex)) | |
4077 dc.SetTextForeground(self._GetTabTextColour(tabIndex)) | |
4078 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
4079 if self._style & NC_ROTATE: | |
4080 angle = (self._style & NC_LEFT) and 90.0 or 270.0 | |
4081 dc.DrawRotatedText(self.GetPageText(tabIndex), xtextpos, ytextpos, angle) | |
4082 else: | |
4083 dc.DrawText(self.GetPageText(tabIndex), xtextpos, ytextpos) | |
4084 | |
4085 def _DrawX(self, dc, tabrect, xrect, textColour): | |
4086 drawx, dxstyle = self.GetDrawX() | |
4087 if drawx: | |
4088 if dxstyle == 1: | |
4089 mins = min(self._padding.x, self._padding.y) + 1 | |
4090 mins = min(mins, 6) | |
4091 dc.SetPen(wx.Pen(textColour, 1)) | |
4092 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
4093 dc.DrawLine(xrect.x, xrect.y, tabrect.x+tabrect.width-2, tabrect.y+3+mins) | |
4094 dc.DrawLine(xrect.x, xrect.y+mins, tabrect.x+tabrect.width-2, tabrect.y+1) | |
4095 dc.DrawRectangle(xrect.x, xrect.y, xrect.width, xrect.height) | |
4096 elif dxstyle == 2: | |
4097 dc.SetPen(wx.Pen(textColour)) | |
4098 dc.SetBrush(wx.Brush(textColour)) | |
4099 dc.DrawRoundedRectangle(xrect.x, xrect.y, xrect.width, xrect.height, 2) | |
4100 dc.SetPen(wx.Pen(self.GetBackgroundColour(), 2)) | |
4101 dc.DrawLine(xrect.x+2, xrect.y+2, xrect.x+xrect.width-3, xrect.y+xrect.height-3) | |
4102 dc.DrawLine(xrect.x+2, xrect.y+xrect.height-3, xrect.x+xrect.width-3, xrect.y+2) | |
4103 else: | |
4104 self._imglist2.Draw(0, dc, xrect.x, xrect.y, wx.IMAGELIST_DRAW_TRANSPARENT, True) | |
4105 | |
4106 def _EnhanceMultiSelectedTab(self, dc, tabIndex, tabrect): | |
4107 dc.SetPen(wx.Pen(self._GetTabTextColour(tabIndex), 1, wx.DOT_DASH)) | |
4108 dc.SetBrush(wx.TRANSPARENT_BRUSH) | |
4109 dc.DrawRoundedRectangle(tabrect.x+self._padding.x/2+1, | |
4110 tabrect.y+self._padding.y/2+1, | |
4111 tabrect.width-self._padding.x-2, | |
4112 tabrect.height-self._padding.y-2-2, 2) | |
4113 | |
4114 def _EnhanceSelectedTab(self, dc, paintTools, tabrect): | |
4115 xselpos = tabrect.x | |
4116 xselsize = tabrect.width | |
4117 yselsize = tabrect.height | |
4118 | |
4119 if self._style & NC_BOTTOM: | |
4120 yselpos = (tabrect.y + tabrect.height) - 2 | |
4121 elif self._style & NC_TOP: | |
4122 yselpos = tabrect.y | |
4123 | |
4124 self._HighlightSelectedTabEdge(dc, paintTools, tabrect) | |
4125 self._ShadowTabEdge(dc, paintTools, tabrect) | |
4126 self._DrawFocusIndicator(dc, paintTools, tabrect) | |
4127 | |
4128 def _FillTab(self, dc, paintTools, tabrect, tabIndex): | |
4129 if self._usegradients: | |
4130 self.DrawGradientOnTab(dc, tabrect, self._pages[tabIndex]._firstcolour, | |
4131 self._pages[tabIndex]._secondcolour) | |
4132 elif not self._tabstyle._normal: | |
4133 self.DrawBuiltinStyle(dc, self._tabstyle, tabrect, tabIndex, | |
4134 self.GetSelection()) | |
4135 | |
4136 def _GetPaintTools(self): | |
4137 back_colour = self.GetBackgroundColour() | |
4138 back_brush = wx.Brush(back_colour) | |
4139 back_pen = wx.Pen(back_colour) | |
4140 | |
4141 border_pen = self._borderpen | |
4142 highlightpen = self._highlightpen | |
4143 if self._tabstyle._normal and not self._usegradients: | |
4144 highlightpen = self._highlightpen2 | |
4145 | |
4146 shadowpen = self._shadowpen | |
4147 upperhighpen = self._upperhigh | |
4148 | |
4149 if self.GetHighlightSelection(): | |
4150 selectionpen = wx.Pen(self._selectioncolour) | |
4151 selectionEdgePen = wx.Pen(self._selectionedgecolour) | |
4152 else: | |
4153 selectionpen = selectionEdgePen = None | |
4154 | |
4155 x_pen = self.GetDrawX() == 1 and wx.BLACK_PEN or None | |
4156 focusindpen = self.GetUseFocusIndicator() and self._focusindpen or None | |
4157 | |
4158 return _TabCtrlPaintTools(back_brush, back_pen, border_pen, highlightpen, | |
4159 shadowpen, upperhighpen, selectionpen, selectionEdgePen, x_pen, | |
4160 focusindpen) | |
4161 | |
4162 def _GetTabBitmap(self, tabIndex): | |
4163 bmp = wx.NullBitmap | |
4164 if self.GetPageImage(tabIndex) >= 0: | |
4165 bmpindex = self.GetPageImage(tabIndex) | |
4166 if self.IsPageEnabled(tabIndex): | |
4167 bmp = self._imglist.GetBitmap(bmpindex) | |
4168 else: | |
4169 bmp = self._grayedlist.GetBitmap(bmpindex) | |
4170 return bmp | |
4171 | |
4172 def _GetTabTextColour(self, tabIndex): | |
4173 if self.IsPageEnabled(tabIndex): | |
4174 result = self.GetPageTextColour(tabIndex) | |
4175 else: | |
4176 result = self._disabledcolour | |
4177 return result | |
4178 | |
4179 def _GetThemePageColour(self, index): | |
4180 if self._tabstyle._macstyle: | |
4181 return NC_MAC_LIGHT | |
4182 elif self._tabstyle._kdetheme: | |
4183 return kdetheme[0] | |
4184 elif self._tabstyle._aqua: | |
4185 if index == self.GetSelection(): | |
4186 return topaqua1[0] | |
4187 else: | |
4188 return distaqua[0] | |
4189 elif self._tabstyle._metal: | |
4190 intens = (230 + 80 * (self._tabrect[0].y-self._tabrect[0].y+1)/self._tabrect[0].height) | |
4191 return wx.Colour(intens, intens, intens) | |
4192 elif self._tabstyle._silver: | |
4193 if index == self.GetSelection(): | |
4194 return silvertheme1[0] | |
4195 else: | |
4196 return silvertheme2[0] | |
4197 elif self._tabstyle._gradient: | |
4198 color = wx.WHITE | |
4199 if self._tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL: | |
4200 if self._style & NC_TOP: | |
4201 color = self._tabstyle.GetSecondGradientColour(index) | |
4202 elif self._style & NC_BOTTOM: | |
4203 color = self._tabstyle.GetFirstGradientColour(index) | |
4204 elif self._tabstyle._gradient & ThemeStyle.GRADIENT_HORIZONTAL and \ | |
4205 self._style & NC_ROTATE: | |
4206 if self._style & NC_LEFT: | |
4207 color = self._tabstyle.GetSecondGradientColour(index) | |
4208 else: | |
4209 color = self._tabstyle.GetFirstGradientColour(index) | |
4210 return color | |
4211 | |
4212 def _HighlightSelectedTabEdge(self, dc, paintTools, tabrect): | |
4213 if self._style & NC_ROTATE: | |
4214 yselpos = tabrect.y + 3 | |
4215 yselsize = tabrect.height - 6 | |
4216 xselpos = self._style & NC_RIGHT and tabrect.x + tabrect.width - 1 or tabrect.x | |
4217 if self.GetHighlightSelection(): | |
4218 dc.SetBrush(paintTools.BackBrush) | |
4219 dc.SetPen(paintTools.SelectionEdgePen) | |
4220 dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) | |
4221 dc.SetPen(paintTools.SelectionPen) | |
4222 for band in range(2): | |
4223 if self._style & NC_RIGHT: | |
4224 xselpos -= 1 | |
4225 else: | |
4226 xselpos += 1 | |
4227 yselpos -= 1 | |
4228 yselsize += 2 | |
4229 dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) | |
4230 else: | |
4231 dc.SetPen(paintTools.HighlightPen) | |
4232 dc.DrawLine(xselpos, yselpos, xselpos, yselpos + yselsize) | |
4233 else: | |
4234 xselpos = tabrect.x + 3 | |
4235 xselsize = tabrect.width - 6 | |
4236 | |
4237 if self._style & NC_BOTTOM: | |
4238 yselpos = tabrect.y + tabrect.height - 1 | |
4239 else: | |
4240 yselpos = tabrect.y | |
4241 dc.SetPen(paintTools.HighlightPen) | |
4242 dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) | |
4243 | |
4244 if self.GetHighlightSelection(): | |
4245 dc.SetBrush(paintTools.BackBrush) | |
4246 dc.SetPen(paintTools.SelectionEdgePen) | |
4247 dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) | |
4248 dc.SetPen(paintTools.SelectionPen) | |
4249 for band in range(2): | |
4250 if self._style & NC_BOTTOM: | |
4251 yselpos -= 1 | |
4252 else: | |
4253 yselpos += 1 | |
4254 xselpos -= 1 | |
4255 xselsize += 2 | |
4256 dc.DrawLine(xselpos, yselpos, xselpos + xselsize, yselpos) | |
4257 | |
4258 def _HighlightTabEdge(self, dc, paintTools, tabrect): | |
4259 if not self._tabstyle._normal or self._usegradients: | |
4260 if self._style & NC_TOP: | |
4261 dc.SetPen(paintTools.UpperHighlightPen) | |
4262 dc.DrawLine(tabrect.x+2, tabrect.y-1, tabrect.x + tabrect.width - 2, tabrect.y-1) | |
4263 else: | |
4264 if self._style & NC_TOP: | |
4265 dc.SetPen(paintTools.HighlightPen) | |
4266 dc.DrawLine(tabrect.x + 3, tabrect.y, tabrect.x + tabrect.width - 3, tabrect.y) | |
4267 | |
4268 def _InitExpandableStyles(self, style): | |
4269 self._expanded = not style & NC_ROTATE | |
4270 if self._expanded: | |
4271 self._expandedstyle = style | |
4272 self._contractedstyle = style | NC_ROTATE | |
4273 else: | |
4274 self._contractedstyle = style | |
4275 self._expandedstyle = (style ^ NC_ROTATE) | NC_FIXED_WIDTH | |
4276 | |
4277 def _InitExpandableTabStyles(self, style, expanded, tabstyle): | |
4278 if tabstyle._gradient: | |
4279 alternatestyle = ThemeStyle() | |
4280 firstcolor = tabstyle.GetFirstGradientColour() | |
4281 secondcolor = tabstyle.GetSecondGradientColour() | |
4282 swapcolors = (tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL and style & NC_RIGHT and expanded) or \ | |
4283 (tabstyle._gradient & ThemeStyle.GRADIENT_HORIZONTAL and style & NC_RIGHT and not expanded) | |
4284 if swapcolors: | |
4285 firstcolor, secondcolor = (secondcolor, firstcolor) | |
4286 if tabstyle._gradient & ThemeStyle.GRADIENT_VERTICAL: | |
4287 othergradient = (tabstyle._gradient ^ ThemeStyle.GRADIENT_VERTICAL) | ThemeStyle.GRADIENT_HORIZONTAL | |
4288 else: | |
4289 othergradient = (tabstyle._gradient ^ ThemeStyle.GRADIENT_HORIZONTAL) | ThemeStyle.GRADIENT_VERTICAL | |
4290 alternatestyle.EnableGradientStyle(True, othergradient) | |
4291 alternatestyle.SetFirstGradientColour(firstcolor) | |
4292 alternatestyle.SetSecondGradientColour(secondcolor) | |
4293 if tabstyle._gradient & ThemeStyle.DIFFERENT_GRADIENT_FOR_SELECTED: | |
4294 firstcolor = tabstyle.GetFirstGradientColour(True) | |
4295 secondcolor = tabstyle.GetSecondGradientColour(True) | |
4296 if swapcolors: | |
4297 firstcolor, secondcolor = (secondcolor, firstcolor) | |
4298 alternatestyle.SetFirstGradientColourSelected(firstcolor) | |
4299 alternatestyle.SetSecondGradientColourSelected(secondcolor) | |
4300 if expanded: | |
4301 self._expandedtabstyle = tabstyle | |
4302 self._contractedtabstyle = alternatestyle | |
4303 else: | |
4304 self._contractedtabstyle = tabstyle | |
4305 self._expandedtabstyle = alternatestyle | |
4306 else: | |
4307 self._expandedtabstyle = tabstyle | |
4308 self._contractedtabstyle = tabstyle | |
4309 | |
4310 def _OnStyleChange(self): | |
4311 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
4312 self.SetBestSize((-1, newheight)) | |
4313 else: | |
4314 self.SetBestSize((self._CalcBestWidth(wx.ClientDC(self)), -1)) | |
4315 self._parent.GetSizer().Layout() | |
4316 self._somethingchanged = True | |
4317 self._firsttime = True | |
4318 self.Refresh() | |
4319 | |
4320 def _ShadowTabEdge(self, dc, paintTools, tabrect): | |
4321 dc.SetPen(paintTools.ShadowPen) | |
4322 if self._style & NC_BOTTOM: | |
4323 dc.DrawLine((tabrect.x + tabrect.width), tabrect.y+1, | |
4324 (tabrect.x+tabrect.width), tabrect.y + tabrect.height-4) | |
4325 elif self._style & NC_TOP: | |
4326 dc.DrawLine(tabrect.x + tabrect.width, tabrect.y+3, | |
4327 tabrect.x+tabrect.width, tabrect.y+tabrect.height-4) | |
4328 | |
4329 def OnPaint(self, event): | |
4330 """ Handles The wx.EVT_PAINT Event For TabCtrl. """ | |
4331 | |
4332 dc = wx.BufferedPaintDC(self) | |
4333 | |
4334 if self.GetPageCount() == 0: | |
4335 event.Skip() | |
4336 return | |
4337 | |
4338 pt = self._GetPaintTools() | |
4339 | |
4340 dc.BeginDrawing() | |
4341 | |
4342 self._DrawBackground(dc, pt) | |
4343 | |
4344 self._CalcMaxTextHeight(dc) | |
4345 | |
4346 posx = self._firsttabpos.x | |
4347 posy = self._firsttabpos.y | |
4348 | |
4349 if self._style & NC_LEFT: | |
4350 _ = 1 | |
4351 | |
4352 if self._firsttime: | |
4353 if not hasattr(self, "_initrect"): | |
4354 self._initrect = [] | |
4355 if self.HasSpinButton() and self._fromdnd: | |
4356 self._firstvisible = self._spinbutton.GetValue() | |
4357 self._firsttime = False | |
4358 self._fromdnd = False | |
4359 else: | |
4360 self._initrect = [] | |
4361 self._firstvisible = 0 | |
4362 else: | |
4363 if self.HasSpinButton(): | |
4364 self._firstvisible = self._spinbutton.GetValue() | |
4365 else: | |
4366 self._firstvisible = 0 | |
4367 | |
4368 lastvisible = self.GetPageCount() | |
4369 | |
4370 #and tabs | |
4371 oncount = -1 | |
4372 | |
4373 self._tabvisible = [1]*self.GetPageCount() | |
4374 | |
4375 tabrect = [] | |
4376 # some theme style rendering routines expect this to exist, so | |
4377 # set it now: | |
4378 self._tabrect = tabrect | |
4379 Xrect = [] | |
4380 | |
4381 for ii in xrange(self._firstvisible, lastvisible): | |
4382 if not self._enablehiding or not self._pages[ii]._ishidden: | |
4383 | |
4384 oncount = oncount + 1 | |
4385 | |
4386 self._tabvisible[ii] = 1 | |
4387 | |
4388 newwidth = self._CalcTabTextWidth(dc, ii) | |
4389 | |
4390 bmpWidth, bmpHeight = self._CalcTabBitmapSize(ii) | |
4391 | |
4392 tabrect.append(self._CalcTabRect(ii, posx, posy, | |
4393 newwidth, bmpWidth, bmpHeight)) | |
4394 | |
4395 self._DrawTab(dc, pt, tabrect[-1], ii) | |
4396 | |
4397 self._DrawTabText(dc, ii, *self._CalcTabTextPosition(ii, | |
4398 tabrect[-1], self._CalcTabBitmapSpace(bmpWidth, bmpHeight))) | |
4399 | |
4400 if bmpWidth: | |
4401 self._DrawTabBitmap(dc, ii, *self._CalcTabBitmapPosition(ii, | |
4402 bmpWidth, bmpHeight, tabrect[-1])) | |
4403 | |
4404 if self.GetSelection() in [ii, ii - 1]: | |
4405 # Handle this special case on the selected tab and | |
4406 # on the tab that follows it (if there is one), to ensure | |
4407 # proper rendering of the selected tab's right edge | |
4408 self._EnhanceSelectedTab(dc, pt, tabrect[self.GetSelection() - self._firstvisible]) | |
4409 | |
4410 if self.GetDrawX()[0]: | |
4411 Xrect.append(self._CalcXRect(tabrect[-1])) | |
4412 self._DrawX(dc, tabrect[-1], Xrect[-1], | |
4413 self._GetTabTextColour(ii)) | |
4414 | |
4415 if ii in self._selectedtabs: | |
4416 self._EnhanceMultiSelectedTab(dc, ii, tabrect[-1]) | |
4417 | |
4418 if self._style & NC_TOP or self._style & NC_BOTTOM: | |
4419 # horizontally positioned tabs along top or bottom | |
4420 posx = posx + tabrect[-1].width | |
4421 else: | |
4422 # vertically stacked tabs along side | |
4423 posy = posy + tabrect[-1].height | |
4424 | |
4425 if self._firsttime: | |
4426 self._initrect.append(tabrect[oncount]) | |
4427 | |
4428 else: | |
4429 | |
4430 self._tabvisible[ii] = 0 | |
4431 | |
4432 self._xrect = Xrect | |
4433 | |
4434 if self._firsttime: | |
4435 self._firsttime = False | |
4436 | |
4437 self.UpdateMenuButton(self.HasMenuButton()) | |
4438 self.UpdateSpinButton() | |
4439 | |
4440 if self._enabledragging: | |
4441 if self._isdragging and not self._isleaving: | |
4442 self.DrawInsertionMark(dc, self._olddragpos) | |
4443 | |
4444 dc.EndDrawing() | |
4445 | |
4446 | |
4447 # ---------------------------------------------------------------------------- # | |
4448 # Class NotebookCtrl | |
4449 # This Is The Main Class Implementation | |
4450 # ---------------------------------------------------------------------------- # | |
4451 | |
4452 class NotebookCtrl(wx.Panel): | |
4453 """ | |
4454 Display one or more windows in a notebook. | |
4455 | |
4456 B{Events}: | |
4457 - B{EVT_NOTEBOOKCTRL_PAGE_CHANGING}: sent when the active | |
4458 page in the notebook is changing | |
4459 - B{EVT_NOTEBOOKCTRL_PAGE_CHANGED}: sent when the active | |
4460 page in the notebook has changed | |
4461 - B{EVT_NOTEBOOKCTRL_PAGE_CLOSING}: sent when a page in the | |
4462 notebook is closing | |
4463 - B{EVT_NOTEBOOKCTRL_PAGE_DND}: sent when a page has been | |
4464 dropped onto the notebook in a drag-drop operation | |
4465 - B{EVT_NOTEBOOKCTRL_PAGE_DCLICK}: sent when the user | |
4466 double-clicks a tab in the notebook | |
4467 - B{EVT_NOTEBOOKCTRL_PAGE_RIGHT}: sent when the user | |
4468 clicks a tab in the notebook with the right mouse | |
4469 button | |
4470 - B{EVT_NOTEBOOKCTRL_PAGE_MIDDLE}: sent when the user | |
4471 clicks a tab in the notebook with the middle mouse | |
4472 button | |
4473 """ | |
4474 | |
4475 def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, | |
4476 style=NC_DEFAULT_STYLE, sizer=wx.HORIZONTAL, margin=2, name="NotebookCtrl"): | |
4477 """ | |
4478 Default Class Constructor. | |
4479 | |
4480 @param style: Style For The NotebookCtrl, Which May Be: | |
4481 a) NC_TOP: NotebookCtrl Placed On Top (Default); | |
4482 b) NC_BOTTOM: NotebookCtrl Placed At The Bottom; | |
4483 c) NC_LEFT: NotebookCtrl Placed At The Left; | |
4484 d) NC_RIGHT: NotebookCtrl Placed At The Right; | |
4485 e) NC_FIXED_WIDTH: All Tabs Have The Same Width; | |
4486 f) wx.NO_BORDER: Shows No Border For The Control (Default, Looks Better); | |
4487 g) wx.STATIC_BORDER: Shows A Static Border On The Control. | |
4488 | |
4489 @param sizer: The Sizer Orientation For The Sizer That Holds | |
4490 All The Panels: Changing This Style Is Only Useful When You | |
4491 Use The Tile Method. In This Case, If sizer=wx.HORIZONTAL, | |
4492 All The Panels Will Be Shown In Columns, While If | |
4493 sizer=wx.VERTICAL All The Panels Will Be Shown In Rows. | |
4494 | |
4495 @param margin: An Integer Number Of Pixels That Add Space | |
4496 Above TabCtrl If style=NC_TOP, Or Below It If | |
4497 style=NC_BOTTOM | |
4498 """ | |
4499 | |
4500 wx.Panel.__init__(self, parent, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE | | |
4501 wx.CLIP_CHILDREN, name=name) | |
4502 | |
4503 self.nb = TabCtrl(self, -1, pos, size, style) | |
4504 | |
4505 self._notebookpages = [] | |
4506 | |
4507 if style & NC_TOP == 0 and style & NC_BOTTOM == 0 \ | |
4508 and style & NC_LEFT == 0 and style & NC_RIGHT == 0: | |
4509 style = style | NC_TOP | |
4510 | |
4511 if style & wx.NO_BORDER == 0 and \ | |
4512 style & wx.STATIC_BORDER == 0: | |
4513 style = style | wx.NO_BORDER | |
4514 | |
4515 self._style = style | |
4516 self._showcolumns = False | |
4517 self._showtabs = True | |
4518 self._sizerstyle = sizer | |
4519 self._custompanel = None | |
4520 self._focusswitch = False | |
4521 self._oldfocus = None | |
4522 | |
4523 if style & NC_TOP or style & NC_BOTTOM: | |
4524 self.sizer = wx.BoxSizer(wx.VERTICAL) | |
4525 self.tabsizer = wx.BoxSizer(wx.VERTICAL) | |
4526 else: | |
4527 self.sizer = wx.BoxSizer(wx.HORIZONTAL) | |
4528 self.tabsizer = wx.BoxSizer(wx.HORIZONTAL) | |
4529 | |
4530 self.bsizer = wx.BoxSizer(sizer) | |
4531 | |
4532 if style & NC_TOP or style & NC_BOTTOM: | |
4533 tabBorderFlag = wx.LEFT | wx.RIGHT | |
4534 else: | |
4535 tabBorderFlag = wx.TOP | wx.BOTTOM | |
4536 | |
4537 if style & NC_TOP or style & NC_LEFT: | |
4538 self.sizer.Add(self.tabsizer, 0, wx.EXPAND | tabBorderFlag, 2) | |
4539 self._AddMargin(style, margin) | |
4540 self.tabsizer.Add(self.nb, 0, wx.EXPAND) | |
4541 self.sizer.Add(self.bsizer, 1, wx.EXPAND) | |
4542 elif style & NC_BOTTOM or style & NC_RIGHT: | |
4543 self.sizer.Add(self.bsizer, 1, wx.EXPAND) | |
4544 self.sizer.Add(self.tabsizer, 0, wx.EXPAND | tabBorderFlag, 2) | |
4545 self.tabsizer.Add(self.nb, 0, wx.EXPAND) | |
4546 self._AddMargin(style, margin) | |
4547 | |
4548 self.SetSizer(self.sizer) | |
4549 | |
4550 self.tabsizer.Show(self.nb, False) | |
4551 | |
4552 self.sizer.Layout() | |
4553 self.Bind(wx.EVT_MOTION, self.OnMouseMotion) | |
4554 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) | |
4555 | |
4556 | |
4557 def OnKeyDown(self, event): | |
4558 """ | |
4559 Handles The wx.EVT_KEY_DOWN Event For NotebookCtrl. This Is Only Processed | |
4560 If The User Navigate Through Tabs With Ctrl-Tab Keyboard Navigation. | |
4561 """ | |
4562 | |
4563 if event.GetKeyCode == wx.WXK_TAB: | |
4564 if event.ControlDown(): | |
4565 sel = self.GetSelection() | |
4566 if sel == self.GetPageCount() - 1: | |
4567 sel = 0 | |
4568 else: | |
4569 sel = sel + 1 | |
4570 | |
4571 while not self.IsPageEnabled(sel): | |
4572 sel = sel + 1 | |
4573 if sel == self.GetPageCount() - 1: | |
4574 sel = 0 | |
4575 | |
4576 self.SetSelection(sel) | |
4577 | |
4578 event.Skip() | |
4579 | |
4580 | |
4581 def OnMouseMotion(self, event): | |
4582 """ Handles The wx.EVT_MOTION Event For NotebookCtrl. """ | |
4583 | |
4584 if self.nb._enabledragging: | |
4585 | |
4586 if event.Dragging() and not event.RightIsDown() and not event.MiddleIsDown(): | |
4587 | |
4588 tolerance = 2 | |
4589 pt = event.GetPosition() | |
4590 dx = abs(pt.x - self.nb._dragstartpos.x) | |
4591 dy = abs(pt.y - self.nb._dragstartpos.y) | |
4592 if dx <= tolerance and dy <= tolerance: | |
4593 self.SetCursor(wx.STANDARD_CURSOR) | |
4594 return | |
4595 | |
4596 self.SetCursor(self.nb._dragcursor) | |
4597 self.nb._isdragging = True | |
4598 | |
4599 else: | |
4600 | |
4601 self.nb._isdragging = False | |
4602 self.SetCursor(wx.STANDARD_CURSOR) | |
4603 | |
4604 if self.nb._showtooltip: | |
4605 if self.nb._istooltipshown: | |
4606 pt = event.GetPosition() | |
4607 self.nb._insidetab = self.nb.GetInsideTab(pt) | |
4608 if self.nb._insidetab < 0: | |
4609 try: | |
4610 self.nb._tipwindow.Destroy() | |
4611 self.nb._istooltipshown = False | |
4612 except: | |
4613 self.nb._istooltipshown = False | |
4614 | |
4615 self.nb.Refresh() | |
4616 | |
4617 event.Skip() | |
4618 | |
4619 | |
4620 def EnableChildFocus(self, enable=True): | |
4621 """ Enables/Disables Sending EVT_NOTEBOOKCTRL_PAGE_CHANGING When In Tile Mode. """ | |
4622 | |
4623 self._focusswitch = enable | |
4624 | |
4625 | |
4626 def FindFocusedPage(self, obj): | |
4627 """ Find Which NotebookCtrl Page Has The Focus Based On Its Child Focus. """ | |
4628 | |
4629 while 1: | |
4630 if obj in self._notebookpages: | |
4631 return obj | |
4632 | |
4633 try: | |
4634 obj = obj.GetParent() | |
4635 except: | |
4636 return None | |
4637 | |
4638 return None | |
4639 | |
4640 | |
4641 def OnFocus(self, event): | |
4642 """ Handles The wx.EVT_CHILD_FOCUS Event For NotebookCtrl. """ | |
4643 | |
4644 if not self._focusswitch: | |
4645 event.Skip() | |
4646 return | |
4647 | |
4648 newfocus = self.FindFocusedPage(event.GetEventObject()) | |
4649 | |
4650 if newfocus == self._oldfocus or newfocus is None: | |
4651 event.Skip() | |
4652 return | |
4653 | |
4654 self._oldfocus = newfocus | |
4655 | |
4656 eventOut = NotebookCtrlEvent(wxEVT_NOTEBOOKCTRL_PAGE_CHANGING, self.GetId()) | |
4657 | |
4658 nPage = self._notebookpages.index(newfocus) | |
4659 eventOut.SetSelection(nPage) | |
4660 eventOut.SetOldSelection(self.GetSelection()) | |
4661 eventOut.SetEventObject(self) | |
4662 | |
4663 if not self.GetEventHandler().ProcessEvent(eventOut): | |
4664 | |
4665 # Program Allows The Page Change | |
4666 self.nb._selection = nPage | |
4667 eventOut.SetEventType(wxEVT_NOTEBOOKCTRL_PAGE_CHANGED) | |
4668 eventOut.SetOldSelection(self.nb._selection) | |
4669 self.GetEventHandler().ProcessEvent(eventOut) | |
4670 | |
4671 event.Skip() | |
4672 | |
4673 | |
4674 def AddPage(self, page, text, select=False, img=-1, hidden=False): | |
4675 """ | |
4676 Add A Page To The Notebook. | |
4677 | |
4678 @param page: Specifies The New Page; | |
4679 @param text: The Tab Text; | |
4680 @param select: Whether The Page Should Be Selected Or Not; | |
4681 @param img: Specifies The Optional Image Index For The New Page. | |
4682 """ | |
4683 | |
4684 self.Freeze() | |
4685 | |
4686 oldselection = self.nb.GetSelection() | |
4687 | |
4688 if self.GetPageCount() == 0: | |
4689 if self.GetCustomPage() is not None: | |
4690 self.bsizer.Detach(self._custompanel) | |
4691 self._custompanel.Show(False) | |
4692 self.bsizer.Layout() | |
4693 | |
4694 self.bsizer.Add(page, 1, wx.EXPAND | wx.ALL, 2) | |
4695 | |
4696 self.nb.AddPage(text, select, img, hidden) | |
4697 self._notebookpages.append(page) | |
4698 | |
4699 page.Bind(wx.EVT_CHILD_FOCUS, self.OnFocus) | |
4700 | |
4701 if select: | |
4702 if oldselection >= 0: | |
4703 self.bsizer.Show(self.GetPage(oldselection), False) | |
4704 | |
4705 self.nb.SetSelection(self.GetPageCount()-1) | |
4706 self.bsizer.Layout() | |
4707 else: | |
4708 if oldselection >= 0: | |
4709 self.bsizer.Show(page, False) | |
4710 else: | |
4711 self.bsizer.Show(page, True) | |
4712 self.nb.SetSelection(self.GetPageCount()-1) | |
4713 self.bsizer.Layout() | |
4714 | |
4715 if self.GetPageCount() == 1: | |
4716 | |
4717 self.bsizer.Show(page, True) | |
4718 | |
4719 if self.nb._hideonsingletab: | |
4720 | |
4721 self._ShowTabCtrl(False) | |
4722 | |
4723 else: | |
4724 self.nb.Show(True) | |
4725 self._ShowTabCtrl(True) | |
4726 | |
4727 else: | |
4728 | |
4729 self.nb.Show(True) | |
4730 self._ShowTabCtrl(True) | |
4731 | |
4732 self.bsizer.Layout() | |
4733 self.sizer.Layout() | |
4734 | |
4735 self.Thaw() | |
4736 | |
4737 self.Tile(self._showcolumns) | |
4738 self.ShowTabs(self._showtabs) | |
4739 | |
4740 | |
4741 def InsertPage(self, nPage, page, text, select=False, img=-1, hidden=False): | |
4742 """ | |
4743 Insert A Page Into The Notebook. | |
4744 | |
4745 @param page: Specifies The New Page; | |
4746 @param nPage: Specifies The Position For The New Page; | |
4747 @param text: The Tab Text; | |
4748 @param select: Whether The Page Should Be Selected Or Not; | |
4749 @param img: Specifies The Optional Image Index For The New Page. | |
4750 @param hidden: C{True} to hide the page; C{False} to display it | |
4751 """ | |
4752 | |
4753 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
4754 raise "\nERROR: Invalid Notebook Page In InsertPage: (" + str(nPage) + ")" | |
4755 | |
4756 self.Freeze() | |
4757 | |
4758 oldselection = self.nb.GetSelection() | |
4759 | |
4760 if self.GetPageCount() == 0: | |
4761 if self.GetCustomPage() is not None: | |
4762 self.bsizer.Detach(self._custompanel) | |
4763 self._custompanel.Show(False) | |
4764 | |
4765 if oldselection >= 0: | |
4766 self.bsizer.Show(oldselection, False) | |
4767 self.bsizer.Layout() | |
4768 | |
4769 if oldselection >= nPage: | |
4770 oldselection = oldselection + 1 | |
4771 | |
4772 self.nb.InsertPage(nPage, text, select, img, hidden) | |
4773 self.bsizer.Insert(nPage, page, 1, wx.EXPAND | wx.ALL, 2) | |
4774 self._notebookpages.insert(nPage, page) | |
4775 self.bsizer.Layout() | |
4776 | |
4777 page.Bind(wx.EVT_CHILD_FOCUS, self.OnFocus) | |
4778 | |
4779 for ii in xrange(self.GetPageCount()): | |
4780 self.bsizer.Show(ii, False) | |
4781 | |
4782 self.bsizer.Layout() | |
4783 | |
4784 if select: | |
4785 self.bsizer.Show(nPage, True) | |
4786 self.bsizer.Layout() | |
4787 else: | |
4788 if oldselection >= 0: | |
4789 self.bsizer.Show(oldselection, True) | |
4790 self.bsizer.Layout() | |
4791 else: | |
4792 self.bsizer.Show(nPage, True) | |
4793 | |
4794 self.bsizer.Layout() | |
4795 | |
4796 if self.GetPageCount() == 1: | |
4797 | |
4798 if self.nb._hideonsingletab: | |
4799 | |
4800 self._ShowTabCtrl(False) | |
4801 | |
4802 else: | |
4803 | |
4804 self.nb.Show(True) | |
4805 self._ShowTabCtrl(True) | |
4806 | |
4807 else: | |
4808 | |
4809 self.nb.Show(True) | |
4810 self._ShowTabCtrl(True) | |
4811 | |
4812 self.sizer.Layout() | |
4813 | |
4814 self.Thaw() | |
4815 | |
4816 self.Tile(self._showcolumns) | |
4817 self.ShowTabs(self._showtabs) | |
4818 | |
4819 | |
4820 def GetPage(self, nPage): | |
4821 """ Returns The Window At The Given Position nPage. """ | |
4822 | |
4823 if nPage < 0 or nPage >= self.GetPageCount(): | |
4824 raise "\nERROR: Invalid Notebook Page In GetPage: (" + str(nPage) + ")" | |
4825 | |
4826 return self._notebookpages[nPage] | |
4827 | |
4828 | |
4829 def DeleteAllPages(self): | |
4830 """ Deletes All NotebookCtrl Pages. """ | |
4831 | |
4832 self.Freeze() | |
4833 | |
4834 counter = self.GetPageCount() - 1 | |
4835 | |
4836 for ii in xrange(self.GetPageCount()): | |
4837 self.bsizer.Detach(counter-ii) | |
4838 panels = self.GetPage(counter-ii) | |
4839 panels.Destroy() | |
4840 | |
4841 self.nb.DeleteAllPages() | |
4842 self._notebookpages = [] | |
4843 self.nb._selection = -1 | |
4844 | |
4845 self.nb.Show(False) | |
4846 | |
4847 custom = self.GetCustomPage() | |
4848 | |
4849 if custom is not None: | |
4850 self.SetCustomPage(custom) | |
4851 custom.Show(True) | |
4852 | |
4853 self.bsizer.Layout() | |
4854 | |
4855 self._ShowTabCtrl(False) | |
4856 | |
4857 self.sizer.Layout() | |
4858 | |
4859 self.Thaw() | |
4860 | |
4861 | |
4862 def DeletePage(self, nPage): | |
4863 """ Deletes The Page nPage, And The Associated Window. """ | |
4864 | |
4865 if nPage < 0 or nPage >= self.GetPageCount(): | |
4866 raise "\nERROR: Invalid Notebook Page In DeletePage: (" + str(nPage) + ")" | |
4867 | |
4868 oldselection = self.GetSelection() | |
4869 | |
4870 self.Freeze() | |
4871 | |
4872 panel = self.GetPage(nPage) | |
4873 self.bsizer.Detach(nPage) | |
4874 | |
4875 self.bsizer.Layout() | |
4876 | |
4877 self._notebookpages.pop(nPage) | |
4878 self.nb.DeletePage(nPage) | |
4879 | |
4880 panel.Destroy() | |
4881 | |
4882 if self.GetPageCount() > 0: | |
4883 if oldselection == nPage: | |
4884 if self.GetSelection() > 0: | |
4885 self.SetSelection(self.GetSelection()-1) | |
4886 else: | |
4887 self.SetSelection(self.GetSelection()) | |
4888 self.bsizer.Show(self.GetSelection()) | |
4889 self.bsizer.Layout() | |
4890 | |
4891 if self.GetPageCount() == 0: | |
4892 self.nb.Show(False) | |
4893 self._ShowTabCtrl(False) | |
4894 | |
4895 custom = self.GetCustomPage() | |
4896 | |
4897 if custom is not None: | |
4898 self.bsizer.Add(custom, 1, wx.EXPAND | wx.ALL, 2) | |
4899 custom.Show(True) | |
4900 | |
4901 self.bsizer.Layout() | |
4902 self.sizer.Layout() | |
4903 self.Thaw() | |
4904 return | |
4905 | |
4906 if self.GetPageCount() == 1: | |
4907 | |
4908 if self.nb._hideonsingletab: | |
4909 | |
4910 self._ShowTabCtrl(False) | |
4911 | |
4912 else: | |
4913 | |
4914 self.nb.Show(True) | |
4915 self._ShowTabCtrl(True) | |
4916 | |
4917 else: | |
4918 | |
4919 self.nb.Show(True) | |
4920 self._ShowTabCtrl(True) | |
4921 | |
4922 self.sizer.Layout() | |
4923 | |
4924 self.Thaw() | |
4925 | |
4926 self.Tile(self._showcolumns) | |
4927 self.ShowTabs(self._showtabs) | |
4928 | |
4929 | |
4930 def SetSelection(self, nPage): | |
4931 """ | |
4932 Sets The Current Tab Selection To The Given nPage. This Call Generates The | |
4933 EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. | |
4934 """ | |
4935 | |
4936 if nPage < 0 or nPage >= self.GetPageCount(): | |
4937 raise "\nERROR: Invalid Notebook Page In SetSelection: (" + str(nPage) + ")" | |
4938 | |
4939 oldselection = self.GetSelection() | |
4940 | |
4941 if oldselection == nPage: | |
4942 return | |
4943 | |
4944 self.nb.SetSelection(nPage) | |
4945 | |
4946 self.Tile(self._showcolumns) | |
4947 self.ShowTabs(self._showtabs) | |
4948 | |
4949 | |
4950 def GetPageCount(self): | |
4951 """ Returns The Number Of Pages In NotebookCtrl. """ | |
4952 | |
4953 return self.nb.GetPageCount() | |
4954 | |
4955 | |
4956 def GetSelection(self): | |
4957 """ Returns The Current Selection. """ | |
4958 | |
4959 return self.nb.GetSelection() | |
4960 | |
4961 | |
4962 def GetImageList(self): | |
4963 """ Returns The Image List Associated With The NotebookCtrl. """ | |
4964 | |
4965 return self.nb.GetImageList() | |
4966 | |
4967 | |
4968 def SetImageList(self, imagelist): | |
4969 """ Associate An Image List To NotebookCtrl. """ | |
4970 | |
4971 self.nb.SetImageList(imagelist) | |
4972 | |
4973 | |
4974 def AssignImageList(self, imagelist): | |
4975 """ Associate An Image List To NotebookCtrl. """ | |
4976 | |
4977 self.nb.AssignImageList(imagelist) | |
4978 | |
4979 | |
4980 def GetPadding(self): | |
4981 """ Returns The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ | |
4982 | |
4983 return self.nb.GetPadding() | |
4984 | |
4985 | |
4986 def SetPadding(self, padding): | |
4987 """ Sets The (Horizontal, Vertical) Padding Of The Text Inside Tabs. """ | |
4988 | |
4989 self.nb.SetPadding(padding) | |
4990 | |
4991 | |
4992 def SetUseFocusIndicator(self, focus=True): | |
4993 """ Globally Enables/Disables Tab Focus Indicator. """ | |
4994 | |
4995 self.nb.SetUseFocusIndicator(focus) | |
4996 | |
4997 | |
4998 def GetUseFocusIndicator(self): | |
4999 """ Returns Globally Enable/Disable State For Tab Focus Indicator. """ | |
5000 | |
5001 return self.nb.GetUseFocusIndicator() | |
5002 | |
5003 | |
5004 def EnablePage(self, nPage, enable=True): | |
5005 """ Enable/Disable The Given Page nPage. """ | |
5006 | |
5007 if nPage < 0 or nPage >= self.GetPageCount(): | |
5008 raise "\nERROR: Invalid Notebook Page In EnablePage: (" + str(nPage) + ")" | |
5009 | |
5010 self.nb.EnablePage(nPage, enable) | |
5011 | |
5012 | |
5013 def IsPageEnabled(self, nPage): | |
5014 """ Returns Whether A Page Is Enabled Or Not. """ | |
5015 | |
5016 if nPage < 0 or nPage >= self.GetPageCount(): | |
5017 raise "\nERROR: Invalid Notebook Page In IsPageEnabled: (" + str(nPage) + ")" | |
5018 | |
5019 return self.nb.IsPageEnabled(nPage) | |
5020 | |
5021 | |
5022 def SetHighlightSelection(self, highlight=True): | |
5023 """ Globally Enables/Disables Tab Highlighting On Tab Selection. """ | |
5024 | |
5025 self.nb.SetHighlightSelection(highlight) | |
5026 | |
5027 | |
5028 def GetHighlightSelection(self): | |
5029 """ Returns Globally Enable/Disable State For Tab Highlighting On Tab Selection. """ | |
5030 | |
5031 return self.nb.GetHighlightSelection() | |
5032 | |
5033 | |
5034 def SetAnimationImages(self, nPage, imgarray): | |
5035 """ | |
5036 Sets An Animation List Associated To The Given Page nPage. | |
5037 | |
5038 @param nPage: The Given Page; | |
5039 @param imgarray: A List Of Image Indexes Of Images Inside The | |
5040 ImageList Associated To NotebookCtrl. | |
5041 """ | |
5042 | |
5043 if nPage < 0 or nPage >= self.GetPageCount(): | |
5044 raise "\nERROR: Invalid Notebook Page In SetAnimationImages: (" + str(nPage) + ")" | |
5045 | |
5046 if not imgarray: | |
5047 raise "\nERROR: Invalid Image Array In SetAnimationImages: (" + repr(imgarray) + ")" | |
5048 | |
5049 if min(imgarray) < 0: | |
5050 raise "\nERROR: Invalid Image Array In SetAnimationImages: (Min(ImgArray) = " + \ | |
5051 str(min(imgarray)) + " < 0)" | |
5052 | |
5053 if max(imgarray) > self.GetImageList().GetImageCount() - 1: | |
5054 raise "\nERROR: Invalid Image Array In SetAnimationImages: (Max(ImgArray) = " + \ | |
5055 str(max(imgarray)) + " > " + str(self.GetImageList().GetImageCount()-1) + ")" | |
5056 | |
5057 self.nb.SetAnimationImages(nPage, imgarray) | |
5058 | |
5059 | |
5060 def GetAnimationImages(self, nPage): | |
5061 """ Returns The Animation Images List Associated To The Given Page nPage. """ | |
5062 | |
5063 if nPage < 0 or nPage >= self.GetPageCount(): | |
5064 raise "\nERROR: Invalid Notebook Page In GetAnimationImages: (" + str(nPage) + ")" | |
5065 | |
5066 return self.nb.GetAnimationImages(nPage) | |
5067 | |
5068 | |
5069 def StartAnimation(self, nPage, timer=500): | |
5070 """ Starts The Animation On The Given Page nPage, With Refreshing Time Rate "timer". """ | |
5071 | |
5072 if nPage < 0 or nPage >= self.GetPageCount(): | |
5073 raise "\nERROR: Invalid Notebook Page In StartAnimation: (" + str(nPage) + ")" | |
5074 | |
5075 self.nb.StartAnimation(nPage, timer) | |
5076 | |
5077 | |
5078 def StopAnimation(self, nPage): | |
5079 """ Stops The Animation On The Given Page nPage. """ | |
5080 | |
5081 if nPage < 0 or nPage >= self.GetPageCount(): | |
5082 raise "\nERROR: Invalid Notebook Page In StopAnimation: (" + str(nPage) + ")" | |
5083 | |
5084 self.nb.StopAnimation(nPage) | |
5085 | |
5086 | |
5087 def EnableDragAndDrop(self, enable=True): | |
5088 """ Globall Enables/Disables Tabs Drag And Drop. """ | |
5089 | |
5090 self.nb.EnableDragAndDrop(enable) | |
5091 | |
5092 | |
5093 def EnableHiding(self, enable=True): | |
5094 """ Globally Enables/Disables Hiding On Tabs In Runtime. """ | |
5095 | |
5096 self.nb.EnableHiding(enable) | |
5097 | |
5098 | |
5099 def SetDrawX(self, drawx=True, style=1, image1=None, image2=None): | |
5100 """ | |
5101 Globally Enables/Disables The Drawing Of A Closing "X" In The Tab. | |
5102 | |
5103 @param drawx: C{True} to enable drawing a closing "X"; C{False} to | |
5104 disable it | |
5105 @param style: the style of the X to draw when C{drawx} is C{True}; | |
5106 possible values are: | |
5107 - C{1}: Small "X" At The Top-Right Of The Tab; | |
5108 - C{2}: Bigger "X" In The Middle Vertical Of The Tab (Like Opera Notebook); | |
5109 - C{3}: Custom "X" Image Is Drawn On Tabs. | |
5110 @param image1: if C{style} is C{3}, the image to use when drawing | |
5111 the X on an unhighlighted tab | |
5112 @param image2: if C{style} is C{3}, the image to use when drawing | |
5113 the X on a highlighted tab | |
5114 """ | |
5115 | |
5116 self.nb.SetDrawX(drawx, style, image1, image2) | |
5117 | |
5118 | |
5119 def GetDrawX(self): | |
5120 """ | |
5121 Returns The Enable/Disable State Of Drawing Of A Small "X" At The Top-Right Of | |
5122 Every Page. | |
5123 """ | |
5124 | |
5125 return self.nb.GetDrawX() | |
5126 | |
5127 | |
5128 def SetImageToCloseButton(self, convert=True): | |
5129 """ Set Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ | |
5130 | |
5131 self.nb.SetImageToCloseButton(convert) | |
5132 | |
5133 | |
5134 def GetImageToCloseButton(self): | |
5135 """ Get Whether The Tab Icon Should Be Converted To The Close Button Or Not. """ | |
5136 | |
5137 return self.nb._convertimage | |
5138 | |
5139 | |
5140 def HideOnSingleTab(self, hide=True): | |
5141 """ Hides The TabCtrl When There Is Only One Tab In NotebookCtrl. """ | |
5142 | |
5143 self.nb.HideOnSingleTab(hide) | |
5144 | |
5145 if self.GetPageCount() == 1: | |
5146 if hide: | |
5147 self._ShowTabCtrl(False) | |
5148 else: | |
5149 self._ShowTabCtrl(True) | |
5150 | |
5151 self.sizer.Layout() | |
5152 | |
5153 | |
5154 def SetPagePopupMenu(self, nPage, menu): | |
5155 """ Sets A Popup Menu Specific To A Single Tab. """ | |
5156 | |
5157 if nPage < 0 or nPage >= self.GetPageCount(): | |
5158 raise "\nERROR: Invalid Notebook Page In SetPagePopupMenu: (" + str(nPage) + ")" | |
5159 | |
5160 self.nb.SetPagePopupMenu(nPage, menu) | |
5161 | |
5162 | |
5163 def GetPagePopupMenu(self, nPage): | |
5164 """ Returns The Popup Menu Associated To A Single Tab. """ | |
5165 | |
5166 if nPage < 0 or nPage >= self.GetPageCount(): | |
5167 raise "\nERROR: Invalid Notebook Page In GetPagePopupMenu: (" + str(nPage) + ")" | |
5168 | |
5169 return self.nb.GetPagePopupMenu(nPage) | |
5170 | |
5171 | |
5172 def SetPageToolTip(self, nPage, tooltip="", timer=500, winsize=400): | |
5173 """ | |
5174 Sets A ToolTip For The Given Page nPage. | |
5175 | |
5176 @param nPage: The Given Page; | |
5177 @param tooltip: The ToolTip String; | |
5178 @param timer: The Timer After Which The Tip Window Is Popped Up; | |
5179 @param winsize: The Maximum Width Of The Tip Window. | |
5180 """ | |
5181 | |
5182 if nPage < 0 or nPage >= self.GetPageCount(): | |
5183 raise "\nERROR: Invalid Notebook Page In SetPageToolTip: (" + str(nPage) + ")" | |
5184 | |
5185 self.nb.SetPageToolTip(nPage, tooltip, timer, winsize) | |
5186 | |
5187 | |
5188 def GetPageToolTip(self, nPage): | |
5189 """ Returns A Tuple With All Page ToolTip Parameters. """ | |
5190 | |
5191 if nPage < 0 or nPage >= self.GetPageCount(): | |
5192 raise "\nERROR: Invalid Notebook Page In GetPageToolTip: (" + str(nPage) + ")" | |
5193 | |
5194 return self.nb.GetPageToolTip(nPage) | |
5195 | |
5196 | |
5197 def EnableToolTip(self, show=True): | |
5198 """ Globally Enables/Disables Tab ToolTips. """ | |
5199 | |
5200 self.nb.EnableToolTip(show) | |
5201 | |
5202 | |
5203 def GetToolTipBackgroundColour(self): | |
5204 """ Returns The ToolTip Window Background Colour. """ | |
5205 | |
5206 return self.nb.GetToolTipBackgroundColour() | |
5207 | |
5208 | |
5209 def SetToolTipBackgroundColour(self, colour=None): | |
5210 """ Sets The ToolTip Window Background Colour. """ | |
5211 | |
5212 if colour is None: | |
5213 colour = wx.Colour(255, 255, 230) | |
5214 | |
5215 self.nb.SetToolTipBackgroundColour(colour) | |
5216 | |
5217 | |
5218 def EnableTabGradients(self, enable=True): | |
5219 """ Globally Enables/Disables Drawing Of Gradient Coloured Tabs For Each Tab. """ | |
5220 | |
5221 self.nb.EnableTabGradients(enable) | |
5222 | |
5223 | |
5224 def SetPageFirstGradientColour(self, nPage, colour=None): | |
5225 """ Sets The Single Tab First Gradient Colour. """ | |
5226 | |
5227 if nPage < 0 or nPage >= self.GetPageCount(): | |
5228 raise "\nERROR: Invalid Notebook Page In SetPageFirstGradientColour: (" + str(nPage) + ")" | |
5229 | |
5230 if colour is None: | |
5231 colour = wx.WHITE | |
5232 | |
5233 self.nb.SetPageFirstGradientColour(nPage, colour) | |
5234 | |
5235 | |
5236 def SetPageSecondGradientColour(self, nPage, colour=None): | |
5237 """ Sets The Single Tab Second Gradient Colour. """ | |
5238 | |
5239 if nPage < 0 or nPage >= self.GetPageCount(): | |
5240 raise "\nERROR: Invalid Notebook Page In SetPageSecondGradientColour: (" + str(nPage) + ")" | |
5241 | |
5242 self.nb.SetPageSecondGradientColour(nPage, colour) | |
5243 | |
5244 | |
5245 def GetPageFirstGradientColour(self, nPage): | |
5246 """ Returns The Single Tab First Gradient Colour. """ | |
5247 | |
5248 if nPage < 0 or nPage >= self.GetPageCount(): | |
5249 raise "\nERROR: Invalid Notebook Page In GetPageFirstGradientColour: (" + str(nPage) + ")" | |
5250 | |
5251 return self.nb.GetPageFirstGradientColour(nPage) | |
5252 | |
5253 | |
5254 def GetPageSecondGradientColour(self, nPage): | |
5255 """ Returns The Single Tab Second Gradient Colour. """ | |
5256 | |
5257 if nPage < 0 or nPage >= self.GetPageCount(): | |
5258 raise "\nERROR: Invalid Notebook Page In GetPageSecondGradientColour: (" + str(nPage) + ")" | |
5259 | |
5260 return self.nb.GetPageSecondGradientColour(nPage) | |
5261 | |
5262 | |
5263 def CancelTip(self): | |
5264 """ Destroys The Tip Window (Probably You Won't Need This One. """ | |
5265 | |
5266 self.nb.CancelTip() | |
5267 | |
5268 | |
5269 def AdvanceSelection(self, forward=True): | |
5270 """ | |
5271 Cycles Through The Tabs. The Call To This Function Generates The | |
5272 EVT_NOTEBOOKCTRL_PAGE_CHANGING Event. | |
5273 """ | |
5274 | |
5275 self.nb.AdvanceSelection(forward) | |
5276 | |
5277 | |
5278 def SetDefaultPage(self, defaultpage=-1): | |
5279 """ | |
5280 Sets The Default Page That Will Be Selected When An Active And Selected | |
5281 Tab Is Made Inactive. | |
5282 """ | |
5283 | |
5284 if defaultpage >= self.GetPageCount(): | |
5285 raise "\nERROR: Invalid Notebook Page In SetDefaultPage: (" + str(defaultpage) + ")" | |
5286 | |
5287 self.nb.SetDefaultPage(defaultpage) | |
5288 | |
5289 | |
5290 def GetDefaultPage(self): | |
5291 """ Returns The Default Page. """ | |
5292 | |
5293 return self.nb.GetDefaultPage() | |
5294 | |
5295 | |
5296 def GetPageText(self, nPage): | |
5297 """ Returns The String For The Given Page nPage. """ | |
5298 | |
5299 if nPage < 0 or nPage >= self.GetPageCount(): | |
5300 raise "\nERROR: Invalid Notebook Page In GetPageText: (" + str(nPage) + ")" | |
5301 | |
5302 return self.nb.GetPageText(nPage) | |
5303 | |
5304 | |
5305 def SetPageText(self, nPage, text): | |
5306 """ Sets The String For The Given Page nPage. """ | |
5307 | |
5308 if nPage < 0 or nPage >= self.GetPageCount(): | |
5309 raise "\nERROR: Invalid Notebook Page In SetPageText: (" + str(nPage) + ")" | |
5310 | |
5311 self.nb.SetPageText(nPage, text) | |
5312 | |
5313 | |
5314 def GetPageImage(self, nPage): | |
5315 """ Returns The Image Index For The Given Page nPage. """ | |
5316 | |
5317 if nPage < 0 or nPage >= self.GetPageCount(): | |
5318 raise "\nERROR: Invalid Notebook Page In GetPageImage: (" + str(nPage) + ")" | |
5319 | |
5320 return self.nb.GetPageImage(nPage) | |
5321 | |
5322 | |
5323 def SetPageImage(self, nPage, img): | |
5324 """ Sets The Image Index For The Given Page nPage. """ | |
5325 | |
5326 if nPage < 0 or nPage >= self.GetPageCount(): | |
5327 raise "\nERROR: Invalid Notebook Page In SetPageImage: (" + str(nPage) + ")" | |
5328 | |
5329 self.nb.SetPageImage(nPage, img) | |
5330 | |
5331 | |
5332 def SetPageTextFont(self, nPage, font=None): | |
5333 """ Sets The Primary Font For The Given Page nPage. """ | |
5334 | |
5335 if nPage < 0 or nPage >= self.GetPageCount(): | |
5336 raise "\nERROR: Invalid Notebook Page In SetPageTextFont: (" + str(nPage) + ")" | |
5337 | |
5338 if font is None: | |
5339 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
5340 | |
5341 self.nb.SetPageTextFont(nPage, font) | |
5342 | |
5343 | |
5344 def GetPageTextFont(self, nPage): | |
5345 """ Returns The Primary Font For The Given Page nPage. """ | |
5346 | |
5347 if nPage < 0 or nPage >= self.GetPageCount(): | |
5348 raise "\nERROR: Invalid Notebook Page In GetPageTextFont: (" + str(nPage) + ")" | |
5349 | |
5350 return self.nb.GetPageTextFont(nPage) | |
5351 | |
5352 | |
5353 def SetPageTextSecondaryFont(self, nPage, font=None): | |
5354 """ Sets The Secondary Font For The Given Page nPage. """ | |
5355 | |
5356 if nPage < 0 or nPage >= self.GetPageCount(): | |
5357 raise "\nERROR: Invalid Notebook Page In SetPageTextSecondaryFont: (" + str(nPage) + ")" | |
5358 | |
5359 if font is None: | |
5360 font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) | |
5361 | |
5362 self.nb.SetPageTextSecondaryFont(nPage, font) | |
5363 | |
5364 | |
5365 def GetPageTextSecondaryFont(self, nPage): | |
5366 """ Returns The Secondary Font For The Given Page nPage. """ | |
5367 | |
5368 if nPage < 0 or nPage >= self.GetPageCount(): | |
5369 raise "\nERROR: Invalid Notebook Page In GetPageTextSecondaryFont: (" + str(nPage) + ")" | |
5370 | |
5371 return self.nb.GetPageTextSecondaryFont(nPage) | |
5372 | |
5373 | |
5374 def SetPageTextColour(self, nPage, colour=None): | |
5375 """ Sets The Text Colour For The Given Page nPage. """ | |
5376 | |
5377 if nPage < 0 or nPage >= self.GetPageCount(): | |
5378 raise "\nERROR: Invalid Notebook Page In SetPageTextColour: (" + str(nPage) + ")" | |
5379 | |
5380 if colour is None: | |
5381 colour = wx.BLACK | |
5382 | |
5383 self.nb.SetPageTextColour(nPage, colour) | |
5384 | |
5385 | |
5386 def GetPageTextColour(self, nPage): | |
5387 """ Returns The Text Colour For The Given Page nPage. """ | |
5388 | |
5389 if nPage < 0 or nPage >= self.GetPageCount(): | |
5390 raise "\nERROR: Invalid Notebook Page In GetPageTextColour: (" + str(nPage) + ")" | |
5391 | |
5392 return self.nb.GetPageTextColour(nPage) | |
5393 | |
5394 | |
5395 def SetPageColour(self, nPage, colour=None): | |
5396 """ Sets The Tab Background Colour For The Given Page nPage. """ | |
5397 | |
5398 if nPage < 0 or nPage >= self.GetPageCount(): | |
5399 raise "\nERROR: Invalid Notebook Page In SetPageColour: (" + str(nPage) + ")" | |
5400 | |
5401 if colour is None: | |
5402 colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE) | |
5403 | |
5404 self.nb.SetPageColour(nPage, colour) | |
5405 | |
5406 | |
5407 def GetPageColour(self, nPage): | |
5408 """ Returns The Tab Background Colour For The Given Page nPage. """ | |
5409 | |
5410 if nPage < 0 or nPage >= self.GetPageCount(): | |
5411 raise "\nERROR: Invalid Notebook Page In GetPageColour: (" + str(nPage) + ")" | |
5412 | |
5413 return self.nb.GetPageColour(nPage) | |
5414 | |
5415 | |
5416 def SetTabHeight(self, height=28): | |
5417 """ Sets The Tabs Height. """ | |
5418 | |
5419 if height <= 0: | |
5420 raise "\nERROR: Impossible To Set An Height <= 0. " | |
5421 | |
5422 self.nb.SetTabHeight(height) | |
5423 | |
5424 | |
5425 def SetControlBackgroundColour(self, colour=None): | |
5426 """ Sets The TabCtrl Background Colour (Behind The Tabs). """ | |
5427 | |
5428 if colour is None: | |
5429 colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE) | |
5430 | |
5431 self.nb.SetBackgroundColour(colour) | |
5432 | |
5433 | |
5434 def ApplyTabTheme(self, theme=None): | |
5435 """ Apply A Particular Theme To Be Drawn On Tabs. """ | |
5436 | |
5437 if theme is None: | |
5438 theme = ThemeStyle() | |
5439 | |
5440 self.nb.ApplyTabTheme(theme) | |
5441 | |
5442 | |
5443 def SetSelectionColour(self, colour=None): | |
5444 """ Sets The Tab Selection Colour (Thin Line Above The Selected Tab). """ | |
5445 | |
5446 if colour is None: | |
5447 colour = wx.Colour(255, 180, 0) | |
5448 | |
5449 self.nb.SetSelectionColour(colour) | |
5450 | |
5451 | |
5452 def SetContourLineColour(self, colour=None): | |
5453 """ Sets The Contour Line Colour (Controur Line Around Tabs). """ | |
5454 | |
5455 self.nb.SetContourLineColour(colour) | |
5456 | |
5457 def Tile(self, show=True, orient=None): | |
5458 """ Shows Pages In Column/Row Mode (One Panel After The Other In Columns/Rows). """ | |
5459 | |
5460 if self._GetTabCtrlWindow().IsShown() == show and orient is None: | |
5461 return | |
5462 | |
5463 self.Freeze() | |
5464 | |
5465 if orient is not None and show: | |
5466 if orient == wx.VERTICAL: | |
5467 norient = wx.HORIZONTAL | |
5468 else: | |
5469 norient = wx.VERTICAL | |
5470 | |
5471 if orient is not None and show: | |
5472 origorient = self.bsizer.GetOrientation() | |
5473 if origorient != norient: | |
5474 for ii in xrange(self.GetPageCount()-1, -1, -1): | |
5475 self.bsizer.Detach(ii) | |
5476 | |
5477 self.sizer.Detach(self.bsizer) | |
5478 self.bsizer.Destroy() | |
5479 | |
5480 self.bsizer = wx.BoxSizer(norient) | |
5481 | |
5482 for ii in xrange(self.GetPageCount()): | |
5483 self.bsizer.Add(self._notebookpages[ii], 1, wx.EXPAND | wx.ALL, 2) | |
5484 | |
5485 if self._style & NC_TOP: | |
5486 self.sizer.Add(self.bsizer, 1, wx.EXPAND) | |
5487 else: | |
5488 self.sizer.Insert(0, self.bsizer, 1, wx.EXPAND) | |
5489 | |
5490 self.bsizer.Layout() | |
5491 self.sizer.Layout() | |
5492 | |
5493 selection = self.GetSelection() | |
5494 | |
5495 if show: | |
5496 self._ShowTabCtrl(False) | |
5497 if self._style & NC_TOP or self._style & NC_LEFT: | |
5498 if len(self.nb._selectedtabs) > 0: | |
5499 for ii in xrange(self.GetPageCount()): | |
5500 if ii in self.nb._selectedtabs: | |
5501 self.bsizer.Show(ii, True) | |
5502 else: | |
5503 self.bsizer.Show(ii, False) | |
5504 else: | |
5505 for ii in xrange(self.GetPageCount()): | |
5506 if self.IsPageEnabled(ii): | |
5507 if not self.nb._enablehiding or not self.nb._pages[ii]._ishidden: | |
5508 self.bsizer.Show(ii, True) | |
5509 else: | |
5510 self.bsizer.Show(ii, False) | |
5511 else: | |
5512 self.bsizer.Show(ii, False) | |
5513 else: | |
5514 if len(self.nb._selectedtabs) > 0: | |
5515 for ii in xrange(self.GetPageCount()): | |
5516 if ii in self.nb._selectedtabs: | |
5517 self.bsizer.Show(ii, True) | |
5518 else: | |
5519 for ii in xrange(self.GetPageCount()): | |
5520 if self.IsPageEnabled(ii): | |
5521 if not self.nb._enablehiding or not self.nb._pages[ii]._ishidden: | |
5522 self.bsizer.Show(ii, True) | |
5523 else: | |
5524 self.bsizer.Show(ii, False) | |
5525 else: | |
5526 self.bsizer.Show(ii, False) | |
5527 else: | |
5528 self._ShowTabCtrl(True) | |
5529 if self._style & NC_TOP or self._style & NC_LEFT: | |
5530 for ii in xrange(self.GetPageCount()): | |
5531 self.bsizer.Show(ii, False) | |
5532 else: | |
5533 for ii in xrange(self.GetPageCount()): | |
5534 self.bsizer.Show(ii, False) | |
5535 | |
5536 if selection < 0: | |
5537 self.bsizer.Layout() | |
5538 self.sizer.Layout() | |
5539 return | |
5540 else: | |
5541 self.bsizer.Show(selection, True) | |
5542 self.bsizer.Layout() | |
5543 | |
5544 self._showcolumns = show | |
5545 | |
5546 self.bsizer.Layout() | |
5547 self.sizer.Layout() | |
5548 | |
5549 self.Thaw() | |
5550 | |
5551 | |
5552 | |
5553 def ShowTabs(self, show=True): | |
5554 """ Shows/Hides Tabs On Request. """ | |
5555 | |
5556 if self._GetTabCtrlWindow().IsShown() == show: | |
5557 return | |
5558 | |
5559 if self.GetPageCount() == 0: | |
5560 return | |
5561 | |
5562 self.Freeze() | |
5563 | |
5564 self._ShowTabCtrl(show) | |
5565 | |
5566 self._showtabs = show | |
5567 | |
5568 self.sizer.Layout() | |
5569 | |
5570 self.Thaw() | |
5571 | |
5572 | |
5573 def GetIndex(self, page): | |
5574 """ Returns The Page Index (Position) Based On The NotebookCtrl Page Passed. """ | |
5575 | |
5576 if page in self._notebookpages: | |
5577 return self._notebookpages.index(page) | |
5578 | |
5579 return -1 | |
5580 | |
5581 | |
5582 def ReparentPage(self, nPage, newParent): | |
5583 """ Reparents The NotebookCtrl Page nPage To A New Parent. """ | |
5584 | |
5585 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
5586 raise "\nERROR: Invalid Notebook Page In ReparentPage: (" + str(nPage) + ")" | |
5587 | |
5588 page = self.GetPage(nPage) | |
5589 page.Reparent(newParent) | |
5590 | |
5591 | |
5592 def ReparentToFrame(self, nPage, createNotebook=False): | |
5593 """ Reparents The NotebookCtrl Page nPage To A New Frame. """ | |
5594 | |
5595 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
5596 raise "\nERROR: Invalid Notebook Page In ReparentToFrame: (" + str(nPage) + ")" | |
5597 | |
5598 self.Freeze() | |
5599 | |
5600 infos = self.GetPageInfo(nPage) | |
5601 panel = self.GetPage(nPage) | |
5602 text = infos["text"] | |
5603 oldparent = panel.GetParent() | |
5604 | |
5605 frame = NCFrame(None, -1, text, nb=self, infos=infos, panel=panel, oldparent=oldparent) | |
5606 | |
5607 if createNotebook: | |
5608 nb = NotebookCtrl(frame, -1, style=self._style, sizer=self._sizerstyle) | |
5609 nb.SetImageList(infos["imagelist"]) | |
5610 self.ReparentToNotebook(nPage, nb) | |
5611 else: | |
5612 self.ReparentPage(nPage, frame) | |
5613 | |
5614 self.nb.DeletePage(nPage, False) | |
5615 | |
5616 self.bsizer.Detach(nPage) | |
5617 self.bsizer.Layout() | |
5618 self.sizer.Layout() | |
5619 | |
5620 self._notebookpages.pop(nPage) | |
5621 | |
5622 self.AdvanceSelection() | |
5623 | |
5624 if self.GetPageCount() == 0: | |
5625 self._ShowTabCtrl(False) | |
5626 | |
5627 self.sizer.Layout() | |
5628 | |
5629 custom = self.GetCustomPage() | |
5630 if custom is not None: | |
5631 self.SetCustomPage(custom) | |
5632 | |
5633 self.Thaw() | |
5634 | |
5635 frame.Show() | |
5636 | |
5637 | |
5638 def ReparentToNotebook(self, nPage, notebook, newPage=None): | |
5639 """ Reparents The NotebookCtrl Page nPage To A New NotebookCtrl. """ | |
5640 | |
5641 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
5642 raise "\nERROR: Invalid Notebook Page In ReparentToNotebook: (" + str(nPage) + ")" | |
5643 | |
5644 if newPage is not None and newPage >= notebook.GetPageCount(): | |
5645 raise "\nERROR: Invalid Notebook New Page In ReparentToNotebook: (" + str(nPage) + ")" | |
5646 | |
5647 self.Freeze() | |
5648 | |
5649 infos = self.GetPageInfo(nPage) | |
5650 panel = self.GetPage(nPage) | |
5651 | |
5652 self.ReparentPage(nPage, notebook) | |
5653 | |
5654 if newPage is None: | |
5655 notebook.AddPage(panel, infos["text"], False, infos["image"]) | |
5656 notebook.SetPageInfo(0, infos) | |
5657 | |
5658 for attr in attrs: | |
5659 setattr(notebook, attr, getattr(self.nb, attr)) | |
5660 | |
5661 self.nb.DeletePage(nPage, False) | |
5662 | |
5663 self.bsizer.Detach(nPage) | |
5664 self.bsizer.Layout() | |
5665 self.sizer.Layout() | |
5666 | |
5667 self._notebookpages.pop(nPage) | |
5668 | |
5669 self.AdvanceSelection() | |
5670 | |
5671 if self.GetPageCount() == 0: | |
5672 self._ShowTabCtrl(False) | |
5673 | |
5674 self.sizer.Layout() | |
5675 | |
5676 self.Thaw() | |
5677 | |
5678 | |
5679 def GetPageInfo(self, nPage): | |
5680 """ Returns All The Style Information For A Given Page. """ | |
5681 | |
5682 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
5683 raise "\nERROR: Invalid Notebook Page In GetPageInfo: (" + str(nPage) + ")" | |
5684 | |
5685 text = self.GetPageText(nPage) | |
5686 image = self.GetPageImage(nPage) | |
5687 font1 = self.GetPageTextFont(nPage) | |
5688 font2 = self.GetPageTextSecondaryFont(nPage) | |
5689 fontcolour = self.GetPageTextColour(nPage) | |
5690 pagecolour = self.GetPageColour(nPage) | |
5691 enabled = self.IsPageEnabled(nPage) | |
5692 tooltip, ontime, winsize = self.GetPageToolTip(nPage) | |
5693 menu = self.GetPagePopupMenu(nPage) | |
5694 firstcol = self.GetPageFirstGradientColour(nPage) | |
5695 secondcol = self.GetPageSecondGradientColour(nPage) | |
5696 ishidden = self.nb._pages[nPage]._ishidden | |
5697 | |
5698 isanimated = 0 | |
5699 timer = None | |
5700 | |
5701 if self.nb._timers[nPage].IsRunning(): | |
5702 isanimated = 1 | |
5703 timer = self.nb._timers[nPage].GetInterval() | |
5704 | |
5705 self.StopAnimation(nPage) | |
5706 animatedimages = self.GetAnimationImages(nPage) | |
5707 | |
5708 infos = {"text": text, "image": image, "font1": font1, "font2": font2, | |
5709 "fontcolour": fontcolour, "pagecolour": pagecolour, "enabled": enabled, | |
5710 "tooltip": tooltip, "ontime": ontime, "winsize": winsize, | |
5711 "menu": menu, "isanimated": isanimated, "timer": timer, | |
5712 "animatedimages": animatedimages, "imagelist": self.nb._imglist, | |
5713 "firstcol": firstcol, "secondcol": secondcol, "ishidden": ishidden} | |
5714 | |
5715 return infos | |
5716 | |
5717 | |
5718 def SetPageInfo(self, nPage, infos): | |
5719 """ Sets All The Style Information For A Given Page. """ | |
5720 | |
5721 if nPage < 0 or (self.GetSelection() >= 0 and nPage >= self.GetPageCount()): | |
5722 raise "\nERROR: Invalid Notebook Page In SetPageInfo: (" + str(nPage) + ")" | |
5723 | |
5724 self.SetPageTextFont(nPage, infos["font1"]) | |
5725 self.SetPageTextSecondaryFont(nPage, infos["font2"]) | |
5726 self.SetPageTextColour(nPage, infos["fontcolour"]) | |
5727 self.SetPageColour(nPage, infos["pagecolour"]) | |
5728 self.EnablePage(nPage, infos["enabled"]) | |
5729 self.SetPageToolTip(nPage, infos["tooltip"], infos["ontime"], infos["winsize"]) | |
5730 self.SetPagePopupMenu(nPage, infos["menu"]) | |
5731 self.SetPageFirstGradientColour(nPage, infos["firstcol"]) | |
5732 self.SetPageSecondGradientColour(nPage, infos["secondcol"]) | |
5733 self.nb._pages[nPage]._ishidden = infos["ishidden"] | |
5734 | |
5735 if infos["isanimated"] and len(infos["animatedimages"]) > 1: | |
5736 self.SetAnimationImages(nPage, infos["animatedimages"]) | |
5737 self.StartAnimation(nPage, infos["timer"]) | |
5738 | |
5739 | |
5740 def SetCustomPage(self, panel): | |
5741 """ Sets A Custom Panel To Show When There Are No Pages Left In NotebookCtrl. """ | |
5742 | |
5743 self.Freeze() | |
5744 | |
5745 if panel is None: | |
5746 if self._custompanel is not None: | |
5747 self.bsizer.Detach(self._custompanel) | |
5748 self._custompanel.Show(False) | |
5749 | |
5750 if self.GetPageCount() == 0: | |
5751 self._ShowTabCtrl(False) | |
5752 else: | |
5753 if self.GetPageCount() == 0: | |
5754 if self._custompanel is not None: | |
5755 self.bsizer.Detach(self._custompanel) | |
5756 self._custompanel.Show(False) | |
5757 | |
5758 self.bsizer.Add(panel, 1, wx.EXPAND | wx.ALL, 2) | |
5759 panel.Show(True) | |
5760 self._ShowTabCtrl(False) | |
5761 else: | |
5762 panel.Show(False) | |
5763 | |
5764 self._custompanel = panel | |
5765 | |
5766 self.bsizer.Layout() | |
5767 self.sizer.Layout() | |
5768 self.Thaw() | |
5769 | |
5770 | |
5771 def GetCustomPage(self): | |
5772 """ Gets A Custom Panel To Show When There Are No Pages Left In NotebookCtrl. """ | |
5773 | |
5774 return self._custompanel | |
5775 | |
5776 | |
5777 def HideTab(self, nPage, hide=True): | |
5778 """ Hides A Tab In The NotebookCtrl. """ | |
5779 | |
5780 self.nb.HideTab(nPage, hide) | |
5781 | |
5782 | |
5783 def HitTest(self, point, flags=0): | |
5784 """ | |
5785 Standard NotebookCtrl HitTest() Method. If Called With 2 Outputs, It | |
5786 Returns The Page Clicked (If Any) And One Of These Flags: | |
5787 | |
5788 NC_HITTEST_NOWHERE = 0 ==> Hit Not On Tab | |
5789 NC_HITTEST_ONICON = 1 ==> Hit On Icon | |
5790 NC_HITTEST_ONLABEL = 2 ==> Hit On Label | |
5791 NC_HITTEST_ONITEM = 4 ==> Hit Generic, On Item | |
5792 NC_HITTEST_ONX = 8 ==> Hit On Closing "X" On Every Page | |
5793 """ | |
5794 | |
5795 return self.nb.HitTest(point, flags) | |
5796 | |
5797 def _AddMargin(self, style, margin): | |
5798 if style & NC_TOP or style & NC_BOTTOM: | |
5799 self.tabsizer.Add((0, margin), 0) | |
5800 elif style & NC_LEFT or style & NC_RIGHT: | |
5801 self.tabsizer.Add((margin, 0), 0) | |
5802 | |
5803 def _GetTabCtrlWindow(self): | |
5804 if self._style & NC_TOP or self._style & NC_LEFT: | |
5805 return self.tabsizer.GetItem(1) | |
5806 else: | |
5807 return self.tabsizer.GetItem(0) | |
5808 | |
5809 def _ShowTabCtrl(self, show): | |
5810 if self._style & NC_TOP: | |
5811 self.sizer.Show(0, show) | |
5812 else: | |
5813 self.sizer.Show(1, show) | |
5814 | |
5815 | |
5816 # ---------------------------------------------------------------------------- # | |
5817 # Class TransientTipWindow | |
5818 # Auxiliary Help Class. Used To Build The Tip Window. | |
5819 # ---------------------------------------------------------------------------- # | |
5820 | |
5821 class _PopupWindow: | |
5822 | |
5823 def _Fill(self, tip, winsize): | |
5824 | |
5825 panel = wx.Panel(self, -1) | |
5826 colour = self.GetParent().GetToolTipBackgroundColour() | |
5827 | |
5828 panel.SetBackgroundColour(colour) | |
5829 | |
5830 # border from sides and top to text (in pixels) | |
5831 border = 5 | |
5832 # how much space between text lines | |
5833 textPadding = 2 | |
5834 max_len = len(tip) | |
5835 tw = winsize | |
5836 | |
5837 mylines = tip.split("\n") | |
5838 | |
5839 sts = wx.StaticText(panel, -1, "\n".join(mylines)) | |
5840 sx, sy = sts.GetBestSize() | |
5841 sts.SetPosition((2, 2)) | |
5842 | |
5843 panel.SetSize((sx+6, sy+6)) | |
5844 self.SetSize(panel.GetSize()) | |
5845 | |
5846 | |
5847 class TransientTipWindow(_PopupWindow, wx.PopupWindow): | |
5848 | |
5849 def __init__(self, parent, tip, winsize): | |
5850 | |
5851 wx.PopupWindow.__init__(self, parent, flags=wx.SIMPLE_BORDER) | |
5852 self._Fill(tip,winsize) | |
5853 | |
5854 | |
5855 def ProcessLeftDown(self, evt): | |
5856 | |
5857 return False | |
5858 | |
5859 | |
5860 def OnDismiss(self): | |
5861 | |
5862 return False | |
5863 | |
5864 | |
5865 class macPopupWindow(wx.Frame): | |
5866 | |
5867 def __init__(self, parent, flags): | |
5868 | |
5869 wx.Frame.__init__(self, parent, id=-1, style=flags|wx.FRAME_NO_TASKBAR|wx.STAY_ON_TOP) | |
5870 self._hideOnActivate = False | |
5871 #Get the parent frame: could be improved maybe? | |
5872 self._parentFrame = parent | |
5873 | |
5874 while True: | |
5875 | |
5876 parent = self._parentFrame.GetParent() | |
5877 | |
5878 if parent: | |
5879 self._parentFrame = parent | |
5880 else: | |
5881 break | |
5882 | |
5883 self.Bind(wx.EVT_ACTIVATE, self.OnActivate) | |
5884 | |
5885 | |
5886 def Show(self, show=True): | |
5887 | |
5888 wx.Frame.Show(self,show) | |
5889 | |
5890 if show: | |
5891 self._parentFrame.Raise() | |
5892 self._hideOnActivate = True | |
5893 | |
5894 | |
5895 def OnActivate(self, evt): | |
5896 """ | |
5897 Let The User Hide The Tooltip By Clicking On It. | |
5898 NotebookCtrl Will Destroy It Later. | |
5899 """ | |
5900 | |
5901 if self._hideOnActivate: | |
5902 wx.Frame.Show(self,False) | |
5903 | |
5904 | |
5905 class macTransientTipWindow(_PopupWindow, macPopupWindow): | |
5906 | |
5907 def __init__(self, parent, tip, winsize): | |
5908 | |
5909 macPopupWindow.__init__(self, parent, flags=wx.SIMPLE_BORDER) | |
5910 self._Fill(tip, winsize) | |
5911 | |
5912 | |
5913 class NCFrame(wx.Frame): | |
5914 | |
5915 def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, | |
5916 size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, nb=None, | |
5917 panel=None, infos=None, oldparent=None): | |
5918 | |
5919 wx.Frame.__init__(self, parent, id, title, pos, size, style) | |
5920 | |
5921 self._infos = infos | |
5922 self._nb = nb | |
5923 self._panel = panel | |
5924 self._oldparent = oldparent | |
5925 | |
5926 self.Bind(wx.EVT_CLOSE, self.OnClose) | |
5927 | |
5928 | |
5929 def OnClose(self, event): | |
5930 | |
5931 try: | |
5932 infos = self._infos | |
5933 self._panel.Reparent(self._oldparent) | |
5934 self._nb.AddPage(self._panel, infos["text"], False, infos["image"]) | |
5935 | |
5936 id = self._nb.GetPageCount() - 1 | |
5937 | |
5938 self._nb.SetPageTextFont(id, infos["font1"]) | |
5939 self._nb.SetPageTextSecondaryFont(id, infos["font2"]) | |
5940 self._nb.SetPageTextColour(id, infos["fontcolour"]) | |
5941 self._nb.SetPageColour(id, infos["pagecolour"]) | |
5942 self._nb.EnablePage(id, infos["enabled"]) | |
5943 self._nb.SetPageToolTip(id, infos["tooltip"], infos["ontime"], infos["winsize"]) | |
5944 self._nb.SetPagePopupMenu(id, infos["menu"]) | |
5945 self._nb.SetPageFirstGradientColour(id, infos["firstcol"]) | |
5946 self._nb.SetPageSecondGradientColour(id, infos["secondcol"]) | |
5947 self._nb._pages[id]._ishidden = infos["ishidden"] | |
5948 | |
5949 if infos["isanimated"] and len(infos["animatedimages"]) > 1: | |
5950 self._nb.SetAnimationImages(id, infos["animatedimages"]) | |
5951 self._nb.StartAnimation(id, infos["timer"]) | |
5952 | |
5953 except: | |
5954 self.Destroy() | |
5955 event.Skip() | |
5956 return | |
5957 | |
5958 self.Destroy() | |
5959 | |
5960 event.Skip() | |
5961 | |
5962 class NotebookCtrlWindowHandler(xrc.XmlResourceHandler): | |
5963 """ | |
5964 Create L{NotebookCtrl} windows defined in Xrc resources. | |
5965 | |
5966 Below is an example of a resource definition:: | |
5967 <?xml version="1.0" encoding="ISO-8859-1"?> | |
5968 <resource> | |
5969 <object class="wxPanel" name="appPanel"> | |
5970 <object class="wxBoxSizer"> | |
5971 <orient>wxVERTICAL</orient> | |
5972 <object class="sizeritem"> | |
5973 <option>1</option> | |
5974 <flag>wxEXPAND</flag> | |
5975 <object class="NotebookCtrl" name="notebook"> | |
5976 <style>wxNO_BORDER | NC_RIGHT | NC_ROTATE | NC_EXPANDABLE </style> | |
5977 <focus>0</focus> | |
5978 <highlight>1</highlight> | |
5979 <tabstyle>NC_GRADIENT_HORIZONTAL | NC_GRADIENT_SELECTION</tabstyle> | |
5980 <color1>#DCDCDC</color1> | |
5981 <color2>#F5F5F5</color2> | |
5982 <selectedcolor1>#C4DADB</selectedcolor1> | |
5983 <selectedcolor2>#FFFFFF</selectedcolor2> | |
5984 <custompagecolor>#C0C0C0</custompagecolor> | |
5985 </object> | |
5986 </object> | |
5987 </object> | |
5988 </object> | |
5989 </resource> | |
5990 | |
5991 @undocumented: CanHandle, DoCreateResource, SetupWindow | |
5992 """ | |
5993 def __init__(self): | |
5994 """ | |
5995 Create a NotebookCtrlWindowHandler instance. | |
5996 """ | |
5997 xrc.XmlResourceHandler.__init__(self) | |
5998 # Specify the window styles recognized by objects of this type | |
5999 self.AddStyle("wxNO_BORDER", wx.NO_BORDER) | |
6000 self.AddStyle("wxTAB_TRAVERSAL", wx.TAB_TRAVERSAL) | |
6001 self.AddStyle("NC_TOP", NC_TOP) | |
6002 self.AddStyle("NC_BOTTOM", NC_BOTTOM) | |
6003 self.AddStyle("NC_LEFT", NC_LEFT) | |
6004 self.AddStyle("NC_RIGHT", NC_RIGHT) | |
6005 self.AddStyle("NC_FIXED_WIDTH", NC_FIXED_WIDTH) | |
6006 self.AddStyle("NC_ROTATE", NC_ROTATE) | |
6007 self.AddStyle("NC_EXPANDABLE", NC_EXPANDABLE) | |
6008 # More styles, used in the tabstyle parameter | |
6009 self.AddStyle("NC_AQUA_LIGHT", NC_AQUA_LIGHT) | |
6010 self.AddStyle("NC_AQUA_DARK", NC_AQUA_DARK) | |
6011 self.AddStyle("NC_AQUA", NC_AQUA) | |
6012 self.AddStyle("NC_METAL", NC_METAL) | |
6013 self.AddStyle("NC_SILVER", NC_SILVER) | |
6014 self.AddStyle("NC_KDE", NC_KDE) | |
6015 self.AddStyle("NC_GRADIENT_VERTICAL", NC_GRADIENT_VERTICAL) | |
6016 self.AddStyle("NC_GRADIENT_HORIZONTAL", NC_GRADIENT_HORIZONTAL) | |
6017 self.AddStyle("NC_GRADIENT_SELECTION", NC_GRADIENT_SELECTION) | |
6018 | |
6019 self.AddWindowStyles() | |
6020 | |
6021 def _CreateResourceInstance(self, parent, id, position, size, style, name): | |
6022 window = NotebookCtrl(parent, id, position, size=size, style=style, name=name) | |
6023 return window | |
6024 | |
6025 def _GetColorParamValue(self, paramName, defaultValue=wx.WHITE): | |
6026 paramValue = self.GetParamValue(paramName) | |
6027 if paramValue: | |
6028 return self.GetColour(paramName) | |
6029 else: | |
6030 return defaultValue | |
6031 | |
6032 def _GetCustomPage(self, window): | |
6033 customPage = wx.Window(window, -1, style = wx.STATIC_BORDER) | |
6034 customPage.SetBackgroundColour(self._GetColorParamValue('custompagecolor')) | |
6035 return customPage | |
6036 | |
6037 def _GetIntParamValue(self, paramName, defaultValue=0): | |
6038 paramValue = self.GetParamValue(paramName) | |
6039 if paramValue: | |
6040 return int(paramValue) | |
6041 else: | |
6042 return defaultValue | |
6043 | |
6044 def _GetTabTheme(self): | |
6045 tabstyle = self.GetStyle("tabstyle") | |
6046 | |
6047 if tabstyle: | |
6048 result = ThemeStyle() | |
6049 if tabstyle & NC_GRADIENT_VERTICAL or tabstyle & NC_GRADIENT_HORIZONTAL: | |
6050 result.EnableGradientStyle(True, tabstyle) | |
6051 result.SetFirstGradientColour(self._GetColorParamValue('color1')) | |
6052 result.SetSecondGradientColour(self._GetColorParamValue('color2')) | |
6053 result.SetFirstGradientColourSelected(self._GetColorParamValue('selectedcolor1')) | |
6054 result.SetSecondGradientColourSelected(self._GetColorParamValue('selectedcolor2')) | |
6055 elif tabstyle & NC_AQUA_LIGHT or tabstyle & NC_AQUA_DARK: | |
6056 result.EnableAquaTheme(True, tabstyle & NC_AQUA_LIGHT and 2 or 1) | |
6057 elif tabstyle & NC_METAL: | |
6058 result.EnableMetalTheme(True) | |
6059 elif tabstyle & NC_KDE: | |
6060 result.EnableKDETheme(True) | |
6061 elif tabstyle & NC_SILVER: | |
6062 result.EnableSilverTheme(True) | |
6063 else: | |
6064 result = GetDefaultTabStyle() | |
6065 return result | |
6066 | |
6067 # This method and the next one are required for XmlResourceHandlers | |
6068 def CanHandle(self, node): | |
6069 return self.IsOfClass(node, "NotebookCtrl") | |
6070 | |
6071 def DoCreateResource(self): | |
6072 # NOTE: wxWindows can be created in either a single-phase or | |
6073 # in a two-phase way. Single phase is what you normally do, | |
6074 # and two-phase creates the instnace first, and then later | |
6075 # creates the actual window when the Create method is called. | |
6076 # (In wxPython the first phase is done using the wxPre* | |
6077 # function, for example, wxPreFrame, wxPrePanel, etc.) | |
6078 # | |
6079 # wxXmlResource supports either method, a premade instance can | |
6080 # be created and populated by xrc using the appropriate | |
6081 # LoadOn* method (such as LoadOnPanel) or xrc can create the | |
6082 # instance too, using the Load* method. However this makes | |
6083 # the handlers a bit more complex. If you can be sure that a | |
6084 # particular class will never be loaded using a pre-existing | |
6085 # instance, then you can make the handle much simpler. I'll | |
6086 # show both methods below. | |
6087 | |
6088 # The simple method assumes that there is no existing | |
6089 # instance. Be sure of that with an assert. | |
6090 assert self.GetInstance() is None | |
6091 | |
6092 # Now create the object | |
6093 window = self._CreateResourceInstance(self.GetParentAsWindow(), | |
6094 self.GetID(), | |
6095 self.GetPosition(), | |
6096 self.GetSize(), | |
6097 self.GetStyle("style", NC_DEFAULT_STYLE), | |
6098 self.GetName()) | |
6099 | |
6100 # Set standard window attributes | |
6101 self.SetupWindow(window) | |
6102 # Create any child windows of this node | |
6103 self.CreateChildren(window) | |
6104 | |
6105 return window | |
6106 | |
6107 def SetupWindow(self, window): | |
6108 super(NotebookCtrlWindowHandler, self).SetupWindow(window) | |
6109 window.ApplyTabTheme(self._GetTabTheme()) | |
6110 window.SetHighlightSelection(self._GetIntParamValue("highlight", 0) != 0) | |
6111 window.SetUseFocusIndicator(self._GetIntParamValue("focus", 1) != 0) | |
6112 window.SetCustomPage(self._GetCustomPage(window)) |