24 |
24 |
25 import wx |
25 import wx |
26 |
26 |
27 from controls.CustomStyledTextCtrl import faces |
27 from controls.CustomStyledTextCtrl import faces |
28 |
28 |
29 TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip |
29 TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip |
30 TOOLTIP_MAX_LINE = 5 # Maximum number of 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 |
31 TOOLTIP_WAIT_PERIOD = 0.5 # Wait period before displaying tooltip in second |
32 |
32 |
33 #------------------------------------------------------------------------------- |
33 # ------------------------------------------------------------------------------- |
34 # Custom ToolTip |
34 # Custom ToolTip |
35 #------------------------------------------------------------------------------- |
35 # ------------------------------------------------------------------------------- |
36 |
36 |
37 """ |
|
38 Class that implements a custom tool tip |
|
39 """ |
|
40 |
37 |
41 class CustomToolTip(wx.PopupWindow): |
38 class CustomToolTip(wx.PopupWindow): |
42 |
39 """ |
|
40 Class that implements a custom tool tip |
|
41 """ |
|
42 |
43 def __init__(self, parent, tip, restricted=True): |
43 def __init__(self, parent, tip, restricted=True): |
44 """ |
44 """ |
45 Constructor |
45 Constructor |
46 @param parent: Parent window |
46 @param parent: Parent window |
47 @param tip: Tip text (may be multiline) |
47 @param tip: Tip text (may be multiline) |
48 @param restricted: Tool tip must follow size restriction in line and |
48 @param restricted: Tool tip must follow size restriction in line and |
49 characters number defined (default True) |
49 characters number defined (default True) |
50 """ |
50 """ |
51 wx.PopupWindow.__init__(self, parent) |
51 wx.PopupWindow.__init__(self, parent) |
52 |
52 |
53 self.Restricted = restricted |
53 self.Restricted = restricted |
54 |
54 |
55 self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) |
55 self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) |
56 self.SetTip(tip) |
56 self.SetTip(tip) |
57 |
57 |
58 # Initialize text font style |
58 # Initialize text font style |
59 self.Font = wx.Font( |
59 self.Font = wx.Font( |
60 faces["size"], |
60 faces["size"], |
61 wx.SWISS, |
61 wx.SWISS, |
62 wx.NORMAL, |
62 wx.NORMAL, |
63 wx.NORMAL, |
63 wx.NORMAL, |
64 faceName = faces["mono"]) |
64 faceName=faces["mono"]) |
65 |
65 |
66 self.Bind(wx.EVT_PAINT, self.OnPaint) |
66 self.Bind(wx.EVT_PAINT, self.OnPaint) |
67 |
67 |
68 def SetFont(self, font): |
68 def SetFont(self, font): |
69 """ |
69 """ |
70 Set tool tip text font style |
70 Set tool tip text font style |
71 @param font: wx.Font object containing font style |
71 @param font: wx.Font object containing font style |
72 """ |
72 """ |
73 self.Font = font |
73 self.Font = font |
74 self.RefreshTip() |
74 self.RefreshTip() |
75 |
75 |
76 def SetTip(self, tip): |
76 def SetTip(self, tip): |
77 """ |
77 """ |
78 Set tool tip text |
78 Set tool tip text |
79 @param tip: Tool tip text |
79 @param tip: Tool tip text |
80 """ |
80 """ |
85 if line != "": |
85 if line != "": |
86 words = line.split() |
86 words = line.split() |
87 new_line = words[0] |
87 new_line = words[0] |
88 for word in words[1:]: |
88 for word in words[1:]: |
89 # Add word to line |
89 # Add word to line |
90 if len(new_line + " " + word) <= \ |
90 if len(new_line + " " + word) <= TOOLTIP_MAX_CHARACTERS: |
91 TOOLTIP_MAX_CHARACTERS: |
|
92 new_line += " " + word |
91 new_line += " " + word |
93 # Create new line |
92 # Create new line |
94 else: |
93 else: |
95 self.Tip.append(new_line) |
94 self.Tip.append(new_line) |
96 new_line = word |
95 new_line = word |
97 self.Tip.append(new_line) |
96 self.Tip.append(new_line) |
98 else: |
97 else: |
99 self.Tip.append(line) |
98 self.Tip.append(line) |
100 |
99 |
101 # Restrict number of lines |
100 # Restrict number of lines |
102 if len(self.Tip) > TOOLTIP_MAX_LINE: |
101 if len(self.Tip) > TOOLTIP_MAX_LINE: |
103 self.Tip = self.Tip[:TOOLTIP_MAX_LINE] |
102 self.Tip = self.Tip[:TOOLTIP_MAX_LINE] |
104 |
103 |
105 # Add ... to the end of last line to indicate that tool tip |
104 # Add ... to the end of last line to indicate that tool tip |
106 # text is too long |
105 # text is too long |
107 if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3: |
106 if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3: |
108 self.Tip[-1] += "..." |
107 self.Tip[-1] += "..." |
109 else: |
108 else: |
110 self.Tip[-1] = self.Tip[-1]\ |
109 self.Tip[-1] = self.Tip[-1][:TOOLTIP_MAX_CHARACTERS - 3] + \ |
111 [:TOOLTIP_MAX_CHARACTERS - 3] + "..." |
110 "..." |
112 else: |
111 else: |
113 self.Tip = tip.splitlines() |
112 self.Tip = tip.splitlines() |
114 |
113 |
115 # Prevent to call wx method in non-wx threads |
114 # Prevent to call wx method in non-wx threads |
116 wx.CallAfter(self.RefreshTip) |
115 wx.CallAfter(self.RefreshTip) |
117 |
116 |
118 def SetToolTipPosition(self, pos): |
117 def SetToolTipPosition(self, pos): |
119 """ |
118 """ |
120 Set tool tip position |
119 Set tool tip position |
121 @param pos: New tool tip position |
120 @param pos: New tool tip position |
122 """ |
121 """ |
123 # Get screen size to prevent tool tip to go out of the screen |
122 # Get screen size to prevent tool tip to go out of the screen |
124 screen_width, screen_height = wx.GetDisplaySize() |
123 screen_width, screen_height = wx.GetDisplaySize() |
125 |
124 |
126 # Calculate position of tool tip to stay in screen limits |
125 # Calculate position of tool tip to stay in screen limits |
127 tip_width, tip_height = self.GetToolTipSize() |
126 tip_width, tip_height = self.GetToolTipSize() |
128 self.SetPosition(wx.Point( |
127 self.SetPosition(wx.Point( |
129 max(0, min(pos.x, screen_width - tip_width)), |
128 max(0, min(pos.x, screen_width - tip_width)), |
130 max(0, min(pos.y, screen_height - tip_height)))) |
129 max(0, min(pos.y, screen_height - tip_height)))) |
131 |
130 |
132 def GetToolTipSize(self): |
131 def GetToolTipSize(self): |
133 """ |
132 """ |
134 Get tool tip size according to tip text and restriction |
133 Get tool tip size according to tip text and restriction |
135 @return: wx.Size(tool_tip_width, tool_tip_height) |
134 @return: wx.Size(tool_tip_width, tool_tip_height) |
136 """ |
135 """ |
137 max_width = max_height = 0 |
136 max_width = max_height = 0 |
138 |
137 |
139 # Create a memory DC for calculating text extent |
138 # Create a memory DC for calculating text extent |
140 dc = wx.MemoryDC() |
139 dc = wx.MemoryDC() |
141 dc.SetFont(self.Font) |
140 dc.SetFont(self.Font) |
142 |
141 |
143 # Compute max tip text size |
142 # Compute max tip text size |
144 for line in self.Tip: |
143 for line in self.Tip: |
145 w, h = dc.GetTextExtent(line) |
144 w, h = dc.GetTextExtent(line) |
146 max_width = max(max_width, w) |
145 max_width = max(max_width, w) |
147 max_height += h |
146 max_height += h |
148 |
147 |
149 return wx.Size(max_width + 4, max_height + 4) |
148 return wx.Size(max_width + 4, max_height + 4) |
150 |
149 |
151 def RefreshTip(self): |
150 def RefreshTip(self): |
152 """ |
151 """ |
153 Refresh tip on screen |
152 Refresh tip on screen |
154 """ |
153 """ |
155 # Prevent to call this function if tool tip destroyed |
154 # Prevent to call this function if tool tip destroyed |
156 if self: |
155 if self: |
157 # Refresh tool tip size and position |
156 # Refresh tool tip size and position |
158 self.SetClientSize(self.GetToolTipSize()) |
157 self.SetClientSize(self.GetToolTipSize()) |
159 |
158 |
160 # Redraw tool tip |
159 # Redraw tool tip |
161 self.Refresh() |
160 self.Refresh() |
162 |
161 |
163 def OnPaint(self, event): |
162 def OnPaint(self, event): |
164 """ |
163 """ |
165 Callback for Paint Event |
164 Callback for Paint Event |
166 @param event: Paint event |
165 @param event: Paint event |
167 """ |
166 """ |
168 # Get buffered paint DC for tool tip |
167 # Get buffered paint DC for tool tip |
169 dc = wx.AutoBufferedPaintDC(self) |
168 dc = wx.AutoBufferedPaintDC(self) |
170 dc.Clear() |
169 dc.Clear() |
171 |
170 |
172 # Set DC drawing style |
171 # Set DC drawing style |
173 dc.SetPen(wx.BLACK_PEN) |
172 dc.SetPen(wx.BLACK_PEN) |
174 dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170))) |
173 dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170))) |
175 dc.SetFont(self.Font) |
174 dc.SetFont(self.Font) |
176 |
175 |
177 # Draw Tool tip |
176 # Draw Tool tip |
178 dc.BeginDrawing() |
177 dc.BeginDrawing() |
179 tip_width, tip_height = self.GetToolTipSize() |
178 tip_width, tip_height = self.GetToolTipSize() |
180 |
179 |
181 # Draw background rectangle |
180 # Draw background rectangle |
182 dc.DrawRectangle(0, 0, tip_width, tip_height) |
181 dc.DrawRectangle(0, 0, tip_width, tip_height) |
183 |
182 |
184 # Draw tool tip text |
183 # Draw tool tip text |
185 line_offset = 0 |
184 line_offset = 0 |
186 for line in self.Tip: |
185 for line in self.Tip: |
187 dc.DrawText(line, 2, line_offset + 2) |
186 dc.DrawText(line, 2, line_offset + 2) |
188 line_width, line_height = dc.GetTextExtent(line) |
187 line_width, line_height = dc.GetTextExtent(line) |
189 line_offset += line_height |
188 line_offset += line_height |
190 |
189 |
191 dc.EndDrawing() |
190 dc.EndDrawing() |
192 |
191 |
193 event.Skip() |
192 event.Skip() |