#! /usr/bin/env python
# -*- coding: utf-8 -*-
#-----------------------------------------------------------------------------
# Name: g3listctrl.py
# Purpose:
#
# Author: Jeremy Arendt
#
# Created: 2004/23/02
# RCS-ID: $Id: g3listctrl.py,v 1.10 2005/11/01 00:12:16 inigo Exp $
# Copyright: (c) 2002
# Licence: See G3.LICENCE.TXT
#-----------------------------------------------------------------------------
import wx
from p2pgauge import Mini_P2P_Gauge
import sys
if sys.platform == "win32":
win32_flag = True
else:
win32_flag = False
class G3ListCtrl(wx.ListCtrl):
def __init__(self, parent, btconfig, name, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.LC_REPORT | wx.LC_VRULES | wx.NO_FULL_REPAINT_ON_RESIZE, list_type=0):
wx.ListCtrl.__init__(self, parent, id, pos, size, style)
self.keyDataMap = {}
self.columns = []
self.ebed_ctrls = []
self.ebed_ctrl_data = {}
self.ebed_col = -1
self.name = name
self.in_onpaint = False
self.bg_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)
#self.bg_color = wx.Color(0,255,0)
#self.SetBackgroundColour(self.bg_color)
self.bg_pen = wx.Pen(self.bg_color, 0, wx.TRANSPARENT)
self.bg_brush = wx.Brush(self.bg_color,wx.SOLID)
self.list_type = list_type
self.btconfig = btconfig
if btconfig != None:
self.cfg = btconfig.Get(name + "_cfg")
else:
self.cfg = None
wx.EVT_LIST_COL_RIGHT_CLICK(self, -1, self.OnColRightClick)
wx.EVT_ERASE_BACKGROUND(self, self.AntiFlicker)
wx.EVT_PAINT(self, self.OnPaint)
wx.EVT_LIST_COL_END_DRAG(self, -1, self.OnColDrag)
wx.EVT_SCROLLWIN(self, self.OnScroll)
def OnScroll(self, event):
event.Skip()
if not win32_flag:
self.OnPaint(event)
def AntiFlicker(self, event):
## if sys.platform == "win32":
## if self.in_onpaint:
## return
if win32_flag:
if self.GetItemCount() > 0:
rect = self.GetItemRect(0)
## else:
## if not win32_flag:
## event.Skip()
## return
rect = wx.Rect(0, 17, 0, 17)
size = self.GetClientSize()
#y_off = 17 #20 is good for XP widgets
y_off = rect[1]
if y_off < 1 or y_off > 50:
y_off = 17
## Don't need this when using the ListCtrlAutoWidthMixin
## c_width = 0
## for i in range(0, self.GetColumnCount()):
## c_width += self.GetColumnWidth(i)
## if c_width > size[0]:
## c_width = size[0]
if self.GetItemCount() == 0:
c_height = 0
else:
c_height = rect.GetHeight() * self.GetItemCount()
if self.GetItemCount() > self.GetCountPerPage():
c_height = rect.GetHeight() * self.GetCountPerPage()
if self.HitTest((10, size[1]-1))[0] != -1:
c_height += size[1] - (y_off+c_height)
dc = event.GetDC()
dc.BeginDrawing()
dc.SetPen(self.bg_pen)
dc.SetBrush(self.bg_brush)
#dc.DrawRectangle(c_width, y_off, size[0]-c_width, c_height)
if self.GetUpdateRegion().ContainsRectDim(0, y_off + c_height, size[0], size[1] - (y_off + c_height)) > 0:
dc.DrawRectangle(0, y_off + c_height, size[0], size[1] - (y_off + c_height))
if self.GetUpdateRegion().ContainsRectDim(0, y_off, 2, c_height) > 0:
dc.DrawRectangle(0, y_off, 2, c_height)
dc.DrawRectangle(0, c_height, size[0], size[1]-c_height) # added to sort out win32 refresh problems with wx2.6
dc.EndDrawing()
def SaveCfg(self):
if self.btconfig == None:
return
if self.cfg == None:
self.cfg = [0] * len(self.columns)
i = 0
for c in self.columns:
self.cfg[i] = (c[0], c[3])
i += 1
self.btconfig.Set(self.name + "_cfg", self.cfg)
def InsertColumns(self, cols):
self.columns = cols
i = 0
j = 0
if self.cfg and len(self.cfg) != len(cols):
self.cfg = None
for c in cols:
info = wx.ListItem()
info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT
info.m_text = c[1]
#info.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
if self.cfg == None:
if c[0]:
info.m_format = c[2]
self.InsertColumnInfo(i, info)
self.SetColumnWidth(i, c[3])
i += 1
else:
try:
visible = self.cfg[j][0]
width = self.cfg[j][1]
except:
visible = wx.LIST_FORMAT_RIGHT
width = wx.LIST_AUTOSIZE_USEHEADER
c[0] = visible
if c[0]:
info.m_format = c[2]
self.InsertColumnInfo(i, info)
self.SetColumnWidth(i, width)
i += 1
j += 1
def MapKey2Idx(self, itemDataMap):
""" Map keys to index (location in list) Because FindItemData is slow.. """
self.keyDataMap = {}
for key in itemDataMap.keys():
self.keyDataMap[key] = self.FindItemData(-1, key)
# maybe not that fast...
def InsertRow_Fast(self, key, fields):
item_idx = self.keyDataMap.get(key, None)
if item_idx != None:
self.SetStringItem(item_idx, 0, fields[0])
else:
item_idx = self.GetItemCount()
self.InsertStringItem(item_idx, fields[0])
i = 1
columns = self.columns
for j in range(1, len(fields)):
if columns[j][0]:
self.SetStringItem(item_idx, i, fields[j])
i += 1
self.SetItemData(item_idx, key)
return item_idx
def InsertRow(self, key, fields):
item_idx = self.FindItemData(-1, key) # <- This is kinda... slow
field = fields[0]
if item_idx < 0:
item_idx = self.GetItemCount()
self.InsertStringItem(item_idx, field)
else:
self.SetStringItem(item_idx, 0, field)
i = 1
columns = self.columns
for j in range(1, len(fields)):
if columns[j][0]:
self.SetStringItem(item_idx, i, fields[j])
i += 1
self.SetItemData(item_idx, key)
return item_idx
def Insert_Ebed_Ctrl(self, key, fraction, havelist=[]):
self.ebed_ctrl_data[key] = (fraction, havelist)
def SetEbedCol(self, col):
self.ebed_col = col
def Embedded_Ctrl(self, size):
return Mini_P2P_Gauge(self, self.btconfig, size, 0, False, self.list_type)
def Embedded_SetValue(self, key, g_ctrl):
if win32_flag:
g = self.ebed_ctrl_data[key]
if g[0] == -1:
g_ctrl.SetValueFinished()
elif g[0] == -2:
g_ctrl.SetValueUnknown()
else:
g_ctrl.SetValue(g[0], g[1], [])
def OnPaint(self, event=None):
self.in_onpaint = True
ebed_col = self.GetActualColumn(self.ebed_col)
if event:
event.Skip()
if self.ebed_col == -1 or len(self.ebed_ctrl_data) == 0:
self.in_onpaint = False
return
if self.columns[self.ebed_col][0] == False or self.GetItemCount() == 0:
for g in self.ebed_ctrls:
g.Destroy()
del self.ebed_ctrls[:]
self.in_onpaint = False
return
if len(self.ebed_ctrl_data) == 0:
return
if win32_flag:
visible_gauges = []
self.ebed_visible = visible_gauges
gauges = self.ebed_ctrl_data
gauge_ctrls = self.ebed_ctrls
index = self.GetTopItem()
end_index = index + min(self.GetCountPerPage(), self.GetItemCount())
if win32_flag:
item_rect = self.GetItemRect(index)
gauge_size = (self.GetColumnWidth(ebed_col)-1, item_rect[3]-4)
while index > -1 and index <= end_index:
## print "while index > -1 and index <= end_index:"
key = self.GetItemData(index)
# this if takes care of a weird case when paint has been called
# before the listitems have been readyed
if not key:
self.in_onpaint = False
return
visible_gauges.append( key )
index = self.GetNextItem(index)
if len(gauge_ctrls) < len(visible_gauges):
new_ctrls = []
for i in range(0, len(visible_gauges)-len(gauge_ctrls)):
g = self.Embedded_Ctrl(gauge_size)
wx.EVT_LEFT_DOWN(g, self.OnEbedLClick)
wx.EVT_RIGHT_DOWN(g, self.OnEbedRClick)
new_ctrls.append(g)
gauge_ctrls.extend(new_ctrls)
elif len(gauge_ctrls) > len(visible_gauges):
last = len(visible_gauges)
for g in gauge_ctrls[last:]:
g.Destroy()
del gauge_ctrls[last:]
x = item_rect[0]
for i in range(0, ebed_col):
x += self.GetColumnWidth(i)
y = item_rect[1] + 2
y_off = 17
inc = item_rect[3]
i = 0
for key in visible_gauges:
g_ctrl = gauge_ctrls[i]
g = gauges[key]
if y > y_off:
if g_ctrl.GetSize() != gauge_size:
g_ctrl.SetSize(gauge_size)
if g_ctrl.GetPosition() != (x, y):
g_ctrl.SetPosition( (x, y) )
self.Embedded_SetValue(key, g_ctrl)
if not g_ctrl.IsShown():
g_ctrl.Show(True)
else:
g_ctrl.Show(False)
g_ctrl.Refresh(False)
g_ctrl.Update()
y += inc
i += 1
self.in_onpaint = False
def OnEbedClick(self, event, key):
pass
# selects list item when L/R click on p2pgauge
def OnEbedLClick(self, event):
i = 0
item_idx = self.GetFirstSelected()
if not event.ShiftDown(): #if shift not pressed
while item_idx > -1: #deselect everything
self.Select(item_idx, False)
item_idx = self.GetNextItem(item_idx)
for g in self.ebed_ctrls: #select item associated with p2pgauge
if g.GetId() == event.GetId():
data = self.ebed_visible[i]
item_idx = self.FindItemData(-1, data)
self.Select(item_idx, True)
item = self.GetItem(item_idx)
self.SetItem(item)
self.SetFocus()
self.OnEbedClick(event, data)
break
i += 1
def OnEbedRClick(self, event):
self.OnEbedLClick(event)
self.OnRightClick(event)
def OnColRightClick(self, event):
self.selected_index = self.GetFirstSelected()
menu = wx.Menu()
if not hasattr(self, "_cmenuId"):
self._cmenuId = [0] * len(self.columns)
for i in range(1, len(self.columns)):
self._cmenuId[i] = wx.NewId()
wx.EVT_MENU(self, self._cmenuId[i], self.OnColMenuItemCheck)
for i in range(1, len(self.columns)):
if self.columns[i][1] != "":
menu.Append(self._cmenuId[i], "%s" % self.columns[i][1], "", True)
if self.columns[i][0]:
menu.Check(self._cmenuId[i], True)
self.PopupMenu(menu, self.ScreenToClient(wx.GetMousePosition()))
menu.Destroy()
def OnColMenuItemCheck(self, event):
chk_idx = self._cmenuId.index( event.GetId() )
found = False
for i in range(1, self.GetColumnCount()):
info = self.GetColumn(i)
if info.m_text == self.columns[chk_idx][1]:
self.DeleteColumn(i)
found = True
break
if not found:
slack = 0
for i in range(1, chk_idx):
if self.columns[i][0] == False and i < chk_idx:
slack += 1
col_idx = chk_idx-slack
info = wx.ListItem()
info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT
info.m_text = self.columns[chk_idx][1]
info.m_format = self.columns[chk_idx][2]
self.InsertColumnInfo(col_idx, info)
self.SetColumnWidth(col_idx, self.columns[chk_idx][3])
self.columns[chk_idx][0] = not self.columns[chk_idx][0]
self.SaveCfg()
wx.CallAfter(self._doResize)
wx.CallAfter(self.OnPaint)
def OnColDrag(self, event):
i = 0
while i < self.GetColumnCount():
coltext = self.GetColumn(i).m_text
if coltext != "":
for col in self.columns:
if hash(col[1]) == hash(coltext):
col[3] = self.GetColumnWidth(i)
break
i += 1
self.SaveCfg()
def GetActualColumn(self, col_index):
i = 0
if not self.columns[col_index][0]:
return -1
for c in self.columns[:col_index]:
if c[0]:
i += 1
return i
def GetLogicalColumn(self, col_index):
i = 0
col2sort = 0
for c in self.columns:
if c[0]:
if i == col_index:
break
i += 1
col2sort += 1
return col2sort
class G3ListCtrl_wCheckBox(G3ListCtrl):
def __init__(self, parent, btconfig, name, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.LC_REPORT | wx.LC_VRULES):
G3ListCtrl.__init__(self, parent, btconfig, name, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.LC_REPORT | wx.LC_VRULES)
def OnEbedClick(self, event, key):
self.ebed_ctrl_data[key] = (not self.ebed_ctrl_data[key][0],)
self.Refresh()
def Embedded_Ctrl(self, size):
return wx.CheckBox(self, -1, "")
def Embedded_SetValue(self, key, g_ctrl):
g_ctrl.SetValue(self.ebed_ctrl_data[key][0])
def Insert_Ebed_Ctrl(self, key, value):
self.ebed_ctrl_data[key] = (value, )
|