Laurent@814: #!/usr/bin/env python Laurent@814: # -*- coding: utf-8 -*- Laurent@814: andrej@1571: # This file is part of Beremiz, a Integrated Development Environment for andrej@1571: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. Laurent@814: # andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD Laurent@814: # andrej@1571: # See COPYING file for copyrights details. Laurent@814: # andrej@1571: # This program is free software; you can redistribute it and/or andrej@1571: # modify it under the terms of the GNU General Public License andrej@1571: # as published by the Free Software Foundation; either version 2 andrej@1571: # of the License, or (at your option) any later version. Laurent@814: # andrej@1571: # This program is distributed in the hope that it will be useful, andrej@1571: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1571: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1571: # GNU General Public License for more details. Laurent@814: # andrej@1571: # You should have received a copy of the GNU General Public License andrej@1571: # along with this program; if not, write to the Free Software andrej@1571: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Laurent@814: Laurent@814: import wx Laurent@1169: Laurent@1169: from controls.CustomStyledTextCtrl import faces Laurent@1169: andrej@1737: TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip andrej@1737: TOOLTIP_MAX_LINE = 5 # Maximum number of line in ToolTip andrej@1737: TOOLTIP_WAIT_PERIOD = 0.5 # Wait period before displaying tooltip in second Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@1169: # Custom ToolTip andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: Laurent@814: Laurent@1169: class CustomToolTip(wx.PopupWindow): andrej@1736: """ andrej@1736: Class that implements a custom tool tip andrej@1736: """ andrej@1730: Laurent@993: def __init__(self, parent, tip, restricted=True): Laurent@1169: """ Laurent@1169: Constructor Laurent@1169: @param parent: Parent window Laurent@1169: @param tip: Tip text (may be multiline) andrej@1730: @param restricted: Tool tip must follow size restriction in line and Laurent@1169: characters number defined (default True) Laurent@1169: """ Laurent@814: wx.PopupWindow.__init__(self, parent) andrej@1730: Laurent@993: self.Restricted = restricted andrej@1730: Laurent@814: self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) Laurent@814: self.SetTip(tip) andrej@1730: Laurent@1169: # Initialize text font style Laurent@1169: self.Font = wx.Font( andrej@1730: faces["size"], andrej@1730: wx.SWISS, andrej@1730: wx.NORMAL, andrej@1730: wx.NORMAL, andrej@1744: faceName=faces["mono"]) andrej@1730: Laurent@814: self.Bind(wx.EVT_PAINT, self.OnPaint) andrej@1730: Laurent@993: def SetFont(self, font): Laurent@1169: """ Laurent@1169: Set tool tip text font style Laurent@1169: @param font: wx.Font object containing font style Laurent@1169: """ Laurent@993: self.Font = font Laurent@993: self.RefreshTip() andrej@1730: Laurent@814: def SetTip(self, tip): Laurent@1169: """ Laurent@1169: Set tool tip text Laurent@1169: @param tip: Tool tip text Laurent@1169: """ Laurent@1169: if self.Restricted: Laurent@1169: # Compute tip text line return Laurent@1169: self.Tip = [] Laurent@1169: for line in tip.splitlines(): Laurent@1169: if line != "": Laurent@1169: words = line.split() Laurent@1169: new_line = words[0] Laurent@1169: for word in words[1:]: Laurent@1169: # Add word to line andrej@1769: if len(new_line + " " + word) <= TOOLTIP_MAX_CHARACTERS: Laurent@1169: new_line += " " + word Laurent@1169: # Create new line Laurent@1169: else: Laurent@1169: self.Tip.append(new_line) Laurent@1169: new_line = word Laurent@1169: self.Tip.append(new_line) Laurent@1169: else: Laurent@1169: self.Tip.append(line) andrej@1730: Laurent@1169: # Restrict number of lines Laurent@1169: if len(self.Tip) > TOOLTIP_MAX_LINE: Laurent@1169: self.Tip = self.Tip[:TOOLTIP_MAX_LINE] andrej@1730: Laurent@1169: # Add ... to the end of last line to indicate that tool tip Laurent@1169: # text is too long Laurent@1169: if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3: Laurent@1169: self.Tip[-1] += "..." Laurent@1169: else: andrej@1771: self.Tip[-1] = self.Tip[-1][:TOOLTIP_MAX_CHARACTERS - 3] + \ andrej@1771: "..." Laurent@814: else: Laurent@1169: self.Tip = tip.splitlines() andrej@1730: Laurent@1169: # Prevent to call wx method in non-wx threads Laurent@814: wx.CallAfter(self.RefreshTip) andrej@1730: Laurent@1170: def SetToolTipPosition(self, pos): Laurent@1170: """ Laurent@1170: Set tool tip position Laurent@1169: @param pos: New tool tip position Laurent@1169: """ Laurent@1169: # Get screen size to prevent tool tip to go out of the screen Laurent@1169: screen_width, screen_height = wx.GetDisplaySize() andrej@1730: Laurent@1169: # Calculate position of tool tip to stay in screen limits Laurent@1169: tip_width, tip_height = self.GetToolTipSize() Laurent@1221: self.SetPosition(wx.Point( Laurent@1169: max(0, min(pos.x, screen_width - tip_width)), Laurent@1221: max(0, min(pos.y, screen_height - tip_height)))) andrej@1730: Laurent@1169: def GetToolTipSize(self): Laurent@1169: """ Laurent@1169: Get tool tip size according to tip text and restriction Laurent@1169: @return: wx.Size(tool_tip_width, tool_tip_height) Laurent@1169: """ Laurent@1169: max_width = max_height = 0 andrej@1730: Laurent@1169: # Create a memory DC for calculating text extent Laurent@1169: dc = wx.MemoryDC() Laurent@1169: dc.SetFont(self.Font) andrej@1730: Laurent@1169: # Compute max tip text size Laurent@814: for line in self.Tip: Laurent@993: w, h = dc.GetTextExtent(line) Laurent@814: max_width = max(max_width, w) Laurent@814: max_height += h andrej@1730: Laurent@1169: return wx.Size(max_width + 4, max_height + 4) andrej@1730: Laurent@814: def RefreshTip(self): Laurent@1169: """ Laurent@1169: Refresh tip on screen Laurent@1169: """ Laurent@1169: # Prevent to call this function if tool tip destroyed Laurent@814: if self: Laurent@1169: # Refresh tool tip size and position Laurent@1221: self.SetClientSize(self.GetToolTipSize()) andrej@1730: Laurent@1169: # Redraw tool tip Laurent@814: self.Refresh() andrej@1730: Laurent@814: def OnPaint(self, event): Laurent@1169: """ Laurent@1169: Callback for Paint Event Laurent@1169: @param event: Paint event Laurent@1169: """ Laurent@1169: # Get buffered paint DC for tool tip Laurent@814: dc = wx.AutoBufferedPaintDC(self) Laurent@814: dc.Clear() andrej@1730: Laurent@1169: # Set DC drawing style Laurent@1172: dc.SetPen(wx.BLACK_PEN) Laurent@814: dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170))) Laurent@993: dc.SetFont(self.Font) andrej@1730: Laurent@1169: # Draw Tool tip Laurent@814: dc.BeginDrawing() Laurent@1169: tip_width, tip_height = self.GetToolTipSize() andrej@1730: Laurent@1169: # Draw background rectangle Laurent@1169: dc.DrawRectangle(0, 0, tip_width, tip_height) andrej@1730: Laurent@1169: # Draw tool tip text Laurent@1169: line_offset = 0 Laurent@814: for line in self.Tip: Laurent@1169: dc.DrawText(line, 2, line_offset + 2) Laurent@1169: line_width, line_height = dc.GetTextExtent(line) Laurent@1169: line_offset += line_height andrej@1730: Laurent@814: dc.EndDrawing() andrej@1730: Laurent@814: event.Skip()