diff -r 7838595559ba -r 53e4a2b775a7 controls/CustomToolTip.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/CustomToolTip.py Thu May 23 18:47:44 2013 +0200 @@ -0,0 +1,200 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +from controls.CustomStyledTextCtrl import faces + +TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip +TOOLTIP_MAX_LINE = 5 # Maximum number of line in ToolTip +TOOLTIP_WAIT_PERIOD = 0.5 # Wait period before displaying tooltip in second + +#------------------------------------------------------------------------------- +# Custom ToolTip +#------------------------------------------------------------------------------- + +""" +Class that implements a custom tool tip +""" + +class CustomToolTip(wx.PopupWindow): + + def __init__(self, parent, tip, restricted=True): + """ + Constructor + @param parent: Parent window + @param tip: Tip text (may be multiline) + @param restricted: Tool tip must follow size restriction in line and + characters number defined (default True) + """ + wx.PopupWindow.__init__(self, parent) + + self.CurrentPosition = wx.Point(0, 0) + self.Restricted = restricted + + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + self.SetTip(tip) + + # Initialize text font style + self.Font = wx.Font( + faces["size"], + wx.SWISS, + wx.NORMAL, + wx.NORMAL, + faceName = faces["mono"]) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def SetFont(self, font): + """ + Set tool tip text font style + @param font: wx.Font object containing font style + """ + self.Font = font + self.RefreshTip() + + def SetTip(self, tip): + """ + Set tool tip text + @param tip: Tool tip text + """ + if self.Restricted: + # Compute tip text line return + self.Tip = [] + for line in tip.splitlines(): + if line != "": + words = line.split() + new_line = words[0] + for word in words[1:]: + # Add word to line + if len(new_line + " " + word) <= \ + TOOLTIP_MAX_CHARACTERS: + new_line += " " + word + # Create new line + else: + self.Tip.append(new_line) + new_line = word + self.Tip.append(new_line) + else: + self.Tip.append(line) + + # Restrict number of lines + if len(self.Tip) > TOOLTIP_MAX_LINE: + self.Tip = self.Tip[:TOOLTIP_MAX_LINE] + + # Add ... to the end of last line to indicate that tool tip + # text is too long + if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3: + self.Tip[-1] += "..." + else: + self.Tip[-1] = self.Tip[-1]\ + [:TOOLTIP_MAX_CHARACTERS - 3] + "..." + else: + self.Tip = tip.splitlines() + + # Prevent to call wx method in non-wx threads + wx.CallAfter(self.RefreshTip) + + def MoveToolTip(self, pos): + """ + Move tool tip + @param pos: New tool tip position + """ + # Get screen size to prevent tool tip to go out of the screen + screen_width, screen_height = wx.GetDisplaySize() + + # Calculate position of tool tip to stay in screen limits + tip_width, tip_height = self.GetToolTipSize() + self.CurrentPosition = wx.Point( + max(0, min(pos.x, screen_width - tip_width)), + max(0, min(pos.y, screen_height - tip_height))) + + self.SetPosition(pos) + + def GetToolTipSize(self): + """ + Get tool tip size according to tip text and restriction + @return: wx.Size(tool_tip_width, tool_tip_height) + """ + max_width = max_height = 0 + + # Create a memory DC for calculating text extent + dc = wx.MemoryDC() + dc.SetFont(self.Font) + + # Compute max tip text size + for line in self.Tip: + w, h = dc.GetTextExtent(line) + max_width = max(max_width, w) + max_height += h + + return wx.Size(max_width + 4, max_height + 4) + + def RefreshTip(self): + """ + Refresh tip on screen + """ + # Prevent to call this function if tool tip destroyed + if self: + # Refresh tool tip size and position + self.SetSize(self.GetToolTipSize()) + self.SetPosition(self.CurrentPosition) + + # Redraw tool tip + self.Refresh() + + def OnPaint(self, event): + """ + Callback for Paint Event + @param event: Paint event + """ + # Get buffered paint DC for tool tip + dc = wx.AutoBufferedPaintDC(self) + dc.Clear() + + # Set DC drawing style + pen = wx.Pen(wx.BLACK) + pen.SetJoin(wx.JOIN_MITER) + pen.SetCap(wx.CAP_PROJECTING) + dc.SetPen(pen) + dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170))) + dc.SetFont(self.Font) + + # Draw Tool tip + dc.BeginDrawing() + tip_width, tip_height = self.GetToolTipSize() + + # Draw background rectangle + dc.DrawRectangle(0, 0, tip_width, tip_height) + + # Draw tool tip text + line_offset = 0 + for line in self.Tip: + dc.DrawText(line, 2, line_offset + 2) + line_width, line_height = dc.GetTextExtent(line) + line_offset += line_height + + dc.EndDrawing() + + event.Skip()