summaryrefslogtreecommitdiff
path: root/jfr_playoff/gui/frames/match.py
diff options
context:
space:
mode:
Diffstat (limited to 'jfr_playoff/gui/frames/match.py')
-rw-r--r--jfr_playoff/gui/frames/match.py856
1 files changed, 856 insertions, 0 deletions
diff --git a/jfr_playoff/gui/frames/match.py b/jfr_playoff/gui/frames/match.py
new file mode 100644
index 0000000..2cf88bf
--- /dev/null
+++ b/jfr_playoff/gui/frames/match.py
@@ -0,0 +1,856 @@
+#coding=utf-8
+
+from collections import OrderedDict
+
+import tkinter as tk
+from tkinter.font import Font
+from tkinter import ttk
+
+from ..frames import GuiFrame, RepeatableFrame, ScrollableFrame
+from ..frames import WidgetRepeater, RepeatableEntry, NumericSpinbox
+from ..frames import SelectionFrame, SelectionButton, RefreshableOptionMenu
+from ..frames.team import DBSelectionField, TeamSelectionFrame
+from ..frames.team import TeamSelectionButton
+from ..frames.visual import PositionsSelectionFrame
+from ..variables import NotifyStringVar, NotifyIntVar
+from ..variables import NotifyNumericVar, NotifyBoolVar
+
+class SwissSettingsFrame(RepeatableFrame):
+ SOURCE_LINK = 0
+ SOURCE_DB = 1
+
+ def _setPositionInfo(self, *args):
+ tournamentFrom = self.setFrom.get(default=1)
+ tournamentTo = min(
+ self.setTo.get(default=1) \
+ if self.setToEnabled.get() else 9999,
+ len(self.winfo_toplevel().getTeams()))
+ swissFrom = self.fetchFrom.get(default=1)
+ swissTo = swissFrom + tournamentTo - tournamentFrom
+ if tournamentTo < tournamentFrom:
+ self.positionsInfo.configure(text='brak miejsc do ustawienia')
+ else:
+ self.positionsInfo.configure(text='%d-%d -> %d-%d' % (
+ swissFrom, swissTo, tournamentFrom, tournamentTo))
+
+ def _setFields(self, *args):
+ checkFields = [self.setToEnabled, self.fetchFromEnabled]
+ for child in self.winfo_children():
+ info = child.grid_info()
+ row = int(info['row'])
+ if row in [1, 2] and not isinstance(child, ttk.Radiobutton):
+ child.configure(
+ state=tk.NORMAL if self.source.get() == 2 - row \
+ else tk.DISABLED)
+ elif row in [5, 6] and isinstance(child, tk.Spinbox):
+ child.configure(
+ state=tk.NORMAL if checkFields[row-5].get() \
+ else tk.DISABLED)
+
+ def renderContent(self):
+ self.source = NotifyIntVar()
+ self.fetchDB = NotifyStringVar()
+ self.fetchLink = NotifyStringVar()
+ self.setFrom = NotifyNumericVar()
+ self.setToEnabled = NotifyBoolVar()
+ self.setTo = NotifyNumericVar()
+ self.fetchFromEnabled = NotifyBoolVar()
+ self.fetchFrom = NotifyNumericVar()
+ self.linkLabel = NotifyStringVar()
+ self.linkRelPath = NotifyStringVar()
+
+ self.columnconfigure(1, weight=1)
+ self.columnconfigure(2, weight=1)
+ self.columnconfigure(3, weight=1)
+
+ (ttk.Label(self, text='Źródło danych:')).grid(
+ row=0, column=0, sticky=tk.W)
+ (ttk.Radiobutton(
+ self, text='Baza danych',
+ variable=self.source, value=self.SOURCE_DB)).grid(
+ row=1, column=0, sticky=tk.W)
+ self.fetchDBField = DBSelectionField(
+ self, self.fetchDB, self.fetchDB.get())
+ self.fetchDBField.grid(row=1, column=1, sticky=tk.W+tk.E)
+ (ttk.Radiobutton(
+ self, text='Strona turnieju',
+ variable=self.source, value=self.SOURCE_LINK)).grid(
+ row=2, column=0, sticky=tk.W)
+ (ttk.Entry(self, textvariable=self.fetchLink, width=20)).grid(
+ row=2, column=1, sticky=tk.W+tk.E)
+
+ (ttk.Separator(self, orient=tk.HORIZONTAL)).grid(
+ row=3, column=0, columnspan=6, sticky=tk.E+tk.W)
+
+ (ttk.Label(
+ self, text='Ustaw od miejsca: ')).grid(
+ row=4, column=0, sticky=tk.W, padx=18)
+ (NumericSpinbox(
+ self, textvariable=self.setFrom,
+ from_=1, to=999, width=5)).grid(
+ row=4, column=1, sticky=tk.W)
+ (ttk.Checkbutton(
+ self, variable=self.setToEnabled,
+ text='Ustaw do miejsca: ')).grid(
+ row=5, column=0, sticky=tk.W)
+ (NumericSpinbox(
+ self, textvariable=self.setTo,
+ from_=1, to=999, width=5)).grid(
+ row=5, column=1, sticky=tk.W)
+ (ttk.Checkbutton(
+ self, variable=self.fetchFromEnabled,
+ text='Pobierz od miejsca: ')).grid(
+ row=6, column=0, sticky=tk.W)
+ (NumericSpinbox(
+ self, textvariable=self.fetchFrom,
+ from_=1, to=999, width=5)).grid(
+ row=6, column=1, sticky=tk.W)
+
+ (ttk.Label(self, text='Miejsca w swissie')).grid(
+ row=4, column=2)
+ (ttk.Label(self, text='Miejsca w klasyfikacji')).grid(
+ row=4, column=3)
+ self.positionsInfo = ttk.Label(self, text=' -> ', font=Font(size=16))
+ self.positionsInfo.grid(row=5, column=2, columnspan=2, rowspan=2)
+
+ (ttk.Label(self, text='Etykieta linku:')).grid(
+ row=8, column=0, sticky=tk.E)
+ (ttk.Entry(self, textvariable=self.linkLabel, width=20)).grid(
+ row=8, column=1, sticky=tk.W+tk.E)
+ (ttk.Label(self, text='(domyślnie: "Turniej o #. miejsce")')).grid(
+ row=8, column=2, sticky=tk.W)
+
+ (ttk.Label(self, text='Względna ścieżka linku do swissa:')).grid(
+ row=1, column=2, sticky=tk.E)
+ (ttk.Entry(self, textvariable=self.linkRelPath, width=20)).grid(
+ row=1, column=3, sticky=tk.W+tk.E)
+
+ (ttk.Separator(self, orient=tk.HORIZONTAL)).grid(
+ row=7, column=0, columnspan=6, sticky=tk.E+tk.W)
+ (ttk.Separator(self, orient=tk.HORIZONTAL)).grid(
+ row=9, column=0, columnspan=6, sticky=tk.E+tk.W)
+
+ self._setFields()
+ self._setPositionInfo()
+
+ self.fetchFromEnabled.trace('w', self._setFields)
+ self.setToEnabled.trace('w', self._setFields)
+ self.source.trace('w', self._setFields)
+ self.setFrom.trace('w', self._setPositionInfo)
+ self.setTo.trace('w', self._setPositionInfo)
+ self.fetchFrom.trace('w', self._setPositionInfo)
+ self.fetchFromEnabled.trace('w', self._setPositionInfo)
+ self.setToEnabled.trace('w', self._setPositionInfo)
+ self.winfo_toplevel().bind(
+ '<<TeamListChanged>>', self._setPositionInfo, add='+')
+
+ def setValue(self, value):
+ if 'database' in value:
+ self.source.set(self.SOURCE_DB)
+ self.fetchDB.set(value['database'])
+ self.fetchLink.set('')
+ else:
+ self.source.set(self.SOURCE_LINK)
+ self.fetchDB.set('')
+ if 'link' in value:
+ self.fetchLink.set(value['link'])
+ else:
+ self.fetchLink.set('')
+ self.setFrom.set(value['position'] if 'position' in value else 1)
+ if 'position_to' in value:
+ self.setToEnabled.set(1)
+ self.setTo.set(value['position_to'])
+ else:
+ self.setToEnabled.set(0)
+ self.setTo.set(1)
+ if 'swiss_position' in value:
+ self.fetchFromEnabled.set(1)
+ self.fetchFrom.set(value['swiss_position'])
+ else:
+ self.fetchFromEnabled.set(0)
+ self.fetchFrom.set(1)
+ self.linkLabel.set(value['label'] if 'label' in value else '')
+ self.linkRelPath.set(
+ value['relative_path'] if 'relative_path' in value else '')
+
+ def getValue(self):
+ config = OrderedDict()
+ if self.source.get() == self.SOURCE_DB:
+ config['database'] = self.fetchDB.get()
+ if self.linkRelPath.get():
+ config['relative_path'] = self.linkRelPath.get()
+ if self.source.get() == self.SOURCE_LINK:
+ config['link'] = self.fetchLink.get()
+ if self.linkLabel.get():
+ config['label'] = self.linkLabel.get()
+ config['position'] = self.setFrom.get()
+ if self.setToEnabled.get():
+ config['position_to'] = self.setTo.get()
+ if self.fetchFromEnabled.get():
+ config['swiss_position'] = self.fetchFrom.get()
+ return config
+
+class SwissesFrame(ScrollableFrame):
+ def renderContent(self, container):
+ self.swisses = WidgetRepeater(container, SwissSettingsFrame)
+ self.swisses.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
+
+ def setValues(self, values):
+ self.swisses.setValue(values)
+
+ def getValues(self):
+ return self.swisses.getValue()
+
+class MatchSelectionButton(SelectionButton):
+ @property
+ def defaultPrompt(self):
+ return 'Wybierz mecze:'
+
+ @property
+ def title(self):
+ return 'Wybór meczów'
+
+ @property
+ def errorMessage(self):
+ return 'W turnieju nie zdefiniowano żadnych meczów'
+
+ def getOptions(self):
+ matches = self.winfo_toplevel().getMatches()
+ values = []
+ prev_match = None
+ for match in matches:
+ if prev_match is not None:
+ if prev_match.getPhase() != match.getPhase():
+ values.append(None)
+ values.append(match)
+ prev_match = match
+ return values
+
+
+class MatchSelectionFrame(SelectionFrame):
+ def renderOption(self, container, option, idx):
+ if option is not None:
+ (ttk.Label(
+ container, text='[%d]' % (self._mapValue(idx, option)))).grid(
+ row=idx+1, column=0)
+ (ttk.Checkbutton(
+ container, text=option.label,
+ variable=self.values[self._mapValue(idx, option)]
+ )).grid(row=idx+1, column=1, sticky=tk.W)
+ else:
+ (ttk.Separator(
+ container, orient=tk.HORIZONTAL)).grid(
+ row=idx+1, column=0, columnspan=2,
+ sticky=tk.E+tk.W, pady=2)
+
+ def _mapValue(self, idx, value):
+ if self.options[idx] is not None:
+ return self.options[idx].getMatchID()
+
+
+class SelectedTeamList(RefreshableOptionMenu):
+ VALUE_LABELS = {
+ 'none': u'%s',
+ 'winner': u'Zwycięzca meczu %d',
+ 'loser': u'Przegrany meczu %d',
+ 'place': u'Drużyna z miejsca %d'
+ }
+
+ def __init__(self, *args, **kwargs):
+ RefreshableOptionMenu.__init__(self, *args, **kwargs)
+ self.master.bind(
+ '<<BracketConfigChanged>>', self.refreshOptions, add='+')
+
+ def getValues(self):
+ config = self.master.getConfig()
+ values = [('none', '')]
+ if isinstance(config, dict):
+ for key in ['winner', 'loser', 'place']:
+ if key in config:
+ for value in config[key]:
+ values.append((key, value))
+ return values
+
+ def getLabel(self, value):
+ return self.VALUE_LABELS[value[0]] % (value[1])
+
+ def getVarValue(self, value):
+ return unicode(value)
+
+
+class BracketMatchSettingsFrame(GuiFrame):
+ SOURCE_TEAM=0
+ SOURCE_BRACKET=1
+ LIST_WIDGETS = {'place': 5, 'winner': 1, 'loser': 3}
+
+ def _enablePanels(self, *args):
+ for widget in self.teamWidgets:
+ widget.configure(
+ state=tk.NORMAL if self.source.get() == self.SOURCE_TEAM
+ else tk.DISABLED)
+ for widget in self.bracketWidgets:
+ widget.configure(
+ state=tk.NORMAL if self.source.get() == self.SOURCE_BRACKET
+ else tk.DISABLED)
+ if self.source.get() == self.SOURCE_BRACKET \
+ and isinstance(widget, SelectedTeamList) \
+ and not self.selected.get():
+ widget.configure(state=tk.DISABLED)
+
+ def _configChangeNotify(self, *args):
+ self.event_generate('<<BracketConfigChanged>>', when='tail')
+
+ def _setPositions(self, positions):
+ self.positions = positions
+ self._configChangeNotify()
+
+ def _setLosers(self, matches):
+ self.losers = matches
+ self._configChangeNotify()
+
+ def _setWinners(self, matches):
+ self.winners = matches
+ self._configChangeNotify()
+
+ def _setTeams(self, teams):
+ if not self._lockTeams:
+ allTeams = [team[0] for team in self.teamWidgets[0].getOptions()]
+ self.teams = [allTeams[idx-1] for idx in teams]
+
+ def renderContent(self):
+ self.source = NotifyIntVar()
+ self.source.trace('w', self._enablePanels)
+ self.source.trace('w', self._configChangeNotify)
+ self.selected = NotifyBoolVar()
+ self.selected.trace('w', self._enablePanels)
+ self.selectedIndex = NotifyStringVar()
+ self.positions = []
+ self.winners = []
+ self.losers = []
+ self.teams = []
+ self._lockTeams = True
+ self.winfo_toplevel().bind(
+ '<<TeamListChanged>>', self._onTeamListChange, add='+')
+ self.winfo_toplevel().bind(
+ '<<MatchListChanged>>', self._onMatchListChange, add='+')
+
+ buttons = [
+ ttk.Radiobutton(
+ self, variable=self.source, value=self.SOURCE_TEAM,
+ text='Konkretne teamy'),
+ ttk.Radiobutton(
+ self, variable=self.source, value=self.SOURCE_BRACKET,
+ text='Z drabinki')]
+ self.teamWidgets = [
+ TeamSelectionButton(
+ self, prompt='Wybierz drużyny:',
+ dialogclass=TeamSelectionFrame,
+ callback=self._setTeams)]
+ self.bracketWidgets = [
+ ttk.Label(self, text='Zwycięzcy meczów:'),
+ MatchSelectionButton(
+ self, prompt='Wybierz mecze:',
+ dialogclass=MatchSelectionFrame,
+ callback=self._setWinners),
+ ttk.Label(self, text='Przegrani meczów:'),
+ MatchSelectionButton(
+ self, prompt='Wybierz mecze:',
+ dialogclass=MatchSelectionFrame,
+ callback=self._setLosers),
+ ttk.Label(self, text='Pozycje początkowe:'),
+ TeamSelectionButton(
+ self, prompt='Wybierz pozycje początkowe:',
+ dialogclass=PositionsSelectionFrame,
+ callback=self._setPositions),
+ ttk.Checkbutton(
+ self, text='Uczestnik został wybrany:',
+ variable=self.selected),
+ SelectedTeamList(self, self.selectedIndex)
+ ]
+
+ for idx, button in enumerate(buttons):
+ button.grid(row=idx, column=0, sticky=tk.W)
+ self.teamWidgets[0].grid(row=0, column=1, sticky=tk.W)
+ for idx, widget in enumerate(self.bracketWidgets):
+ widget.grid(row=1+idx/2, column=1+idx%2, sticky=tk.W)
+
+ self._enablePanels()
+
+ self._lockTeams = False
+
+ def _onTeamListChange(self, *args):
+ teamsToSet = []
+ teams = [team[0] for team in self.teamWidgets[0].getOptions()]
+ for team in self.teams:
+ try:
+ teamsToSet.append(teams.index(team)+1)
+ except ValueError:
+ pass
+ self._lockTeams = True
+ self.teamWidgets[0].setPositions(teamsToSet)
+ self._lockTeams = False
+
+ def _onMatchListChange(self, *args):
+ try:
+ matches = [
+ match.getMatchID() for match
+ in self.bracketWidgets[
+ self.LIST_WIDGETS['winner']].getOptions()
+ if match is not None]
+ self.bracketWidgets[self.LIST_WIDGETS['winner']].setPositions([
+ winner for winner in self.winners if winner in matches])
+ self.bracketWidgets[self.LIST_WIDGETS['loser']].setPositions([
+ loser for loser in self.losers if loser in matches])
+ except tk.TclError as e:
+ # we're probably trying to update our widget when
+ # WE'RE the match that's being destroyed
+ pass
+
+ def setValue(self, value):
+ if isinstance(value, (str, unicode)):
+ value = [value]
+ if isinstance(value, list):
+ self.source.set(self.SOURCE_TEAM)
+ self.teams = list(set(value))
+ for idx in self.LIST_WIDGETS.values():
+ self.bracketWidgets[idx].setPositions([])
+ else:
+ self.source.set(self.SOURCE_BRACKET)
+ self.teams = []
+ for key, idx in self.LIST_WIDGETS.iteritems():
+ self.bracketWidgets[idx].setPositions(
+ value[key]
+ if key in value and isinstance(value[key], list)
+ else [])
+
+ def setSelectedTeam(self, team):
+ if team > -1:
+ self.selectedIndex.set(self.bracketWidgets[7].getValues()[team+1])
+ self.selected.set(1)
+ else:
+ self.selectedIndex.set(('none', ''))
+ self.selected.set(0)
+
+ def getSelectedTeam(self):
+ if self.selected.get():
+ try:
+ return self.bracketWidgets[7].getValues().index(
+ self.selectedIndex.get())
+ except ValueError:
+ return -1
+ else:
+ return -1
+
+ def getConfig(self):
+ if self.source.get() == self.SOURCE_TEAM:
+ return self.teams
+ else:
+ config = OrderedDict()
+ lists = {
+ 5: self.positions,
+ 1: self.winners,
+ 3: self.losers
+ }
+ for key, idx in self.LIST_WIDGETS.iteritems():
+ values = lists[idx]
+ if len(values) > 0:
+ config[key] = values
+ return config
+
+ def getValue(self):
+ return self.getConfig()
+
+class MatchSettingsFrame(RepeatableFrame):
+ SCORE_SOURCE_DB = 0
+ SCORE_SOURCE_LINK = 1
+ SCORE_SOURCE_CUSTOM = 2
+
+ def destroy(self, *args, **kwargs):
+ self.winfo_toplevel().event_generate(
+ '<<MatchListChanged>>', when='tail')
+ RepeatableFrame.destroy(self, *args, **kwargs)
+
+ def _enablePanels(self, *args):
+ for val, fields in self.scoreWidgets.iteritems():
+ for field in fields:
+ field.configure(
+ state=tk.NORMAL if self.source.get() == val
+ else tk.DISABLED)
+ if not self.scoreNotFinished.get():
+ self.scoreWidgets[self.SCORE_SOURCE_CUSTOM][-2].configure(
+ state=tk.DISABLED)
+
+ def _updateName(self, *args):
+ self.nameLabel.configure(text=self.label)
+
+ def _setWinnerPositions(self, values):
+ self.winnerPositions = values
+
+ def _setLoserPositions(self, values):
+ self.loserPositions = values
+
+ def renderContent(self):
+ self.nameLabel = ttk.Label(self)
+ self.matchID = NotifyIntVar()
+ self.matchID.trace('w', self._updateName)
+ self.matchID.set(self.winfo_toplevel().getNewMatchID(self))
+ self.winfo_toplevel().bind(
+ '<<PhaseRenamed>>', self._updateName, add='+')
+ self.link = NotifyStringVar()
+
+ self.source = NotifyIntVar()
+ self.source.trace('w', self._enablePanels)
+
+ self.scoreDB = NotifyStringVar()
+ self.scoreRound = NotifyNumericVar()
+ self.scoreTable = NotifyNumericVar()
+ self.scoreCustom = [NotifyStringVar(), NotifyStringVar()]
+ self.scoreNotFinished = NotifyBoolVar()
+ self.scoreNotFinished.trace('w', self._enablePanels)
+ self.scoreBoards = NotifyNumericVar()
+
+ self.winnerPositions = []
+ self.loserPositions = []
+
+ self.columnconfigure(1, weight=1)
+ self.columnconfigure(2, weight=1)
+
+ self.nameLabel.grid(row=0, column=0, sticky=tk.W)
+ (ttk.Label(self, text='Link:')).grid(row=0, column=1, sticky=tk.E)
+ (ttk.Entry(self, textvariable=self.link)).grid(
+ row=0, column=2, sticky=tk.W+tk.E)
+
+ bracketGroup = ttk.LabelFrame(self, text='Dane drabinki')
+ bracketGroup.grid(row=1, column=0, columnspan=3, sticky=tk.W+tk.E)
+
+ bracketGroup.columnconfigure(0, weight=1)
+ bracketGroup.columnconfigure(1, weight=1)
+
+ homeTeam = ttk.LabelFrame(bracketGroup, text='Team gospodarzy')
+ homeTeam.grid(row=0, column=0, sticky=tk.W+tk.E)
+ awayTeam = ttk.LabelFrame(bracketGroup, text='Team gości')
+ awayTeam.grid(row=0, column=1, sticky=tk.W+tk.E)
+
+ teamFrames = [homeTeam, awayTeam]
+ self.bracketSettings = []
+ for frame in teamFrames:
+ bracket = BracketMatchSettingsFrame(frame)
+ bracket.grid(row=0, column=0, sticky=tk.N+tk.S+tk.W+tk.E)
+ self.bracketSettings.append(bracket)
+
+ scoreGroup = ttk.LabelFrame(self, text='Dane wyniku meczu')
+ scoreGroup.grid(row=4, column=0, columnspan=3, sticky=tk.W+tk.E)
+
+ scoreGroup.columnconfigure(1, weight=1)
+ scoreGroup.columnconfigure(3, weight=1)
+
+ self.scoreWidgets = {
+ self.SCORE_SOURCE_DB: [
+ DBSelectionField(scoreGroup, self.scoreDB, self.scoreDB.get()),
+ ttk.Label(scoreGroup, text='Runda:'),
+ NumericSpinbox(
+ scoreGroup, width=3,
+ textvariable=self.scoreRound, from_=1, to=999),
+ ttk.Label(scoreGroup, text='Stół:'),
+ NumericSpinbox(
+ scoreGroup, width=3,
+ textvariable=self.scoreTable, from_=1, to=999)
+ ],
+ self.SCORE_SOURCE_LINK: [
+ ttk.Entry(scoreGroup, textvariable=self.link),
+ # TODO: TC support (Round/Session)
+ #ttk.Label(scoreGroup, text='Sesja:'),
+ #NumericSpinbox(
+ # scoreGroup,
+ #textvariable=self.scoreSession, from_=1, to=999),
+ #ttk.Label(scoreGroup, text='Runda:'),
+ #NumericSpinbox(
+ # scoreGroup,
+ #textvariable=self.scoreRound, from_=1, to=999),
+ ttk.Label(scoreGroup, text='Stół:'),
+ NumericSpinbox(
+ scoreGroup, width=3,
+ textvariable=self.scoreTable, from_=1, to=999)
+ ],
+ self.SCORE_SOURCE_CUSTOM: [
+ ttk.Entry(
+ scoreGroup, textvariable=self.scoreCustom[0],
+ width=10, justify=tk.RIGHT),
+ ttk.Label(scoreGroup, text=':'),
+ ttk.Entry(
+ scoreGroup, textvariable=self.scoreCustom[1],
+ width=10, justify=tk.RIGHT),
+ ttk.Checkbutton(
+ scoreGroup, variable=self.scoreNotFinished,
+ text='mecz nie został zakończony, rozegrano:'),
+ NumericSpinbox(
+ scoreGroup, width=3,
+ textvariable=self.scoreBoards, from_=0, to=999),
+ ttk.Label(scoreGroup, text='rozdań')
+ ]
+ }
+
+ (ttk.Radiobutton(
+ scoreGroup, variable=self.source, value=self.SCORE_SOURCE_DB,
+ text='Baza danych')).grid(row=0, column=0, sticky=tk.W)
+ self.scoreWidgets[self.SCORE_SOURCE_DB][0].grid(
+ row=0, column=1, columnspan=3, sticky=tk.W+tk.E)
+ for idx in range(1, 5):
+ self.scoreWidgets[self.SCORE_SOURCE_DB][idx].grid(
+ row=0, column=idx+3)
+ (ttk.Radiobutton(
+ scoreGroup, variable=self.source, value=self.SCORE_SOURCE_LINK,
+ text='Strona z wynikami')).grid(row=1, column=0, sticky=tk.W)
+ self.scoreWidgets[self.SCORE_SOURCE_LINK][0].grid(
+ row=1, column=1, columnspan=3, sticky=tk.W+tk.E)
+ self.scoreWidgets[self.SCORE_SOURCE_LINK][1].grid(
+ row=1, column=4)
+ self.scoreWidgets[self.SCORE_SOURCE_LINK][2].grid(
+ row=1, column=5)
+ (ttk.Radiobutton(
+ scoreGroup, variable=self.source, value=self.SCORE_SOURCE_CUSTOM,
+ text='Ustaw ręcznie')).grid(row=2, column=0, sticky=tk.W)
+ for idx in range(0, 3):
+ self.scoreWidgets[self.SCORE_SOURCE_CUSTOM][idx].grid(
+ row=2, column=idx+1, sticky=tk.E if idx == 0 else tk.W)
+ self.scoreWidgets[self.SCORE_SOURCE_CUSTOM][3].grid(
+ row=2, column=4, columnspan=4)
+ for idx in range(4, 6):
+ self.scoreWidgets[self.SCORE_SOURCE_CUSTOM][idx].grid(
+ row=2, column=idx+5)
+
+ (ttk.Label(bracketGroup, text='Zwycięzca zajmie miejsca:')).grid(
+ row=1, column=0, sticky=tk.E)
+ self.winnerPositionsBtn = TeamSelectionButton(
+ bracketGroup, prompt='Wybierz pozycje końcowe:',
+ dialogclass=PositionsSelectionFrame,
+ callback=self._setWinnerPositions)
+ self.winnerPositionsBtn.grid(row=1, column=1, sticky=tk.W)
+ (ttk.Label(bracketGroup, text='Przegrany zajmie miejsca:')).grid(
+ row=2, column=0, sticky=tk.E)
+ self.loserPositionsBtn = TeamSelectionButton(
+ bracketGroup, prompt='Wybierz pozycje końcowe:',
+ dialogclass=PositionsSelectionFrame,
+ callback=self._setLoserPositions)
+ self.loserPositionsBtn.grid(row=2, column=1, sticky=tk.W)
+
+ self._enablePanels()
+
+ self.winfo_toplevel().event_generate(
+ '<<MatchListChanged>>', when='tail')
+
+ @classmethod
+ def info(cls):
+ return 'Nowy mecz'
+
+ def getMatchID(self):
+ return self.matchID.get()
+
+ def getPhase(self):
+ obj = self
+ while not isinstance(obj, MatchPhaseFrame):
+ obj = obj.master
+ if obj is None:
+ break
+ return obj
+
+ @property
+ def label(self):
+ try:
+ phase = self.getPhase()
+ return 'Mecz #%d [faza: %s]' % (
+ self.getMatchID(),
+ phase.master.tab(phase)['text'].strip()
+ if phase is not None else '')
+ except tk.TclError:
+ # we're probably just being created, ignore
+ return ''
+
+ def setValue(self, value):
+ self.matchID.set(value['id'] if 'id' in value else 0)
+ self.link.set(value['link'] if 'link' in value else '')
+
+ self.scoreDB.set(value['database'] if 'database' in value else '')
+ self.scoreRound.set(value['round'] if 'round' in value else 1)
+ self.scoreTable.set(value['table'] if 'table' in value else 1)
+
+ if 'score' in value:
+ for idx in range(0, 2):
+ self.scoreCustom[idx].set(
+ value['score'][idx]
+ if isinstance(value['score'], list)
+ and len(value['score']) > 1
+ else 0)
+ self.scoreNotFinished.set(
+ 'running' in value and value['running'] >= 0)
+ self.scoreBoards.set(
+ value['running'] if 'running' in value
+ and value['running'] >= 0 else 0)
+ else:
+ self.scoreNotFinished.set(0)
+ self.scoreBoards.set(0)
+
+ self.source.set(
+ self.SCORE_SOURCE_DB if 'database' in value else (
+ self.SCORE_SOURCE_CUSTOM if 'table' not in value
+ else self.SCORE_SOURCE_LINK
+ ))
+
+ if 'teams' in value and isinstance(value['teams'], list):
+ for idx, val in enumerate(value['teams']):
+ if idx < 2:
+ self.bracketSettings[idx].setValue(val)
+ else:
+ for idx in range(0, 2):
+ self.bracketSettings[idx].setValue({})
+
+ self.winnerPositionsBtn.setPositions(
+ value['winner']
+ if 'winner' in value and isinstance(value['winner'], list)
+ else [])
+ self.loserPositionsBtn.setPositions(
+ value['loser']
+ if 'loser' in value and isinstance(value['loser'], list)
+ else [])
+
+ if 'selected_teams' in value \
+ and isinstance(value['selected_teams'], list):
+ for idx, val in enumerate(value['selected_teams']):
+ if idx < 2:
+ self.bracketSettings[idx].setSelectedTeam(val)
+ else:
+ for idx in range(0, 2):
+ self.bracketSettings[idx].setSelectedTeam(-1)
+
+ def getValue(self):
+ config = OrderedDict()
+ config['id'] = self.matchID.get()
+ if self.link.get():
+ config['link'] = self.link.get()
+
+ config['teams'] = [bracket.getValue()
+ for bracket in self.bracketSettings]
+
+ if len(self.winnerPositions):
+ config['winner'] = self.winnerPositions
+ if len(self.loserPositions):
+ config['loser'] = self.loserPositions
+
+ selected = [bracket.getSelectedTeam()
+ for bracket in self.bracketSettings]
+ if len([s for s in selected if s > -1]):
+ config['selected_teams'] = selected
+
+ if self.source.get() == self.SCORE_SOURCE_DB:
+ config['database'] = self.scoreDB.get()
+ config['round'] = self.scoreRound.get()
+ if self.source.get() != self.SCORE_SOURCE_CUSTOM:
+ config['table'] = self.scoreTable.get()
+
+ if self.source.get() == self.SCORE_SOURCE_CUSTOM:
+ config['score'] = []
+ for score in self.scoreCustom:
+ try:
+ config['score'].append(float(score.get()))
+ except ValueError:
+ config['score'].append(0.0)
+ if self.scoreNotFinished.get():
+ config['running'] = self.scoreBoards.get()
+
+ return config
+
+ if 'selected_teams' in value \
+ and isinstance(value['selected_teams'], list):
+ for idx, val in enumerate(value['selected_teams']):
+ if idx < 2:
+ self.bracketSettings[idx].setSelectedTeam(val)
+ else:
+ for idx in range(0, 2):
+ self.bracketSettings[idx].setSelectedTeam(-1)
+
+
+
+class MatchSeparator(RepeatableFrame):
+ def renderContent(self):
+ (ttk.Separator(self, orient=tk.HORIZONTAL)).pack(
+ side=tk.TOP, fill=tk.X, expand=True)
+
+ @classmethod
+ def info(cls):
+ return 'Odstęp między meczami'
+
+
+class MatchPhaseFrame(ScrollableFrame):
+ def _updateLinks(self, *args):
+ for match in self.matches.widgets:
+ if isinstance(match, MatchSettingsFrame):
+ match_link = match.link.get()
+ if not len(match_link) or match_link == self.previousLink:
+ match.link.set(self.link.get())
+ self.previousLink = self.link.get()
+
+ def _signalPhaseRename(self, *args):
+ self.winfo_toplevel().event_generate('<<PhaseRenamed>>', when='tail')
+
+ def renderContent(self, container):
+ self.name = NotifyStringVar()
+ self.link = NotifyStringVar()
+ self.previousLink = ''
+
+ headerFrame = tk.Frame(container)
+ headerFrame.pack(side=tk.TOP, fill=tk.X, expand=True)
+ (ttk.Label(headerFrame, text='Nazwa:')).pack(side=tk.LEFT)
+ (ttk.Entry(headerFrame, textvariable=self.name)).pack(
+ side=tk.LEFT, fill=tk.X, expand=True)
+ (ttk.Label(headerFrame, text='Link:')).pack(side=tk.LEFT)
+ (ttk.Entry(headerFrame, textvariable=self.link)).pack(
+ side=tk.LEFT, fill=tk.X, expand=True)
+
+ self.matches = WidgetRepeater(
+ container, [MatchSettingsFrame, MatchSeparator],
+ onAdd=self._matchAdded)
+ self.matches.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
+
+ self.link.trace('w', self._updateLinks)
+ self.name.trace('w', self._signalPhaseRename)
+
+ def _matchAdded(self, widget):
+ self.after(100, self.canvas.yview_moveto, 1.0)
+
+ def setValues(self, values):
+ matches = values['matches'] if 'matches' in values else []
+ dummies = values['dummies'] if 'dummies' in values else []
+ objects = [(MatchSeparator, None)] * (len(matches) + len(dummies))
+ idx = 0
+ for match in matches:
+ while idx in dummies:
+ idx += 1
+ objects[idx] = (MatchSettingsFrame, match)
+ idx += 1
+ self.matches.setValue(objects)
+ self.link.set(values['link'] if 'link' in values else '')
+ self.name.set(values['title'] if 'title' in values else '')
+ self.winfo_toplevel().event_generate(
+ '<<MatchListChanged>>', when='tail')
+
+ def getConfig(self):
+ config = OrderedDict()
+ if self.name.get():
+ config['title'] = self.name.get()
+ if self.link.get():
+ config['link'] = self.link.get()
+ values = self.matches.getValue()
+ dummies = []
+ matches = []
+ for idx, value in enumerate(values):
+ if value is None:
+ dummies.append(idx)
+ else:
+ matches.append(value)
+ if len(dummies):
+ config['dummies'] = dummies
+ config['matches'] = matches
+ return config
+
+
+__all__ = ['SwissesFrame', 'MatchPhaseFrame', 'MatchSettingsFrame']