Coverage for /Users/Newville/Codes/xraylarch/larch/wxlib/reportframe.py: 19%
178 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
1import sys
2import wx
3import wx.grid as wxgrid
4import wx.lib.scrolledpanel as scrolled
5from wx.richtext import RichTextCtrl
7from . import (FONTSIZE, Font, FRAMESTYLE, MenuItem, LEFT, CEN, SimpleText,
8 FileOpen, FileSave, GridPanel, Button, HLine, pack)
10from larch.utils.strutils import break_longstring
12LEFT = wx.ALIGN_LEFT
13CEN |= wx.ALL
15NROWS = 25
17# from larch.wxlib import (BitmapButton, SetTip, GridPanel, FloatCtrl,
18# FloatSpin, FloatSpinWithPin, get_icon, SimpleText,
19# pack, Button, HLine, Choice, Check, MenuItem,
20# GUIColors, CEN, LEFT, FRAMESTYLE, Font, FileSave,
21# FileOpen, FONTSIZE)
23class ReportFrame(wx.Frame):
24 """basic frame for displaying a text report -- should be improved!
25 """
26 def __init__(self, parent=None, text=None, size=(725, 600),
27 title='Report', default_filename='out.txt', wildcard='*.txt', **kws):
28 self.default_filename = default_filename
29 self.wildcard = wildcard
30 wx.Frame.__init__(self, parent, size=size, style=FRAMESTYLE, **kws)
31 self.SetTitle(title)
32 self.menubar = wx.MenuBar()
33 fmenu = wx.Menu()
35 MenuItem(self, fmenu, "Save", "Save Text to File", self.onSave)
36 MenuItem(self, fmenu, "Quit", "Exit", self.onClose)
37 self.menubar.Append(fmenu, "&File")
38 self.SetMenuBar(self.menubar)
39 self.Bind(wx.EVT_CLOSE, self.onClose)
41 self.report = RichTextCtrl(self,size=size, style=wx.VSCROLL)
42 self.report.SetEditable(False)
43 self.report.SetFont(wx.Font(FONTSIZE+1, wx.MODERN, wx.NORMAL, wx.BOLD))
45 self.report.SetMinSize((500, 500))
47 sizer = wx.BoxSizer(wx.VERTICAL)
48 sizer.Add(self.report, 1, wx.ALL|wx.GROW, 2)
49 pack(self, sizer)
50 if text is not None:
51 self.set_text(text)
52 self.Show()
53 self.Raise()
55 def set_text(self, text):
56 self.report.SetEditable(True)
57 self.report.SetValue(text)
58 self.report.SetEditable(False)
61 def onClose(self, event=None):
62 self.Destroy()
64 def onSave(self, eventt=None):
65 wildcard = f'{self.wildcard}|All files (*.*)|*.*'
66 path = FileSave(self, message='Save text to file',
67 wildcard=wildcard,
68 default_file=self.default_filename)
69 if path is not None:
70 with open(path, 'w', encoding=sys.getdefaultencoding()) as fh:
71 fh.write(self.report.GetValue())
72 fh.write('')
75class DictFrame(wx.Frame):
76 """ simple display of dict"""
77 def __init__(self, parent, data=None, title='Dictionary', **kws):
78 self.parent = parent
79 self.title = title
80 if data is None: data = {}
81 self.data = data
83 wx.Frame.__init__(self, None, -1, title, style=FRAMESTYLE, **kws)
86 export_btn = Button(self, 'Save to Tab-Separated File', size=(225, -1),
87 action=self.export)
89 collabels = [' Label ', ' Value ']
90 colsizes = [200, 550]
91 coltypes = ['string', 'string']
92 coldefs = [' ', ' ']
94 self.datagrid = DataTableGrid(self, nrows=NROWS,
95 collabels=collabels,
96 datatypes=coltypes,
97 defaults=coldefs,
98 colsizes=colsizes,
99 rowlabelsize=40)
101 self.datagrid.SetMinSize((850, 500))
102 self.datagrid.EnableEditing(False)
104 sizer = wx.BoxSizer(wx.VERTICAL)
105 sizer.Add(export_btn, 0, LEFT, 2)
106 sizer.Add((5, 5), 0, LEFT, 2)
107 sizer.Add(self.datagrid, 1, LEFT, 2)
109 pack(self, sizer)
111 self.Show()
112 self.Raise()
113 self.SetSize(self.GetBestSize())
114 wx.CallAfter(self.set_data)
116 def export(self, event=None):
117 wildcard = 'CSV file (*.csv)|*.csv|All files (*.*)|*.*'
118 fname = self.title + '.csv'
119 fname = FileSave(self, message='Save Tab-Separated-Value Data File',
120 wildcard=wildcard, default_file=fname)
121 if fname is None:
122 return
124 buff = ['Label\tValue']
125 for k, v in self.data.items():
126 k = k.replace('\t', '_')
127 if not isinstance(v, str): v = repr(v)
128 v = v.replace('\t', ' ')
129 buff.append(f"{k}\t{v}")
131 buff.append('')
132 with open(fname, 'w', encoding=sys.getdefaultencoding()) as fh:
133 fh.write('\n'.join(buff))
135 msg = f"Exported data '{fname}'"
136 writer = getattr(self.parent, 'write_message', sys.stdout)
137 writer(msg)
140 def set_data(self, data=None):
141 if data is None:
142 data = self.data
143 if data is None:
144 return
146 grid_data = []
147 rowsize = []
148 n_entries = len(data)
150 for key, val in data.items():
151 if not isinstance(val, str):
152 val = repr(val)
153 xval = break_longstring(val)
154 val = '\n'.join(xval)
155 rowsize.append(len(xval))
156 grid_data.append([key, val])
158 nrows = self.datagrid.table.GetRowsCount()
159 if len(grid_data) > nrows:
160 self.datagrid.AppendRows(len(grid_data)+8 - nrows)
162 self.datagrid.table.Clear()
163 self.datagrid.table.data = grid_data
164 for i, rsize in enumerate(rowsize):
165 self.datagrid.SetRowSize(i, rsize*20)
167 self.datagrid.table.View.Refresh()
170class DataTable(wxgrid.GridTableBase):
171 def __init__(self, nrows=NROWS, collabels=['a', 'b'],
172 datatypes=['str', 'float:12,4'],
173 defaults=[None, None]):
175 wxgrid.GridTableBase.__init__(self)
177 self.ncols = len(collabels)
178 self.nrows = nrows
179 self.colLabels = collabels
180 self.dataTypes = []
181 for i, d in enumerate(datatypes):
182 if d.lower().startswith('str'):
183 self.dataTypes.append(wxgrid.GRID_VALUE_STRING)
184 defval = ''
185 elif d.lower().startswith('float:'):
186 xt, opt = d.split(':')
187 self.dataTypes.append(wxgrid.GRID_VALUE_FLOAT+':%s' % opt)
188 defval = 0.0
189 if defaults[i] is None:
190 defaults[i] = defval
191 self.defaults = defaults
192 self.data = []
193 for i in range(self.nrows):
194 self.data.append(defaults)
196 def GetNumberRows(self):
197 return self.nrows
199 def GetNumberCols(self):
200 return self.ncols
202 def GetValue(self, row, col):
203 try:
204 return self.data[row][col]
205 except IndexError:
206 return ''
208 def SetValue(self, row, col, value):
209 self.data[row][col] = value
211 def GetColLabelValue(self, col):
212 return self.colLabels[col]
214 def GetRowLabelValue(self, row):
215 return " %d" % (row+1)
217 def GetTypeName(self, row, col):
218 return self.dataTypes[col]
220 def CanGetValueAs(self, row, col, typeName):
221 colType = self.dataTypes[col].split(':')[0]
222 if typeName == colType:
223 return True
224 else:
225 return False
227 def CanSetValueAs(self, row, col, typeName):
228 return self.CanGetValueAs(row, col, typeName)
230 def AppendRows(self, numRows=1, **kws):
231 self.nrows = self.nrows + numRows
232 msg = wxgrid.GridTableMessage(self,
233 wxgrid.GRIDTABLE_NOTIFY_ROWS_APPENDED, numRows)
234 self.GetView().ProcessTableMessage(msg)
235 return True
238class DataTableGrid(wxgrid.Grid):
239 def __init__(self, parent, nrows=NROWS, rowlabelsize=35,
240 collabels=['a', 'b'],
241 datatypes=['str', 'float:12,4'],
242 defaults=['', ''],
243 colsizes=[200, 100]):
245 wxgrid.Grid.__init__(self, parent, -1)
247 self.table = DataTable(nrows=nrows, collabels=collabels,
248 datatypes=datatypes, defaults=defaults)
250 self.SetTable(self.table, True)
251 self.SetRowLabelSize(rowlabelsize)
252 self.SetMargins(10, 10)
253 self.EnableDragRowSize()
254 self.EnableDragColSize()
255 self.AutoSizeColumns(False)
256 for i, csize in enumerate(colsizes):
257 self.SetColSize(i, csize)
259 self.Bind(wxgrid.EVT_GRID_CELL_LEFT_DCLICK, self.OnLeftDClick)
261 def OnLeftDClick(self, evt):
262 if self.CanEnableCellControl():
263 self.EnableCellEditControl()