controls/CustomToolTip.py
changeset 1169 53e4a2b775a7
parent 1166 2ed9675be08d
child 1170 074e46cdedbc
equal deleted inserted replaced
1168:7838595559ba 1169:53e4a2b775a7
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     5 #based on the plcopen standard. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 import wx
       
    26 
       
    27 from controls.CustomStyledTextCtrl import faces
       
    28 
       
    29 TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip
       
    30 TOOLTIP_MAX_LINE = 5        # Maximum number of line in ToolTip
       
    31 TOOLTIP_WAIT_PERIOD = 0.5   # Wait period before displaying tooltip in second
       
    32 
       
    33 #-------------------------------------------------------------------------------
       
    34 #                               Custom ToolTip
       
    35 #-------------------------------------------------------------------------------
       
    36 
       
    37 """
       
    38 Class that implements a custom tool tip
       
    39 """
       
    40 
       
    41 class CustomToolTip(wx.PopupWindow):
       
    42     
       
    43     def __init__(self, parent, tip, restricted=True):
       
    44         """
       
    45         Constructor
       
    46         @param parent: Parent window
       
    47         @param tip: Tip text (may be multiline)
       
    48         @param restricted: Tool tip must follow size restriction in line and 
       
    49             characters number defined (default True)
       
    50         """
       
    51         wx.PopupWindow.__init__(self, parent)
       
    52         
       
    53         self.CurrentPosition = wx.Point(0, 0)
       
    54         self.Restricted = restricted
       
    55         
       
    56         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
       
    57         self.SetTip(tip)
       
    58         
       
    59         # Initialize text font style
       
    60         self.Font = wx.Font(
       
    61             faces["size"], 
       
    62             wx.SWISS, 
       
    63             wx.NORMAL, 
       
    64             wx.NORMAL, 
       
    65             faceName = faces["mono"])
       
    66         
       
    67         self.Bind(wx.EVT_PAINT, self.OnPaint)
       
    68     
       
    69     def SetFont(self, font):
       
    70         """
       
    71         Set tool tip text font style
       
    72         @param font: wx.Font object containing font style
       
    73         """
       
    74         self.Font = font
       
    75         self.RefreshTip()
       
    76     
       
    77     def SetTip(self, tip):
       
    78         """
       
    79         Set tool tip text
       
    80         @param tip: Tool tip text
       
    81         """
       
    82         if self.Restricted:
       
    83             # Compute tip text line return
       
    84             self.Tip = []
       
    85             for line in tip.splitlines():
       
    86                 if line != "":
       
    87                     words = line.split()
       
    88                     new_line = words[0]
       
    89                     for word in words[1:]:
       
    90                         # Add word to line
       
    91                         if len(new_line + " " + word) <= \
       
    92                             TOOLTIP_MAX_CHARACTERS:
       
    93                             new_line += " " + word
       
    94                         # Create new line
       
    95                         else:
       
    96                             self.Tip.append(new_line)
       
    97                             new_line = word
       
    98                     self.Tip.append(new_line)
       
    99                 else:
       
   100                     self.Tip.append(line)
       
   101             
       
   102             # Restrict number of lines
       
   103             if len(self.Tip) > TOOLTIP_MAX_LINE:
       
   104                 self.Tip = self.Tip[:TOOLTIP_MAX_LINE]
       
   105                 
       
   106                 # Add ... to the end of last line to indicate that tool tip
       
   107                 # text is too long
       
   108                 if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3:
       
   109                     self.Tip[-1] += "..."
       
   110                 else:
       
   111                     self.Tip[-1] = self.Tip[-1]\
       
   112                         [:TOOLTIP_MAX_CHARACTERS - 3] + "..."
       
   113         else:
       
   114             self.Tip = tip.splitlines()
       
   115         
       
   116         # Prevent to call wx method in non-wx threads
       
   117         wx.CallAfter(self.RefreshTip)
       
   118     
       
   119     def MoveToolTip(self, pos):
       
   120         """
       
   121         Move tool tip
       
   122         @param pos: New tool tip position
       
   123         """
       
   124         # Get screen size to prevent tool tip to go out of the screen
       
   125         screen_width, screen_height = wx.GetDisplaySize()
       
   126         
       
   127         # Calculate position of tool tip to stay in screen limits
       
   128         tip_width, tip_height = self.GetToolTipSize()
       
   129         self.CurrentPosition = wx.Point(
       
   130             max(0, min(pos.x, screen_width - tip_width)),
       
   131             max(0, min(pos.y, screen_height - tip_height))) 
       
   132         
       
   133         self.SetPosition(pos)
       
   134     
       
   135     def GetToolTipSize(self):
       
   136         """
       
   137         Get tool tip size according to tip text and restriction
       
   138         @return: wx.Size(tool_tip_width, tool_tip_height)
       
   139         """
       
   140         max_width = max_height = 0
       
   141         
       
   142         # Create a memory DC for calculating text extent
       
   143         dc = wx.MemoryDC()
       
   144         dc.SetFont(self.Font)
       
   145         
       
   146         # Compute max tip text size
       
   147         for line in self.Tip:
       
   148             w, h = dc.GetTextExtent(line)
       
   149             max_width = max(max_width, w)
       
   150             max_height += h
       
   151         
       
   152         return wx.Size(max_width + 4, max_height + 4)
       
   153     
       
   154     def RefreshTip(self):
       
   155         """
       
   156         Refresh tip on screen
       
   157         """
       
   158         # Prevent to call this function if tool tip destroyed
       
   159         if self:
       
   160             # Refresh tool tip size and position
       
   161             self.SetSize(self.GetToolTipSize())
       
   162             self.SetPosition(self.CurrentPosition)
       
   163             
       
   164             # Redraw tool tip
       
   165             self.Refresh()
       
   166     
       
   167     def OnPaint(self, event):
       
   168         """
       
   169         Callback for Paint Event
       
   170         @param event: Paint event
       
   171         """
       
   172         # Get buffered paint DC for tool tip
       
   173         dc = wx.AutoBufferedPaintDC(self)
       
   174         dc.Clear()
       
   175         
       
   176         # Set DC drawing style
       
   177         pen = wx.Pen(wx.BLACK)
       
   178         pen.SetJoin(wx.JOIN_MITER)
       
   179         pen.SetCap(wx.CAP_PROJECTING)
       
   180         dc.SetPen(pen)
       
   181         dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170)))
       
   182         dc.SetFont(self.Font)
       
   183         
       
   184         # Draw Tool tip
       
   185         dc.BeginDrawing()
       
   186         tip_width, tip_height = self.GetToolTipSize()
       
   187         
       
   188         # Draw background rectangle
       
   189         dc.DrawRectangle(0, 0, tip_width, tip_height)
       
   190         
       
   191         # Draw tool tip text
       
   192         line_offset = 0
       
   193         for line in self.Tip:
       
   194             dc.DrawText(line, 2, line_offset + 2)
       
   195             line_width, line_height = dc.GetTextExtent(line)
       
   196             line_offset += line_height
       
   197         
       
   198         dc.EndDrawing()
       
   199         
       
   200         event.Skip()