44 return [wx.Point(xoffset + 1, yoffset - height + 1), |
45 return [wx.Point(xoffset + 1, yoffset - height + 1), |
45 wx.Point(xoffset + width / 2, yoffset - 2), |
46 wx.Point(xoffset + width / 2, yoffset - 2), |
46 wx.Point(xoffset + width - 1, yoffset - height + 1)] |
47 wx.Point(xoffset + width - 1, yoffset - height + 1)] |
47 |
48 |
48 class LogScrollBar(wx.Panel): |
49 class LogScrollBar(wx.Panel): |
49 |
50 |
50 def __init__(self, parent, size): |
51 def __init__(self, parent, size): |
51 wx.Panel.__init__(self, parent, size=size) |
52 wx.Panel.__init__(self, parent, size=size) |
52 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) |
53 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) |
53 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) |
54 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) |
54 self.Bind(wx.EVT_MOTION, self.OnMotion) |
55 self.Bind(wx.EVT_MOTION, self.OnMotion) |
55 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) |
56 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) |
56 self.Bind(wx.EVT_PAINT, self.OnPaint) |
57 self.Bind(wx.EVT_PAINT, self.OnPaint) |
57 self.Bind(wx.EVT_SIZE, self.OnResize) |
58 self.Bind(wx.EVT_SIZE, self.OnResize) |
58 |
59 |
59 self.ThumbPosition = 0. # -1 <= ThumbPosition <= 1 |
60 self.ThumbPosition = 0. # -1 <= ThumbPosition <= 1 |
60 self.ThumbScrollingStartPos = None |
61 self.ThumbScrollingStartPos = None |
61 |
62 |
62 def GetRangeRect(self): |
63 def GetRangeRect(self): |
63 width, height = self.GetClientSize() |
64 width, height = self.GetClientSize() |
64 return wx.Rect(0, width, width, height - 2 * width) |
65 return wx.Rect(0, width, width, height - 2 * width) |
65 |
66 |
66 def GetThumbRect(self): |
67 def GetThumbRect(self): |
67 width, height = self.GetClientSize() |
68 width, height = self.GetClientSize() |
68 range_rect = self.GetRangeRect() |
69 range_rect = self.GetRangeRect() |
69 thumb_size = range_rect.height * THUMB_SIZE_RATIO |
70 thumb_size = range_rect.height * THUMB_SIZE_RATIO |
70 thumb_range = range_rect.height - thumb_size |
71 thumb_range = range_rect.height - thumb_size |
71 thumb_center_position = (thumb_size + (self.ThumbPosition + 1) * thumb_range) / 2. |
72 thumb_center_position = (thumb_size + (self.ThumbPosition + 1) * thumb_range) / 2. |
72 thumb_start = int(thumb_center_position - thumb_size / 2.) |
73 thumb_start = int(thumb_center_position - thumb_size / 2.) |
73 thumb_end = int(thumb_center_position + thumb_size / 2.) |
74 thumb_end = int(thumb_center_position + thumb_size / 2.) |
74 return wx.Rect(0, range_rect.y + thumb_start, width, thumb_end - thumb_start) |
75 return wx.Rect(0, range_rect.y + thumb_start, width, thumb_end - thumb_start) |
75 |
76 |
76 def RefreshThumbPosition(self, thumb_position=None): |
77 def RefreshThumbPosition(self, thumb_position=None): |
77 if thumb_position is None: |
78 if thumb_position is None: |
78 thumb_position = self.ThumbPosition |
79 thumb_position = self.ThumbPosition |
79 if self.Parent.IsMessagePanelTop(): |
80 if self.Parent.IsMessagePanelTop(): |
80 thumb_position = max(0., thumb_position) |
81 thumb_position = max(0., thumb_position) |
101 elif posy < width: |
102 elif posy < width: |
102 self.Parent.ScrollMessagePanelByPage(1) |
103 self.Parent.ScrollMessagePanelByPage(1) |
103 elif posy > height - width: |
104 elif posy > height - width: |
104 self.Parent.ScrollMessagePanelByPage(-1) |
105 self.Parent.ScrollMessagePanelByPage(-1) |
105 event.Skip() |
106 event.Skip() |
106 |
107 |
107 def OnLeftUp(self, event): |
108 def OnLeftUp(self, event): |
108 self.ThumbScrollingStartPos = None |
109 self.ThumbScrollingStartPos = None |
109 self.RefreshThumbPosition(0.) |
110 self.RefreshThumbPosition(0.) |
110 if self.HasCapture(): |
111 if self.HasCapture(): |
111 self.ReleaseMouse() |
112 self.ReleaseMouse() |
112 event.Skip() |
113 event.Skip() |
113 |
114 |
114 def OnMotion(self, event): |
115 def OnMotion(self, event): |
115 if event.Dragging() and self.ThumbScrollingStartPos is not None: |
116 if event.Dragging() and self.ThumbScrollingStartPos is not None: |
116 posx, posy = event.GetPosition() |
117 posx, posy = event.GetPosition() |
117 width, height = self.GetClientSize() |
118 width, height = self.GetClientSize() |
118 range_rect = self.GetRangeRect() |
119 range_rect = self.GetRangeRect() |
119 thumb_size = range_rect.height * THUMB_SIZE_RATIO |
120 thumb_size = range_rect.height * THUMB_SIZE_RATIO |
120 thumb_range = range_rect.height - thumb_size |
121 thumb_range = range_rect.height - thumb_size |
121 self.RefreshThumbPosition( |
122 self.RefreshThumbPosition( |
122 max(-1., min((posy - self.ThumbScrollingStartPos.y) * 2. / thumb_range, 1.))) |
123 max(-1., min((posy - self.ThumbScrollingStartPos.y) * 2. / thumb_range, 1.))) |
123 event.Skip() |
124 event.Skip() |
124 |
125 |
125 def OnResize(self, event): |
126 def OnResize(self, event): |
126 self.Refresh() |
127 self.Refresh() |
127 event.Skip() |
128 event.Skip() |
128 |
129 |
129 def OnEraseBackground(self, event): |
130 def OnEraseBackground(self, event): |
130 pass |
131 pass |
131 |
132 |
132 def OnPaint(self, event): |
133 def OnPaint(self, event): |
133 dc = wx.BufferedPaintDC(self) |
134 dc = wx.BufferedPaintDC(self) |
134 dc.Clear() |
135 dc.Clear() |
135 dc.BeginDrawing() |
136 dc.BeginDrawing() |
136 |
137 |
137 gc = wx.GCDC(dc) |
138 gc = wx.GCDC(dc) |
138 |
139 |
139 width, height = self.GetClientSize() |
140 width, height = self.GetClientSize() |
140 |
141 |
141 gc.SetPen(wx.Pen(wx.NamedColour("GREY"), 3)) |
142 gc.SetPen(wx.Pen(wx.NamedColour("GREY"), 3)) |
142 gc.SetBrush(wx.GREY_BRUSH) |
143 gc.SetBrush(wx.GREY_BRUSH) |
143 |
144 |
144 gc.DrawLines(ArrowPoints(wx.TOP, width * 0.75, width * 0.5, 2, (width + height) / 4 - 3)) |
145 gc.DrawLines(ArrowPoints(wx.TOP, width * 0.75, width * 0.5, 2, (width + height) / 4 - 3)) |
145 gc.DrawLines(ArrowPoints(wx.TOP, width * 0.75, width * 0.5, 2, (width + height) / 4 + 3)) |
146 gc.DrawLines(ArrowPoints(wx.TOP, width * 0.75, width * 0.5, 2, (width + height) / 4 + 3)) |
146 |
147 |
147 gc.DrawLines(ArrowPoints(wx.BOTTOM, width * 0.75, width * 0.5, 2, (height * 3 - width) / 4 + 3)) |
148 gc.DrawLines(ArrowPoints(wx.BOTTOM, width * 0.75, width * 0.5, 2, (height * 3 - width) / 4 + 3)) |
148 gc.DrawLines(ArrowPoints(wx.BOTTOM, width * 0.75, width * 0.5, 2, (height * 3 - width) / 4 - 3)) |
149 gc.DrawLines(ArrowPoints(wx.BOTTOM, width * 0.75, width * 0.5, 2, (height * 3 - width) / 4 - 3)) |
149 |
150 |
150 thumb_rect = self.GetThumbRect() |
151 thumb_rect = self.GetThumbRect() |
151 exclusion_rect = wx.Rect(thumb_rect.x, thumb_rect.y, |
152 exclusion_rect = wx.Rect(thumb_rect.x, thumb_rect.y, |
152 thumb_rect.width, thumb_rect.height) |
153 thumb_rect.width, thumb_rect.height) |
153 if self.Parent.IsMessagePanelTop(): |
154 if self.Parent.IsMessagePanelTop(): |
154 exclusion_rect.y, exclusion_rect.height = width, exclusion_rect.y + exclusion_rect.height - width |
155 exclusion_rect.y, exclusion_rect.height = width, exclusion_rect.y + exclusion_rect.height - width |
156 exclusion_rect.height = height - width - exclusion_rect.y |
157 exclusion_rect.height = height - width - exclusion_rect.y |
157 if exclusion_rect != thumb_rect: |
158 if exclusion_rect != thumb_rect: |
158 colour = wx.NamedColour("LIGHT GREY") |
159 colour = wx.NamedColour("LIGHT GREY") |
159 gc.SetPen(wx.Pen(colour)) |
160 gc.SetPen(wx.Pen(colour)) |
160 gc.SetBrush(wx.Brush(colour)) |
161 gc.SetBrush(wx.Brush(colour)) |
161 |
162 |
162 gc.DrawRectangle(exclusion_rect.x, exclusion_rect.y, |
163 gc.DrawRectangle(exclusion_rect.x, exclusion_rect.y, |
163 exclusion_rect.width, exclusion_rect.height) |
164 exclusion_rect.width, exclusion_rect.height) |
164 |
165 |
165 gc.SetPen(wx.GREY_PEN) |
166 gc.SetPen(wx.GREY_PEN) |
166 gc.SetBrush(wx.GREY_BRUSH) |
167 gc.SetBrush(wx.GREY_BRUSH) |
167 |
168 |
168 gc.DrawPolygon(ArrowPoints(wx.TOP, width, width, 0, 0)) |
169 gc.DrawPolygon(ArrowPoints(wx.TOP, width, width, 0, 0)) |
169 |
170 |
170 gc.DrawPolygon(ArrowPoints(wx.BOTTOM, width, width, 0, height)) |
171 gc.DrawPolygon(ArrowPoints(wx.BOTTOM, width, width, 0, height)) |
171 |
172 |
172 gc.DrawRectangle(thumb_rect.x, thumb_rect.y, |
173 gc.DrawRectangle(thumb_rect.x, thumb_rect.y, |
173 thumb_rect.width, thumb_rect.height) |
174 thumb_rect.width, thumb_rect.height) |
174 |
175 |
175 dc.EndDrawing() |
176 dc.EndDrawing() |
176 event.Skip() |
177 event.Skip() |
177 |
178 |
178 BUTTON_SIZE = (30, 15) |
179 BUTTON_SIZE = (30, 15) |
179 |
180 |
180 class LogButton(): |
181 class LogButton(): |
181 |
182 |
182 def __init__(self, label, callback): |
183 def __init__(self, label, callback): |
183 self.Position = wx.Point(0, 0) |
184 self.Position = wx.Point(0, 0) |
184 self.Size = wx.Size(*BUTTON_SIZE) |
185 self.Size = wx.Size(*BUTTON_SIZE) |
185 self.Label = label |
186 self.Label = label |
186 self.Shown = True |
187 self.Shown = True |
187 self.Callback = callback |
188 self.Callback = callback |
188 |
189 |
189 def __del__(self): |
190 def __del__(self): |
190 self.callback = None |
191 self.callback = None |
191 |
192 |
192 def GetSize(self): |
193 def GetSize(self): |
193 return self.Size |
194 return self.Size |
194 |
195 |
195 def SetPosition(self, x, y): |
196 def SetPosition(self, x, y): |
196 self.Position = wx.Point(x, y) |
197 self.Position = wx.Point(x, y) |
197 |
198 |
198 def HitTest(self, x, y): |
199 def HitTest(self, x, y): |
199 rect = wx.Rect(self.Position.x, self.Position.y, |
200 rect = wx.Rect(self.Position.x, self.Position.y, |
200 self.Size.width, self.Size.height) |
201 self.Size.width, self.Size.height) |
201 if rect.InsideXY(x, y): |
202 if rect.InsideXY(x, y): |
202 return True |
203 return True |
203 return False |
204 return False |
204 |
205 |
205 def ProcessCallback(self): |
206 def ProcessCallback(self): |
206 if self.Callback is not None: |
207 if self.Callback is not None: |
207 wx.CallAfter(self.Callback) |
208 wx.CallAfter(self.Callback) |
208 |
209 |
209 def Draw(self, dc): |
210 def Draw(self, dc): |
210 dc.SetPen(wx.TRANSPARENT_PEN) |
211 dc.SetPen(wx.TRANSPARENT_PEN) |
211 dc.SetBrush(wx.Brush(wx.NamedColour("LIGHT GREY"))) |
212 dc.SetBrush(wx.Brush(wx.NamedColour("LIGHT GREY"))) |
212 |
213 |
213 dc.DrawRectangle(self.Position.x, self.Position.y, |
214 dc.DrawRectangle(self.Position.x, self.Position.y, |
214 self.Size.width, self.Size.height) |
215 self.Size.width, self.Size.height) |
215 |
216 |
216 w, h = dc.GetTextExtent(self.Label) |
217 w, h = dc.GetTextExtent(self.Label) |
217 dc.DrawText(self.Label, |
218 dc.DrawText(self.Label, |
218 self.Position.x + (self.Size.width - w) / 2, |
219 self.Position.x + (self.Size.width - w) / 2, |
219 self.Position.y + (self.Size.height - h) / 2) |
220 self.Position.y + (self.Size.height - h) / 2) |
220 |
221 |
221 DATE_INFO_SIZE = 10 |
222 DATE_INFO_SIZE = 10 |
222 MESSAGE_INFO_SIZE = 18 |
223 MESSAGE_INFO_SIZE = 18 |
223 |
224 |
224 class LogMessage: |
225 class LogMessage: |
225 |
226 |
226 def __init__(self, tv_sec, tv_nsec, level, level_bitmap, msg): |
227 def __init__(self, tv_sec, tv_nsec, level, level_bitmap, msg): |
227 self.Date = datetime.utcfromtimestamp(tv_sec) |
228 self.Date = datetime.utcfromtimestamp(tv_sec) |
228 self.Seconds = self.Date.second + tv_nsec * 1e-9 |
229 self.Seconds = self.Date.second + tv_nsec * 1e-9 |
229 self.Date = self.Date.replace(second=0) |
230 self.Date = self.Date.replace(second=0) |
230 self.Timestamp = tv_sec + tv_nsec * 1e-9 |
231 self.Timestamp = tv_sec + tv_nsec * 1e-9 |
231 self.Level = level |
232 self.Level = level |
232 self.LevelBitmap = level_bitmap |
233 self.LevelBitmap = level_bitmap |
233 self.Message = msg |
234 self.Message = msg |
234 self.DrawDate = True |
235 self.DrawDate = True |
235 |
236 |
236 def __cmp__(self, other): |
237 def __cmp__(self, other): |
237 if self.Date == other.Date: |
238 if self.Date == other.Date: |
238 return cmp(self.Seconds, other.Seconds) |
239 return cmp(self.Seconds, other.Seconds) |
239 return cmp(self.Date, other.Date) |
240 return cmp(self.Date, other.Date) |
240 |
241 |
241 def GetFullText(self): |
242 def GetFullText(self): |
242 date = self.Date.replace(second=int(self.Seconds)) |
243 date = self.Date.replace(second=int(self.Seconds)) |
243 nsec = (self.Seconds % 1.) * 1e9 |
244 nsec = (self.Seconds % 1.) * 1e9 |
244 return "%s at %s.%9.9d:\n%s" % ( |
245 return "%s at %s.%9.9d:\n%s" % ( |
245 LogLevels[self.Level], |
246 LogLevels[self.Level], |
246 str(date), nsec, |
247 str(date), nsec, |
247 self.Message) |
248 self.Message) |
248 |
249 |
249 def Draw(self, dc, offset, width, draw_date): |
250 def Draw(self, dc, offset, width, draw_date): |
250 if draw_date: |
251 if draw_date: |
251 datetime_text = self.Date.strftime("%d/%m/%y %H:%M") |
252 datetime_text = self.Date.strftime("%d/%m/%y %H:%M") |
252 dw, dh = dc.GetTextExtent(datetime_text) |
253 dw, dh = dc.GetTextExtent(datetime_text) |
253 dc.DrawText(datetime_text, (width - dw) / 2, offset + (DATE_INFO_SIZE - dh) / 2) |
254 dc.DrawText(datetime_text, (width - dw) / 2, offset + (DATE_INFO_SIZE - dh) / 2) |
254 offset += DATE_INFO_SIZE |
255 offset += DATE_INFO_SIZE |
255 |
256 |
256 seconds_text = "%12.9f" % self.Seconds |
257 seconds_text = "%12.9f" % self.Seconds |
257 sw, sh = dc.GetTextExtent(seconds_text) |
258 sw, sh = dc.GetTextExtent(seconds_text) |
258 dc.DrawText(seconds_text, 5, offset + (MESSAGE_INFO_SIZE - sh) / 2) |
259 dc.DrawText(seconds_text, 5, offset + (MESSAGE_INFO_SIZE - sh) / 2) |
259 |
260 |
260 bw, bh = self.LevelBitmap.GetWidth(), self.LevelBitmap.GetHeight() |
261 bw, bh = self.LevelBitmap.GetWidth(), self.LevelBitmap.GetHeight() |
261 dc.DrawBitmap(self.LevelBitmap, 10 + sw, offset + (MESSAGE_INFO_SIZE - bh) / 2) |
262 dc.DrawBitmap(self.LevelBitmap, 10 + sw, offset + (MESSAGE_INFO_SIZE - bh) / 2) |
262 |
263 |
263 text = self.Message.replace("\n", " ") |
264 text = self.Message.replace("\n", " ") |
264 mw, mh = dc.GetTextExtent(text) |
265 mw, mh = dc.GetTextExtent(text) |
265 dc.DrawText(text, 15 + sw + bw, offset + (MESSAGE_INFO_SIZE - mh) / 2) |
266 dc.DrawText(text, 15 + sw + bw, offset + (MESSAGE_INFO_SIZE - mh) / 2) |
266 |
267 |
267 def GetHeight(self, draw_date): |
268 def GetHeight(self, draw_date): |
268 if draw_date: |
269 if draw_date: |
269 return DATE_INFO_SIZE + MESSAGE_INFO_SIZE |
270 return DATE_INFO_SIZE + MESSAGE_INFO_SIZE |
270 return MESSAGE_INFO_SIZE |
271 return MESSAGE_INFO_SIZE |
271 |
272 |
278 (_("1h"), HOUR), |
279 (_("1h"), HOUR), |
279 (_("1m"), MINUTE), |
280 (_("1m"), MINUTE), |
280 (_("1s"), SECOND)] |
281 (_("1s"), SECOND)] |
281 |
282 |
282 class LogViewer(DebugViewer, wx.Panel): |
283 class LogViewer(DebugViewer, wx.Panel): |
283 |
284 |
284 def __init__(self, parent, window): |
285 def __init__(self, parent, window): |
285 wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER) |
286 wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER) |
286 DebugViewer.__init__(self, None, False, False) |
287 DebugViewer.__init__(self, None, False, False) |
287 |
288 |
288 main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) |
289 main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) |
289 main_sizer.AddGrowableCol(0) |
290 main_sizer.AddGrowableCol(0) |
290 main_sizer.AddGrowableRow(1) |
291 main_sizer.AddGrowableRow(1) |
291 |
292 |
292 filter_sizer = wx.BoxSizer(wx.HORIZONTAL) |
293 filter_sizer = wx.BoxSizer(wx.HORIZONTAL) |
293 main_sizer.AddSizer(filter_sizer, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) |
294 main_sizer.AddSizer(filter_sizer, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) |
294 |
295 |
295 self.MessageFilter = wx.ComboBox(self, style=wx.CB_READONLY) |
296 self.MessageFilter = wx.ComboBox(self, style=wx.CB_READONLY) |
296 self.MessageFilter.Append(_("All")) |
297 self.MessageFilter.Append(_("All")) |
297 levels = LogLevels[:3] |
298 levels = LogLevels[:3] |
298 levels.reverse() |
299 levels.reverse() |
299 for level in levels: |
300 for level in levels: |
300 self.MessageFilter.Append(_(level)) |
301 self.MessageFilter.Append(_(level)) |
301 self.Bind(wx.EVT_COMBOBOX, self.OnMessageFilterChanged, self.MessageFilter) |
302 self.Bind(wx.EVT_COMBOBOX, self.OnMessageFilterChanged, self.MessageFilter) |
302 filter_sizer.AddWindow(self.MessageFilter, 1, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) |
303 filter_sizer.AddWindow(self.MessageFilter, 1, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) |
303 |
304 |
304 self.SearchMessage = wx.SearchCtrl(self, style=wx.TE_PROCESS_ENTER) |
305 self.SearchMessage = wx.SearchCtrl(self, style=wx.TE_PROCESS_ENTER) |
305 self.SearchMessage.ShowSearchButton(True) |
306 self.SearchMessage.ShowSearchButton(True) |
306 self.SearchMessage.ShowCancelButton(True) |
307 self.SearchMessage.ShowCancelButton(True) |
307 self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchMessageChanged, self.SearchMessage) |
308 self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchMessageChanged, self.SearchMessage) |
308 self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, |
309 self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, |
309 self.OnSearchMessageSearchButtonClick, self.SearchMessage) |
310 self.OnSearchMessageSearchButtonClick, self.SearchMessage) |
310 self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, |
311 self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, |
311 self.OnSearchMessageCancelButtonClick, self.SearchMessage) |
312 self.OnSearchMessageCancelButtonClick, self.SearchMessage) |
312 filter_sizer.AddWindow(self.SearchMessage, 3, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) |
313 filter_sizer.AddWindow(self.SearchMessage, 3, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) |
313 |
314 |
314 self.CleanButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("Clean"), |
315 self.CleanButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("Clean"), |
315 size=wx.Size(28, 28), style=wx.NO_BORDER) |
316 size=wx.Size(28, 28), style=wx.NO_BORDER) |
316 self.CleanButton.SetToolTipString(_("Clean log messages")) |
317 self.CleanButton.SetToolTipString(_("Clean log messages")) |
317 self.Bind(wx.EVT_BUTTON, self.OnCleanButton, self.CleanButton) |
318 self.Bind(wx.EVT_BUTTON, self.OnCleanButton, self.CleanButton) |
318 filter_sizer.AddWindow(self.CleanButton) |
319 filter_sizer.AddWindow(self.CleanButton) |
319 |
320 |
320 message_panel_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) |
321 message_panel_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) |
321 message_panel_sizer.AddGrowableCol(0) |
322 message_panel_sizer.AddGrowableCol(0) |
322 message_panel_sizer.AddGrowableRow(0) |
323 message_panel_sizer.AddGrowableRow(0) |
323 main_sizer.AddSizer(message_panel_sizer, border=5, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) |
324 main_sizer.AddSizer(message_panel_sizer, border=5, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) |
324 |
325 |
325 self.MessagePanel = wx.Panel(self) |
326 self.MessagePanel = wx.Panel(self) |
326 if wx.Platform == '__WXMSW__': |
327 if wx.Platform == '__WXMSW__': |
327 self.Font = wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName='Courier New') |
328 self.Font = wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName='Courier New') |
328 else: |
329 else: |
329 self.Font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName='Courier') |
330 self.Font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName='Courier') |
335 self.MessagePanel.Bind(wx.EVT_MOUSEWHEEL, self.OnMessagePanelMouseWheel) |
336 self.MessagePanel.Bind(wx.EVT_MOUSEWHEEL, self.OnMessagePanelMouseWheel) |
336 self.MessagePanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnMessagePanelEraseBackground) |
337 self.MessagePanel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnMessagePanelEraseBackground) |
337 self.MessagePanel.Bind(wx.EVT_PAINT, self.OnMessagePanelPaint) |
338 self.MessagePanel.Bind(wx.EVT_PAINT, self.OnMessagePanelPaint) |
338 self.MessagePanel.Bind(wx.EVT_SIZE, self.OnMessagePanelResize) |
339 self.MessagePanel.Bind(wx.EVT_SIZE, self.OnMessagePanelResize) |
339 message_panel_sizer.AddWindow(self.MessagePanel, flag=wx.GROW) |
340 message_panel_sizer.AddWindow(self.MessagePanel, flag=wx.GROW) |
340 |
341 |
341 self.MessageScrollBar = LogScrollBar(self, wx.Size(16, -1)) |
342 self.MessageScrollBar = LogScrollBar(self, wx.Size(16, -1)) |
342 message_panel_sizer.AddWindow(self.MessageScrollBar, flag=wx.GROW) |
343 message_panel_sizer.AddWindow(self.MessageScrollBar, flag=wx.GROW) |
343 |
344 |
344 self.SetSizer(main_sizer) |
345 self.SetSizer(main_sizer) |
345 |
346 |
346 self.LeftButtons = [] |
347 self.LeftButtons = [] |
347 for label, callback in [("+" + text, self.GenerateOnDurationButton(duration)) |
348 for label, callback in [("+" + text, self.GenerateOnDurationButton(duration)) |
348 for text, duration in CHANGE_TIMESTAMP_BUTTONS]: |
349 for text, duration in CHANGE_TIMESTAMP_BUTTONS]: |
349 self.LeftButtons.append(LogButton(label, callback)) |
350 self.LeftButtons.append(LogButton(label, callback)) |
350 |
351 |
351 self.RightButtons = [] |
352 self.RightButtons = [] |
352 for label, callback in [("-" + text, self.GenerateOnDurationButton(-duration)) |
353 for label, callback in [("-" + text, self.GenerateOnDurationButton(-duration)) |
353 for text, duration in CHANGE_TIMESTAMP_BUTTONS]: |
354 for text, duration in CHANGE_TIMESTAMP_BUTTONS]: |
354 self.RightButtons.append(LogButton(label, callback)) |
355 self.RightButtons.append(LogButton(label, callback)) |
355 |
356 |
356 self.MessageFilter.SetSelection(0) |
357 self.MessageFilter.SetSelection(0) |
357 self.LogSource = None |
358 self.LogSource = None |
358 self.ResetLogMessages() |
359 self.ResetLogMessages() |
359 self.ParentWindow = window |
360 self.ParentWindow = window |
360 |
361 |
361 self.LevelIcons = [GetBitmap("LOG_" + level) for level in LogLevels] |
362 self.LevelIcons = [GetBitmap("LOG_" + level) for level in LogLevels] |
362 self.LevelFilters = [range(i) for i in xrange(4, 0, -1)] |
363 self.LevelFilters = [range(i) for i in xrange(4, 0, -1)] |
363 self.CurrentFilter = self.LevelFilters[0] |
364 self.CurrentFilter = self.LevelFilters[0] |
364 self.CurrentSearchValue = "" |
365 self.CurrentSearchValue = "" |
365 |
366 |
366 self.ScrollSpeed = 0. |
367 self.ScrollSpeed = 0. |
367 self.LastStartTime = None |
368 self.LastStartTime = None |
368 self.ScrollTimer = wx.Timer(self, -1) |
369 self.ScrollTimer = wx.Timer(self, -1) |
369 self.Bind(wx.EVT_TIMER, self.OnScrollTimer, self.ScrollTimer) |
370 self.Bind(wx.EVT_TIMER, self.OnScrollTimer, self.ScrollTimer) |
370 |
371 |
371 self.LastMousePos = None |
372 self.LastMousePos = None |
372 self.MessageToolTip = None |
373 self.MessageToolTip = None |
373 self.MessageToolTipTimer = wx.Timer(self, -1) |
374 self.MessageToolTipTimer = wx.Timer(self, -1) |
374 self.Bind(wx.EVT_TIMER, self.OnMessageToolTipTimer, self.MessageToolTipTimer) |
375 self.Bind(wx.EVT_TIMER, self.OnMessageToolTipTimer, self.MessageToolTipTimer) |
375 |
376 |
376 def __del__(self): |
377 def __del__(self): |
377 self.ScrollTimer.Stop() |
378 self.ScrollTimer.Stop() |
378 |
379 |
379 def ResetLogMessages(self): |
380 def ResetLogMessages(self): |
380 self.previous_log_count = [None]*LogLevelsCount |
381 self.previous_log_count = [None]*LogLevelsCount |
381 self.OldestMessages = [] |
382 self.OldestMessages = [] |
382 self.LogMessages = [] |
383 self.LogMessages = [] |
383 self.LogMessagesTimestamp = numpy.array([]) |
384 self.LogMessagesTimestamp = numpy.array([]) |
384 self.CurrentMessage = None |
385 self.CurrentMessage = None |
385 self.HasNewData = False |
386 self.HasNewData = False |
386 |
387 |
387 def SetLogSource(self, log_source): |
388 def SetLogSource(self, log_source): |
388 self.LogSource = log_source |
389 self.LogSource = proxy(log_source) if log_source else None |
389 self.CleanButton.Enable(self.LogSource is not None) |
390 self.CleanButton.Enable(self.LogSource is not None) |
390 if log_source is not None: |
391 if log_source is not None: |
391 self.ResetLogMessages() |
392 self.ResetLogMessages() |
392 self.RefreshView() |
393 self.RefreshView() |
393 |
394 |
394 def GetLogMessageFromSource(self, msgidx, level): |
395 def GetLogMessageFromSource(self, msgidx, level): |
395 if self.LogSource is not None: |
396 if self.LogSource is not None: |
396 answer = self.LogSource.GetLogMessage(level, msgidx) |
397 answer = self.LogSource.GetLogMessage(level, msgidx) |
397 if answer is not None: |
398 if answer is not None: |
398 msg, tick, tv_sec, tv_nsec = answer |
399 msg, tick, tv_sec, tv_nsec = answer |
399 return LogMessage(tv_sec, tv_nsec, level, self.LevelIcons[level], msg) |
400 return LogMessage(tv_sec, tv_nsec, level, self.LevelIcons[level], msg) |
400 return None |
401 return None |
401 |
402 |
402 def SetLogCounters(self, log_count): |
403 def SetLogCounters(self, log_count): |
403 new_messages = [] |
404 new_messages = [] |
404 for level, count, prev in zip(xrange(LogLevelsCount), log_count, self.previous_log_count): |
405 for level, count, prev in zip(xrange(LogLevelsCount), log_count, self.previous_log_count): |
405 if count is not None and prev != count: |
406 if count is not None and prev != count: |
406 if prev is None: |
407 if prev is None: |
439 self.ScrollToLast(False) |
440 self.ScrollToLast(False) |
440 self.ResetMessageToolTip() |
441 self.ResetMessageToolTip() |
441 self.MessageToolTipTimer.Stop() |
442 self.MessageToolTipTimer.Stop() |
442 self.ParentWindow.SelectTab(self) |
443 self.ParentWindow.SelectTab(self) |
443 self.NewDataAvailable(None) |
444 self.NewDataAvailable(None) |
444 |
445 |
445 def FilterLogMessage(self, message, timestamp=None): |
446 def FilterLogMessage(self, message, timestamp=None): |
446 return (message.Level in self.CurrentFilter and |
447 return (message.Level in self.CurrentFilter and |
447 message.Message.find(self.CurrentSearchValue) != -1 and |
448 message.Message.find(self.CurrentSearchValue) != -1 and |
448 (timestamp is None or message.Timestamp < timestamp)) |
449 (timestamp is None or message.Timestamp < timestamp)) |
449 |
450 |
450 def GetMessageByTimestamp(self, timestamp): |
451 def GetMessageByTimestamp(self, timestamp): |
451 if self.CurrentMessage is not None: |
452 if self.CurrentMessage is not None: |
452 msgidx = numpy.argmin(abs(self.LogMessagesTimestamp - timestamp)) |
453 msgidx = numpy.argmin(abs(self.LogMessagesTimestamp - timestamp)) |
453 message = self.LogMessages[msgidx] |
454 message = self.LogMessages[msgidx] |
454 if self.FilterLogMessage(message) and message.Timestamp > timestamp: |
455 if self.FilterLogMessage(message) and message.Timestamp > timestamp: |
455 return self.GetPreviousMessage(msgidx, timestamp) |
456 return self.GetPreviousMessage(msgidx, timestamp) |
456 return message, msgidx |
457 return message, msgidx |
457 return None, None |
458 return None, None |
458 |
459 |
459 def GetNextMessage(self, msgidx): |
460 def GetNextMessage(self, msgidx): |
460 while msgidx < len(self.LogMessages) - 1: |
461 while msgidx < len(self.LogMessages) - 1: |
461 message = self.LogMessages[msgidx + 1] |
462 message = self.LogMessages[msgidx + 1] |
462 if self.FilterLogMessage(message): |
463 if self.FilterLogMessage(message): |
463 return message, msgidx + 1 |
464 return message, msgidx + 1 |
464 msgidx += 1 |
465 msgidx += 1 |
465 return None, None |
466 return None, None |
466 |
467 |
467 def GetPreviousMessage(self, msgidx, timestamp=None): |
468 def GetPreviousMessage(self, msgidx, timestamp=None): |
468 message = None |
469 message = None |
469 while 0 < msgidx < len(self.LogMessages): |
470 while 0 < msgidx < len(self.LogMessages): |
470 message = self.LogMessages[msgidx - 1] |
471 message = self.LogMessages[msgidx - 1] |
471 if self.FilterLogMessage(message, timestamp): |
472 if self.FilterLogMessage(message, timestamp): |
488 else: |
489 else: |
489 message = None |
490 message = None |
490 self.OldestMessages[level] = (-1, None) |
491 self.OldestMessages[level] = (-1, None) |
491 if message is not None: |
492 if message is not None: |
492 message_idx = 0 |
493 message_idx = 0 |
493 while (message_idx < len(self.LogMessages) and |
494 while (message_idx < len(self.LogMessages) and |
494 self.LogMessages[message_idx] < message): |
495 self.LogMessages[message_idx] < message): |
495 message_idx += 1 |
496 message_idx += 1 |
496 if len(self.LogMessages) > 0: |
497 if len(self.LogMessages) > 0: |
497 current_message = self.LogMessages[self.CurrentMessage] |
498 current_message = self.LogMessages[self.CurrentMessage] |
498 else: |
499 else: |
499 current_message = message |
500 current_message = message |
500 self.LogMessages.insert(message_idx, message) |
501 self.LogMessages.insert(message_idx, message) |
501 self.LogMessagesTimestamp = numpy.insert( |
502 self.LogMessagesTimestamp = numpy.insert( |
502 self.LogMessagesTimestamp, |
503 self.LogMessagesTimestamp, |
503 [message_idx], |
504 [message_idx], |
504 [message.Timestamp]) |
505 [message.Timestamp]) |
505 self.CurrentMessage = self.LogMessages.index(current_message) |
506 self.CurrentMessage = self.LogMessages.index(current_message) |
506 if message_idx == 0 and self.FilterLogMessage(message, timestamp): |
507 if message_idx == 0 and self.FilterLogMessage(message, timestamp): |
507 return message, 0 |
508 return message, 0 |
508 for idx, msg in self.OldestMessages: |
509 for idx, msg in self.OldestMessages: |
509 if msg is not None and (message is None or msg > message): |
510 if msg is not None and (message is None or msg > message): |
510 message = msg |
511 message = msg |
511 return None, None |
512 return None, None |
512 |
513 |
513 def RefreshNewData(self, *args, **kwargs): |
514 def RefreshNewData(self, *args, **kwargs): |
514 if self.HasNewData: |
515 if self.HasNewData: |
515 self.HasNewData = False |
516 self.HasNewData = False |
516 self.RefreshView() |
517 self.RefreshView() |
517 DebugViewer.RefreshNewData(self, *args, **kwargs) |
518 DebugViewer.RefreshNewData(self, *args, **kwargs) |
518 |
519 |
519 def RefreshView(self): |
520 def RefreshView(self): |
520 width, height = self.MessagePanel.GetClientSize() |
521 width, height = self.MessagePanel.GetClientSize() |
521 bitmap = wx.EmptyBitmap(width, height) |
522 bitmap = wx.EmptyBitmap(width, height) |
522 dc = wx.BufferedDC(wx.ClientDC(self.MessagePanel), bitmap) |
523 dc = wx.BufferedDC(wx.ClientDC(self.MessagePanel), bitmap) |
523 dc.Clear() |
524 dc.Clear() |
524 dc.BeginDrawing() |
525 dc.BeginDrawing() |
525 |
526 |
526 if self.CurrentMessage is not None: |
527 if self.CurrentMessage is not None: |
527 |
528 |
528 dc.SetFont(self.Font) |
529 dc.SetFont(self.Font) |
529 |
530 |
530 for button in self.LeftButtons + self.RightButtons: |
531 for button in self.LeftButtons + self.RightButtons: |
531 button.Draw(dc) |
532 button.Draw(dc) |
532 |
533 |
533 message_idx = self.CurrentMessage |
534 message_idx = self.CurrentMessage |
534 message = self.LogMessages[message_idx] |
535 message = self.LogMessages[message_idx] |
535 draw_date = True |
536 draw_date = True |
536 offset = 5 |
537 offset = 5 |
537 while offset < height and message is not None: |
538 while offset < height and message is not None: |
538 message.Draw(dc, offset, width, draw_date) |
539 message.Draw(dc, offset, width, draw_date) |
539 offset += message.GetHeight(draw_date) |
540 offset += message.GetHeight(draw_date) |
540 |
541 |
541 previous_message, message_idx = self.GetPreviousMessage(message_idx) |
542 previous_message, message_idx = self.GetPreviousMessage(message_idx) |
542 if previous_message is not None: |
543 if previous_message is not None: |
543 draw_date = message.Date != previous_message.Date |
544 draw_date = message.Date != previous_message.Date |
544 message = previous_message |
545 message = previous_message |
545 |
546 |
546 dc.EndDrawing() |
547 dc.EndDrawing() |
547 |
548 |
548 self.MessageScrollBar.RefreshThumbPosition() |
549 self.MessageScrollBar.RefreshThumbPosition() |
549 |
550 |
550 def IsMessagePanelTop(self, message_idx=None): |
551 def IsMessagePanelTop(self, message_idx=None): |
551 if message_idx is None: |
552 if message_idx is None: |
552 message_idx = self.CurrentMessage |
553 message_idx = self.CurrentMessage |
553 if message_idx is not None: |
554 if message_idx is not None: |
554 return self.GetNextMessage(message_idx)[0] is None |
555 return self.GetNextMessage(message_idx)[0] is None |
555 return True |
556 return True |
556 |
557 |
557 def IsMessagePanelBottom(self, message_idx=None): |
558 def IsMessagePanelBottom(self, message_idx=None): |
558 if message_idx is None: |
559 if message_idx is None: |
559 message_idx = self.CurrentMessage |
560 message_idx = self.CurrentMessage |
560 if message_idx is not None: |
561 if message_idx is not None: |
561 width, height = self.MessagePanel.GetClientSize() |
562 width, height = self.MessagePanel.GetClientSize() |
601 else: |
602 else: |
602 if seconds > 0 and self.CurrentMessage == msgidx and msgidx < len(self.LogMessages) - 1: |
603 if seconds > 0 and self.CurrentMessage == msgidx and msgidx < len(self.LogMessages) - 1: |
603 msgidx += 1 |
604 msgidx += 1 |
604 self.CurrentMessage = msgidx |
605 self.CurrentMessage = msgidx |
605 self.RefreshView() |
606 self.RefreshView() |
606 |
607 |
607 def ResetMessagePanel(self): |
608 def ResetMessagePanel(self): |
608 if len(self.LogMessages) > 0: |
609 if len(self.LogMessages) > 0: |
609 self.CurrentMessage = len(self.LogMessages) - 1 |
610 self.CurrentMessage = len(self.LogMessages) - 1 |
610 message = self.LogMessages[self.CurrentMessage] |
611 message = self.LogMessages[self.CurrentMessage] |
611 while message is not None and not self.FilterLogMessage(message): |
612 while message is not None and not self.FilterLogMessage(message): |
612 message, self.CurrentMessage = self.GetPreviousMessage(self.CurrentMessage) |
613 message, self.CurrentMessage = self.GetPreviousMessage(self.CurrentMessage) |
613 self.RefreshView() |
614 self.RefreshView() |
614 |
615 |
615 def OnMessageFilterChanged(self, event): |
616 def OnMessageFilterChanged(self, event): |
616 self.CurrentFilter = self.LevelFilters[self.MessageFilter.GetSelection()] |
617 self.CurrentFilter = self.LevelFilters[self.MessageFilter.GetSelection()] |
617 self.ResetMessagePanel() |
618 self.ResetMessagePanel() |
618 event.Skip() |
619 event.Skip() |
619 |
620 |
620 def OnSearchMessageChanged(self, event): |
621 def OnSearchMessageChanged(self, event): |
621 self.CurrentSearchValue = self.SearchMessage.GetValue() |
622 self.CurrentSearchValue = self.SearchMessage.GetValue() |
622 self.ResetMessagePanel() |
623 self.ResetMessagePanel() |
623 event.Skip() |
624 event.Skip() |
624 |
625 |
625 def OnSearchMessageSearchButtonClick(self, event): |
626 def OnSearchMessageSearchButtonClick(self, event): |
626 self.CurrentSearchValue = self.SearchMessage.GetValue() |
627 self.CurrentSearchValue = self.SearchMessage.GetValue() |
627 self.ResetMessagePanel() |
628 self.ResetMessagePanel() |
628 event.Skip() |
629 event.Skip() |
629 |
630 |
630 def OnSearchMessageCancelButtonClick(self, event): |
631 def OnSearchMessageCancelButtonClick(self, event): |
631 self.CurrentSearchValue = "" |
632 self.CurrentSearchValue = "" |
632 self.SearchMessage.SetValue("") |
633 self.SearchMessage.SetValue("") |
633 self.ResetMessagePanel() |
634 self.ResetMessagePanel() |
634 event.Skip() |
635 event.Skip() |
635 |
636 |
636 def OnCleanButton(self, event): |
637 def OnCleanButton(self, event): |
637 if self.LogSource is not None: |
638 if self.LogSource is not None: |
638 self.LogSource.ResetLogCount() |
639 self.LogSource.ResetLogCount() |
639 self.ResetLogMessages() |
640 self.ResetLogMessages() |
640 self.RefreshView() |
641 self.RefreshView() |
641 event.Skip() |
642 event.Skip() |
642 |
643 |
643 def GenerateOnDurationButton(self, duration): |
644 def GenerateOnDurationButton(self, duration): |
644 def OnDurationButton(): |
645 def OnDurationButton(): |
645 self.ScrollMessagePanelByTimestamp(duration) |
646 self.ScrollMessagePanelByTimestamp(duration) |
646 return OnDurationButton |
647 return OnDurationButton |
647 |
648 |
648 def GetCopyMessageToClipboardFunction(self, message): |
649 def GetCopyMessageToClipboardFunction(self, message): |
649 def CopyMessageToClipboardFunction(event): |
650 def CopyMessageToClipboardFunction(event): |
650 self.ParentWindow.SetCopyBuffer(message.GetFullText()) |
651 self.ParentWindow.SetCopyBuffer(message.GetFullText()) |
651 return CopyMessageToClipboardFunction |
652 return CopyMessageToClipboardFunction |
652 |
653 |
653 def GetMessageByScreenPos(self, posx, posy): |
654 def GetMessageByScreenPos(self, posx, posy): |
654 if self.CurrentMessage is not None: |
655 if self.CurrentMessage is not None: |
655 width, height = self.MessagePanel.GetClientSize() |
656 width, height = self.MessagePanel.GetClientSize() |
656 message_idx = self.CurrentMessage |
657 message_idx = self.CurrentMessage |
657 message = self.LogMessages[message_idx] |
658 message = self.LogMessages[message_idx] |
658 draw_date = True |
659 draw_date = True |
659 offset = 5 |
660 offset = 5 |
660 |
661 |
661 while offset < height and message is not None: |
662 while offset < height and message is not None: |
662 if draw_date: |
663 if draw_date: |
663 offset += DATE_INFO_SIZE |
664 offset += DATE_INFO_SIZE |
664 |
665 |
665 if offset <= posy < offset + MESSAGE_INFO_SIZE: |
666 if offset <= posy < offset + MESSAGE_INFO_SIZE: |
666 return message |
667 return message |
667 |
668 |
668 offset += MESSAGE_INFO_SIZE |
669 offset += MESSAGE_INFO_SIZE |
669 |
670 |
670 previous_message, message_idx = self.GetPreviousMessage(message_idx) |
671 previous_message, message_idx = self.GetPreviousMessage(message_idx) |
671 if previous_message is not None: |
672 if previous_message is not None: |
672 draw_date = message.Date != previous_message.Date |
673 draw_date = message.Date != previous_message.Date |
673 message = previous_message |
674 message = previous_message |
674 return None |
675 return None |
675 |
676 |
676 def OnMessagePanelLeftUp(self, event): |
677 def OnMessagePanelLeftUp(self, event): |
677 if self.CurrentMessage is not None: |
678 if self.CurrentMessage is not None: |
678 posx, posy = event.GetPosition() |
679 posx, posy = event.GetPosition() |
679 for button in self.LeftButtons + self.RightButtons: |
680 for button in self.LeftButtons + self.RightButtons: |
680 if button.HitTest(posx, posy): |
681 if button.HitTest(posx, posy): |
681 button.ProcessCallback() |
682 button.ProcessCallback() |
682 break |
683 break |
683 event.Skip() |
684 event.Skip() |
684 |
685 |
685 def OnMessagePanelRightUp(self, event): |
686 def OnMessagePanelRightUp(self, event): |
686 message = self.GetMessageByScreenPos(*event.GetPosition()) |
687 message = self.GetMessageByScreenPos(*event.GetPosition()) |
687 if message is not None: |
688 if message is not None: |
688 menu = wx.Menu(title='') |
689 menu = wx.Menu(title='') |
689 |
690 |
690 new_id = wx.NewId() |
691 new_id = wx.NewId() |
691 menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Copy")) |
692 menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Copy")) |
692 self.Bind(wx.EVT_MENU, self.GetCopyMessageToClipboardFunction(message), id=new_id) |
693 self.Bind(wx.EVT_MENU, self.GetCopyMessageToClipboardFunction(message), id=new_id) |
693 |
694 |
694 self.MessagePanel.PopupMenu(menu) |
695 self.MessagePanel.PopupMenu(menu) |
695 menu.Destroy() |
696 menu.Destroy() |
696 event.Skip() |
697 event.Skip() |
697 |
698 |
698 def OnMessagePanelLeftDCLick(self, event): |
699 def OnMessagePanelLeftDCLick(self, event): |
699 message = self.GetMessageByScreenPos(*event.GetPosition()) |
700 message = self.GetMessageByScreenPos(*event.GetPosition()) |
700 if message is not None: |
701 if message is not None: |
701 self.SearchMessage.SetFocus() |
702 self.SearchMessage.SetFocus() |
702 self.SearchMessage.SetValue(message.Message) |
703 self.SearchMessage.SetValue(message.Message) |
703 event.Skip() |
704 event.Skip() |
704 |
705 |
705 def ResetMessageToolTip(self): |
706 def ResetMessageToolTip(self): |
706 if self.MessageToolTip is not None: |
707 if self.MessageToolTip is not None: |
707 self.MessageToolTip.Destroy() |
708 self.MessageToolTip.Destroy() |
708 self.MessageToolTip = None |
709 self.MessageToolTip = None |
709 |
710 |
710 def OnMessageToolTipTimer(self, event): |
711 def OnMessageToolTipTimer(self, event): |
711 if self.LastMousePos is not None: |
712 if self.LastMousePos is not None: |
712 message = self.GetMessageByScreenPos(*self.LastMousePos) |
713 message = self.GetMessageByScreenPos(*self.LastMousePos) |
713 if message is not None: |
714 if message is not None: |
714 tooltip_pos = self.MessagePanel.ClientToScreen(self.LastMousePos) |
715 tooltip_pos = self.MessagePanel.ClientToScreen(self.LastMousePos) |
717 self.MessageToolTip = CustomToolTip(self.MessagePanel, message.GetFullText(), False) |
718 self.MessageToolTip = CustomToolTip(self.MessagePanel, message.GetFullText(), False) |
718 self.MessageToolTip.SetFont(self.Font) |
719 self.MessageToolTip.SetFont(self.Font) |
719 self.MessageToolTip.SetToolTipPosition(tooltip_pos) |
720 self.MessageToolTip.SetToolTipPosition(tooltip_pos) |
720 self.MessageToolTip.Show() |
721 self.MessageToolTip.Show() |
721 event.Skip() |
722 event.Skip() |
722 |
723 |
723 def OnMessagePanelMotion(self, event): |
724 def OnMessagePanelMotion(self, event): |
724 if not event.Dragging(): |
725 if not event.Dragging(): |
725 self.ResetMessageToolTip() |
726 self.ResetMessageToolTip() |
726 self.LastMousePos = event.GetPosition() |
727 self.LastMousePos = event.GetPosition() |
727 self.MessageToolTipTimer.Start(int(TOOLTIP_WAIT_PERIOD * 1000), oneShot=True) |
728 self.MessageToolTipTimer.Start(int(TOOLTIP_WAIT_PERIOD * 1000), oneShot=True) |
728 event.Skip() |
729 event.Skip() |
729 |
730 |
730 def OnMessagePanelLeaveWindow(self, event): |
731 def OnMessagePanelLeaveWindow(self, event): |
731 self.ResetMessageToolTip() |
732 self.ResetMessageToolTip() |
732 self.LastMousePos = None |
733 self.LastMousePos = None |
733 self.MessageToolTipTimer.Stop() |
734 self.MessageToolTipTimer.Stop() |
734 event.Skip() |
735 event.Skip() |
735 |
736 |
736 def OnMessagePanelMouseWheel(self, event): |
737 def OnMessagePanelMouseWheel(self, event): |
737 self.ScrollMessagePanel(event.GetWheelRotation() / event.GetWheelDelta()) |
738 self.ScrollMessagePanel(event.GetWheelRotation() / event.GetWheelDelta()) |
738 event.Skip() |
739 event.Skip() |
739 |
740 |
740 def OnMessagePanelEraseBackground(self, event): |
741 def OnMessagePanelEraseBackground(self, event): |
741 pass |
742 pass |
742 |
743 |
743 def OnMessagePanelPaint(self, event): |
744 def OnMessagePanelPaint(self, event): |
744 self.RefreshView() |
745 self.RefreshView() |
745 event.Skip() |
746 event.Skip() |
746 |
747 |
747 def OnMessagePanelResize(self, event): |
748 def OnMessagePanelResize(self, event): |
748 width, height = self.MessagePanel.GetClientSize() |
749 width, height = self.MessagePanel.GetClientSize() |
749 offset = 2 |
750 offset = 2 |
750 for button in self.LeftButtons: |
751 for button in self.LeftButtons: |
751 button.SetPosition(offset, 2) |
752 button.SetPosition(offset, 2) |