summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gui.py4
-rw-r--r--jfr_playoff/gui/__init__.py16
-rw-r--r--jfr_playoff/gui/frames/__init__.py86
-rw-r--r--jfr_playoff/gui/frames/team.py265
-rw-r--r--jfr_playoff/gui/tabs.py145
5 files changed, 516 insertions, 0 deletions
diff --git a/gui.py b/gui.py
new file mode 100644
index 0000000..3677b41
--- /dev/null
+++ b/gui.py
@@ -0,0 +1,4 @@
+from jfr_playoff.gui import PlayoffGUI
+
+gui = PlayoffGUI()
+gui.run()
diff --git a/jfr_playoff/gui/__init__.py b/jfr_playoff/gui/__init__.py
new file mode 100644
index 0000000..d9c455d
--- /dev/null
+++ b/jfr_playoff/gui/__init__.py
@@ -0,0 +1,16 @@
+import tkinter as tk
+from tkinter import ttk
+
+from .tabs import *
+
+class PlayoffGUI(object):
+ def __init__(self):
+ self.root = tk.Tk()
+
+ def run(self):
+ self.notebook = ttk.Notebook(self.root)
+ self.notebook.pack(fill=tk.BOTH, expand=True)
+ for tab in tabs.__all__:
+ tabObj = globals()[tab](self.notebook)
+ self.notebook.add(tabObj, text=tabObj.title)
+ self.root.mainloop()
diff --git a/jfr_playoff/gui/frames/__init__.py b/jfr_playoff/gui/frames/__init__.py
new file mode 100644
index 0000000..c046e53
--- /dev/null
+++ b/jfr_playoff/gui/frames/__init__.py
@@ -0,0 +1,86 @@
+#coding=utf-8
+
+import tkinter as tk
+from tkinter import ttk
+
+class WidgetRepeater(tk.Frame):
+ def __init__(self, master, widgetClass, headers=None, *args, **kwargs):
+ if not issubclass(widgetClass, RepeatableFrame):
+ raise AttributeError(
+ 'WidgetRepeater widget must be a RepeatableFrame')
+ tk.Frame.__init__(self, master, **kwargs)
+ self.widgetClass = widgetClass
+ self.widgets = []
+ self.headers = headers
+ self.addButton = ttk.Button(
+ self, text='[+]', width=5, command=self._addWidget)
+ self.renderContent()
+
+ def _findWidget(self, row, column):
+ for children in self.children.values():
+ info = children.grid_info()
+ if info['row'] == str(row) and info['column'] == str(column):
+ return children
+ return None
+
+ def _addWidget(self):
+ removeButton = ttk.Button(
+ self, text='[-]', width=5,
+ command=lambda i=len(self.widgets): self._removeWidget(i))
+ removeButton.grid(row=len(self.widgets), column=0, sticky=tk.N)
+ widget = self.widgetClass(self)
+ self.widgets.append(widget)
+ self._updateGrid()
+
+ def _removeWidget(self, idx):
+ self.widgets.pop(idx).destroy()
+ self._findWidget(row=len(self.widgets), column=0).destroy()
+ self._updateGrid()
+
+ def _updateGrid(self):
+ for idx, widget in enumerate(self.widgets):
+ widget.grid(row=idx, column=1, sticky=tk.W+tk.E+tk.N+tk.S)
+ self.addButton.grid(
+ row=len(self.widgets), column=0, columnspan=1, sticky=tk.W+tk.N)
+
+ def _renderHeader(self):
+ if self.headers:
+ headerFrame = tk.Frame(self)
+ for idx, header in enumerate(self.headers):
+ headerFrame.columnconfigure(idx, weight=1)
+ widget = header[0](headerFrame, **header[1])
+ widget.grid(row=0, column=idx, sticky=tk.W+tk.E+tk.N)
+ self.widgets.append(headerFrame)
+ (tk.Label(self, text=' ')).grid(
+ row=0, column=0, sticky=tk.W+tk.E+tk.N)
+
+ def renderContent(self):
+ self.columnconfigure(1, weight=1)
+ self._renderHeader()
+ self._updateGrid()
+
+class RepeatableFrame(tk.Frame):
+ def __init__(self, *args, **kwargs):
+ tk.Frame.__init__(self, *args, **kwargs)
+ self.renderContent()
+
+ def renderContent(self):
+ pass
+
+ def getValue(self):
+ pass
+
+ def setValue(self, value):
+ pass
+
+class RepeatableEntry(RepeatableFrame):
+ def renderContent(self):
+ self.value = tk.StringVar()
+ self.field = ttk.Entry(self, textvariable=self.value)
+ self.field.pack(expand=True, fill=tk.BOTH)
+
+ def getValue(self):
+ return self.value.get()
+
+ def setValue(self, value):
+ return self.value.set(value)
diff --git a/jfr_playoff/gui/frames/team.py b/jfr_playoff/gui/frames/team.py
new file mode 100644
index 0000000..5869a7a
--- /dev/null
+++ b/jfr_playoff/gui/frames/team.py
@@ -0,0 +1,265 @@
+#coding=utf-8
+
+import tkinter as tk
+from tkinter.font import Font
+from tkinter import ttk
+import tkMessageBox
+
+from ..frames import RepeatableFrame, WidgetRepeater, RepeatableEntry
+
+class ManualTeamRow(RepeatableFrame):
+ def renderContent(self):
+ self.fullname = ttk.Entry(self, width=20)
+ self.fullname.grid(row=0, column=0)
+ self.shortname = ttk.Entry(self, width=20)
+ self.shortname.grid(row=0, column=1)
+ self.flag = ttk.Entry(self, width=10)
+ self.flag.grid(row=0, column=2)
+ self.position = ttk.Entry(self, width=10)
+ self.position.grid(row=0, column=3)
+
+class TeamManualSettingsFrame(tk.Frame):
+ def __init__(self, *args, **kwargs):
+ tk.Frame.__init__(self, *args, **kwargs)
+ self.renderContent()
+
+ def renderContent(self):
+ headers = [
+ (ttk.Label, {'text': 'Pełna nazwa', 'width': 20}),
+ (ttk.Label, {'text': 'Skrócona nazwa', 'width': 20}),
+ (ttk.Label, {'text': 'Ikona', 'width': 10}),
+ (ttk.Label, {'text': 'Poz. końc.', 'width': 10}),
+ ]
+ (WidgetRepeater(self, ManualTeamRow, headers=headers)).grid(
+ row=1, column=0, columnspan=5)
+
+class TeamSelectionFrame(tk.Frame):
+ def __init__(self, master, title='', teams=[],
+ selected=None, callback=None):
+ tk.Frame.__init__(self, master=master)
+ self.values = []
+ self.renderContent(title, teams, selected)
+ self.callback = callback
+
+ def _save(self):
+ if self.callback:
+ self.callback(
+ [idx+1 for idx, value
+ in enumerate(self.values) if value.get()])
+ self.master.destroy()
+
+ def renderContent(self, title, teams, selected):
+ self.columnconfigure(1, weight=1)
+ (ttk.Label(self, text=title)).grid(row=0, column=0, columnspan=2)
+ row = 1
+ for team in teams:
+ (ttk.Label(self, text='[%d]' % (row))).grid(row=row, column=0)
+ self.values.append(tk.IntVar())
+ (ttk.Checkbutton(
+ self, text=team[0],
+ variable=self.values[row-1]
+ )).grid(row=row, column=1, sticky=tk.W)
+ if selected and selected(row-1, team):
+ self.values[row-1].set(True)
+ row += 1
+ (ttk.Button(self, text='Zapisz', command=self._save)).grid(
+ row=row, column=0, columnspan=2)
+
+class TeamFetchSettingsFrame(tk.Frame):
+ SOURCE_LINK = 0
+ SOURCE_DB = 1
+
+ def __init__(self, *args, **kwargs):
+ tk.Frame.__init__(self, *args, **kwargs)
+ self.renderContent()
+
+ def _setFinishingPositions(self, positions):
+ self.finishingPositions = positions
+ self.finishingPositionsBtn.configure(
+ text='[wybrano: %d]' % (len(self.finishingPositions)))
+
+ def _chooseFinishingPositions(self):
+ if not self.master.teams:
+ tkMessageBox.showerror(
+ 'Wybór teamów', 'W turnieju nie ma teamów do wyboru')
+ self._setFinishingPositions([])
+ else:
+ dialog = tk.Toplevel(self)
+ selectionFrame = TeamSelectionFrame(
+ dialog, title='Wybierz teamy, które zakończyły rozgrywki ' + \
+ 'na swojej pozycji:',
+ teams=self.master.teams,
+ selected=lambda idx, team: idx+1 in self.finishingPositions,
+ callback=self._setFinishingPositions)
+ selectionFrame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
+
+
+ def renderContent(self):
+ (ttk.Label(self, text=' ')).grid(row=0, column=0, rowspan=2)
+
+ self.fetchSource = tk.IntVar()
+ self.fetchSource.set(self.SOURCE_LINK)
+ (ttk.Radiobutton(
+ self, text='Baza danych',
+ variable=self.fetchSource, value=self.SOURCE_DB)).grid(
+ row=0, column=1, columnspan=2, sticky=tk.W)
+ self.fetchDB = tk.StringVar()
+ (ttk.OptionMenu(self, self.fetchDB, '')).grid(
+ row=0, column=3, sticky=tk.W+tk.E)
+
+ (ttk.Radiobutton(
+ self, text='Strona wyników',
+ variable=self.fetchSource, value=self.SOURCE_LINK)).grid(
+ row=1, column=1, columnspan=2, sticky=tk.W)
+ self.fetchLink = ttk.Entry(self, width=20)
+ self.fetchLink.grid(row=1, column=3)
+
+ (ttk.Label(self, text='Pobierz do ')).grid(
+ row=2, column=0, columnspan=2, sticky=tk.W)
+ self.fetchLimit = tk.StringVar()
+ self.fetchLimit.set(0)
+ (tk.Spinbox(
+ self, from_=0, to=9999, width=5, justify=tk.RIGHT,
+ textvariable=self.fetchLimit)).grid(
+ row=2, column=2, sticky=tk.W)
+ (ttk.Label(self, text=' miejsca (0 = wszystkie)')).grid(
+ row=2, column=3, sticky=tk.W+tk.E)
+
+ (ttk.Label(self, text='Pozycje końcowe: ')).grid(
+ row=3, column=0, columnspan=3, sticky=tk.W+tk.E)
+ self.finishingPositionsBtn = ttk.Button(
+ self, command=self._chooseFinishingPositions)
+ self.finishingPositionsBtn.grid(row=3, column=3, sticky=tk.W)
+ self._setFinishingPositions([])
+
+class TeamSettingsFrame(tk.Frame):
+ FORMAT_FETCH = 0
+ FORMAT_MANUAL = 1
+
+ def __init__(self, *args, **kwargs):
+ tk.Frame.__init__(self, *args, **kwargs)
+ self.renderContent()
+
+ def _setPanelState(self, frame, state):
+ for child in frame.winfo_children():
+ if isinstance(child, tk.Frame):
+ self._setPanelState(child, state)
+ else:
+ child.configure(state=state)
+
+ def _enablePanels(self, *args):
+ panels = {self.FORMAT_FETCH: self.fetchSettingsFrame,
+ self.FORMAT_MANUAL: self.manualSettingsFrame}
+ for value, panel in panels.iteritems():
+ self._setPanelState(
+ frame=panel,
+ state=tk.NORMAL \
+ if self.teamFormat.get()==value else tk.DISABLED)
+
+ def setTeams(self, teams):
+ self.teams = teams
+ # emit event or sth
+
+ def renderContent(self):
+ self.teamFormat = tk.IntVar()
+ self.teamFormat.trace('w', self._enablePanels)
+
+ (ttk.Radiobutton(
+ self, text='Pobierz z JFR Teamy:',
+ variable=self.teamFormat, value=self.FORMAT_FETCH)).grid(
+ row=0, column=0, sticky=tk.W)
+
+ self.fetchSettingsFrame = TeamFetchSettingsFrame(self)
+ self.fetchSettingsFrame.grid(row=1, column=0, sticky=tk.W+tk.E)
+
+ (ttk.Separator(
+ self, orient=tk.HORIZONTAL)).grid(
+ row=2, column=0, sticky=tk.W+tk.E)
+
+ (ttk.Radiobutton(
+ self, text='Ustaw ręcznie:',
+ variable=self.teamFormat, value=self.FORMAT_MANUAL)).grid(
+ row=3, column=0, sticky=tk.W+tk.E)
+
+ self.manualSettingsFrame = TeamManualSettingsFrame(self)
+ self.manualSettingsFrame.grid(row=4, column=0, sticky=tk.W+tk.E)
+
+ self.teamFormat.set(self.FORMAT_MANUAL)
+ self.setTeams([])
+
+class TeamAliasRow(RepeatableFrame):
+ def renderContent(self):
+ self.columnconfigure(0, weight=1)
+ self.columnconfigure(1, weight=1)
+ self.teamName = tk.StringVar()
+ (ttk.OptionMenu(self, self.teamName, '')).grid(
+ row=0, column=0, sticky=tk.W+tk.E+tk.N)
+ self.names = WidgetRepeater(self, RepeatableEntry)
+ self.names.grid(row=0, column=1, sticky=tk.W+tk.E)
+
+class TeamAliasFrame(tk.Frame):
+ def __init__(self, *args, **kwags):
+ tk.Frame.__init__(self, *args, **kwags)
+ self.renderContent()
+
+ def renderContent(self):
+ self.columnconfigure(0, weight=1)
+ (ttk.Label(self, text='Aliasy teamów')).grid(
+ row=0, column=0, sticky=tk.W+tk.E)
+ self.repeater = WidgetRepeater(self, TeamAliasRow)
+ self.repeater.grid(row=1, column=0, sticky=tk.W+tk.E)
+
+class TeamPreviewFrame(tk.Frame):
+ def __init__(self, *args, **kwags):
+ tk.Frame.__init__(self, *args, **kwags)
+ self.tieValues = []
+ self.tieFields = []
+ self.renderContent()
+
+ def setTeams(self, teams):
+ self.teamList.grid(
+ row=1, column=0, rowspan=len(teams)+2, sticky=tk.W+tk.E+tk.N)
+ self.tieValues = self.tieValues[0:len(teams)]
+ for idx in range(len(teams), len(self.tieFields)):
+ self.tieFields[idx].remove()
+ for idx, team in enumerate(teams):
+ self.teamList.insert('', tk.END, values=team, tag=idx)
+ if idx >= len(self.tieFields):
+ self.tieValues.append(tk.StringVar())
+ self.tieFields.append(
+ tk.Spinbox(
+ self, from_=0, to=9999, width=5, font=Font(size=10),
+ textvariable=self.tieValues[idx]))
+ self.tieFields[idx].grid(
+ row=idx+2, column=1, sticky=tk.W+tk.E+tk.N)
+ (ttk.Label(self, text=' ')).grid(row=1, column=1, pady=3)
+ (ttk.Label(self, text=' ')).grid(row=len(teams)+2, column=1)
+ self.rowconfigure(1, weight=0)
+ self.rowconfigure(len(teams)+2, weight=1)
+ (ttk.Label(
+ self,
+ text='Kolejność rozstrzygania remisów w klasyfikacji ' + \
+ 'pobranej z bazy JFR Teamy',
+ anchor=tk.E)).grid(row=len(teams)+3, column=0, sticky=tk.E)
+ (ttk.Label(self, text='⬏', font=Font(size=20))).grid(
+ row=len(teams)+3, column=1, sticky=tk.W+tk.N)
+ self.rowconfigure(len(teams)+3, weight=1)
+
+ def renderContent(self):
+ self.columnconfigure(0, weight=1)
+ (ttk.Label(self, text='Podgląd listy teamów')).grid(
+ row=0, column=0, columnspan=2, sticky=tk.W+tk.E)
+ self.teamList = ttk.Treeview(
+ self, show='headings',
+ columns=['fullname','shortname','icon','position'],
+ selectmode='browse')
+ for col, heading in enumerate(
+ [('Nazwa', 100), ('Skrócona nazwa', 100),
+ ('Ikona', 20), ('Poz. końc.', 20)]):
+ self.teamList.heading(col, text=heading[0])
+ if heading[1]:
+ self.teamList.column(col, width=heading[1], stretch=True)
+
+ self.setTeams([])
+
+__all__ = ['TeamSettingsFrame', 'TeamAliasFrame', 'TeamPreviewFrame']
diff --git a/jfr_playoff/gui/tabs.py b/jfr_playoff/gui/tabs.py
new file mode 100644
index 0000000..bbcb4b0
--- /dev/null
+++ b/jfr_playoff/gui/tabs.py
@@ -0,0 +1,145 @@
+#coding=utf-8
+
+import os
+
+import tkinter as tk
+from tkinter import ttk
+import tkFileDialog as tkfd
+
+from .frames.team import *
+
+class PlayoffTab(ttk.Frame):
+ def __init__(self, master):
+ ttk.Frame.__init__(self, master)
+ self.frame = ttk.Frame(self)
+ self.frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
+ self.renderContent(self.frame)
+
+ @property
+ def title(self):
+ pass
+
+ def renderContent(self, container):
+ pass
+
+class MainSettingsTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Główne ustawienia'
+
+ def _chooseOutputPath(self):
+ currentPath = self.outputPath.get()
+ filename = tkfd.asksaveasfilename(
+ initialdir=os.path.dirname(currentPath) if currentPath else '.',
+ title='Wybierz plik wyjściowy',
+ filetypes=(('HTML files', '*.html'),))
+ if filename:
+ if not filename.lower().endswith('.html'):
+ filename = filename + '.html'
+ self.outputPath.set(filename)
+
+ def _updateRefreshFields(self):
+ self.refreshInterval.configure(
+ state=tk.NORMAL if self.refresh.get() else tk.DISABLED)
+
+ def renderContent(self, container):
+ (ttk.Label(container, text='Plik wynikowy:')).grid(
+ row=0, column=0, sticky=tk.E, pady=2)
+ outputPath = tk.Frame(container)
+ outputPath.grid(row=0, column=1, sticky=tk.E+tk.W, pady=2)
+ self.outputPath = tk.StringVar()
+ (ttk.Entry(outputPath, width=60, textvariable=self.outputPath)).grid(
+ row=0, column=0, sticky=tk.W+tk.E)
+ (ttk.Button(
+ outputPath,
+ text='[]', command=self._chooseOutputPath)).grid(row=0, column=1)
+ outputPath.columnconfigure(0, weight=1)
+
+ (ttk.Separator(container, orient=tk.HORIZONTAL)).grid(
+ row=1, column=0, columnspan=2, sticky=tk.E+tk.W, pady=2)
+
+ (ttk.Label(container, text='Ustawienia strony')).grid(
+ row=2, column=0, columnspan=2, sticky=tk.W, pady=5)
+ (ttk.Label(container, text='Tytuł:')).grid(
+ row=3, column=0, sticky=tk.E, pady=2)
+ self.pageTitle = tk.StringVar()
+ (tk.Entry(container, textvariable=self.pageTitle)).grid(
+ row=3, column=1, sticky=tk.W+tk.E, pady=2)
+ (ttk.Label(container, text='Logoh:')).grid(
+ row=4, column=0, sticky=tk.E+tk.N, pady=2)
+ self.pageLogoh = tk.Text(container, width=45, height=10)
+ self.pageLogoh.grid(
+ row=4, column=1,
+ sticky=tk.W+tk.N+tk.E+tk.S, pady=2)
+
+ (ttk.Label(container, text='Odświeżaj:')).grid(
+ row=5, column=0, sticky=tk.E, pady=2)
+ refreshPanel = tk.Frame(container)
+ refreshPanel.grid(row=5, column=1, sticky=tk.W+tk.E, pady=2)
+ self.refresh = tk.IntVar()
+ (ttk.Checkbutton(
+ refreshPanel,
+ command=self._updateRefreshFields, variable=self.refresh)).grid(
+ row=0, column=0)
+ (ttk.Label(refreshPanel, text='co:')).grid(row=0, column=1)
+ self.refreshInterval = tk.Spinbox(
+ refreshPanel, from_=30, to=3600, width=5, justify=tk.RIGHT)
+ self.refreshInterval.grid(row=0, column=2)
+ (ttk.Label(refreshPanel, text='sekund')).grid(row=0, column=3)
+ self._updateRefreshFields()
+
+ container.columnconfigure(1, weight=1)
+ container.rowconfigure(4, weight=1)
+
+class TeamsTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Uczestnicy'
+
+ def renderContent(self, container):
+ settingsFrame = TeamSettingsFrame(container, padx=5, pady=5)
+ settingsFrame.grid(row=0, column=0, sticky=tk.N+tk.E+tk.S+tk.W)
+ settingsFrame.columnconfigure(2, weight=1)
+ previewFrame = TeamPreviewFrame(container)
+ previewFrame.grid(row=0, column=1, rowspan=2,
+ sticky=tk.N+tk.E+tk.W)
+ aliasFrame = TeamAliasFrame(container)
+ aliasFrame.grid(row=1, column=0,
+ sticky=tk.N+tk.E+tk.S+tk.W)
+ container.columnconfigure(0, weight=1)
+ container.columnconfigure(1, weight=3)
+ container.rowconfigure(0, weight=2)
+ container.rowconfigure(1, weight=1)
+
+class MatchesTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Mecze'
+
+class SwissesTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Swissy'
+
+class NetworkTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Sieć'
+
+class VisualTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Wygląd'
+
+class StyleTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Style'
+
+class TranslationsTab(PlayoffTab):
+ @property
+ def title(self):
+ return 'Tłumaczenia'
+
+__all__ = ['MainSettingsTab', 'TeamsTab', 'MatchesTab', 'SwissesTab',
+ 'NetworkTab', 'VisualTab', 'StyleTab', 'TranslationsTab']