# -*- coding: utf-8 -*- """ @brief activities_dashboard This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @author: Anna Petrasova (akratoc@ncsu.edu) """ import wx try: import wx.html2 as webview except ImportError: webview = None class MultipleDashboardFrame(wx.Frame): def __init__(self, parent, fontsize, maximum, title, formatting_string, vertical=False): wx.Frame.__init__(self, parent, style=wx.NO_BORDER) if isinstance(maximum, list): self.list_maximum = maximum self.list_title = title self.list_formatting_string = formatting_string else: self.list_maximum = [maximum] self.list_title = [title] self.list_formatting_string = [formatting_string] self.labels = [] self.titles = [] self.gauges = [] self.sizer = wx.GridBagSizer(5, 5) for i in range(len(self.list_maximum)): if vertical: if title: self.titles.append(wx.StaticText(self, label=self.list_title[i] + ':', style=wx.ALIGN_LEFT)) self.labels.append(wx.StaticText(self, style=wx.ALIGN_RIGHT)) self.gauges.append(wx.Gauge(self, range=self.list_maximum[i])) else: if title: self.titles.append(wx.StaticText(self, label=self.list_title[i], style=wx.ALIGN_CENTER)) self.labels.append(wx.StaticText(self, style=wx.ALIGN_CENTRE_HORIZONTAL)) self.gauges.append(wx.Gauge(self, range=self.list_maximum[i], style=wx.GA_VERTICAL)) font = wx.Font(fontsize, wx.DEFAULT, wx.NORMAL, wx.BOLD) self.labels[i].SetFont(font) if title: self.titles[i].SetFont(font) if vertical: if title: self.sizer.Add(self.titles[i], pos=(i, 0), flag=wx.ALL|wx.ALIGN_BOTTOM) self.sizer.Add(self.gauges[i], pos=(i, 1), flag=wx.ALL|wx.EXPAND) self.sizer.Add(self.labels[i], pos=(i, 2), flag=wx.ALL|wx.ALIGN_BOTTOM) else: if title: self.sizer.Add(self.titles[i], pos=(0, i), flag=wx.ALL|wx.ALIGN_CENTER) extra = wx.BoxSizer(wx.HORIZONTAL) extra.AddStretchSpacer() extra.Add(self.gauges[i], flag=wx.EXPAND) extra.AddStretchSpacer() self.sizer.Add(extra, pos=(1, i), flag=wx.ALL|wx.EXPAND) self.sizer.Add(self.labels[i], pos=(2, i), flag=wx.ALL|wx.ALIGN_CENTER) self.sizer.AddGrowableCol(i, 0) if vertical: self.sizer.AddGrowableCol(1, 1) else: self.sizer.AddGrowableRow(1) self.SetSizer(self.sizer) self.sizer.Fit(self) def show_value(self, values): if not isinstance(values, list): values = [values] if len(self.gauges) != len(values): print('wrong number of values!') return for i in range(len(self.gauges)): if values[i] is None: self.labels[i].SetLabel('') self.gauges[i].SetValue(0) continue self.labels[i].SetLabel(self.list_formatting_string[i].format(values[i])) if values[i] > self.list_maximum[i]: values[i] = self.list_maximum[i] self.gauges[i].SetValue(values[i]) self.sizer.Layout() self.Layout() class MultipleHTMLDashboardFrame(wx.Frame): def __init__(self, parent, fontsize, average, maximum, title, formatting_string, vertical=False, grid=False): wx.Frame.__init__(self, parent, style=wx.NO_BORDER) self.panel = wx.Panel(parent=self) self.fontsize = fontsize self.average = average self.vertical = vertical self.grid = grid # grid layout may not be implemented in webkit # TODO: average not used yet here # TODO: vertical not supported # maximum, title and formatting_string are lists self.list_maximum = maximum self.list_title = title self.list_formatting_string = formatting_string self.sizer = wx.BoxSizer(wx.VERTICAL) if webview: self.textCtrl = webview.WebView.New(self) values=[None] * len(title) html = self._content_grid(values) if self.grid else self._content_table(values) self.textCtrl.SetPage(html, '') self.sizer.Add(self.textCtrl, 1, wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, 5) self.SetSizer(self.sizer) self.sizer.Fit(self.panel) def _progressbar(self): return \ """ progress {{ display: inline-block; width: 100%; padding: 0px 0 0 0; margin: 0; background: none; border: 0; border-radius: 15px; text-align: left; position: relative; font-family: sans-serif; font-size: {fontsize}px; }} progress::-webkit-progress-bar {{ display: inline-block; width: 100%; margin: 0 auto; background-color: #CCC; border-radius: 15px; box-shadow: 0px 0px 6px #777 inset; }} progress::-webkit-progress-value {{ display: inline-block; width: 100%; float: left; margin: 0px 0px 0 0; background: #F70; border-radius: 15px; box-shadow: 0px 0px 6px #666 inset; }} """ def _head_grid(self): return \ """<!DOCTYPE html><html><head><style> .grid-container {{ display: grid; grid-template-columns: auto 1fr auto; padding: 0px; }} .grid-item {{ background-color: rgba(255, 255, 255, 0.8); padding: 0px; font-size: {fontsize}px; text-align: left; white-space: nowrap; }} """ \ + self._progressbar() + \ """ </style></head><body> <div class="grid-container"> """ def _head_table(self): return \ """<!DOCTYPE html><html><head><style> td {{ white-space: nowrap; }} /* There are simpler solutions than table width, but work only in presumably newer browsers. */ table td:nth-child(2) {{ width: 100%; }} """ \ + self._progressbar() + \ """ </style></head><body> <table style="width:100%"> """ def _end_grid(self): return "</div></body></html>" def _end_table(self): return "</table></body></html>" def _progress_element(self, max_value, value): # minimum is needed to generate a valid progress element value = min(max_value, value) return '<progress max="{max}" value="{val}"></progress>'.format( max=max_value, val=value) def _content_grid(self, values): div = '<div class="grid-item">{item}</div>' html = self._head_grid().format(fontsize=self.fontsize) for i in range(len(self.list_title)): if values[i] is None: values[i] = 0 label = '' else: label = self.list_formatting_string[i].format(values[i]) html += div.format(item=self.list_title[i] + ':') html += div.format(item=self._progress_element( max_value=self.list_maximum[i], value=values[i])) html += div.format(item=label) html += self._end_grid() return html def _content_table(self, values): div = '<td>{item}</td>' html = self._head_table().format(fontsize=self.fontsize) for i in range(len(self.list_title)): html += '<tr>' if values[i] is None: values[i] = 0 label = '' else: label = self.list_formatting_string[i].format(values[i]) html += div.format(item=self.list_title[i] + ':') html += div.format(item=self._progress_element( max_value=self.list_maximum[i], value=values[i])) html += div.format(item=label) html += '</tr>' html += self._end_table() return html def show_value(self, values): if len(self.list_title) != len(values): print('wrong number of values!') return html = self._content_grid(values) if self.grid else self._content_table(values) if webview: self.textCtrl.SetPage(html, '') if __name__ == "__main__": app = wx.App() test = 'html' if test == 'html': fr = MultipleHTMLDashboardFrame( parent=None, fontsize=10, average=1, maximum=[200, 100, 20], title=['T 1', 'T 2', 'T 3'], formatting_string=['{}', '{}', '{}'], vertical=True, grid=False) fr.SetPosition((700, 200)) fr.SetSize((850, 800)) fr.show_value([5000, 20, 1000000]) elif test == 'wx': fr = MultipleDashboardFrame(parent=None, fontsize=10, maximum=[200, 100, 20], title=['T 1', 'T 2', 'T 3'], formatting_string=['{}', '{}', '{}'], vertical=True) fr.SetPosition((700, 200)) fr.SetSize((200, 150)) fr.show_value([200, 20, 0]) fr.Show() app.MainLoop()