# HG changeset patch # User Laurent Bessard # Date 1369327664 -7200 # Node ID 53e4a2b775a7905d38837e7603fa0569fb5cf5f8 # Parent 7838595559ba9c998973ac7293a6600b3fa8fe11 Move CustomToolTip from GraphicCommons to controls 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() diff -r 7838595559ba -r 53e4a2b775a7 controls/LogViewer.py --- a/controls/LogViewer.py Fri May 17 20:58:34 2013 +0200 +++ b/controls/LogViewer.py Thu May 23 18:47:44 2013 +0200 @@ -28,7 +28,8 @@ import wx -from graphics import DebugViewer, REFRESH_PERIOD, ToolTip, TOOLTIP_WAIT_PERIOD +from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD +from graphics import DebugViewer, REFRESH_PERIOD from targets.typemapping import LogLevelsCount, LogLevels from util.BitmapLibrary import GetBitmap @@ -699,7 +700,7 @@ tooltip_pos = self.MessagePanel.ClientToScreen(self.LastMousePos) tooltip_pos.x += 10 tooltip_pos.y += 10 - self.MessageToolTip = ToolTip(self.MessagePanel, message.GetFullText(), False) + self.MessageToolTip = CustomToolTip(self.MessagePanel, message.GetFullText(), False) self.MessageToolTip.SetFont(self.Font) self.MessageToolTip.MoveToolTip(tooltip_pos) self.MessageToolTip.Show() diff -r 7838595559ba -r 53e4a2b775a7 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Fri May 17 20:58:34 2013 +0200 +++ b/graphics/GraphicCommons.py Thu May 23 18:47:44 2013 +0200 @@ -29,6 +29,8 @@ import datetime from threading import Lock,Timer +from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD + #------------------------------------------------------------------------------- # Common constants #------------------------------------------------------------------------------- @@ -102,9 +104,6 @@ # Define highlight refresh inhibition period in second REFRESH_HIGHLIGHT_PERIOD = 0.1 -# Define tooltip wait for displaying period in second -TOOLTIP_WAIT_PERIOD = 0.5 - HANDLE_CURSORS = { (1, 1) : 2, (3, 3) : 2, @@ -555,119 +554,6 @@ dc.SetUserScale(scalex, scaley) #------------------------------------------------------------------------------- -# Viewer ToolTip -#------------------------------------------------------------------------------- - -""" -Class that implements a custom tool tip -""" - -if wx.Platform == '__WXMSW__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Courier New', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 10, - } -else: - faces = { 'times': 'Times', - 'mono' : 'Courier', - 'helv' : 'Helvetica', - 'other': 'new century schoolbook', - 'size' : 12, - } - -TOOLTIP_MAX_CHARACTERS = 30 -TOOLTIP_MAX_LINE = 5 - -class ToolTip(wx.PopupWindow): - - def __init__(self, parent, tip, restricted=True): - wx.PopupWindow.__init__(self, parent) - - self.CurrentPosition = wx.Point(0, 0) - self.Restricted = restricted - - self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - self.SetTip(tip) - - 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): - self.Font = font - self.RefreshTip() - - def SetTip(self, tip): - lines = [] - for line in tip.splitlines(): - if self.Restricted and line != "": - words = line.split() - new_line = words[0] - for word in words[1:]: - if len(new_line + " " + word) <= TOOLTIP_MAX_CHARACTERS: - new_line += " " + word - else: - lines.append(new_line) - new_line = word - lines.append(new_line) - else: - lines.append(line) - if self.Restricted and len(lines) > TOOLTIP_MAX_LINE: - self.Tip = lines[:TOOLTIP_MAX_LINE] - 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 = lines - wx.CallAfter(self.RefreshTip) - - def MoveToolTip(self, pos): - screen_size = wx.GetDisplaySize() - w, h = self.GetTipExtent() - self.CurrentPosition = wx.Point( - max(0, min(pos.x, screen_size[0] - w - 4)), - max(0, min(pos.y, screen_size[1] - h - 4))) - self.SetPosition(pos) - - def GetTipExtent(self): - max_width = 0 - max_height = 0 - for line in self.Tip: - dc = wx.MemoryDC() - dc.SetFont(self.Font) - w, h = dc.GetTextExtent(line) - max_width = max(max_width, w) - max_height += h - return max_width, max_height - - def RefreshTip(self): - if self: - w, h = self.GetTipExtent() - self.SetSize(wx.Size(w + 4, h + 4)) - self.SetPosition(self.CurrentPosition) - self.Refresh() - - def OnPaint(self, event): - dc = wx.AutoBufferedPaintDC(self) - dc.Clear() - dc.SetPen(MiterPen(wx.BLACK)) - dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170))) - dc.SetFont(self.Font) - dc.BeginDrawing() - w, h = self.GetTipExtent() - dc.DrawRectangle(0, 0, w + 4, h + 4) - offset = 0 - for line in self.Tip: - dc.DrawText(line, 2, offset + 2) - w, h = dc.GetTextExtent(line) - offset += h - dc.EndDrawing() - event.Skip() - -#------------------------------------------------------------------------------- # Helpers for highlighting text #------------------------------------------------------------------------------- @@ -1107,7 +993,7 @@ def OnToolTipTimer(self, event): value = self.GetToolTipValue() if value is not None and self.ToolTipPos is not None: - self.ToolTip = ToolTip(self.Parent, value) + self.ToolTip = CustomToolTip(self.Parent, value) self.ToolTip.MoveToolTip(self.ToolTipPos) self.ToolTip.Show()