listpick 0.1.13.57__tar.gz → 0.1.13.58__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. {listpick-0.1.13.57 → listpick-0.1.13.58}/CHANGELOG.md +1 -0
  2. {listpick-0.1.13.57/src/listpick.egg-info → listpick-0.1.13.58}/PKG-INFO +1 -1
  3. {listpick-0.1.13.57 → listpick-0.1.13.58}/setup.py +1 -1
  4. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/listpick_app.py +86 -41
  5. listpick-0.1.13.58/src/listpick/listpick_app_problem_branch.py +3248 -0
  6. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/utils.py +5 -5
  7. {listpick-0.1.13.57 → listpick-0.1.13.58/src/listpick.egg-info}/PKG-INFO +1 -1
  8. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick.egg-info/SOURCES.txt +1 -0
  9. {listpick-0.1.13.57 → listpick-0.1.13.58}/.gitignore +0 -0
  10. {listpick-0.1.13.57 → listpick-0.1.13.58}/LICENSE.txt +0 -0
  11. {listpick-0.1.13.57 → listpick-0.1.13.58}/README.md +0 -0
  12. {listpick-0.1.13.57 → listpick-0.1.13.58}/TODO.md +0 -0
  13. {listpick-0.1.13.57 → listpick-0.1.13.58}/assets/aria2tui_screenshot.png +0 -0
  14. {listpick-0.1.13.57 → listpick-0.1.13.58}/assets/file_compare.png +0 -0
  15. {listpick-0.1.13.57 → listpick-0.1.13.58}/assets/lpfman.png +0 -0
  16. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/footer_string_example.py +0 -0
  17. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/input.toml +0 -0
  18. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/input.txt +0 -0
  19. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/list_files.toml +0 -0
  20. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/list_files_empty.toml +0 -0
  21. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/picker_example.py +0 -0
  22. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/setup.cfg +0 -0
  23. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/template.py +0 -0
  24. {listpick-0.1.13.57 → listpick-0.1.13.58}/examples/video_duplicates.toml +0 -0
  25. {listpick-0.1.13.57 → listpick-0.1.13.58}/listpick.py +0 -0
  26. {listpick-0.1.13.57 → listpick-0.1.13.58}/requirements.txt +0 -0
  27. {listpick-0.1.13.57 → listpick-0.1.13.58}/setup.cfg +0 -0
  28. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/__init__.py +0 -0
  29. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/__main__.py +0 -0
  30. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/__init__.py +0 -0
  31. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/build_help.py +0 -0
  32. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/footer.py +0 -0
  33. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/help_screen.py +0 -0
  34. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/input_field.py +0 -0
  35. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/keys.py +0 -0
  36. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/pane_stuff.py +0 -0
  37. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/ui/picker_colours.py +0 -0
  38. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/__init__.py +0 -0
  39. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/clipboard_operations.py +0 -0
  40. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/config.py +0 -0
  41. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/dump.py +0 -0
  42. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/filtering.py +0 -0
  43. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/generate_data.py +0 -0
  44. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/options_selectors.py +0 -0
  45. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/paste_operations.py +0 -0
  46. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/picker_log.py +0 -0
  47. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/search_and_filter_utils.py +0 -0
  48. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/searching.py +0 -0
  49. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/sorting.py +0 -0
  50. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick/utils/table_to_list_of_lists.py +0 -0
  51. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick.egg-info/dependency_links.txt +0 -0
  52. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick.egg-info/entry_points.txt +0 -0
  53. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick.egg-info/requires.txt +0 -0
  54. {listpick-0.1.13.57 → listpick-0.1.13.58}/src/listpick.egg-info/top_level.txt +0 -0
  55. {listpick-0.1.13.57 → listpick-0.1.13.58}/tests/kitty_control.sh +0 -0
  56. {listpick-0.1.13.57 → listpick-0.1.13.58}/tests/sorting_dates.csv +0 -0
@@ -25,6 +25,7 @@
25
25
  - Setup logging for the Picker class. Currently still very basic but will track to the last function that was run before crash if the --debug flag is passed to the picker.
26
26
  - Added pin_cursor options which keeps the cursor on the same row during a refresh rather than tracking the id of the highlighted row.
27
27
  - Updated StandardFooter. Now shows information on two lines rather than three; all cursor and selection information on the first line and the sort information on the second. Cursor, Visual (de)selection now abreviated to C, VS, and VDS.
28
+ - Added try-except wrapper to draw_screen function to prevent crashes during rapid resizing.
28
29
 
29
30
  ## [0.1.13] 2025-07-28
30
31
  - Cell-based picker is now supported.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: listpick
3
- Version: 0.1.13.57
3
+ Version: 0.1.13.58
4
4
  Summary: Listpick is a powerful TUI data tool for creating TUI apps or viewing/comparing tabulated data.
5
5
  Home-page: https://github.com/grimandgreedy/listpick
6
6
  Author: Grim
@@ -16,7 +16,7 @@ with open("README.md", "r", encoding = "utf-8") as fh:
16
16
 
17
17
  setuptools.setup(
18
18
  name = "listpick",
19
- version = "0.1.13.57",
19
+ version = "0.1.13.58",
20
20
  author = "Grim",
21
21
  author_email = "grimandgreedy@protonmail.com",
22
22
  description = "Listpick is a powerful TUI data tool for creating TUI apps or viewing/comparing tabulated data.",
@@ -140,6 +140,7 @@ class Picker:
140
140
  footer_string_refresh_function: Optional[Callable] = None,
141
141
  footer_timer: float=1,
142
142
  get_footer_string_startup=False,
143
+ unicode_char_width: bool = True,
143
144
 
144
145
  colours_start: int =0,
145
146
  colours_end: int =-1,
@@ -256,7 +257,7 @@ class Picker:
256
257
  self.footer_string_refresh_function = footer_string_refresh_function
257
258
  self.footer_timer = footer_timer
258
259
  self.get_footer_string_startup = get_footer_string_startup,
259
-
260
+ self.unicode_char_width = unicode_char_width
260
261
 
261
262
 
262
263
  self.colours_start = colours_start
@@ -312,17 +313,12 @@ class Picker:
312
313
  self.debug_level = debug_level
313
314
 
314
315
 
315
-
316
-
317
316
  self.initialise_picker_state(reset_colours=self.reset_colours)
318
317
 
319
-
320
318
  # Note: We have to set the footer after initialising the picker state so that the footer can use the get_function_data method
321
319
  self.footer_options = [StandardFooter(self.stdscr, colours_start, self.get_function_data), CompactFooter(self.stdscr, colours_start, self.get_function_data), NoFooter(self.stdscr, colours_start, self.get_function_data)]
322
320
  self.footer = self.footer_options[self.footer_style]
323
321
 
324
- # self.footer = CompactFooter(self.stdscr, colours_start, self.get_function_data)
325
-
326
322
 
327
323
  def calculate_section_sizes(self):
328
324
  """
@@ -384,7 +380,6 @@ class Picker:
384
380
  def initialise_picker_state(self, reset_colours=False) -> None:
385
381
  """ Initialise state variables for the picker. These are: debugging and colours. """
386
382
 
387
-
388
383
  if curses.has_colors() and self.colours != None:
389
384
  # raise Exception("Terminal does not support color")
390
385
  curses.start_color()
@@ -694,7 +689,7 @@ class Picker:
694
689
  # rows = [v[1] for v in self.indexed_items] if len(self.indexed_items) else self.items
695
690
  # Determine widths based only on the currently displayed indexed rows
696
691
  rows = [v[1] for v in self.indexed_items[start_index:end_index]] if len(self.indexed_items) else self.items
697
- self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
692
+ self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w, unicode_char_width=self.unicode_char_width)
698
693
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
699
694
  visible_columns_total_width = sum(visible_column_widths) + len(self.separator)*(len(visible_column_widths)-1)
700
695
 
@@ -793,10 +788,10 @@ class Picker:
793
788
  else:
794
789
  cell_value = self.indexed_items[row][1][col] + self.separator
795
790
  # cell_value = cell_value[:min(cell_width, cell_max_width)-len(self.separator)]
796
- cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width)-len(self.separator))
791
+ cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width)-len(self.separator), self.unicode_char_width)
797
792
  cell_value = cell_value + self.separator
798
793
  # cell_value = cell_value
799
- cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width))
794
+ cell_value = truncate_to_display_width(cell_value, min(cell_width, cell_max_width), self.unicode_char_width)
800
795
  # row_str = truncate_to_display_width(row_str_left_adj, min(w-self.startx, visible_columns_total_width))
801
796
  self.stdscr.addstr(y, cell_pos, cell_value, curses.color_pair(self.colours_start+colour_pair_number) | curses.A_BOLD)
802
797
  # Part of the cell is on screen
@@ -838,7 +833,7 @@ class Picker:
838
833
  def draw_highlights(highlights: list[dict], idx: int, y: int, item: tuple[int, list[str]]):
839
834
  self.logger.debug(f"function: draw_highlights()")
840
835
  if len(highlights) == 0: return None
841
- full_row_str = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)
836
+ full_row_str = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols, self.unicode_char_width)
842
837
  row_str = full_row_str[self.leftmost_char:]
843
838
  for highlight in highlights:
844
839
  if "row" in highlight:
@@ -854,13 +849,13 @@ class Picker:
854
849
  continue
855
850
 
856
851
  elif type(highlight["field"]) == type(0) and highlight["field"] not in self.hidden_columns:
857
- match = re.search(highlight["match"], truncate_to_display_width(item[1][highlight["field"]], self.column_widths[highlight["field"]], centre=False), re.IGNORECASE)
852
+ match = re.search(highlight["match"], truncate_to_display_width(item[1][highlight["field"]], self.column_widths[highlight["field"]], centre=False, unicode_char_width=self.unicode_char_width), re.IGNORECASE)
858
853
  if not match: continue
859
854
  field_start = sum([width for i, width in enumerate(self.column_widths[:highlight["field"]]) if i not in self.hidden_columns]) + sum([1 for i in range(highlight["field"]) if i not in self.hidden_columns])*wcswidth(self.separator)
860
855
 
861
856
  ## We want to search the non-centred values but highlight the centred values.
862
857
  if self.centre_in_cols:
863
- tmp = truncate_to_display_width(item[1][highlight["field"]], self.column_widths[highlight["field"]], self.centre_in_cols)
858
+ tmp = truncate_to_display_width(item[1][highlight["field"]], self.column_widths[highlight["field"]], self.centre_in_cols, self.unicode_char_width)
864
859
  field_start += (len(tmp) - len(tmp.lstrip()))
865
860
 
866
861
  highlight_start = field_start + match.start()
@@ -882,11 +877,11 @@ class Picker:
882
877
  item = self.indexed_items[idx]
883
878
  y = idx - start_index + self.top_space
884
879
 
885
- row_str = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)[self.leftmost_char:]
880
+ # row_str = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)[self.leftmost_char:]
886
881
  # row_str = truncate_to_display_width(row_str, min(w-self.startx, visible_columns_total_width))
887
- row_str_orig = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)
882
+ row_str_orig = format_row(item[1], self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols, self.unicode_char_width)
888
883
  row_str_left_adj = clip_left(row_str_orig, self.leftmost_char)
889
- row_str = truncate_to_display_width(row_str_left_adj, min(w-self.startx, visible_columns_total_width))
884
+ row_str = truncate_to_display_width(row_str_left_adj, min(w-self.startx, visible_columns_total_width), self.unicode_char_width)
890
885
  # row_str = truncate_to_display_width(row_str, min(w-self.startx, visible_columns_total_width))[self.leftmost_char:]
891
886
 
892
887
  ## Display the standard row
@@ -899,7 +894,7 @@ class Picker:
899
894
 
900
895
  # Higlight cursor cell and selected cells
901
896
  if self.cell_cursor:
902
- self.selected_cells_by_row = get_selected_cells_by_row(self.cell_selections)
897
+ # self.selected_cells_by_row = get_selected_cells_by_row(self.cell_selections)
903
898
  if item[0] in self.selected_cells_by_row:
904
899
  for j in self.selected_cells_by_row[item[0]]:
905
900
  highlight_cell(idx, j, visible_column_widths, colour_pair_number=25)
@@ -993,6 +988,7 @@ class Picker:
993
988
  self.stdscr.addstr(h - 1, w-footer_string_width-1, " "*footer_string_width, curses.color_pair(self.colours_start+24))
994
989
  self.stdscr.addstr(h - 1, w-footer_string_width-1, f"{disp_string}", curses.color_pair(self.colours_start+24))
995
990
 
991
+ self.stdscr.refresh()
996
992
  ## Display infobox
997
993
  if self.display_infobox:
998
994
  self.infobox(self.stdscr, message=self.infobox_items, title=self.infobox_title)
@@ -1140,6 +1136,7 @@ class Picker:
1140
1136
  "debug": self.debug,
1141
1137
  "debug_level": self.debug_level,
1142
1138
  "reset_colours": self.reset_colours,
1139
+ "unicode_char_width": self.unicode_char_width,
1143
1140
  }
1144
1141
  return function_data
1145
1142
 
@@ -1393,6 +1390,8 @@ class Picker:
1393
1390
  self.initialise_variables()
1394
1391
  elif setting == "pc":
1395
1392
  self.pin_cursor = not self.pin_cursor
1393
+ elif setting == "unicode":
1394
+ self.unicode_char_width = not self.unicode_char_width
1396
1395
 
1397
1396
  elif setting.startswith("ft"):
1398
1397
  if len(setting) > 2 and setting[2:].isnumeric():
@@ -1456,7 +1455,6 @@ class Picker:
1456
1455
  self.draw_screen(self.indexed_items, self.highlights)
1457
1456
  self.notification(self.stdscr, message=f"Theme {self.colour_theme_number} applied.")
1458
1457
 
1459
-
1460
1458
  else:
1461
1459
  self.user_settings = ""
1462
1460
  return None
@@ -1489,7 +1487,8 @@ class Picker:
1489
1487
  self.selections[self.indexed_items[i][0]] = True
1490
1488
  for i in self.cell_selections.keys():
1491
1489
  self.cell_selections[i] = True
1492
-
1490
+ for row in range(len(self.indexed_items)):
1491
+ self.selected_cells_by_row[row] = list(range(len(self.indexed_items[row][1])))
1493
1492
  self.draw_screen(self.indexed_items, self.highlights)
1494
1493
 
1495
1494
  def deselect_all(self) -> None:
@@ -1499,6 +1498,7 @@ class Picker:
1499
1498
  self.selections[i] = False
1500
1499
  for i in self.cell_selections.keys():
1501
1500
  self.cell_selections[i] = False
1501
+ self.selected_cells_by_row = {}
1502
1502
  self.draw_screen(self.indexed_items, self.highlights)
1503
1503
 
1504
1504
  def handle_visual_selection(self, selecting:bool = True) -> None:
@@ -1527,9 +1527,18 @@ class Picker:
1527
1527
  xend = max(self.start_selection_col, self.selected_column)
1528
1528
  for i in range(ystart, yend + 1):
1529
1529
  if self.indexed_items[i][0] not in self.unselectable_indices:
1530
- for j in range(xstart, xend+1):
1531
- cell_index = (self.indexed_items[i][0], j)
1530
+ row = self.indexed_items[i][0]
1531
+ if row not in self.selected_cells_by_row:
1532
+ self.selected_cells_by_row[row] = []
1533
+
1534
+ for col in range(xstart, xend+1):
1535
+ cell_index = (row, col)
1532
1536
  self.cell_selections[cell_index] = True
1537
+
1538
+ self.selected_cells_by_row[row].append(col)
1539
+ # Remove duplicates
1540
+ self.selected_cells_by_row[row] = list(set(self.selected_cells_by_row[row]))
1541
+
1533
1542
  self.start_selection = -1
1534
1543
  self.end_selection = -1
1535
1544
  self.is_selecting = False
@@ -1551,10 +1560,19 @@ class Picker:
1551
1560
  xstart = min(self.start_selection_col, self.selected_column)
1552
1561
  xend = max(self.start_selection_col, self.selected_column)
1553
1562
  for i in range(ystart, yend + 1):
1563
+ row = self.indexed_items[i][0]
1554
1564
  if self.indexed_items[i][0] not in self.unselectable_indices:
1555
- for j in range(xstart, xend+1):
1556
- cell_index = (self.indexed_items[i][0], j)
1557
- self.cell_selections[cell_index] = False
1565
+ if row in self.selected_cells_by_row:
1566
+ for col in range(xstart, xend+1):
1567
+ try:
1568
+ self.selected_cells_by_row[row].remove(col)
1569
+ except:
1570
+ pass
1571
+ cell_index = (row, col)
1572
+ self.cell_selections[cell_index] = False
1573
+ if self.selected_cells_by_row[row] == []:
1574
+ del self.selected_cells_by_row[row]
1575
+
1558
1576
  self.start_selection = -1
1559
1577
  self.end_selection = -1
1560
1578
  self.is_deselecting = False
@@ -1833,7 +1851,7 @@ class Picker:
1833
1851
 
1834
1852
  def get_word_list(self) -> list[str]:
1835
1853
  """ Get a list of all words used in any cell of the picker. Used for completion in search/filter input_field. """
1836
- self.logger.info(f"function: infobox()")
1854
+ self.logger.info(f"function: get_word_list()")
1837
1855
  translator = str.maketrans('', '', string.punctuation)
1838
1856
 
1839
1857
  words = []
@@ -2076,6 +2094,7 @@ class Picker:
2076
2094
  options += [["rh", "Toggle row header"]]
2077
2095
  options += [["modes", "Toggle modes"]]
2078
2096
  options += [["ft", "Cycle through footer styles (accepts ft#)"]]
2097
+ options += [["unicode", "Toggle b/w using len and wcwidth to calculate char width."]]
2079
2098
  options += [[f"s{i}", f"Select col. {i}"] for i in range(len(self.items[0]))]
2080
2099
  options += [[f"!{i}", f"Toggle col. {i}"] for i in range(len(self.items[0]))]
2081
2100
  options += [["ara", "Add empty row after cursor."]]
@@ -2140,11 +2159,31 @@ class Picker:
2140
2159
  if len(self.indexed_items) > 0:
2141
2160
  item_index = self.indexed_items[self.cursor_pos][0]
2142
2161
  cell_index = (self.indexed_items[self.cursor_pos][0], self.selected_column)
2162
+ row, col = cell_index
2143
2163
  selected_count = sum(self.selections.values())
2144
2164
  if self.max_selected == -1 or selected_count >= self.max_selected:
2145
2165
  self.toggle_item(item_index)
2146
2166
 
2147
2167
  self.cell_selections[cell_index] = not self.cell_selections[cell_index]
2168
+ ## Set self.selected_cells_by_row
2169
+ # If any cells in the current row are selected
2170
+ if row in self.selected_cells_by_row:
2171
+ # If the current cell is selected then remove it
2172
+ if col in self.selected_cells_by_row[row]:
2173
+ # If the current cell is the only cell in the row that is selected then remove the row from the dict
2174
+ if len(self.selected_cells_by_row[row]) == 1:
2175
+
2176
+ del self.selected_cells_by_row[row]
2177
+ # else remove only the index of the current cell
2178
+ else:
2179
+ self.selected_cells_by_row[row].remove(col)
2180
+ # If there are cells in the row that are selected then append the current cell to the row
2181
+ else:
2182
+ self.selected_cells_by_row[row].append(col)
2183
+ # Add the a list containing only the current column
2184
+ else:
2185
+ self.selected_cells_by_row[row] = [col]
2186
+
2148
2187
  self.cursor_down()
2149
2188
  elif self.check_key("select_all", key, self.keys_dict): # Select all (m or ctrl-a)
2150
2189
  self.select_all()
@@ -2278,7 +2317,7 @@ class Picker:
2278
2317
 
2279
2318
  ## Scroll with column select
2280
2319
  rows = self.get_visible_rows()
2281
- self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
2320
+ self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w, unicode_char_width=self.unicode_char_width)
2282
2321
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
2283
2322
  column_set_width = sum(visible_column_widths)+len(self.separator)*len(visible_column_widths)
2284
2323
  start_of_cell = sum(visible_column_widths[:self.selected_column])+len(self.separator)*self.selected_column
@@ -2305,8 +2344,7 @@ class Picker:
2305
2344
 
2306
2345
  ## Scroll with column select
2307
2346
  rows = self.get_visible_rows()
2308
- self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
2309
-
2347
+ self.column_widths = get_column_widths(rows, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w, unicode_char_width=self.unicode_char_width)
2310
2348
  visible_column_widths = [c for i,c in enumerate(self.column_widths) if i not in self.hidden_columns]
2311
2349
  column_set_width = sum(visible_column_widths)+len(self.separator)*len(visible_column_widths)
2312
2350
  start_of_cell = sum(visible_column_widths[:self.selected_column])+len(self.separator)*self.selected_column
@@ -2321,18 +2359,13 @@ class Picker:
2321
2359
  self.leftmost_char = start_of_cell
2322
2360
 
2323
2361
  self.leftmost_char = max(0, min(column_set_width - display_width + 5, self.leftmost_char))
2324
- #
2362
+
2325
2363
  elif self.check_key("scroll_right", key, self.keys_dict):
2326
2364
  self.logger.info(f"key_function scroll_right")
2327
- rows = self.get_visible_rows()
2328
- longest_row_str_len = 0
2329
- for i in range(len(rows)):
2330
- item = rows[i]
2331
- row_str = format_row(item, self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)[self.leftmost_char:]
2332
- if len(row_str) > longest_row_str_len: longest_row_str_len=len(row_str)
2333
-
2334
- if longest_row_str_len >= w-self.startx:
2335
- self.leftmost_char = self.leftmost_char+5
2365
+ if len(self.indexed_items):
2366
+ row_width = sum(self.column_widths) + len(self.separator)*(len(self.column_widths)-1)
2367
+ if row_width-self.leftmost_char >= w-self.startx:
2368
+ self.leftmost_char = self.leftmost_char+5
2336
2369
 
2337
2370
  elif self.check_key("scroll_left", key, self.keys_dict):
2338
2371
  self.logger.info(f"key_function scroll_left")
@@ -2349,7 +2382,7 @@ class Picker:
2349
2382
  rows = self.get_visible_rows()
2350
2383
  for i in range(len(rows)):
2351
2384
  item = rows[i]
2352
- row_str = format_row(item, self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols)
2385
+ row_str = format_row(item, self.hidden_columns, self.column_widths, self.separator, self.centre_in_cols, self.unicode_char_width)
2353
2386
  if len(row_str) > longest_row_str_len: longest_row_str_len=len(row_str)
2354
2387
  # for i in range(len(self.indexed_items)):
2355
2388
  # item = self.indexed_items[i]
@@ -2450,7 +2483,7 @@ class Picker:
2450
2483
  elif key == curses.KEY_RESIZE: # Terminal resize signal
2451
2484
 
2452
2485
  self.calculate_section_sizes()
2453
- self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w)
2486
+ self.column_widths = get_column_widths(self.items, header=self.header, max_column_width=self.max_column_width, number_columns=self.number_columns, max_total_width=w, unicode_char_width=self.unicode_char_width)
2454
2487
 
2455
2488
  self.draw_screen(self.indexed_items, self.highlights)
2456
2489
 
@@ -2860,7 +2893,6 @@ class Picker:
2860
2893
  def set_colours(pick: int = 0, start: int = 0) -> Optional[int]:
2861
2894
  """ Initialise curses colour pairs from dictionary. """
2862
2895
 
2863
-
2864
2896
  global COLOURS_SET, notification_colours, help_colours
2865
2897
  if COLOURS_SET: return None
2866
2898
  if start == None: start = 0
@@ -3108,6 +3140,13 @@ def main() -> None:
3108
3140
  # 'name': 'mp4',
3109
3141
  # },
3110
3142
  # ]
3143
+ highlights = [
3144
+ {
3145
+ "field": 1,
3146
+ "match": "a",
3147
+ "color": 8,
3148
+ }
3149
+ ]
3111
3150
  function_data["cell_cursor"] = True
3112
3151
  function_data["display_modes"] = True
3113
3152
  function_data["centre_in_cols"] = True
@@ -3118,6 +3157,12 @@ def main() -> None:
3118
3157
  function_data["centre_in_terminal_vertical"] = True
3119
3158
  function_data["highlight_full_row"] = True
3120
3159
  function_data["pin_cursor"] = True
3160
+ function_data["display_infobox"] = True
3161
+ function_data["infobox_items"] = [["1"], ["2"], ["3"]]
3162
+ function_data["infobox_title"] = "Title"
3163
+ function_data["footer_string"] = "Title"
3164
+ function_data["highlights"] = highlights
3165
+ function_data["show_footer"] = False
3121
3166
  # function_data["debug"] = True
3122
3167
  # function_data["debug_level"] = 1
3123
3168
  stdscr = start_curses()