📄 listbox.py
字号:
if row_offset >= maxrow: # must scroll further than 1 line row_offset = maxrow-1 self.change_focus((maxcol,maxrow),pos, row_offset, 'above', ) return # if all else fails, keep the current focus. self.shift_focus((maxcol,maxrow), focus_row_offset-1) def _keypress_page_up( self, (maxcol, maxrow) ): middle, top, bottom = self.calculate_visible( (maxcol,maxrow), focus=1 ) if middle is None: return 'page up' row_offset, focus_widget, focus_pos, focus_rows, cursor = middle trim_top, fill_above = top # topmost_visible is row_offset rows above top row of # focus (+ve) or -row_offset rows below top row of focus (-ve) topmost_visible = row_offset # scroll_from_row is (first match) # 1. topmost visible row if focus is not selectable # 2. row containing cursor if focus has a cursor # 3. top row of focus widget if it is visible # 4. topmost visible row otherwise if not focus_widget.selectable(): scroll_from_row = topmost_visible elif cursor is not None: x,y = cursor scroll_from_row = -y elif row_offset >= 0: scroll_from_row = 0 else: scroll_from_row = topmost_visible # snap_rows is maximum extra rows to scroll when # snapping to new a focus snap_rows = topmost_visible - scroll_from_row # move row_offset to the new desired value (1 "page" up) row_offset = scroll_from_row + maxrow # not used below: scroll_from_row = topmost_visible = None # gather potential target widgets t = [] # add current focus t.append((row_offset,focus_widget,focus_pos,focus_rows)) pos = focus_pos # include widgets from calculate_visible(..) for widget, pos, rows in fill_above: row_offset -= rows t.append( (row_offset, widget, pos, rows) ) # add newly visible ones, including within snap_rows snap_region_start = len(t) while row_offset > -snap_rows: widget, pos = self.body.get_prev(pos) if widget is None: break rows = widget.rows((maxcol,)) row_offset -= rows # determine if one below puts current one into snap rgn if row_offset > 0: snap_region_start += 1 t.append( (row_offset, widget, pos, rows) ) # if we can't fill the top we need to adjust the row offsets row_offset, w, p, r = t[-1] if row_offset > 0: adjust = - row_offset t = [(ro+adjust, w, p, r) for (ro,w,p,r) in t] # if focus_widget (first in t) is off edge, remove it row_offset, w, p, r = t[0] if row_offset >= maxrow: del t[0] snap_region_start -= 1 # we'll need this soon self.update_pref_col_from_focus((maxcol,maxrow)) # choose the topmost selectable and (newly) visible widget # search within snap_rows then visible region search_order = ( range( snap_region_start, len(t)) + range( snap_region_start-1, -1, -1 ) ) #assert 0, `t, search_order` bad_choices = [] cut_off_selectable_chosen = 0 for i in search_order: row_offset, widget, pos, rows = t[i] if not widget.selectable(): continue # try selecting this widget pref_row = max(0, -row_offset) # if completely within snap region, adjust row_offset if rows + row_offset <= 0: self.change_focus( (maxcol,maxrow), pos, -(rows-1), 'below', (self.pref_col, rows-1), snap_rows-((-row_offset)-(rows-1))) else: self.change_focus( (maxcol,maxrow), pos, row_offset, 'below', (self.pref_col, pref_row), snap_rows ) # if we're as far up as we can scroll, take this one if (fill_above and self.body.get_prev(fill_above[-1][1]) == (None,None) ): pass #return # find out where that actually puts us middle, top, bottom = self.calculate_visible( (maxcol,maxrow), focus=1 ) act_row_offset, _ign1, _ign2, _ign3, _ign4 = middle # discard chosen widget if it will reduce scroll amount # because of a fixed cursor (absolute last resort) if act_row_offset > row_offset+snap_rows: bad_choices.append(i) continue if act_row_offset < row_offset: bad_choices.append(i) continue # also discard if off top edge (second last resort) if act_row_offset < 0: bad_choices.append(i) cut_off_selectable_chosen = 1 continue return # anything selectable is better than what follows: if cut_off_selectable_chosen: return if fill_above and focus_widget.selectable(): # if we're at the top and have a selectable, return if self.body.get_prev(fill_above[-1][1]) == (None,None): pass #return # if still none found choose the topmost widget good_choices = [j for j in search_order if j not in bad_choices] for i in good_choices + search_order: row_offset, widget, pos, rows = t[i] if pos == focus_pos: continue # if completely within snap region, adjust row_offset if rows + row_offset <= 0: snap_rows -= (-row_offset) - (rows-1) row_offset = -(rows-1) self.change_focus( (maxcol,maxrow), pos, row_offset, 'below', None, snap_rows ) return # no choices available, just shift current one self.shift_focus((maxcol, maxrow), min(maxrow-1,row_offset)) # final check for pathological case where we may fall short middle, top, bottom = self.calculate_visible( (maxcol,maxrow), focus=1 ) act_row_offset, _ign1, pos, _ign2, _ign3 = middle if act_row_offset >= row_offset: # no problem return # fell short, try to select anything else above if not t: return _ign1, _ign2, pos, _ign3 = t[-1] widget, pos = self.body.get_prev(pos) if widget is None: # no dice, we're stuck here return # bring in only one row if possible rows = widget.rows((maxcol,), focus=1) self.change_focus((maxcol,maxrow), pos, -(rows-1), 'below', (self.pref_col, rows-1), 0 ) def _keypress_page_down( self, (maxcol, maxrow) ): middle, top, bottom = self.calculate_visible( (maxcol,maxrow), focus=1 ) if middle is None: return 'page down' row_offset, focus_widget, focus_pos, focus_rows, cursor = middle trim_bottom, fill_below = bottom # bottom_edge is maxrow-focus_pos rows below top row of focus bottom_edge = maxrow - row_offset # scroll_from_row is (first match) # 1. bottom edge if focus is not selectable # 2. row containing cursor + 1 if focus has a cursor # 3. bottom edge of focus widget if it is visible # 4. bottom edge otherwise if not focus_widget.selectable(): scroll_from_row = bottom_edge elif cursor is not None: x,y = cursor scroll_from_row = y + 1 elif bottom_edge >= focus_rows: scroll_from_row = focus_rows else: scroll_from_row = bottom_edge # snap_rows is maximum extra rows to scroll when # snapping to new a focus snap_rows = bottom_edge - scroll_from_row # move row_offset to the new desired value (1 "page" down) row_offset = -scroll_from_row # not used below: scroll_from_row = bottom_edge = None # gather potential target widgets t = [] # add current focus t.append((row_offset,focus_widget,focus_pos,focus_rows)) pos = focus_pos row_offset += focus_rows # include widgets from calculate_visible(..) for widget, pos, rows in fill_below: t.append( (row_offset, widget, pos, rows) ) row_offset += rows # add newly visible ones, including within snap_rows snap_region_start = len(t) while row_offset < maxrow+snap_rows: widget, pos = self.body.get_next(pos) if widget is None: break rows = widget.rows((maxcol,)) t.append( (row_offset, widget, pos, rows) ) row_offset += rows # determine if one above puts current one into snap rgn if row_offset < maxrow: snap_region_start += 1 # if we can't fill the bottom we need to adjust the row offsets row_offset, w, p, rows = t[-1] if row_offset + rows < maxrow: adjust = maxrow - (row_offset + rows) t = [(ro+adjust, w, p, r) for (ro,w,p,r) in t] # if focus_widget (first in t) is off edge, remove it row_offset, w, p, rows = t[0] if row_offset+rows <= 0: del t[0] snap_region_start -= 1 # we'll need this soon self.update_pref_col_from_focus((maxcol,maxrow)) # choose the bottommost selectable and (newly) visible widget # search within snap_rows then visible region search_order = ( range( snap_region_start, len(t)) + range( snap_region_start-1, -1, -1 ) ) #assert 0, `t, search_order` bad_choices = [] cut_off_selectable_chosen = 0 for i in search_order: row_offset, widget, pos, rows = t[i] if not widget.selectable(): continue # try selecting this widget pref_row = min(maxrow-row_offset-1, rows-1) # if completely within snap region, adjust row_offset if row_offset >= maxrow: self.change_focus( (maxcol,maxrow), pos, maxrow-1, 'above', (self.pref_col, 0), snap_rows+maxrow-row_offset-1 ) else: self.change_focus( (maxcol,maxrow), pos, row_offset, 'above', (self.pref_col, pref_row), snap_rows ) # find out where that actually puts us middle, top, bottom = self.calculate_visible( (maxcol,maxrow), focus=1 ) act_row_offset, _ign1, _ign2, _ign3, _ign4 = middle # discard chosen widget if it will reduce scroll amount # because of a fixed cursor (absolute last resort) if act_row_offset < row_offset-snap_rows: bad_choices.append(i) continue if act_row_offset > row_offset: bad_choices.append(i) continue # also discard if off top edge (second last resort) if act_row_offset+rows > maxrow: bad_choices.append(i) cut_off_selectable_chosen = 1 continue return # anything selectable is better than what follows: if cut_off_selectable_chosen: return # if still none found choose the bottommost widget good_choices = [j for j in search_order if j not in bad_choices] for i in good_choices + search_order: row_offset, widget, pos, rows = t[i] if pos == focus_pos: continue # if completely within snap region, adjust row_offset if row_offset >= maxrow: snap_rows -= snap_rows+maxrow-row_offset-1 row_offset = maxrow-1 self.change_focus( (maxcol,maxrow), pos, row_offset, 'above', None, snap_rows ) return # no choices available, just shift current one self.shift_focus((maxcol, maxrow), max(1-focus_rows,row_offset)) # final check for pathological case where we may fall short middle, top, bottom = self.calculate_visible( (maxcol,maxrow), focus=1 ) act_row_offset, _ign1, pos, _ign2, _ign3 = middle if act_row_offset <= row_offset: # no problem return # fell short, try to select anything else below if not t: return _ign1, _ign2, pos, _ign3 = t[-1] widget, pos = self.body.get_next(pos) if widget is None: # no dice, we're stuck here return # bring in only one row if possible rows = widget.rows((maxcol,), focus=1) self.change_focus((maxcol,maxrow), pos, maxrow-1, 'above', (self.pref_col, 0), 0 ) def mouse_event(self, (maxcol, maxrow), event, button, col, row, focus): """ Pass the event to the contained widgets. May change focus on button 1 press. """ middle, top, bottom = self.calculate_visible((maxcol, maxrow), focus=True) if middle is None: return False _ignore, focus_widget, focus_pos, focus_rows, cursor = middle trim_top, fill_above = top _ignore, fill_below = bottom fill_above.reverse() # fill_above is in bottom-up order w_list = ( fill_above + [ (focus_widget, focus_pos, focus_rows) ] + fill_below ) wrow = -trim_top for w, w_pos, w_rows in w_list: if wrow + w_rows > row: break wrow += w_rows else: return False focus = focus and w == focus_widget if is_mouse_press(event) and button==1: if w.selectable(): self.change_focus((maxcol,maxrow), w_pos, wrow) if not hasattr(w,'mouse_event'): return False return w.mouse_event((maxcol,), event, button, col, row-wrow, focus) def ends_visible(self, (maxcol, maxrow), focus=False): """Return a list that may contain 'top' and/or 'bottom'. convenience function for checking whether the top and bottom of the list are visible """ l = [] middle,top,bottom = self.calculate_visible( (maxcol,maxrow), focus=focus ) if middle is None: # empty listbox return ['top','bottom'] trim_top, above = top trim_bottom, below = bottom if trim_bottom == 0: row_offset, w, pos, rows, c = middle row_offset += rows for w, pos, rows in below: row_offset += rows if row_offset < maxrow: l.append( 'bottom' ) elif self.body.get_next(pos) == (None,None): l.append( 'bottom' ) if trim_top == 0: row_offset, w, pos, rows, c = middle for w, pos, rows in above: row_offset -= rows if self.body.get_prev(pos) == (None,None): l.append( 'top' ) return l
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -