Module LabelBook
[hide private]
[frames] | no frames]

Source Code for Module LabelBook

   1  # --------------------------------------------------------------------------- # 
   2  # LABELBOOK And FLATIMAGEBOOK Widgets wxPython IMPLEMENTATION 
   3  # 
   4  # Original C++ Code From Eran, embedded in the FlatMenu source code 
   5  # 
   6  # 
   7  # License: wxWidgets license 
   8  # 
   9  # 
  10  # Python Code By: 
  11  # 
  12  # Andrea Gavana, @ 03 Nov 2006 
  13  # Latest Revision: 03 Nov 2006, 22.30 GMT 
  14  # 
  15  # 
  16  # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please 
  17  # Write To Me At: 
  18  # 
  19  # andrea.gavana@gmail.com 
  20  # gavana@kpo.kz 
  21  # 
  22  # Or, Obviously, To The wxPython Mailing List!!! 
  23  # 
  24  # 
  25  # End Of Comments 
  26  # --------------------------------------------------------------------------- # 
  27   
  28  """ 
  29  Description 
  30  =========== 
  31   
  32  LabelBook and FlatImageBook are a quasi-full implementations of the wx.Notebook, 
  33  and designed to be a drop-in replacement for wx.Notebook. The API functions are 
  34  similar so one can expect the function to behave in the same way. 
  35  LabelBook anf FlatImageBook share their appearance with wx.Toolbook and 
  36  wx.Listbook, while having more options for custom drawings, label positioning, 
  37  mouse pointing and so on. Moreover, they retain also some visual characteristics 
  38  of the Outlook address book. 
  39   
  40  Some features: 
  41   
  42    - They are generic controls; 
  43    - Supports for left, right, top (FlatImageBook only), bottom (FlatImageBook 
  44      only) book styles; 
  45    - Possibility to draw images only, text only or both (FlatImageBook only); 
  46    - Support for a "pin-button", that allows the user to shrink/expand the book 
  47      tab area; 
  48    - Shadows behind tabs (LabelBook only); 
  49    - Gradient shading of the tab area (LabelBook only); 
  50    - Web-like mouse pointing on tabs style (LabelBook only); 
  51    - Many customizable colours (tab area, active tab text, tab borders, active 
  52      tab, highlight) - LabelBook only. 
  53     
  54  And much more. See the demo for a quasi-complete review of all the functionalities 
  55  of LabelBook and FlatImageBook. 
  56   
  57   
  58  Events 
  59  ====== 
  60   
  61  LabelBook and FlatImageBook implement 4 events: 
  62   
  63    - EVT_IMAGENOTEBOOK_PAGE_CHANGING; 
  64    - EVT_IMAGENOTEBOOK_PAGE_CHANGED; 
  65    - EVT_IMAGENOTEBOOK_PAGE_CLOSING; 
  66    - EVT_IMAGENOTEBOOK_PAGE_CLOSED. 
  67   
  68   
  69  Supported Platforms 
  70  =================== 
  71   
  72  LabelBook and FlatImageBook have been tested on the following platforms: 
  73    * Windows (Windows XP); 
  74    * Linux Ubuntu (Dapper 6.06) 
  75   
  76   
  77  License And Version: 
  78  =================== 
  79   
  80  LabelBook and FlatImageBook are freeware and distributed under the wxPython license.  
  81   
  82   
  83  Latest Revision: Andrea Gavana @ 03 Nov 2006, 22.30 GMT 
  84   
  85  Version 0.1. 
  86   
  87  """ 
  88   
  89  __docformat__ = "epytext" 
  90   
  91   
  92  #---------------------------------------------------------------------- 
  93  # Beginning Of IMAGENOTEBOOK wxPython Code 
  94  #---------------------------------------------------------------------- 
  95   
  96  import wx 
  97   
  98  from ArtManager import ArtManager, DCSaver 
  99  from Resources import * 
 100   
 101  # Check for the new method in 2.7 (not present in 2.6.3.3) 
 102  if wx.VERSION_STRING < "2.7": 
 103      wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point) 
 104   
 105  wxEVT_IMAGENOTEBOOK_PAGE_CHANGED = wx.NewEventType() 
 106  wxEVT_IMAGENOTEBOOK_PAGE_CHANGING = wx.NewEventType() 
 107  wxEVT_IMAGENOTEBOOK_PAGE_CLOSING = wx.NewEventType() 
 108  wxEVT_IMAGENOTEBOOK_PAGE_CLOSED = wx.NewEventType() 
 109   
 110  #-----------------------------------# 
 111  #        ImageNotebookEvent 
 112  #-----------------------------------# 
 113   
 114  EVT_IMAGENOTEBOOK_PAGE_CHANGED = wx.PyEventBinder(wxEVT_IMAGENOTEBOOK_PAGE_CHANGED, 1) 
 115  """Notify client objects when the active page in L{ImageNotebook}  
 116  has changed.""" 
 117  EVT_IMAGENOTEBOOK_PAGE_CHANGING = wx.PyEventBinder(wxEVT_IMAGENOTEBOOK_PAGE_CHANGING, 1) 
 118  """Notify client objects when the active page in L{ImageNotebook}  
 119  is about to change.""" 
 120  EVT_IMAGENOTEBOOK_PAGE_CLOSING = wx.PyEventBinder(wxEVT_IMAGENOTEBOOK_PAGE_CLOSING, 1) 
 121  """Notify client objects when a page in L{ImageNotebook} is closing.""" 
 122  EVT_IMAGENOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_IMAGENOTEBOOK_PAGE_CLOSED, 1) 
 123  """Notify client objects when a page in L{ImageNotebook} has been closed.""" 
 124   
 125   
 126  # ---------------------------------------------------------------------------- # 
 127  # Class ImageNotebookEvent 
 128  # ---------------------------------------------------------------------------- # 
 129   
130 -class ImageNotebookEvent(wx.PyCommandEvent):
131 """ 132 This events will be sent when a EVT_IMAGENOTEBOOK_PAGE_CHANGED, 133 EVT_IMAGENOTEBOOK_PAGE_CHANGING, EVT_IMAGENOTEBOOK_PAGE_CLOSING, 134 EVT_IMAGENOTEBOOK_PAGE_CLOSED is mapped in the parent. 135 """ 136
137 - def __init__(self, eventType, id=1, sel=-1, oldsel=-1):
138 """ Default class constructor. """ 139 140 wx.PyCommandEvent.__init__(self, eventType, id) 141 self._eventType = eventType 142 self._sel = sel 143 self._oldsel = oldsel 144 self._allowed = True
145 146
147 - def SetSelection(self, s):
148 """ Sets the event selection. """ 149 150 self._sel = s
151 152
153 - def SetOldSelection(self, s):
154 """ Sets the event old selection. """ 155 156 self._oldsel = s
157 158
159 - def GetSelection(self):
160 """ Returns the event selection. """ 161 162 return self._sel
163 164
165 - def GetOldSelection(self):
166 """ Returns the old event selection. """ 167 168 return self._oldsel
169 170
171 - def Veto(self):
172 """Vetos the event. """ 173 174 self._allowed = False
175 176
177 - def Allow(self):
178 """Allows the event. """ 179 180 self._allowed = True
181 182
183 - def IsAllowed(self):
184 """Returns whether the event is allowed or not. """ 185 186 return self._allowed
187 188 189 # ---------------------------------------------------------------------------- # 190 # Class ImageInfo 191 # ---------------------------------------------------------------------------- # 192
193 -class ImageInfo:
194 """ 195 This class holds all the information (caption, image, etc...) belonging to a 196 single tab in L{ImageNotebook}. 197 """
198 - def __init__(self, strCaption="", imageIndex=-1):
199 """ 200 Default Class Constructor. 201 202 Parameters: 203 @param strCaption: the tab caption; 204 @param imageIndex: the tab image index based on the assigned (set) wx.ImageList (if any). 205 """ 206 207 self._pos = wx.Point() 208 self._size = wx.Size() 209 self._strCaption = strCaption 210 self._ImageIndex = imageIndex 211 self._captionRect = wx.Rect()
212 213
214 - def SetCaption(self, value):
215 """ Sets the tab caption. """ 216 217 self._strCaption = value
218 219
220 - def GetCaption(self):
221 """ Returns the tab caption. """ 222 223 return self._strCaption
224 225
226 - def SetPosition(self, value):
227 """ Sets the tab position. """ 228 229 self._pos = value
230 231
232 - def GetPosition(self):
233 """ Returns the tab position. """ 234 235 return self._pos
236 237
238 - def SetSize(self, value):
239 """ Sets the tab size. """ 240 241 self._size = value
242 243
244 - def GetSize(self):
245 """ Returns the tab size. """ 246 247 return self._size
248 249
250 - def SetImageIndex(self, value):
251 """ Sets the tab image index. """ 252 253 self._ImageIndex = value
254 255
256 - def GetImageIndex(self):
257 """ Returns the tab image index. """ 258 259 return self._ImageIndex
260 261
262 - def SetTextRect(self, rect):
263 """ Sets the rect available for the tab text. """ 264 265 self._captionRect = rect
266 267
268 - def GetTextRect(self):
269 """ Returns the rect available for the tab text. """ 270 271 return self._captionRect
272 273 274 # ---------------------------------------------------------------------------- # 275 # Class ImageContainerBase 276 # ---------------------------------------------------------------------------- # 277
278 -class ImageContainerBase(wx.Panel):
279 """ 280 Base class for FlatImageBook image container. 281 """
282 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 283 style=0, name="ImageContainerBase"):
284 """ 285 Default class constructor. 286 287 Parameters: 288 @param parent - parent window 289 @param id - Window id 290 @param pos - Window position 291 @param size - Window size 292 @param style - possible style INB_XXX 293 """ 294 295 self._nIndex = -1 296 self._nImgSize = 16 297 self._ImageList = None 298 self._nHoeveredImgIdx = -1 299 self._bCollapsed = False 300 self._tabAreaSize = (-1, -1) 301 self._nPinButtonStatus = INB_PIN_NONE 302 self._pagesInfoVec = [] 303 self._pinBtnRect = wx.Rect() 304 305 wx.Panel.__init__(self, parent, id, pos, size, style | wx.NO_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE, name)
306 307
308 - def HasFlag(self, flag):
309 """ Tests for existance of flag in the style. """ 310 311 style = self.GetParent().GetWindowStyleFlag() 312 res = (style & flag and [True] or [False])[0] 313 return res
314 315
316 - def ClearFlag(self, flag):
317 """ Removes flag from the style. """ 318 319 style = self.GetParent().GetWindowStyleFlag() 320 style &= ~(flag) 321 wx.Panel.SetWindowStyleFlag(self, style)
322 323
324 - def AssignImageList(self, imglist):
325 """ Assigns an image list to the ImageContainerBase. """ 326 327 if imglist and imglist.GetImageCount() != 0: 328 self._nImgSize = imglist.GetBitmap(0).GetHeight() 329 330 self._ImageList = imglist
331 332
333 - def GetImageList(self):
334 """ Return the image list for ImageContainerBase. """ 335 336 return self._ImageList
337 338
339 - def GetImageSize(self):
340 """ Returns the image size inside the ImageContainerBase image list. """ 341 342 return self._nImgSize
343 344
345 - def FixTextSize(self, dc, text, maxWidth):
346 """ 347 Fixes the text, to fit maxWidth value. If the text length exceeds 348 maxWidth value this function truncates it and appends two dots at 349 the end. ("Long Long Long Text" might become "Long Long...) 350 """ 351 352 return ArtManager.Get().TruncateText(dc, text, maxWidth)
353 354
355 - def CanDoBottomStyle(self):
356 """ 357 Allows the parent to examine the children type. Some implementation 358 (such as LabelBook), does not support top/bottom images, only left/right. 359 """ 360 361 return False
362 363
364 - def AddPage(self, caption, selected=True, imgIdx=-1):
365 """ Adds a page to the container. """ 366 367 self._pagesInfoVec.append(ImageInfo(caption, imgIdx)) 368 if selected or len(self._pagesInfoVec) == 1: 369 self._nIndex = len(self._pagesInfoVec)-1 370 371 self.Refresh()
372 373
374 - def ClearAll(self):
375 """ Deletes all the pages in the container. """ 376 377 self._pagesInfoVec = [] 378 self._nIndex = wx.NOT_FOUND
379 380
381 - def DoDeletePage(self, page):
382 """ Does the actual page deletion. """ 383 384 # Remove the page from the vector 385 book = self.GetParent() 386 self._pagesInfoVec.pop(page) 387 388 if self._nIndex >= page: 389 self._nIndex = self._nIndex - 1 390 391 # The delete page was the last first on the array, 392 # but the book still has more pages, so we set the 393 # active page to be the first one (0) 394 if self._nIndex < 0 and len(self._pagesInfoVec) > 0: 395 self._nIndex = 0 396 397 # Refresh the tabs 398 if self._nIndex >= 0: 399 400 book._bForceSelection = True 401 book.SetSelection(self._nIndex) 402 book._bForceSelection = False 403 404 if not self._pagesInfoVec: 405 # Erase the page container drawings 406 dc = wx.ClientDC(self) 407 dc.Clear()
408 409
410 - def OnSize(self, event):
411 """ Handles the wx.EVT_SIZE event for ImageContainerBase. """ 412 413 self.Refresh() # Call on paint 414 event.Skip()
415 416
417 - def OnEraseBackground(self, event):
418 """ Handles the wx.EVT_ERASE_BACKGROUND event for ImageContainerBase. """ 419 420 pass
421 422
423 - def HitTest(self, pt):
424 """ 425 Returns the index of the tab at the specified position or wx.NOT_FOUND 426 if None, plus the flag style of HitTest. 427 """ 428 429 style = self.GetParent().GetWindowStyleFlag() 430 431 if style & INB_USE_PIN_BUTTON: 432 if self._pinBtnRect.Contains(pt): 433 return -1, IMG_OVER_PIN 434 435 for i in xrange(len(self._pagesInfoVec)): 436 437 if self._pagesInfoVec[i].GetPosition() == wx.Point(-1, -1): 438 break 439 440 # For Web Hover style, we test the TextRect 441 if not self.HasFlag(INB_WEB_HILITE): 442 buttonRect = wx.RectPS(self._pagesInfoVec[i].GetPosition(), self._pagesInfoVec[i].GetSize()) 443 else: 444 buttonRect = self._pagesInfoVec[i].GetTextRect() 445 446 if buttonRect.Contains(pt): 447 return i, IMG_OVER_IMG 448 449 if self.PointOnSash(pt): 450 return -1, IMG_OVER_EW_BORDER 451 else: 452 return -1, IMG_NONE
453 454
455 - def PointOnSash(self, pt):
456 """ Tests whether pt is located on the sash. """ 457 458 # Check if we are on a the sash border 459 cltRect = self.GetClientRect() 460 461 if self.HasFlag(INB_LEFT) or self.HasFlag(INB_TOP): 462 if pt.x > cltRect.x + cltRect.width - 4: 463 return True 464 465 else: 466 if pt.x < 4: 467 return True 468 469 return False
470 471
472 - def OnMouseLeftDown(self, event):
473 """ Handles the wx.EVT_LEFT_DOWN event for ImageContainerBase. """ 474 475 newSelection = -1 476 event.Skip() 477 478 # Support for collapse/expand 479 style = self.GetParent().GetWindowStyleFlag() 480 if style & INB_USE_PIN_BUTTON: 481 482 if self._pinBtnRect.Contains(event.GetPosition()): 483 484 self._nPinButtonStatus = INB_PIN_PRESSED 485 dc = wx.ClientDC(self) 486 self.DrawPin(dc, self._pinBtnRect, not self._bCollapsed) 487 return 488 489 # Incase panel is collapsed, there is nothing 490 # to check 491 if self._bCollapsed: 492 return 493 494 tabIdx, where = self.HitTest(event.GetPosition()) 495 496 if where == IMG_OVER_IMG: 497 self._nHoeveredImgIdx = -1 498 499 if tabIdx == -1: 500 return 501 502 self.GetParent().SetSelection(tabIdx)
503 504
505 - def OnMouseLeaveWindow(self, event):
506 """ Handles the wx.EVT_LEAVE_WINDOW event for ImageContainerBase. """ 507 508 bRepaint = self._nHoeveredImgIdx != -1 509 self._nHoeveredImgIdx = -1 510 511 # Make sure the pin button status is NONE 512 # incase we were in pin button style 513 style = self.GetParent().GetWindowStyleFlag() 514 515 if style & INB_USE_PIN_BUTTON: 516 517 self._nPinButtonStatus = INB_PIN_NONE 518 dc = wx.ClientDC(self) 519 self.DrawPin(dc, self._pinBtnRect, not self._bCollapsed) 520 521 # Restore cursor 522 wx.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) 523 524 if bRepaint: 525 self.Refresh()
526 527
528 - def OnMouseLeftUp(self, event):
529 """ Handles the wx.EVT_LEFT_UP event for ImageContainerBase. """ 530 531 style = self.GetParent().GetWindowStyleFlag() 532 533 if style & INB_USE_PIN_BUTTON: 534 535 bIsLabelContainer = not self.CanDoBottomStyle() 536 537 if self._pinBtnRect.Contains(event.GetPosition()): 538 539 self._nPinButtonStatus = INB_PIN_NONE 540 self._bCollapsed = not self._bCollapsed 541 542 if self._bCollapsed: 543 544 # Save the current tab area width 545 self._tabAreaSize = self.GetSize() 546 547 if bIsLabelContainer: 548 549 self.SetSizeHints(20, self._tabAreaSize.y) 550 551 else: 552 553 if style & INB_BOTTOM or style & INB_TOP: 554 self.SetSizeHints(self._tabAreaSize.x, 20) 555 else: 556 self.SetSizeHints(20, self._tabAreaSize.y) 557 558 else: 559 560 if bIsLabelContainer: 561 562 self.SetSizeHints(self._tabAreaSize.x, -1) 563 564 else: 565 566 # Restore the tab area size 567 if style & INB_BOTTOM or style & INB_TOP: 568 self.SetSizeHints(-1, self._tabAreaSize.y) 569 else: 570 self.SetSizeHints(self._tabAreaSize.x, -1) 571 572 self.GetParent().GetSizer().Layout() 573 self.Refresh() 574 return
575 576
577 - def OnMouseMove(self, event):
578 """ Handles the wx.EVT_MOTION event for ImageContainerBase. """ 579 580 style = self.GetParent().GetWindowStyleFlag() 581 if style & INB_USE_PIN_BUTTON: 582 583 # Check to see if we are in the pin button rect 584 if not self._pinBtnRect.Contains(event.GetPosition()) and self._nPinButtonStatus == INB_PIN_PRESSED: 585 586 self._nPinButtonStatus = INB_PIN_NONE 587 dc = wx.ClientDC(self) 588 self.DrawPin(dc, self._pinBtnRect, not self._bCollapsed) 589 590 imgIdx, where = self.HitTest(event.GetPosition()) 591 self._nHoeveredImgIdx = imgIdx 592 593 if not self._bCollapsed: 594 595 if self._nHoeveredImgIdx >= 0 and self._nHoeveredImgIdx < len(self._pagesInfoVec): 596 597 # Change the cursor to be Hand 598 if self.HasFlag(INB_WEB_HILITE) and self._nHoeveredImgIdx != self._nIndex: 599 wx.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) 600 601 else: 602 603 # Restore the cursor only if we have the Web hover style set, 604 # and we are not currently hovering the sash 605 if self.HasFlag(INB_WEB_HILITE) and not self.PointOnSash(event.GetPosition()): 606 wx.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) 607 608 # Dont display hover effect when hoevering the 609 # selected label 610 611 if self._nHoeveredImgIdx == self._nIndex: 612 self._nHoeveredImgIdx = -1 613 614 self.Refresh()
615 616
617 - def DrawPin(self, dc, rect, downPin):
618 """ Draw a pin button, that allows collapsing of the image panel. """ 619 620 # Set the bitmap according to the button status 621 622 if downPin: 623 pinBmp = wx.BitmapFromXPMData(pin_down_xpm) 624 else: 625 pinBmp = wx.BitmapFromXPMData(pin_left_xpm) 626 627 xx = rect.x + 2 628 629 if self._nPinButtonStatus in [INB_PIN_HOVER, INB_PIN_NONE]: 630 631 dc.SetBrush(wx.TRANSPARENT_BRUSH) 632 dc.SetPen(wx.BLACK_PEN) 633 dc.DrawRectangle(xx, rect.y, 16, 16) 634 635 # Draw upper and left border with grey color 636 dc.SetPen(wx.WHITE_PEN) 637 dc.DrawLine(xx, rect.y, xx + 16, rect.y) 638 dc.DrawLine(xx, rect.y, xx, rect.y + 16) 639 640 elif self._nPinButtonStatus == INB_PIN_PRESSED: 641 642 dc.SetBrush(wx.TRANSPARENT_BRUSH) 643 dc.SetPen(wx.Pen(wx.NamedColor("LIGHT GREY"))) 644 dc.DrawRectangle(xx, rect.y, 16, 16) 645 646 # Draw upper and left border with grey color 647 dc.SetPen(wx.BLACK_PEN) 648 dc.DrawLine(xx, rect.y, xx + 16, rect.y) 649 dc.DrawLine(xx, rect.y, xx, rect.y + 16) 650 651 # Set the masking 652 pinBmp.SetMask(wx.Mask(pinBmp, wx.WHITE)) 653 654 # Draw the new bitmap 655 dc.DrawBitmap(pinBmp, xx, rect.y, True) 656 657 # Save the pin rect 658 self._pinBtnRect = rect
659 660 661 # ---------------------------------------------------------------------------- # 662 # Class ImageContainer 663 # ---------------------------------------------------------------------------- # 664
665 -class ImageContainer(ImageContainerBase):
666 """ 667 Base class for FlatImageBook image container. 668 """ 669
670 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 671 style=0, name="ImageContainer"):
672 """ 673 Default class constructor. 674 675 Parameters: 676 @param parent - parent window 677 @param id - Window id 678 @param pos - Window position 679 @param size - Window size 680 @param style - possible style INB_XXX 681 """ 682 683 ImageContainerBase.__init__(self, parent, id, pos, size, style, name) 684 685 self.Bind(wx.EVT_PAINT, self.OnPaint) 686 self.Bind(wx.EVT_SIZE, self.OnSize) 687 self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) 688 self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) 689 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) 690 self.Bind(wx.EVT_MOTION, self.OnMouseMove) 691 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeaveWindow)
692 693
694 - def OnSize(self, event):
695 """ Handles the wx.EVT_SIZE event for ImageContainer. """ 696 697 ImageContainerBase.OnSize(self, event) 698 event.Skip()
699 700
701 - def OnMouseLeftDown(self, event):
702 """ Handles the wx.EVT_LEFT_DOWN event for ImageContainer. """ 703 704 ImageContainerBase.OnMouseLeftDown(self, event) 705 event.Skip()
706 707
708 - def OnMouseLeftUp(self, event):
709 """ Handles the wx.EVT_LEFT_UP event for ImageContainer. """ 710 711 ImageContainerBase.OnMouseLeftUp(self, event) 712 event.Skip()
713 714
715 - def OnEraseBackground(self, event):
716 """ Handles the wx.EVT_ERASE_BACKGROUND event for ImageContainer. """ 717 718 ImageContainerBase.OnEraseBackground(self, event)
719 720
721 - def OnMouseMove(self, event):
722 """ Handles the wx.EVT_MOTION event for ImageContainer. """ 723 724 ImageContainerBase.OnMouseMove(self, event) 725 event.Skip()
726 727
728 - def OnMouseLeaveWindow(self, event):
729 """ Handles the wx.EVT_LEAVE_WINDOW event for ImageContainer. """ 730 731 ImageContainerBase.OnMouseLeaveWindow(self, event) 732 event.Skip()
733 734
735 - def CanDoBottomStyle(self):
736 """ 737 Allows the parent to examine the children type. Some implementation 738 (such as LabelBook), does not support top/bottom images, only left/right. 739 """ 740 741 return True
742 743
744 - def OnPaint(self, event):
745 """ Handles the wx.EVT_PAINT event for ImageContainer. """ 746 747 dc = wx.BufferedPaintDC(self) 748 style = self.GetParent().GetWindowStyleFlag() 749 750 backBrush = wx.WHITE_BRUSH 751 if style & INB_BORDER: 752 borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DSHADOW)) 753 else: 754 borderPen = wx.TRANSPARENT_PEN 755 756 size = self.GetSize() 757 758 # Background 759 dc.SetBrush(backBrush) 760 761 borderPen.SetWidth(1) 762 dc.SetPen(borderPen) 763 dc.DrawRectangle(0, 0, size.x, size.y) 764 bUsePin = (style & INB_USE_PIN_BUTTON and [True] or [False])[0] 765 766 if bUsePin: 767 768 # Draw the pin button 769 clientRect = self.GetClientRect() 770 pinRect = wx.Rect(clientRect.GetX() + clientRect.GetWidth() - 20, 2, 20, 20) 771 self.DrawPin(dc, pinRect, not self._bCollapsed) 772 773 if self._bCollapsed: 774 return 775 776 borderPen = wx.BLACK_PEN 777 borderPen.SetWidth(1) 778 dc.SetPen(borderPen) 779 dc.DrawLine(0, size.y, size.x, size.y) 780 dc.DrawPoint(0, size.y) 781 782 clientSize = 0 783 bUseYcoord = (style & INB_RIGHT or style & INB_LEFT) 784 785 if bUseYcoord: 786 clientSize = size.GetHeight() 787 else: 788 clientSize = size.GetWidth() 789 790 # We reserver 20 pixels for the 'pin' button 791 792 # The drawing of the images start position. This is 793 # depenedent of the style, especially when Pin button 794 # style is requested 795 796 if bUsePin: 797 if style & INB_TOP or style & INB_BOTTOM: 798 pos = (style & INB_BORDER and [0] or [1])[0] 799 else: 800 pos = (style & INB_BORDER and [20] or [21])[0] 801 else: 802 pos = (style & INB_BORDER and [0] or [1])[0] 803 804 nPadding = 4 # Pad text with 2 pixels on the left and right 805 nTextPaddingLeft = 2 806 807 count = 0 808 809 for i in xrange(len(self._pagesInfoVec)): 810 811 count = count + 1 812 813 # incase the 'fit button' style is applied, we set the rectangle width to the 814 # text width plus padding 815 # Incase the style IS applied, but the style is either LEFT or RIGHT 816 # we ignore it 817 normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) 818 dc.SetFont(normalFont) 819 820 textWidth, textHeight = dc.GetTextExtent(self._pagesInfoVec[i].GetCaption()) 821 822 # Restore font to be normal 823 normalFont.SetWeight(wx.FONTWEIGHT_NORMAL) 824 dc.SetFont(normalFont) 825 826 # Default values for the surronounding rectangle 827 # around a button 828 rectWidth = self._nImgSize * 2 # To avoid the recangle to 'touch' the borders 829 rectHeight = self._nImgSize * 2 830 831 # Incase the style requires non-fixed button (fit to text) 832 # recalc the rectangle width 833 if style & INB_FIT_BUTTON and \ 834 not ((style & INB_LEFT) or (style & INB_RIGHT)) and \ 835 not self._pagesInfoVec[i].GetCaption() == "" and \ 836 not (style & INB_SHOW_ONLY_IMAGES): 837 838 rectWidth = ((textWidth + nPadding * 2) > rectWidth and [nPadding * 2 + textWidth] or [rectWidth])[0] 839 840 # Make the width an even number 841 if rectWidth % 2 != 0: 842 rectWidth += 1 843 844 # Check that we have enough space to draw the button 845 # If Pin button is used, consider its space as well (applicable for top/botton style) 846 # since in the left/right, its size is already considered in 'pos' 847 pinBtnSize = (bUsePin and [20] or [0])[0] 848 849 if pos + rectWidth + pinBtnSize > clientSize: 850 break 851 852 # Calculate the button rectangle 853 modRectWidth = ((style & INB_LEFT or style & INB_RIGHT) and [rectWidth - 2] or [rectWidth])[0] 854 modRectHeight = ((style & INB_LEFT or style & INB_RIGHT) and [rectHeight] or [rectHeight - 2])[0] 855 856 if bUseYcoord: 857 buttonRect = wx.Rect(1, pos, modRectWidth, modRectHeight) 858 else: 859 buttonRect = wx.Rect(pos , 1, modRectWidth, modRectHeight) 860 861 # Check if we need to draw a rectangle around the button 862 if self._nIndex == i: 863 864 # Set the colors 865 penColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION) 866 brushColor = ArtManager.Get().LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION), 75) 867 868 dc.SetPen(wx.Pen(penColor)) 869 dc.SetBrush(wx.Brush(brushColor)) 870 871 # Fix the surrounding of the rect if border is set 872 if style & INB_BORDER: 873 874 if style & INB_TOP or style & INB_BOTTOM: 875 buttonRect = wx.Rect(buttonRect.x + 1, buttonRect.y, buttonRect.width - 1, buttonRect.height) 876 else: 877 buttonRect = wx.Rect(buttonRect.x, buttonRect.y + 1, buttonRect.width, buttonRect.height - 1) 878 879 dc.DrawRectangleRect(buttonRect) 880 881 if self._nHoeveredImgIdx == i: 882 883 # Set the colors 884 penColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION) 885 brushColor = ArtManager.Get().LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION), 90) 886 887 dc.SetPen(wx.Pen(penColor)) 888 dc.SetBrush(wx.Brush(brushColor)) 889 890 # Fix the surrounding of the rect if border is set 891 if style & INB_BORDER: 892 893 if style & INB_TOP or style & INB_BOTTOM: 894 buttonRect = wx.Rect(buttonRect.x + 1, buttonRect.y, buttonRect.width - 1, buttonRect.height) 895 else: 896 buttonRect = wx.Rect(buttonRect.x, buttonRect.y + 1, buttonRect.width, buttonRect.height - 1) 897 898 dc.DrawRectangleRect(buttonRect) 899 900 if bUseYcoord: 901 rect = wx.Rect(0, pos, rectWidth, rectWidth) 902 else: 903 rect = wx.Rect(pos, 0, rectWidth, rectWidth) 904 905 # Incase user set both flags: 906 # INB_SHOW_ONLY_TEXT and INB_SHOW_ONLY_IMAGES 907 # We override them to display both 908 909 if style & INB_SHOW_ONLY_TEXT and style & INB_SHOW_ONLY_IMAGES: 910 911 style ^= INB_SHOW_ONLY_TEXT 912 style ^= INB_SHOW_ONLY_IMAGES 913 wx.Panel.SetWindowStyleFlag(self, style) 914 915 # Draw the caption and text 916 imgTopPadding = 10 917 if not style & INB_SHOW_ONLY_TEXT and self._pagesInfoVec[i].GetImageIndex() != -1: 918 919 if bUseYcoord: 920 921 imgXcoord = self._nImgSize / 2 922 imgYcoord = (style & INB_SHOW_ONLY_IMAGES and [pos + self._nImgSize / 2] or [pos + imgTopPadding])[0] 923 924 else: 925 926 imgXcoord = pos + (rectWidth / 2) - (self._nImgSize / 2) 927 imgYcoord = (style & INB_SHOW_ONLY_IMAGES and [self._nImgSize / 2] or [imgTopPadding])[0] 928 929 self._ImageList.Draw(self._pagesInfoVec[i].GetImageIndex(), dc, 930 imgXcoord, imgYcoord, 931 wx.IMAGELIST_DRAW_TRANSPARENT, True) 932 933 # Draw the text 934 if not style & INB_SHOW_ONLY_IMAGES and not self._pagesInfoVec[i].GetCaption() == "": 935 936 dc.SetFont(normalFont) 937 938 # Check if the text can fit the size of the rectangle, 939 # if not truncate it 940 fixedText = self._pagesInfoVec[i].GetCaption() 941 if not style & INB_FIT_BUTTON or (style & INB_LEFT or (style & INB_RIGHT)): 942 943 fixedText = self.FixTextSize(dc, self._pagesInfoVec[i].GetCaption(), self._nImgSize *2 - 4) 944 945 # Update the length of the text 946 textWidth, textHeight = dc.GetTextExtent(fixedText) 947 948 if bUseYcoord: 949 950 textOffsetX = ((rectWidth - textWidth) / 2 ) 951 textOffsetY = (not style & INB_SHOW_ONLY_TEXT and [pos + self._nImgSize + imgTopPadding + 3] or \ 952 [pos + ((self._nImgSize * 2 - textHeight) / 2 )])[0] 953 954 else: 955 956 textOffsetX = (rectWidth - textWidth) / 2 + pos + nTextPaddingLeft 957 textOffsetY = (not style & INB_SHOW_ONLY_TEXT and [self._nImgSize + imgTopPadding + 3] or \ 958 [((self._nImgSize * 2 - textHeight) / 2 )])[0] 959 960 dc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)) 961 dc.DrawText(fixedText, textOffsetX, textOffsetY) 962 963 # Update the page info 964 self._pagesInfoVec[i].SetPosition(buttonRect.GetPosition()) 965 self._pagesInfoVec[i].SetSize(buttonRect.GetSize()) 966 967 pos += rectWidth 968 969 # Update all buttons that can not fit into the screen as non-visible 970 for ii in xrange(count, len(self._pagesInfoVec)): 971 self._pagesInfoVec[ii].SetPosition(wx.Point(-1, -1)) 972 973 # Draw the pin button 974 if bUsePin: 975 976 clientRect = self.GetClientRect() 977 pinRect = wx.Rect(clientRect.GetX() + clientRect.GetWidth() - 20, 2, 20, 20) 978 self.DrawPin(dc, pinRect, not self._bCollapsed)
979 980 981 # ---------------------------------------------------------------------------- # 982 # Class LabelContainer 983 # ---------------------------------------------------------------------------- # 984
985 -class LabelContainer(ImageContainerBase):
986 """ Base class for LabelBook. """ 987
988 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 989 style=0, name="LabelContainer"):
990 """ 991 Default class constructor. 992 993 Parameters: 994 @param parent - parent window 995 @param id - Window id 996 @param pos - Window position 997 @param size - Window size 998 @param style - possible style INB_XXX 999 """ 1000 1001 ImageContainerBase.__init__(self, parent, id, pos, size, style, name) 1002 self._nTabAreaWidth = 100 1003 self._oldCursor = wx.NullCursor 1004 self._colorsMap = {} 1005 self._skin = wx.NullBitmap 1006 self._sashRect = wx.Rect() 1007 1008 self.Bind(wx.EVT_PAINT, self.OnPaint) 1009 self.Bind(wx.EVT_SIZE, self.OnSize) 1010 self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) 1011 self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) 1012 self.Bind(wx.EVT_MOTION, self.OnMouseMove) 1013 self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeaveWindow) 1014 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
1015 1016
1017 - def OnSize(self, event):
1018 """ Handles the wx.EVT_SIZE event for LabelContainer. """ 1019 1020 ImageContainerBase.OnSize(self, event) 1021 event.Skip()
1022 1023
1024 - def OnEraseBackground(self, event):
1025 """ Handles the wx.EVT_ERASE_BACKGROUND event for LabelContainer. """ 1026 1027 ImageContainerBase.OnEraseBackground(self, event)
1028 1029
1030 - def GetTabAreaWidth(self):
1031 """ Returns the width of the tab area. """ 1032 1033 return self._nTabAreaWidth
1034 1035
1036 - def SetTabAreaWidth(self, width):
1037 """ Sets the width of the tab area. """ 1038 1039 self._nTabAreaWidth = width
1040 1041
1042 - def CanDoBottomStyle(self):
1043 """ 1044 Allows the parent to examine the children type. Some implementation 1045 (such as LabelBook), does not support top/bottom images, only left/right. 1046 """ 1047 1048 return False
1049 1050
1051 - def SetBackgroundBitmap(self, bmp):
1052 """ Sets the background bitmap for the control""" 1053 1054 self._skin = bmp
1055 1056
1057 - def OnPaint(self, event):
1058 """ Handles the wx.EVT_PAINT event for LabelContainer. """ 1059 1060 dc = wx.BufferedPaintDC(self) 1061 backBrush = wx.Brush(self._colorsMap[INB_TAB_AREA_BACKGROUND_COLOR]) 1062 if self.HasFlag(INB_BORDER): 1063 borderPen = wx.Pen(self._colorsMap[INB_TABS_BORDER_COLOR]) 1064 else: 1065 borderPen = wx.TRANSPARENT_PEN 1066 1067 size = self.GetSize() 1068 1069 # Set the pen & brush 1070 dc.SetBrush(backBrush) 1071 dc.SetPen(borderPen) 1072 1073 if self.HasFlag(INB_GRADIENT_BACKGROUND) and not self._skin.Ok(): 1074 1075 # Draw graident in the background area 1076 startColor = self._colorsMap[INB_TAB_AREA_BACKGROUND_COLOR] 1077 endColor = ArtManager.Get().LightColour(self._colorsMap[INB_TAB_AREA_BACKGROUND_COLOR], 50) 1078 ArtManager.Get().PaintStraightGradientBox(dc, wx.Rect(0, 0, size.x / 2, size.y), startColor, endColor, False) 1079 ArtManager.Get().PaintStraightGradientBox(dc, wx.Rect(size.x / 2, 0, size.x / 2, size.y), endColor, startColor, False) 1080 1081 else: 1082 1083 # Draw the border and background 1084 if self._skin.Ok(): 1085 1086 dc.SetBrush(wx.TRANSPARENT_BRUSH) 1087 self.DrawBackgroundBitmap(dc) 1088 1089 dc.DrawRectangleRect(wx.Rect(0, 0, size.x, size.y)) 1090 1091 # Draw border 1092 if self.HasFlag(INB_BORDER) and self.HasFlag(INB_GRADIENT_BACKGROUND): 1093 1094 # Just draw the border with transparent brush 1095 dc.SetBrush(wx.TRANSPARENT_BRUSH) 1096 dc.DrawRectangleRect(wx.Rect(0, 0, size.x, size.y)) 1097 1098 bUsePin = (self.HasFlag(INB_USE_PIN_BUTTON) and [True] or [False])[0] 1099 1100 if bUsePin: 1101 1102 # Draw the pin button 1103 clientRect = self.GetClientRect() 1104 pinRect = wx.Rect(clientRect.GetX() + clientRect.GetWidth() - 20, 2, 20, 20) 1105 self.DrawPin(dc, pinRect, not self._bCollapsed) 1106 1107 if self._bCollapsed: 1108 return 1109 1110 dc.SetPen(wx.BLACK_PEN) 1111 self.SetSizeHints(self._nTabAreaWidth, -1) 1112 1113 # We reserve 20 pixels for the pin button 1114 posy = 20 1115 count = 0 1116 1117 for i in xrange(len(self._pagesInfoVec)): 1118 count = count+1 1119 # Default values for the surronounding rectangle 1120 # around a button 1121 rectWidth = self._nTabAreaWidth 1122 rectHeight = self._nImgSize * 2 1123 1124 # Check that we have enough space to draw the button 1125 if posy + rectHeight > size.GetHeight(): 1126 break 1127 1128 # Calculate the button rectangle 1129 posx = 0 1130 1131 buttonRect = wx.Rect(posx, posy, rectWidth, rectHeight) 1132 indx = self._pagesInfoVec[i].GetImageIndex() 1133 1134 if indx == -1: 1135 bmp = wx.NullBitmap 1136 else: 1137 bmp = self._ImageList.GetBitmap(indx) 1138 1139 self.DrawLabel(dc, buttonRect, self._pagesInfoVec[i].GetCaption(), bmp, 1140 self._pagesInfoVec[i], self.HasFlag(INB_LEFT) or self.HasFlag(INB_TOP), 1141 i, self._nIndex == i, self._nHoeveredImgIdx == i) 1142 1143 posy += rectHeight 1144 1145 # Update all buttons that can not fit into the screen as non-visible 1146 for ii in xrange(count, len(self._pagesInfoVec)): 1147 self._pagesInfoVec[i].SetPosition(wx.Point(-1, -1)) 1148 1149 if bUsePin: 1150 1151 clientRect = self.GetClientRect() 1152 pinRect = wx.Rect(clientRect.GetX() + clientRect.GetWidth() - 20, 2, 20, 20) 1153 self.DrawPin(dc, pinRect, not self._bCollapsed)
1154 1155
1156 - def DrawBackgroundBitmap(self, dc):
1157 """ Draws a bitmap as the background of the control. """ 1158 1159 clientRect = self.GetClientRect() 1160 width = clientRect.GetWidth() 1161 height = clientRect.GetHeight() 1162 coveredY = coveredX = 0 1163 xstep = self._skin.GetWidth() 1164 ystep = self._skin.GetHeight() 1165 bmpRect = wx.Rect(0, 0, xstep, ystep) 1166 if bmpRect != clientRect: 1167 1168 mem_dc = wx.MemoryDC() 1169 bmp = wx.EmptyBitmap(width, height) 1170 mem_dc.SelectObject(bmp) 1171 1172 while coveredY < height: 1173 1174 while coveredX < width: 1175 1176 mem_dc.DrawBitmap(self._skin, coveredX, coveredY, True) 1177 coveredX += xstep 1178 1179 coveredX = 0 1180 coveredY += ystep 1181 1182 mem_dc.SelectObject(wx.NullBitmap) 1183 #self._skin = bmp 1184 dc.DrawBitmap(bmp, 0, 0) 1185 1186 else: 1187 1188 dc.DrawBitmap(self._skin, 0, 0)
1189 1190
1191 - def OnMouseLeftUp(self, event):
1192 """ Handles the wx.EVT_LEFT_UP event for LabelContainer. """ 1193 1194 if self.HasFlag(INB_NO_RESIZE): 1195 1196 ImageContainerBase.OnMouseLeftUp(self, event) 1197 return 1198 1199 if self.HasCapture(): 1200 self.ReleaseMouse() 1201 1202 # Sash was being dragged? 1203 if not self._sashRect.IsEmpty(): 1204 1205 # Remove sash 1206 ArtManager.Get().DrawDragSash(self._sashRect) 1207 self.Resize(event) 1208 1209 self._sashRect = wx.Rect() 1210 return 1211 1212 self._sashRect = wx.Rect() 1213 1214 # Restore cursor 1215 if self._oldCursor.Ok(): 1216 1217 wx.SetCursor(self._oldCursor) 1218 self._oldCursor = wx.NullCursor 1219 1220 ImageContainerBase.OnMouseLeftUp(self, event)
1221 1222
1223 - def Resize(self, event):
1224 """ Actually resizes the tab area. """ 1225 1226 # Resize our size 1227 self._tabAreaSize = self.GetSize() 1228 newWidth = self._tabAreaSize.x 1229 x = event.GetX() 1230 1231 if self.HasFlag(INB_BOTTOM) or self.HasFlag(INB_RIGHT): 1232 1233 newWidth -= event.GetX() 1234 1235 else: 1236 1237 newWidth = x 1238 1239 if newWidth < 100: # Dont allow width to be lower than that 1240 newWidth = 100 1241 1242 self.SetSizeHints(newWidth, self._tabAreaSize.y) 1243 1244 # Update the tab new area width 1245 self._nTabAreaWidth = newWidth 1246 self.GetParent().Freeze() 1247 self.GetParent().GetSizer().Layout() 1248 self.GetParent().Thaw()
1249 1250
1251 - def OnMouseMove(self, event):
1252 """ Handles the wx.EVT_MOTION event for LabelContainer. """ 1253 1254 if self.HasFlag(INB_NO_RESIZE): 1255 1256 ImageContainerBase.OnMouseMove(self, event) 1257 return 1258 1259 # Remove old sash 1260 if not self._sashRect.IsEmpty(): 1261 ArtManager.Get().DrawDragSash(self._sashRect) 1262 1263 if event.LeftIsDown(): 1264 1265 if not self._sashRect.IsEmpty(): 1266 1267 # Progress sash, and redraw it 1268 clientRect = self.GetClientRect() 1269 pt = self.ClientToScreen(wx.Point(event.GetX(), 0)) 1270 self._sashRect = wx.RectPS(pt, wx.Size(4, clientRect.height)) 1271 ArtManager.Get().DrawDragSash(self._sashRect) 1272 1273 else: 1274 1275 # Sash is not being dragged 1276 if self._oldCursor.Ok(): 1277 wx.SetCursor(self._oldCursor) 1278 self._oldCursor = wx.NullCursor 1279 1280 else: 1281 1282 if self.HasCapture(): 1283 self.ReleaseMouse() 1284 1285 if self.PointOnSash(event.GetPosition()): 1286 1287 # Change cursor to EW cursor 1288 self._oldCursor = self.GetCursor() 1289 wx.SetCursor(wx.StockCursor(wx.CURSOR_SIZEWE)) 1290 1291 elif self._oldCursor.Ok(): 1292 1293 wx.SetCursor(self._oldCursor) 1294 self._oldCursor = wx.NullCursor 1295 1296 self._sashRect = wx.Rect() 1297 ImageContainerBase.OnMouseMove(self, event)
1298 1299
1300 - def OnMouseLeftDown(self, event):
1301 """ Handles the wx.EVT_LEFT_DOWN event for LabelContainer. """ 1302 1303 if self.HasFlag(INB_NO_RESIZE): 1304 1305 ImageContainerBase.OnMouseLeftDown(self, event) 1306 return 1307 1308 imgIdx, where = self.HitTest(event.GetPosition()) 1309 1310 if IMG_OVER_EW_BORDER == where and not self._bCollapsed: 1311 1312 # We are over the sash 1313 if not self._sashRect.IsEmpty(): 1314 ArtManager.Get().DrawDragSash(self._sashRect) 1315 else: 1316 # first time, begin drawing sash 1317 self.CaptureMouse() 1318 1319 # Change mouse cursor 1320 self._oldCursor = self.GetCursor() 1321 wx.SetCursor(wx.StockCursor(wx.CURSOR_SIZEWE)) 1322 1323 clientRect = self.GetClientRect() 1324 pt = self.ClientToScreen(wx.Point(event.GetX(), 0)) 1325 self._sashRect = wx.RectPS(pt, wx.Size(4, clientRect.height)) 1326 1327 ArtManager.Get().DrawDragSash(self._sashRect) 1328 1329 else: 1330 ImageContainerBase.OnMouseLeftDown(self, event)
1331 1332
1333 - def OnMouseLeaveWindow(self, event):
1334 """ Handles the wx.EVT_LEAVE_WINDOW event for LabelContainer. """ 1335 1336 if self.HasFlag(INB_NO_RESIZE): 1337 1338 ImageContainerBase.OnMouseLeaveWindow(self, event) 1339 return 1340 1341 # If Sash is being dragged, ignore this event 1342 if not self.HasCapture(): 1343 ImageContainerBase.OnMouseLeaveWindow(self, event)
1344 1345
1346 - def DrawRegularHover(self, dc, rect):
1347 """ Draws a rounded rectangle around the current tab. """ 1348 1349 # The hovered tab with default border 1350 dc.SetBrush(wx.TRANSPARENT_BRUSH) 1351 dc.SetPen(wx.Pen(wx.WHITE)) 1352 1353 # We draw CCW 1354 if self.HasFlag(INB_RIGHT) or self.HasFlag(INB_TOP): 1355 1356 # Right images 1357 # Upper line 1358 dc.DrawLine(rect.x + 1, rect.y, rect.x + rect.width, rect.y) 1359 1360 # Right line (white) 1361 dc.DrawLine(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height) 1362 1363 # Bottom diagnol - we change pen 1364 dc.SetPen(wx.Pen(self._colorsMap[INB_TABS_BORDER_COLOR])) 1365 1366 # Bottom line 1367 dc.DrawLine(rect.x + rect.width, rect.y + rect.height, rect.x, rect.y + rect.height) 1368 1369 else: 1370 1371 # Left images 1372 # Upper line white 1373 dc.DrawLine(rect.x, rect.y, rect.x + rect.width - 1, rect.y) 1374 1375 # Left line 1376 dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height) 1377 1378 # Bottom diagnol, we change the pen 1379 dc.SetPen(wx.Pen(self._colorsMap[INB_TABS_BORDER_COLOR])) 1380 1381 # Bottom line 1382 dc.DrawLine(rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height)
1383 1384
1385 - def DrawWebHover(self, dc, caption, xCoord, yCoord):
1386 """ Draws a web style hover effect (cursor set to hand & text is underlined). """ 1387 1388 # Redraw the text with underlined font 1389 underLinedFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) 1390 underLinedFont.SetUnderlined(True) 1391 dc.SetFont(underLinedFont) 1392 dc.DrawText(caption, xCoord, yCoord)
1393 1394
1395 - def SetColour(self, which, color):
1396 """ Sets a colour for a parameter. """ 1397 1398 self._colorsMap[which] = color
1399 1400
1401 - def GetColour(self, which):
1402 """ Returns a colour for a parameter. """ 1403 1404 if not self._colorsMap.has_key(which): 1405 return wx.Colour() 1406 1407 return self._colorsMap[which]
1408 1409
1410 - def InitializeColors(self):
1411 """ Initializes the colors map to be used for this control. """ 1412 1413 # Initialize map colors 1414 self._colorsMap.update({INB_TAB_AREA_BACKGROUND_COLOR: ArtManager.Get().LightColour(ArtManager.Get().FrameColour(), 50)}) 1415 self._colorsMap.update({INB_ACTIVE_TAB_COLOR: ArtManager.Get().GetMenuFaceColour()}) 1416 self._colorsMap.update({INB_TABS_BORDER_COLOR: wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DSHADOW)}) 1417 self._colorsMap.update({INB_HILITE_TAB_COLOR: wx.NamedColor("LIGHT BLUE")}) 1418 self._colorsMap.update({INB_TEXT_COLOR: wx.WHITE}) 1419 self._colorsMap.update({INB_ACTIVE_TEXT_COLOR: wx.BLACK}) 1420 1421 # dont allow bright colour one on the other 1422 if not ArtManager.Get().IsDark(self._colorsMap[INB_TAB_AREA_BACKGROUND_COLOR]) and \ 1423 not ArtManager.Get().IsDark(self._colorsMap[INB_TEXT_COLOR]): 1424 1425 self._colorsMap[INB_TEXT_COLOR] = ArtManager.Get().DarkColour(self._colorsMap[INB_TEXT_COLOR], 100)
1426 1427
1428 - def DrawLabel(self, dc, rect, text, bmp, imgInfo, orientationLeft, imgIdx, selected, hover):
1429 """ Draws label using the specified dc. """ 1430 1431 dcsaver = DCSaver(dc) 1432 nPadding = 6 1433 1434 if orientationLeft: 1435 1436 rect.x += nPadding 1437 rect.width -= nPadding 1438 1439 else: 1440 1441 rect.width -= nPadding 1442 1443 textRect = wx.Rect(*rect) 1444 imgRect = wx.Rect(*rect) 1445 1446 dc.SetFont(wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)) 1447 1448 # First we define the rectangle for the text 1449 w, h = dc.GetTextExtent(text) 1450 1451 #------------------------------------------------------------------------- 1452 # Label layout: 1453 # [ nPadding | Image | nPadding | Text | nPadding ] 1454 #------------------------------------------------------------------------- 1455 1456 # Text bounding rectangle 1457 textRect.x += nPadding 1458 textRect.y = rect.y + (rect.height - h)/2 1459 textRect.width = rect.width - 2 * nPadding 1460 1461 if bmp.Ok(): 1462 textRect.x += (bmp.GetWidth() + nPadding) 1463 textRect.width -= (bmp.GetWidth() + nPadding) 1464 1465 textRect.height = h 1466 1467 # Truncate text if needed 1468 caption = ArtManager.Get().TruncateText(dc, text, textRect.width) 1469 1470 # Image bounding rectangle 1471 if bmp.Ok(): 1472 1473 imgRect.x += nPadding 1474 imgRect.width = bmp.GetWidth() 1475 imgRect.y = rect.y + (rect.height - bmp.GetHeight())/2 1476 imgRect.height = bmp.GetHeight() 1477 1478 # Draw bounding rectangle 1479 if selected: 1480 1481 # First we colour the tab 1482 dc.SetBrush(wx.Brush(self._colorsMap[INB_ACTIVE_TAB_COLOR])) 1483 1484 if self.HasFlag(INB_BORDER): 1485 dc.SetPen(wx.Pen(self._colorsMap[INB_TABS_BORDER_COLOR])) 1486 else: 1487 dc.SetPen(wx.Pen(self._colorsMap[INB_ACTIVE_TAB_COLOR])) 1488 1489 labelRect = wx.Rect(*rect) 1490 1491 if orientationLeft: 1492 labelRect.width += 3 1493 else: 1494 labelRect.width += 3 1495 labelRect.x -= 3 1496 1497 dc.DrawRoundedRectangleRect(labelRect, 3) 1498 1499 if not orientationLeft and self.HasFlag(INB_DRAW_SHADOW): 1500 dc.SetPen(wx.BLACK_PEN) 1501 dc.DrawPoint(labelRect.x + labelRect.width - 1, labelRect.y + labelRect.height - 1) 1502 1503 # Draw the text & bitmap 1504 if caption != "": 1505 1506 if selected: 1507 dc.SetTextForeground(self._colorsMap[INB_ACTIVE_TEXT_COLOR]) 1508 else: 1509 dc.SetTextForeground(self._colorsMap[INB_TEXT_COLOR]) 1510 1511 dc.DrawText(caption, textRect.x, textRect.y) 1512 imgInfo.SetTextRect(textRect) 1513 1514 else: 1515 1516 imgInfo.SetTextRect(wx.Rect()) 1517 1518 if bmp.Ok(): 1519 dc.DrawBitmap(bmp, imgRect.x, imgRect.y, True) 1520 1521 # Drop shadow 1522 if self.HasFlag(INB_DRAW_SHADOW) and selected: 1523 1524 sstyle = 0 1525 if orientationLeft: 1526 sstyle = BottomShadow 1527 else: 1528 sstyle = BottomShadowFull | RightShadow 1529 1530 if self.HasFlag(INB_WEB_HILITE): 1531 1532 # Always drop shadow for this style 1533 ArtManager.Get().DrawBitmapShadow(dc, rect, sstyle) 1534 1535 else: 1536 1537 if imgIdx+1 != self._nHoeveredImgIdx: 1538 1539 ArtManager.Get().DrawBitmapShadow(dc, rect, sstyle) 1540 1541 # Draw hover effect 1542 if hover: 1543 1544 if self.HasFlag(INB_WEB_HILITE) and caption != "": 1545 self.DrawWebHover(dc, caption, textRect.x, textRect.y) 1546 else: 1547 self.DrawRegularHover(dc, rect) 1548 1549 # Update the page information bout position and size 1550 imgInfo.SetPosition(rect.GetPosition()) 1551 imgInfo.SetSize(rect.GetSize())
1552 1553 1554 # ---------------------------------------------------------------------------- # 1555 # Class FlatBookBase 1556 # ---------------------------------------------------------------------------- # 1557
1558 -class FlatBookBase(wx.Panel):
1559 """ Base class for the containing window for LabelBook and FlatImageBook. """ 1560
1561 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 1562 style=0, name="FlatBookBase"):
1563 """ 1564 Default class constructor. 1565 1566 Parameters: 1567 @param parent - parent window 1568 @param id - Window id 1569 @param pos - Window position 1570 @param size - Window size 1571 @param style - possible style INB_XXX 1572 """ 1573 1574 self._pages = None 1575 self._bInitializing = True 1576 self._pages = None 1577 self._bForceSelection = False 1578 self._windows = [] 1579 1580 style |= wx.TAB_TRAVERSAL 1581 wx.Panel.__init__(self, parent, id, pos, size, style, name) 1582 self._bInitializing = False
1583 1584
1585 - def SetWindowStyleFlag(self, style):
1586 """ Sets the window style. """ 1587 1588 wx.Panel.SetWindowStyleFlag(self, style) 1589 1590 # Check that we are not in initialization process 1591 if self._bInitializing: 1592 return 1593 1594 if not self._pages: 1595 return 1596 1597 # Detach the windows attached to the sizer 1598 if self.GetSelection() >= 0: 1599 self._mainSizer.Detach(self._windows[self.GetSelection()]) 1600 1601 self._mainSizer.Detach(self._pages) 1602 1603 # Create new sizer with the requested orientaion 1604 className = self.GetName() 1605 1606 if className == "LabelBook": 1607 self._mainSizer = wx.BoxSizer(wx.HORIZONTAL) 1608 else: 1609 if style & INB_LEFT or style & INB_RIGHT: 1610 self._mainSizer = wx.BoxSizer(wx.HORIZONTAL) 1611 else: 1612 self._mainSizer = wx.BoxSizer(wx.VERTICAL) 1613 1614 self.SetSizer(self._mainSizer) 1615 1616 # Add the tab container and the separator 1617 self._mainSizer.Add(self._pages, 0, wx.EXPAND) 1618 1619 if className == "FlatImageBook": 1620 1621 if style & INB_LEFT or style & INB_RIGHT: 1622 self._pages.SetSizeHints(self._pages._nImgSize * 2, -1) 1623 else: 1624 self._pages.SetSizeHints(-1, self._pages._nImgSize * 2) 1625 1626 # Attach the windows back to the sizer to the sizer 1627 if self.GetSelection() >= 0: 1628 self.DoSetSelection(self._windows[self.GetSelection()]) 1629 1630 self._mainSizer.Layout() 1631 dummy = wx.SizeEvent() 1632 wx.PostEvent(self, dummy) 1633 self._pages.Refresh()
1634 1635
1636 - def AddPage(self, page, text, select=True, imageId=-1):
1637 """ 1638 Adds a page to the book. 1639 The call to this function generates the page changing events 1640 """ 1641 1642 if not page: 1643 return 1644 1645 page.Reparent(self) 1646 1647 self._windows.append(page) 1648 1649 if select or len(self._windows) == 1: 1650 self.DoSetSelection(page) 1651 else: 1652 page.Hide() 1653 1654 self._pages.AddPage(text, select, imageId) 1655 self.Refresh()
1656 1657
1658 - def DeletePage(self, page):
1659 """ 1660 Deletes the specified page, and the associated window. 1661 The call to this function generates the page changing events. 1662 """ 1663 1664 if page >= len(self._windows) or page < 0: 1665 return 1666 1667 # Fire a closing event 1668 event = ImageNotebookEvent(wxEVT_IMAGENOTEBOOK_PAGE_CLOSING, self.GetId()) 1669 event.SetSelection(page) 1670 event.SetEventObject(self) 1671 self.GetEventHandler().ProcessEvent(event) 1672 1673 # The event handler allows it? 1674 if not event.IsAllowed(): 1675 return 1676 1677 self.Freeze() 1678 1679 # Delete the requested page 1680 pageRemoved = self._windows[page] 1681 1682 # If the page is the current window, remove it from the sizer 1683 # as well 1684 if page == self.GetSelection(): 1685 self._mainSizer.Detach(pageRemoved) 1686 1687 # Remove it from the array as well 1688 self._windows.pop(page) 1689 1690 # Now we can destroy it in wxWidgets use Destroy instead of delete 1691 pageRemoved.Destroy() 1692 self._mainSizer.Layout() 1693 1694 self.Thaw() 1695 1696 self._pages.DoDeletePage(page) 1697 self.Refresh() 1698 1699 # Fire a closed event 1700 closedEvent = ImageNotebookEvent(wxEVT_IMAGENOTEBOOK_PAGE_CLOSED, self.GetId()) 1701 closedEvent.SetSelection(page) 1702 closedEvent.SetEventObject(self) 1703 self.GetEventHandler().ProcessEvent(closedEvent)
1704 1705
1706 - def DeleteAllPages(self):
1707 """ Deletes all the pages in the book. """ 1708 1709 if not self._windows: 1710 return 1711 1712 self.Freeze() 1713 1714 for win in self._windows: 1715 win.Destroy() 1716 1717 self._windows = [] 1718 self.Thaw() 1719 1720 # remove old selection 1721 self._pages.ClearAll() 1722 self._pages.Refresh()
1723 1724
1725 - def SetSelection(self, page):
1726 """ 1727 Changes the selection from currently visible/selected page to the page 1728 given by page. 1729 """ 1730 1731 if page >= len(self._windows): 1732 return 1733 1734 if page == self.GetSelection() and not self._bForceSelection: 1735 return 1736 1737 oldSelection = self.GetSelection() 1738 1739 # Generate an event that indicates that an image is about to be selected 1740 event = ImageNotebookEvent(wxEVT_IMAGENOTEBOOK_PAGE_CHANGING, self.GetId()) 1741 event.SetSelection(page) 1742 event.SetOldSelection(oldSelection) 1743 event.SetEventObject(self) 1744 self.GetEventHandler().ProcessEvent(event) 1745 1746 # The event handler allows it? 1747 if not event.IsAllowed() and not self._bForceSelection: 1748 return 1749 1750 self.DoSetSelection(self._windows[page]) 1751 # Now we can update the new selection 1752 self._pages._nIndex = page 1753 1754 # Refresh calls the OnPaint of this class 1755 self._pages.Refresh() 1756 1757 # Generate an event that indicates that an image was selected 1758 eventChanged = ImageNotebookEvent(wxEVT_IMAGENOTEBOOK_PAGE_CHANGED, self.GetId()) 1759 eventChanged.SetEventObject(self) 1760 eventChanged.SetOldSelection(oldSelection) 1761 eventChanged.SetSelection(page) 1762 self.GetEventHandler().ProcessEvent(eventChanged)
1763 1764
1765 - def AssignImageList(self, imglist):
1766 """ Assigns an image list to the control. """ 1767 1768 self._pages.AssignImageList(imglist) 1769 1770 # Force change 1771 self.SetWindowStyleFlag(self.GetWindowStyleFlag())
1772 1773
1774 - def GetSelection(self):
1775 """ Returns the current selection. """ 1776 1777 if self._pages: 1778 return self._pages._nIndex 1779 else: 1780 return -1
1781 1782
1783 - def DoSetSelection(self, window):
1784 """ Select the window by the provided pointer. """ 1785 1786 curSel = self.GetSelection() 1787 style = self.GetWindowStyleFlag() 1788 # Replace the window in the sizer 1789 self.Freeze() 1790 1791 # Check if a new selection was made 1792 bInsertFirst = (style & INB_BOTTOM or style & INB_RIGHT) 1793 1794 if curSel >= 0: 1795 1796 # Remove the window from the main sizer 1797 self._mainSizer.Detach(self._windows[curSel]) 1798 self._windows[curSel].Hide() 1799 1800 if bInsertFirst: 1801 self._mainSizer.Insert(0, window, 1, wx.EXPAND) 1802 else: 1803 self._mainSizer.Add(window, 1, wx.EXPAND) 1804 1805 window.Show() 1806 self._mainSizer.Layout() 1807 self.Thaw()
1808 1809
1810 - def GetImageList(self):
1811 """ Returns the associated image list. """ 1812 1813 return self._pages.GetImageList()
1814 1815
1816 - def GetPageCount(self):
1817 """ Returns the number of pages in the book. """ 1818 1819 return len(self._windows)
1820 1821 1822 # ---------------------------------------------------------------------------- # 1823 # Class FlatImageBook 1824 # ---------------------------------------------------------------------------- # 1825
1826 -class FlatImageBook(FlatBookBase):
1827 """ 1828 Default implementation of the image book, it is like a wx.Notebook, except that 1829 images are used to control the different pages. This container is usually used 1830 for configuration dialogs etc. 1831 Currently, this control works properly for images of 32x32 and bigger. 1832 """ 1833
1834 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 1835 style=0, name="FlatImageBook"):
1836 """ 1837 Default class constructor. 1838 1839 Parameters: 1840 @param parent - parent window 1841 @param id - Window id 1842 @param pos - Window position 1843 @param size - Window size 1844 @param style - possible style INB_XXX 1845 """ 1846 1847 FlatBookBase.__init__(self, parent, id, pos, size, style, name) 1848 1849 self._pages = self.CreateImageContainer() 1850 1851 if style & INB_LEFT or style & INB_RIGHT: 1852 self._mainSizer = wx.BoxSizer(wx.HORIZONTAL) 1853 else: 1854 self._mainSizer = wx.BoxSizer(wx.VERTICAL) 1855 1856 self.SetSizer(self._mainSizer) 1857 1858 # Add the tab container to the sizer 1859 self._mainSizer.Add(self._pages, 0, wx.EXPAND) 1860 1861 if style & INB_LEFT or style & INB_RIGHT: 1862 self._pages.SetSizeHints(self._pages.GetImageSize() * 2, -1) 1863 else: 1864 self._pages.SetSizeHints(-1, self._pages.GetImageSize() * 2) 1865 1866 self._mainSizer.Layout()
1867 1868
1869 - def CreateImageContainer(self):
1870 1871 return ImageContainer(self, wx.ID_ANY)
1872 1873 1874 # ---------------------------------------------------------------------------- # 1875 # Class LabelBook 1876 # ---------------------------------------------------------------------------- # 1877
1878 -class LabelBook(FlatBookBase):
1879 """ 1880 An implementation of a notebook control - except that instead of having 1881 tabs to show labels, it labels to the right or left (arranged horozontally). 1882 """
1883 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, 1884 style=0, name="LabelBook"):
1885 """ 1886 Default class constructor. 1887 1888 Parameters: 1889 @param parent - parent window 1890 @param id - Window id 1891 @param pos - Window position 1892 @param size - Window size 1893 @param style - possible style INB_XXX 1894 """ 1895 1896 FlatBookBase.__init__(self, parent, id, pos, size, style, name) 1897 1898 self._pages = self.CreateImageContainer() 1899 1900 # Label book specific initialization 1901 self._mainSizer = wx.BoxSizer(wx.HORIZONTAL) 1902 self.SetSizer(self._mainSizer) 1903 1904 # Add the tab container to the sizer 1905 self._mainSizer.Add(self._pages, 0, wx.EXPAND) 1906 self._pages.SetSizeHints(self._pages.GetTabAreaWidth(), -1) 1907 1908 # Initialize the colors maps 1909 self._pages.InitializeColors() 1910 1911 self.Bind(wx.EVT_SIZE, self.OnSize)
1912 1913
1914 - def CreateImageContainer(self):
1915 """ Creates the image container (LabelContainer). """ 1916 1917 return LabelContainer(self, wx.ID_ANY)
1918 1919
1920 - def SetColour(self, which, color):
1921 """ Sets the colour for the specified parameter. """ 1922 1923 self._pages.SetColour(which, color)
1924 1925
1926 - def GetColour(self, which):
1927 """ Returns the colour for the specified parameter. """ 1928 1929 return self._pages.GetColour(which)
1930 1931
1932 - def OnSize(self, event):
1933 """ Handles the wx.EVT_SIZE for LabelBook. """ 1934 1935 self._pages.Refresh() 1936 event.Skip()
1937