diff --git a/.github/workflows/check-patch.yaml b/.github/workflows/check-patch.yaml index 629ab892b..ba67d37d1 100644 --- a/.github/workflows/check-patch.yaml +++ b/.github/workflows/check-patch.yaml @@ -9,7 +9,7 @@ jobs: - name: Install tools run: | sudo apt-get update - sudo apt-get install gettext + sudo apt-get install gettext wdiff - name: Checkout uses: actions/checkout@v3 with: diff --git a/chirp/wxui/memedit.py b/chirp/wxui/memedit.py index 89ac3a32e..ee309e55d 100644 --- a/chirp/wxui/memedit.py +++ b/chirp/wxui/memedit.py @@ -569,6 +569,10 @@ def __init__(self, memedit): self.data.Add(wx.CustomDataObject(common.CHIRP_DATA_MEMORY)) self.SetDataObject(self.data) + def parse_data(self): + data = self.data.GetObject(common.CHIRP_DATA_MEMORY) + return pickle.loads(data.GetData().tobytes()) + def OnData(self, x, y, defResult): if not self.GetData(): return wx.DragNone @@ -578,8 +582,7 @@ def OnData(self, x, y, defResult): if row < 0: return wx.DragCancel LOG.debug('Memory dropped on row %s,%s' % (row, cell)) - data = self.data.GetObject(common.CHIRP_DATA_MEMORY) - payload = pickle.loads(data.GetData().tobytes()) + payload = self.parse_data() original_locs = [m.number for m in payload['mems']] source = self._memedit.FindWindowById(payload.pop('source')) if not self._memedit._cb_paste_memories(payload, row=row): @@ -593,11 +596,20 @@ def OnData(self, x, y, defResult): return defResult def OnDragOver(self, x, y, defResult): + if self.GetData(): + payload = self.parse_data() + rows = len(payload['mems']) + else: + rows = 1 + x, y = self._memedit._grid.CalcUnscrolledPosition(x, y) y -= self._memedit._grid.GetColLabelSize() row, cell = self._memedit._grid.XYToCell(x, y) + max_row = self._memedit._grid.GetNumberRows() if row >= 0: - self._memedit._grid.SelectRow(row) + self._memedit._grid.ClearSelection() + for i in range(row, min(max_row, row + rows)): + self._memedit._grid.SelectRow(i, addToSelected=True) return defResult def OnDrop(self, x, y): @@ -659,28 +671,67 @@ def __init__(self, radio, *a, **k): self._grid.Bind(wx.grid.EVT_GRID_CELL_BEGIN_DRAG, self._memory_drag) row_labels = self._grid.GetGridRowLabelWindow() row_labels.Bind(wx.EVT_LEFT_DOWN, self._row_click) + row_labels.Bind(wx.EVT_LEFT_UP, self._row_click) row_labels.Bind(wx.EVT_MOTION, self._rowheader_mouseover) + self._dragging_rows = None self._dc = wx.ScreenDC() self.set_cell_attrs() def _row_click(self, event): - if event.AltDown(): - return self._memory_drag(event) + # In order to override the drag-to-multi-select behavior of the base + # grid, we need to basically reimplement what happens when a user + # clicks on a row header. Shift for block select, Ctrl/Cmd for add- + # to-selection, and then drag to actually copy/move memories. + if sys.platform == 'darwin': + multi = event.CmdDown() else: - event.Skip() + multi = event.ControlDown() + cur_selected = self._grid.GetSelectedRows() + x, y = self._grid.CalcUnscrolledPosition(event.GetX(), event.GetY()) + row, _cell = self._grid.XYToCell(x, y) + if event.LeftDown(): + # Record where we clicked in case we start to drag, but only if + # they started that drag from one of the selected memories. + self._dragging_rows = (row, event.GetX(), event.GetY()) + elif self._dragging_rows is not None: + # Never dragged, so skip to get regular behavior + self._dragging_rows = None + try: + first_row = cur_selected[0] + except IndexError: + first_row = 0 + if event.ShiftDown(): + # Find the block the user wants and select all of it + start = min(row, first_row) + end = max(row, first_row) + self._grid.SelectBlock(start, 0, end, 0) + elif multi and row in cur_selected: + # The row is currently selected and we were clicked with the + # multi-select key held, so we need to select everything *but* + # the clicked row. + cur_selected.remove(row) + self._grid.ClearSelection() + for row in cur_selected: + self._grid.SelectRow(row, addToSelected=True) + else: + # They clicked on a row, add to selection if the multi-select + # key is held, otherwise select only this row. + self._grid.SelectRow(row, addToSelected=multi) + else: + # Unclick but we started a drag + self._dragging_rows = None def _rowheader_mouseover(self, event): - event.Skip() - if len(self.get_selected_rows_safe()) <= 1: - return - self._grid.YToRow(event.GetY()) - if sys.platform == 'darwin': - key = 'option' - else: - key = 'alt' - event.GetEventObject().SetToolTip( - _('Hold %(key)s to drag multiple memories') % {'key': key}) + if self._dragging_rows is not None: + row, x, y = self._dragging_rows + if row not in self._grid.GetSelectedRows(): + # Drag started from a non-selected cell, so ignore + return + if abs(event.GetX() - x) > 10 or abs(event.GetY() - y) > 10: + # Enough motion to consider this a drag motion + self._dragging_rows = None + return self._memory_drag(event) def _memory_drag(self, event): data = self.cb_copy_getdata() diff --git a/chirp/wxui/settingsedit.py b/chirp/wxui/settingsedit.py index 96f7f589a..24e568d81 100644 --- a/chirp/wxui/settingsedit.py +++ b/chirp/wxui/settingsedit.py @@ -40,6 +40,7 @@ def __init__(self, radio, *a, **k): sizer.Add(self._group_control, 1, wx.EXPAND) self._initialized = False + self._restore_selection = None def _initialize(self, job): self.stop_wait_dialog() @@ -48,6 +49,9 @@ def _initialize(self, job): raise job.result self._settings = job.result self._load_settings() + if self._restore_selection is not None: + self._group_control.SetSelection(self._restore_selection) + self._restore_selection = None def selected(self): if not self._initialized: @@ -56,7 +60,19 @@ def selected(self): self.do_radio(lambda job: wx.CallAfter(self._initialize, job), 'get_settings') + def get_scroll_pos(self): + return self._group_control.GetSelection() + + def set_scroll_pos(self, pos): + try: + self._group_control.SetSelection(pos) + except AssertionError: + # If we're in the middle of a load, stash the position so we will + # restore it once we have everything. + self._restore_selection = pos + def refresh(self): + self._restore_selection = self._group_control.GetSelection() self._group_control.DeleteAllPages() # Next select will re-load everything self._initialized = False diff --git a/tools/check_commit.sh b/tools/check_commit.sh index 844187a18..c92c2b023 100755 --- a/tools/check_commit.sh +++ b/tools/check_commit.sh @@ -55,7 +55,7 @@ if grep '/cpep8.blacklist' added_lines; then fi grep -i 'license' added_lines > license_lines -if grep -iv '(GNU General Public License|Free Software Foundation)' license_lines; then +if grep -ivE '(GNU General Public License|Free Software Foundation|gnu.org.licenses)' license_lines; then fail 'Files must be GPLv3 licensed (or not contain any license language)' fi @@ -79,4 +79,15 @@ if echo $added_files | grep -q chirp.drivers && ! echo $added_files | grep -q te fail All new drivers should include a test image fi +existing_drivers=$(git ls-tree --name-only $BASE chirp/drivers/) +limit=20 +for nf in $added_files; do + for of in $existing_drivers; do + change=$(wdiff -s $of $nf | grep $of | sed -r 's/.* ([0-9]+)% changed/\1/') + if [ "$change" -lt "$limit" ]; then + fail "New file $nf shares at least $((100 - $change))% with $of!" + fi + done +done + exit $RETCODE