From ca57b37aab2c21fb82c1406bf5272ce311a83e78 Mon Sep 17 00:00:00 2001 From: Joe R Date: Wed, 22 Dec 2021 20:30:04 -0500 Subject: [PATCH] Game/cardset/table tile search functionality. --- po/de_pysol.po | 11 ++++- po/fr_pysol.po | 11 ++++- po/it_pysol.po | 11 ++++- po/pl_pysol.po | 11 ++++- po/pysol.pot | 9 ++++ po/ru_pysol.po | 11 ++++- pysollib/app.py | 13 +++++ pysollib/tile/selectcardset.py | 78 +++++++++++++++++++++++++++--- pysollib/tile/selectgame.py | 80 +++++++++++++++++++++++++++++-- pysollib/tile/selecttile.py | 87 +++++++++++++++++++++++++++++++--- 10 files changed, 299 insertions(+), 23 deletions(-) diff --git a/po/de_pysol.po b/po/de_pysol.po index 315c1872..ef33c8f2 100644 --- a/po/de_pysol.po +++ b/po/de_pysol.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: PySol 0.0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2021-12-10 22:21-0500\n" +"PO-Revision-Date: 2021-12-21 22:33-0500\n" "Last-Translator: H. Schaekel \n" "Language-Team: German\n" "Language: de\n" @@ -3189,6 +3189,15 @@ msgstr "Abbruch bestätigen" msgid "Update statistics and logs" msgstr "Erneuert Statistiken und Protokolle" +msgid "Tree View" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Search:" +msgstr "" + #: pysollib/pysolgtk/selectcardset.py:142 pysollib/tile/selectcardset.py:98 #: pysollib/tile/selectcardset.py:115 pysollib/tile/selectcardset.py:132 #: pysollib/tk/selectcardset.py:97 pysollib/tk/selectcardset.py:114 diff --git a/po/fr_pysol.po b/po/fr_pysol.po index 5cd96968..32df5f2b 100644 --- a/po/fr_pysol.po +++ b/po/fr_pysol.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: 1.02\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2021-12-10 22:21-0500\n" +"PO-Revision-Date: 2021-12-21 22:33-0500\n" "Last-Translator: Eric Rausch \n" "Language-Team: French\n" "Language: fr\n" @@ -3235,6 +3235,15 @@ msgstr "Confirmation en sortie" msgid "Update statistics and logs" msgstr "Mise à jour stats et journaux" +msgid "Tree View" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Search:" +msgstr "" + #: pysollib/pysolgtk/selectcardset.py:142 pysollib/tile/selectcardset.py:98 #: pysollib/tile/selectcardset.py:115 pysollib/tile/selectcardset.py:132 #: pysollib/tk/selectcardset.py:97 pysollib/tk/selectcardset.py:114 diff --git a/po/it_pysol.po b/po/it_pysol.po index 38651954..5b9a9f25 100644 --- a/po/it_pysol.po +++ b/po/it_pysol.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: it_pysol\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2021-12-10 22:21-0500\n" +"PO-Revision-Date: 2021-12-21 22:33-0500\n" "Last-Translator: Giuliano Colla \n" "Language-Team: Italiano \n" "Language: it\n" @@ -3296,6 +3296,15 @@ msgstr "Conferma uscita" msgid "Update statistics and logs" msgstr "Aggiorna statistiche e log" +msgid "Tree View" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Search:" +msgstr "" + #: pysollib/pysolgtk/selectcardset.py:142 pysollib/tile/selectcardset.py:98 #: pysollib/tile/selectcardset.py:115 pysollib/tile/selectcardset.py:132 #: pysollib/tk/selectcardset.py:97 pysollib/tk/selectcardset.py:114 diff --git a/po/pl_pysol.po b/po/pl_pysol.po index bd7ec140..3a14a902 100644 --- a/po/pl_pysol.po +++ b/po/pl_pysol.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2021-12-10 22:21-0500\n" +"PO-Revision-Date: 2021-12-21 22:33-0500\n" "Last-Translator: Jerzy Trzeciak \n" "Language-Team: Polish \n" "Language: pl\n" @@ -3335,6 +3335,15 @@ msgstr "Potwierdź zakończenie" msgid "Update statistics and logs" msgstr "Uaktualnij statystyki i logi" +msgid "Tree View" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Search:" +msgstr "" + #: pysollib/pysolgtk/selectcardset.py:142 pysollib/tile/selectcardset.py:98 #: pysollib/tile/selectcardset.py:115 pysollib/tile/selectcardset.py:132 #: pysollib/tk/selectcardset.py:97 pysollib/tk/selectcardset.py:114 diff --git a/po/pysol.pot b/po/pysol.pot index b7e3ff3e..78694c71 100644 --- a/po/pysol.pot +++ b/po/pysol.pot @@ -3061,6 +3061,15 @@ msgstr "" msgid "Update statistics and logs" msgstr "" +msgid "Tree View" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Search:" +msgstr "" + #: pysollib/pysolgtk/selectcardset.py:142 pysollib/tile/selectcardset.py:98 #: pysollib/tile/selectcardset.py:115 pysollib/tile/selectcardset.py:132 #: pysollib/tk/selectcardset.py:97 pysollib/tk/selectcardset.py:114 diff --git a/po/ru_pysol.po b/po/ru_pysol.po index fc37e558..1d804bc4 100644 --- a/po/ru_pysol.po +++ b/po/ru_pysol.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-12-10 10:19-0500\n" -"PO-Revision-Date: 2021-12-10 22:22-0500\n" +"PO-Revision-Date: 2021-12-21 22:32-0500\n" "Last-Translator: Skomoroh \n" "Language-Team: Russian \n" "Language: ru\n" @@ -3307,6 +3307,15 @@ msgstr "Подтверждение выхода" msgid "Update statistics and logs" msgstr "Обновлять статистику и лог" +msgid "Tree View" +msgstr "" + +msgid "Search" +msgstr "" + +msgid "Search:" +msgstr "" + #: pysollib/pysolgtk/selectcardset.py:142 pysollib/tile/selectcardset.py:98 #: pysollib/tile/selectcardset.py:115 pysollib/tile/selectcardset.py:132 #: pysollib/tk/selectcardset.py:97 pysollib/tk/selectcardset.py:114 diff --git a/pysollib/app.py b/pysollib/app.py index af895919..4d76c214 100644 --- a/pysollib/app.py +++ b/pysollib/app.py @@ -614,6 +614,19 @@ class Application: def getFont(self, name): return self.opt.fonts.get(name) + # + # search logic + # + + def checkSearchString(self, search_string, check_string): + terms = search_string.split() + if len(terms) == 0: + return True + for term in terms: + if term.upper() not in check_string.upper(): + return False + return True + # # cardset # diff --git a/pysollib/tile/selectcardset.py b/pysollib/tile/selectcardset.py index 5755dbda..31c8d36e 100644 --- a/pysollib/tile/selectcardset.py +++ b/pysollib/tile/selectcardset.py @@ -28,7 +28,7 @@ from pysollib.mygettext import _ from pysollib.resource import CSI from pysollib.ui.tktile.selecttree import SelectDialogTreeData from pysollib.ui.tktile.tkcanvas import MfxCanvasImage -from pysollib.ui.tktile.tkutil import loadImage +from pysollib.ui.tktile.tkutil import bind, loadImage from pysollib.util import CARDSET from six.moves import tkinter @@ -222,7 +222,7 @@ class SelectCardsetDialogWithPreview(MfxDialog): self.app = app self.cardset_values = None # padx, pady = kw.padx, kw.pady - padx, pady = 5, 5 + padx, pady = 4, 4 if self.TreeDataHolder_Class.data is None: self.TreeDataHolder_Class.data = self.TreeData_Class(manager, key) # @@ -236,17 +236,53 @@ class SelectCardsetDialogWithPreview(MfxDialog): self.top.wm_minsize(400, 200) paned_window = ttk.PanedWindow(top_frame, orient='horizontal') - paned_window.pack(expand=True, fill='both') + paned_window.pack(expand=True, fill='both', padx=8, pady=8) left_frame = ttk.Frame(paned_window) right_frame = ttk.Frame(paned_window) paned_window.add(left_frame) paned_window.add(right_frame) + + notebook = ttk.Notebook(left_frame) + notebook.grid(row=0, column=0, sticky='nsew', + padx=padx, pady=pady) + tree_frame = ttk.Frame(notebook) + notebook.add(tree_frame, text=_('Tree View')) + search_frame = ttk.Frame(notebook) + notebook.add(search_frame, text=_('Search')) + + # Tree font = app.getFont("default") - self.tree = self.Tree_Class(self, left_frame, key=key, + self.tree = self.Tree_Class(self, tree_frame, key=key, default=kw.default, font=font, width=w1) - self.tree.frame.grid(row=0, column=0, sticky='nsew', - padx=padx, pady=pady) + self.tree.frame.pack(padx=padx, pady=pady, expand=True, fill='both') + + # Search + searchText = tkinter.StringVar() + self.list_searchlabel = tkinter.Label(search_frame, text="Search:", + justify='left', anchor='w') + self.list_searchlabel.pack(side="top", fill='both', ipadx=1) + self.list_searchtext = tkinter.Entry(search_frame, + textvariable=searchText) + self.list_searchtext.pack(side="top", fill='both', + padx=padx, pady=pady, ipadx=1) + searchText.trace('w', self.performSearch) + + self.list_scrollbar = tkinter.Scrollbar(search_frame) + self.list_scrollbar.pack(side="right", fill='both') + + self.createBitmaps(search_frame, kw) + self.list = tkinter.Listbox(search_frame, exportselection=False) + self.list.pack(padx=padx, pady=pady, expand=True, side='left', + fill='both', ipadx=1) + self.updateSearchList("") + bind(self.list, '<>', self.selectSearchResult) + bind(self.list, '', + lambda e: self.list.selection_clear(0, 'end')) + + self.list.config(yscrollcommand=self.list_scrollbar.set) + self.list_scrollbar.config(command=self.list.yview) + if USE_PIL: # var = tkinter.DoubleVar() @@ -318,6 +354,7 @@ class SelectCardsetDialogWithPreview(MfxDialog): padx=padx, pady=pady) self._updateAutoScale() + # left_frame.rowconfigure(0, weight=1) left_frame.columnconfigure(0, weight=1) @@ -429,6 +466,35 @@ class SelectCardsetDialogWithPreview(MfxDialog): def _updateScale(self, v): self.updatePreview() + def performSearch(self, *args): + self.updateSearchList(self.list_searchtext.get()) + + def updateSearchList(self, searchString): + self.list.delete(0, "end") + self.list.vbar_show = True + cardsets = self.manager.getAllSortedByName() + + results = [] + for cardset in cardsets: + if self.app.checkSearchString(searchString, cardset.name): + results.append(cardset.name) + results.sort() + pos = 0 + for result in results: + self.list.insert(pos, result) + pos += 1 + + def selectSearchResult(self, event): + oldcur = self.list["cursor"] + self.list["cursor"] = "watch" + sel = self.list.get(self.list.curselection()) + cardset = self.manager.getByName(sel).index + self.list.update_idletasks() + self.tree.n_selections += 1 + self.tree.updateSelection(cardset) + self.updatePreview(cardset) + self.list["cursor"] = oldcur + def updatePreview(self, key=None): if key == self.preview_key: return diff --git a/pysollib/tile/selectgame.py b/pysollib/tile/selectgame.py index 8f6f9c49..74e0b3a1 100644 --- a/pysollib/tile/selectgame.py +++ b/pysollib/tile/selectgame.py @@ -29,9 +29,10 @@ from pysollib.mfxutil import format_time from pysollib.mygettext import _ from pysollib.resource import CSI from pysollib.ui.tktile.selecttree import SelectDialogTreeData -from pysollib.ui.tktile.tkutil import unbind_destroy +from pysollib.ui.tktile.tkutil import bind, unbind_destroy from six.moves import UserList +from six.moves import tkinter from six.moves import tkinter_ttk as ttk from .selecttree import SelectDialogTreeCanvas @@ -243,9 +244,9 @@ class SelectGameData(SelectDialogTreeData): lambda gi: gi.si.game_flags & GI.GT_CHILDREN), SelectGameNode(None, _("Games with Scoring"), lambda gi: gi.si.game_flags & GI.GT_SCORE), - SelectGameNode( - None, _("Games with Separate Decks"), - lambda gi: gi.si.game_flags & GI.GT_SEPARATE_DECKS), + SelectGameNode(None, _("Games with Separate Decks"), + lambda gi: gi.si.game_flags & + GI.GT_SEPARATE_DECKS), SelectGameNode(None, _("Open Games (all cards visible)"), lambda gi: gi.si.game_flags & GI.GT_OPEN), SelectGameNode(None, _("Relaxed Variants"), @@ -282,6 +283,7 @@ class SelectGameDialog(MfxDialog): kw = self.initKw(kw) MfxDialog.__init__(self, parent, title, kw.resizable, kw.default) top_frame, bottom_frame = self.createFrames(kw) + self.createBitmaps(top_frame, kw) # self.app = app @@ -342,6 +344,7 @@ class SelectGameDialogWithPreview(SelectGameDialog): kw = self.initKw(kw) MfxDialog.__init__(self, parent, title, kw.resizable, kw.default) top_frame, bottom_frame = self.createFrames(kw) + self.createBitmaps(top_frame, kw) # self.app = app @@ -373,12 +376,47 @@ class SelectGameDialogWithPreview(SelectGameDialog): right_frame = ttk.Frame(paned_window) paned_window.add(left_frame) paned_window.add(right_frame) + + notebook = ttk.Notebook(left_frame) + notebook.pack(expand=True, fill='both') + tree_frame = ttk.Frame(notebook) + notebook.add(tree_frame, text=_('Tree View')) + search_frame = ttk.Frame(notebook) + notebook.add(search_frame, text=_('Search')) + # Tree font = app.getFont("default") - self.tree = self.Tree_Class(self, left_frame, key=gameid, + self.tree = self.Tree_Class(self, tree_frame, key=gameid, default=kw.default, font=font, width=w1) self.tree.frame.pack(padx=padx, pady=pady, expand=True, fill='both') + + # Search + searchText = tkinter.StringVar() + self.list_searchlabel = tkinter.Label(search_frame, text="Search:", + justify='left', anchor='w') + self.list_searchlabel.pack(side="top", fill='both', ipadx=1) + self.list_searchtext = tkinter.Entry(search_frame, + textvariable=searchText) + self.list_searchtext.pack(side="top", fill='both', + padx=padx, pady=pady, ipadx=1) + searchText.trace('w', self.performSearch) + + self.list_scrollbar = tkinter.Scrollbar(search_frame) + self.list_scrollbar.pack(side="right", fill='both') + + self.createBitmaps(search_frame, kw) + self.list = tkinter.Listbox(search_frame, exportselection=False) + self.list.pack(padx=padx, pady=pady, expand=True, side='left', + fill='both', ipadx=1) + self.updateSearchList("") + bind(self.list, '<>', self.selectSearchResult) + bind(self.list, '', + lambda e: self.list.selection_clear(0, 'end')) + + self.list.config(yscrollcommand=self.list_scrollbar.set) + self.list_scrollbar.config(command=self.list.yview) + # LabelFrame info_frame = ttk.LabelFrame(right_frame, text=_('About game')) info_frame.grid(row=0, column=0, padx=padx, pady=pady, @@ -467,6 +505,38 @@ class SelectGameDialogWithPreview(SelectGameDialog): destruct(self.preview_app) self.preview_app = None + def performSearch(self, *args): + self.updateSearchList(self.list_searchtext.get()) + + def updateSearchList(self, searchString): + self.list.delete(0, "end") + self.list.vbar_show = True + games = self.app.gdb.getAllGames() + + results = [] + for game in games: + if self.app.checkSearchString(searchString, game.name): + results.append(game.name) + for altname in game.altnames: + if self.app.checkSearchString(searchString, altname): + results.append(altname) + results.sort() + pos = 0 + for result in results: + self.list.insert(pos, result) + pos += 1 + + def selectSearchResult(self, event): + oldcur = self.list["cursor"] + self.list["cursor"] = "watch" + sel = self.list.get(self.list.curselection()) + game = self.app.gdb.getGameByName(sel) + self.list.update_idletasks() + self.tree.n_selections += 1 + self.tree.updateSelection(game) + self.updatePreview(game) + self.list["cursor"] = oldcur + def updatePreview(self, gameid, animations=10): if gameid == self.preview_key: return diff --git a/pysollib/tile/selecttile.py b/pysollib/tile/selecttile.py index f8ba7981..9597fb16 100644 --- a/pysollib/tile/selecttile.py +++ b/pysollib/tile/selecttile.py @@ -26,6 +26,7 @@ import os from pysollib.mfxutil import KwStruct from pysollib.mygettext import _ from pysollib.ui.tktile.selecttree import SelectDialogTreeData +from pysollib.ui.tktile.tkutil import bind import six from six.moves import tkinter @@ -136,18 +137,59 @@ class SelectTileDialogWithPreview(MfxDialog): geometry = ("%dx%d+%d+%d" % (w, h, (sw - w) / 2, (sh - h) / 2)) self.top.wm_minsize(400, 200) + padx, pady = 4, 4 + + paned_window = ttk.PanedWindow(top_frame, orient='horizontal') + paned_window.pack(expand=True, fill='both', padx=8, pady=8) + left_frame = ttk.Frame(paned_window) + right_frame = ttk.Frame(paned_window) + paned_window.add(left_frame) + paned_window.add(right_frame) + + notebook = ttk.Notebook(left_frame) + notebook.pack(expand=True, fill='both') + tree_frame = ttk.Frame(notebook) + notebook.add(tree_frame, text=_('Tree View')) + search_frame = ttk.Frame(notebook) + notebook.add(search_frame, text=_('Search')) + font = app.getFont("default") padx, pady = 4, 4 - frame = ttk.Frame(top_frame) - frame.pack(fill='both', expand=True, - padx=kw.padx-padx, pady=kw.pady-pady) - self.tree = self.Tree_Class(self, frame, key=key, default=kw.default, + self.tree = self.Tree_Class(self, tree_frame, key=key, + default=kw.default, font=font, width=w1) - self.tree.frame.pack(side="left", fill='both', expand=False, - padx=padx, pady=pady) - self.preview = MfxScrolledCanvas(frame, hbar=0, vbar=0) + self.tree.frame.pack(padx=padx, pady=pady, expand=True, fill='both') + + # Search + searchText = tkinter.StringVar() + self.list_searchlabel = tkinter.Label(search_frame, text="Search:", + justify='left', anchor='w') + self.list_searchlabel.pack(side="top", fill='both', ipadx=1) + self.list_searchtext = tkinter.Entry(search_frame, + textvariable=searchText) + self.list_searchtext.pack(side="top", fill='both', + padx=padx, pady=pady, ipadx=1) + searchText.trace('w', self.performSearch) + + self.list_scrollbar = tkinter.Scrollbar(search_frame) + self.list_scrollbar.pack(side="right", fill='both') + + self.createBitmaps(search_frame, kw) + self.list = tkinter.Listbox(search_frame, exportselection=False) + self.list.pack(padx=padx, pady=pady, expand=True, side='left', + fill='both', ipadx=1) + self.updateSearchList("") + bind(self.list, '<>', self.selectSearchResult) + bind(self.list, '', + lambda e: self.list.selection_clear(0, 'end')) + + self.list.config(yscrollcommand=self.list_scrollbar.set) + self.list_scrollbar.config(command=self.list.yview) + + self.preview = MfxScrolledCanvas(right_frame, hbar=0, vbar=0) self.preview.pack(side="right", fill='both', expand=True, padx=padx, pady=pady) + self.preview.canvas.preview = 1 # create a preview of the current state self.preview_key = -1 @@ -200,6 +242,37 @@ class SelectTileDialogWithPreview(MfxDialog): return MfxDialog.mDone(self, button) + def performSearch(self, *args): + self.updateSearchList(self.list_searchtext.get()) + + def updateSearchList(self, searchString): + self.list.delete(0, "end") + self.list.vbar_show = True + tiles = self.manager.getAllSortedByName() + + results = [] + for tile in tiles: + if tile.name == 'None': + continue + if self.app.checkSearchString(searchString, tile.name): + results.append(tile.name) + results.sort() + pos = 0 + for result in results: + self.list.insert(pos, result) + pos += 1 + + def selectSearchResult(self, event): + oldcur = self.list["cursor"] + self.list["cursor"] = "watch" + sel = self.list.get(self.list.curselection()) + cardset = self.manager.getByName(sel).index + self.list.update_idletasks() + self.tree.n_selections += 1 + self.tree.updateSelection(cardset) + self.updatePreview(cardset) + self.list["cursor"] = oldcur + def updatePreview(self, key): if key == self.preview_key: return