From 96e25b351a3d3acff3eef16ecf10f6da84d5030a Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Fri, 16 Dec 2022 17:06:48 -0800 Subject: [PATCH] Add a super-basic printing implementation This is not something I have ever wanted, but it has been requested plenty of times. Since wx makes this easy, this adds a super bare- bones implementation that seems to work for me, which I think is probably worthwhile. It doesn't handle multiple pages super elegantly, and probably needs to have a "print selection" option, but it works. Related to one of chirp's oldest bugs: #249 --- chirp/wxui/main.py | 10 ++++ chirp/wxui/memedit.py | 3 ++ chirp/wxui/printing.py | 102 +++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + setup.py | 3 +- 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 chirp/wxui/printing.py diff --git a/chirp/wxui/main.py b/chirp/wxui/main.py index 71f6f4c3..23e0b7ae 100644 --- a/chirp/wxui/main.py +++ b/chirp/wxui/main.py @@ -468,6 +468,9 @@ class ChirpMain(wx.Frame): file_menu.Append(wx.MenuItem(file_menu, wx.ID_SEPARATOR)) + print_item = file_menu.Append(wx.ID_PRINT) + self.Bind(wx.EVT_MENU, self._menu_print, print_item) + close_item = file_menu.Append(wx.ID_CLOSE) close_item.SetAccel(wx.AcceleratorEntry(wx.MOD_CONTROL, ord('W'))) self.Bind(wx.EVT_MENU, self._menu_close, close_item) @@ -647,6 +650,12 @@ class ChirpMain(wx.Frame): return menu_bar + def _menu_print(self, event): + from chirp.wxui import printing + p = printing.MemoryPrinter(self, self.current_editorset.radio, + self.current_editorset.current_editor) + p.print(self.current_editorset.current_editor.get_selected_memories()) + def make_toolbar(self): tb = self.CreateToolBar() @@ -764,6 +773,7 @@ class ChirpMain(wx.Frame): (self._goto_item, can_goto), (self._find_next_item, can_goto), (wx.ID_FIND, can_goto), + (wx.ID_PRINT, can_goto), (self._export_menu_item, can_close), ] for ident, enabled in items: diff --git a/chirp/wxui/memedit.py b/chirp/wxui/memedit.py index e12c97af..d7b58d8a 100644 --- a/chirp/wxui/memedit.py +++ b/chirp/wxui/memedit.py @@ -1023,6 +1023,9 @@ class ChirpMemEdit(common.ChirpEditor, common.ChirpSyncEditor): r.set_memory(self._memory_cache[row]) r.save(filename) + def get_selected_memories(self): + return [self.row2mem(r) for r in self._grid.GetSelectedRows()] + class ChirpLiveMemEdit(ChirpMemEdit, common.ChirpAsyncEditor): pass diff --git a/chirp/wxui/printing.py b/chirp/wxui/printing.py new file mode 100644 index 00000000..c24768a8 --- /dev/null +++ b/chirp/wxui/printing.py @@ -0,0 +1,102 @@ +# Copyright 2022 Dan Smith +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import wx.html + +import yattag + +from chirp.wxui import common +from chirp.wxui import report + + +class MemoryPrinter(wx.html.HtmlEasyPrinting): + def __init__(self, parent, radio, memedit): + super().__init__() + self._radio = radio + self._features = radio.get_features() + self._col_defs = memedit._col_defs + # Set some default printer and page options. + self.GetPrintData().SetPaperId(wx.PAPER_LETTER) # wx.PAPER_A4 + self.GetPrintData().SetOrientation(wx.LANDSCAPE) # wx.PORTRAIT + # Black and white printing if False. + self.GetPrintData().SetColour(False) + self.GetPageSetupData().SetMarginTopLeft((0, 5)) + self.GetPageSetupData().SetMarginBottomRight((10, 10)) + self.SetFonts('Sans', 'Courier', (8,) * 7) + + def _memory(self, doc, mem): + tag = doc.tag + with tag('td'): + with tag('tt'): + doc.text(mem.number) + for col_def in self._col_defs: + if not col_def.valid: + continue + with tag('td'): + with tag('tt'): + doc.text(col_def.render_value(mem)) + + def _memory_table(self, doc, only_memories): + tag = doc.tag + lo, hi = self._features.memory_bounds + row = 0 + + # This is arbitrary, unsure if it will work on all platforms + # or not + ROWS_PER_PAGE = 35 + + memories = [] + for i in range(lo, hi + 1): + mem = self._radio.get_memory(i) + if not mem.empty: + memories.append(mem) + + for i in range(0, len(memories), ROWS_PER_PAGE): + with tag('div', ('style', 'page-break-before:always')): + pass + with tag('table', ('border', '1'), ('width', '100%'), + ('cellspacing', '0')): + with tag('tr'): + with tag('th'): + doc.text('#') + for col_def in self._col_defs: + if not col_def.valid: + continue + with tag('th'): + doc.text(col_def.label) + for row in range(i, i + ROWS_PER_PAGE): + try: + mem = memories[row] + except IndexError: + continue + if (only_memories and mem.number not in only_memories): + continue + with tag('tr'): + try: + self._memory(doc, mem) + except IndexError: + pass + + @common.error_proof() + def print(self, only_memories=None): + report.report_model(self._radio, 'print') + if only_memories and len(only_memories) == 1: + # Only print selection if there is more than one row selected + only_memories = None + doc, tag, text = yattag.Doc().tagtext() + with tag('html'): + with tag('body'): + self._memory_table(doc, only_memories) + return self.PreviewText(doc.getvalue()) diff --git a/requirements.txt b/requirements.txt index 8430130c..3578402a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ requests pywin32; platform_system=="Windows" suds importlib-resources;python_version<"3.10" +yattag diff --git a/setup.py b/setup.py index d611210a..bd6ab9cd 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,8 @@ setup(name='chirp', 'pyserial', 'six', 'future', - 'importlib-resources;python_version<"3.10"' + 'importlib-resources;python_version<"3.10"', + 'yattag', ], extras_require={ 'wx': ['wxPython'],