Add build script.

This commit is contained in:
luxick
2018-02-24 14:06:59 +01:00
parent af57942ad8
commit f1160ddb55
12 changed files with 868 additions and 347 deletions

18
build.py Normal file
View File

@@ -0,0 +1,18 @@
"""
Package application using zipapp into an executable zip archive
"""
import os
import zipapp
INTERPRETER = '/usr/bin/env python3'
SOURCE_PATH = 'dsst'
TARGET_FILENAME = 'dsst'
# The bundled file should be placed into the build directory
target_path = os.path.join(os.path.dirname(__file__), 'build')
# Make sure it exists
if not os.path.isdir(target_path):
os.mkdir(target_path)
target = os.path.join(target_path, TARGET_FILENAME)
# Create archive
zipapp.create_archive(source=SOURCE_PATH, target=target, interpreter=INTERPRETER)

10
dsst/__main__.py Normal file
View File

@@ -0,0 +1,10 @@
import sys
import os.path
# Add current directory to python path
path = os.path.realpath(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(path))
from dsst_gtk3 import gtk_ui
if __name__ == '__main__':
gtk_ui.main()

View File

@@ -3,6 +3,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from datetime import datetime
from dsst_sql import sql
from dsst_gtk3 import util
def enter_string_dialog(builder: Gtk.Builder, title: str, value=None) -> str:
@@ -105,3 +106,41 @@ def show_manage_drinks_dialog(builder: Gtk.Builder):
result = dialog.run()
dialog.hide()
return result
def show_edit_death_dialog(builder: Gtk.Builder, episode_id: int, death: sql.Death=None):
dialog = builder.get_object("edit_death_dialog") # type: Gtk.Dialog
dialog.set_transient_for(builder.get_object("main_window"))
with sql.connection.atomic():
if death:
index = util.Util.get_index_of_combo_model(builder.get_object('edit_death_enemy_combo'), 0, death.enemy.id)
builder.get_object('edit_death_enemy_combo').set_active(index)
# TODO Default drink should be set in config
default_drink = sql.Drink.get().name
store = builder.get_object('player_penalties_store')
store.clear()
for player in builder.get_object('episode_players_store'):
store.append([None, player[1], default_drink, player[0]])
# Run the dialog
result = dialog.run()
dialog.hide()
if result != Gtk.ResponseType.OK:
sql.connection.rollback()
return False
# Collect info from widgets and save to database
player_id = util.Util.get_combo_value(builder.get_object('edit_death_player_combo'), 0)
enemy_id = util.Util.get_combo_value(builder.get_object('edit_death_enemy_combo'), 3)
comment = builder.get_object('edit_death_comment_entry').get_text()
if not death:
death = sql.Death.create(episode=episode_id, player=player_id, enemy=enemy_id, info=comment)
store = builder.get_object('player_penalties_store')
size = builder.get_object('edit_death_size_spin').get_value()
for entry in store:
drink_id = sql.Drink.get(sql.Drink.name == entry[2])
sql.Penalty.create(size=size, player=entry[3], death=death.id, drink=drink_id)
return True

View File

@@ -9,14 +9,18 @@ from dsst_gtk3 import util
from dsst_sql import sql, sql_func
class DSSTGtkUi:
class GtkUi:
""" The main UI class """
def __init__(self):
# Load Glade UI files
self.ui = Gtk.Builder()
self.ui.add_from_file(os.path.join(os.path.dirname(__file__), 'resources', 'glade', 'window.glade'))
self.ui.add_from_file(os.path.join(os.path.dirname(__file__), 'resources', 'glade', 'dialogs.glade'))
glade_resources = [
['dsst_gtk3', 'resources', 'glade', 'window.glade'],
['dsst_gtk3', 'resources', 'glade', 'dialogs.glade']
]
for path in glade_resources:
self.ui.add_from_string(util.Util.load_ui_resource_string(path))
# Connect signal handlers to UI
self.handlers = handlers.Handlers(self)
self.ui.connect_signals(self.handlers)
@@ -45,14 +49,20 @@ class DSSTGtkUi:
for season in sql.Season.select().order_by(sql.Season.number):
store.append([season.id, season.game_name])
def reload_for_season(self, season_id):
# Reload after season was changed ##################################################################################
def reload_for_season(self):
season_id = self.get_selected_season_id()
if season_id is None or season_id == -1:
return
# Rebuild episodes store
ep_id = self.get_selected_episode_id()
selection = self.ui.get_object('episodes_tree_view').get_selection()
# selection.handler_block_by_func(self.handlers.on_selected_episode_changed)
store = self.ui.get_object('episodes_store')
store.clear()
for episode in sql_func.get_episodes_for_season(season_id):
store.append([episode.id, episode.number, str(episode.date)])
# Load player stats for season
player_stats = {}
for episode in sql_func.get_episodes_for_season(season_id):
@@ -64,20 +74,31 @@ class DSSTGtkUi:
for name, stats in player_stats.items():
store.append([name, stats[0], stats[1]])
# Load enemy stats for season
enemy_stats = {enemy.name: [0, 0] for enemy in sql.Season.get(sql.Season.id == season_id).enemies}
enemy_stats = {enemy.name: [0, 0, enemy.id] for enemy in sql.Season.get(sql.Season.id == season_id).enemies}
store = self.ui.get_object('enemy_season_store')
store.clear()
for name, stats in enemy_stats.items():
store.append([name, stats[0], stats[1]])
store.append([name, stats[0], stats[1], stats[2]])
def reload_for_episode(self, episode_id):
pass
# Reload after episode was changed #################################################################################
def reload_for_episode(self):
episode_id = self.get_selected_episode_id()
if not episode_id:
return
store = self.ui.get_object('episode_players_store')
store.clear()
for player in sql.Episode.get(sql.Episode.id == self.get_selected_episode_id()).players:
store.append([player.id, player.name, player.hex_id])
def get_selected_season_id(self):
season_id = util.Util.get_combo_value(self.ui.get_object('season_combo_box'), 0)
return season_id if season_id != -1 else None
def get_selected_episode_id(self):
(model, tree_iter) = self.ui.get_object('episodes_tree_view').get_selection().get_selected()
return model.get_value(tree_iter, 0) if tree_iter else None
if __name__ == '__main__':
DSSTGtkUi()
def main():
GtkUi()
Gtk.main()

View File

@@ -1,10 +1,15 @@
from dsst_gtk3.gtk_ui import DSSTGtkUi
from dsst_sql import sql
from dsst_gtk3 import dialogs, util
from dsst_gtk3 import dialogs, gtk_ui
class CenterHandlers:
def __init__(self, app: DSSTGtkUi):
def __init__(self, app: 'gtk_ui.GtkUi'):
self.app = app
def do_add_death(self, *_):
pass
ep_id = self.app.get_selected_episode_id()
result = dialogs.show_edit_death_dialog(self.app.ui, ep_id)
if result:
self.app.reload_for_season()
def on_penalty_drink_changed(self, widget, path, text):
self.app.ui.get_object('player_penalties_store')[path][2] = text

View File

@@ -1,10 +1,9 @@
from dsst_gtk3.gtk_ui import DSSTGtkUi
from dsst_gtk3 import dialogs, util
from dsst_gtk3 import dialogs, util, gtk_ui
from dsst_sql import sql
class DialogHandlers:
def __init__(self, app: DSSTGtkUi):
def __init__(self, app: 'gtk_ui.GtkUi'):
self.app = app
def do_add_player_to_episode(self, combo):
@@ -20,7 +19,7 @@ class DialogHandlers:
store.append([player_id, player.name, player.hex_id])
def do_add_enemy(self, entry):
if entry.get_text:
if entry.get_text():
store = self.app.ui.get_object('enemy_season_store')
enemy = sql.Enemy.create(name=entry.get_text(), season=self.app.get_selected_season_id())
store.append([enemy.name, False, 0])
@@ -30,7 +29,7 @@ class DialogHandlers:
result = dialogs.show_manage_drinks_dialog(self.app.ui)
def do_add_drink(self, entry):
if entry.get_text:
if entry.get_text():
store = self.app.ui.get_object('drink_store')
drink = sql.Drink.create(name=entry.get_text(), vol='0')
store.append([drink.id, drink.name, drink.vol])

View File

@@ -6,6 +6,8 @@ from dsst_gtk3.handlers.players import PlayerHandlers
from dsst_gtk3.handlers.dialog_handlers import DialogHandlers
from dsst_gtk3.handlers.center_handlers import CenterHandlers
from dsst_sql import sql
class Handlers(LeftColumnHandlers, PlayerHandlers, DialogHandlers, CenterHandlers):
""" Class containing all signal handlers for the GTK GUI """
@@ -26,3 +28,10 @@ class Handlers(LeftColumnHandlers, PlayerHandlers, DialogHandlers, CenterHandler
:param args: Arguments to the delete event
"""
Gtk.main_quit()
# DEBUG Functions ##################################################################################################
@staticmethod
def do_delete_database(*_):
sql.drop_tables()
sql.create_tables()

View File

@@ -1,11 +1,9 @@
from datetime import datetime
from dsst_gtk3.gtk_ui import DSSTGtkUi
from dsst_sql import sql
from dsst_gtk3 import dialogs, util
from dsst_gtk3 import dialogs, gtk_ui
class LeftColumnHandlers:
def __init__(self, app: DSSTGtkUi):
def __init__(self, app: 'gtk_ui.GtkUi'):
self.app = app
def do_add_season(self, *_):
@@ -15,11 +13,14 @@ class LeftColumnHandlers:
self.app.reload_seasons()
def do_season_selected(self, *_):
self.app.reload_for_season(self.app.get_selected_season_id())
self.app.reload_for_season()
def do_add_episode(self, *_):
season_id = self.app.get_selected_season_id()
if not season_id:
return
episode = dialogs.show_episode_dialog(self.app.ui, 'Create new Episode', season_id)
self.app.reload_for_season(season_id)
self.app.reload_for_season()
def on_selected_episode_changed(self, *_):
self.app.reload_for_episode()

View File

@@ -1,10 +1,9 @@
from dsst_gtk3.gtk_ui import DSSTGtkUi
from dsst_gtk3 import dialogs, util
from dsst_gtk3 import dialogs, gtk_ui
from dsst_sql import sql
class PlayerHandlers:
def __init__(self, app: DSSTGtkUi):
def __init__(self, app: 'gtk_ui.GtkUi'):
self.app = app
def do_manage_players(self, *_):

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,7 @@
import os
from zipfile import ZipFile
class Util:
@staticmethod
def get_combo_value(combo, index: int):
@@ -7,3 +11,33 @@ class Util:
return combo.get_model().get_value(tree_iter, index)
else:
return -1
@staticmethod
def get_index_of_combo_model(combo, column: int, value: int):
model = combo.get_model()
return [model.index(entry) for entry in model if entry[column] == value]
@staticmethod
def load_ui_resource_string(resource_path: list) -> str:
""" Load content of Glade UI files from resources path
:param resource_path: List of directory names from 'dsst' base directory
:return: String content of the Glade file
"""
if os.path.isdir(os.path.dirname(__file__)):
return Util.load_ui_resource_from_file(resource_path)
else:
return Util.load_ui_resource_from_archive(resource_path)
@staticmethod
def load_ui_resource_from_file(resource_path: list) -> str:
project_base_dir = os.path.dirname(os.path.dirname(__file__))
full_path = os.path.join(project_base_dir, *resource_path)
with open(full_path, 'r') as file:
return file.read()
@staticmethod
def load_ui_resource_from_archive(resource_path: list) -> str:
zip_path = os.path.dirname(os.path.dirname(__file__))
with ZipFile(zip_path, 'r') as archive:
return archive.read(str(os.path.join(*resource_path))).decode('utf-8')

View File

@@ -58,13 +58,23 @@ class Death(Model):
info = CharField(null=True)
player = ForeignKeyField(Player)
enemy = ForeignKeyField(Enemy)
penalty = ForeignKeyField(Drink)
episode = ForeignKeyField(Episode, backref='deaths')
class Meta:
database = connection
class Penalty(Model):
id = AutoField()
size = DecimalField()
ForeignKeyField(Drink)
ForeignKeyField(Player, backref='penalties')
ForeignKeyField(Death, backref='penalties')
class Meta:
database = connection
class Victory(Model):
id = AutoField()
info = CharField(null=True)
@@ -77,8 +87,11 @@ class Victory(Model):
def create_tables():
models = [Season, Episode, Player, Drink, Enemy, Death, Victory, Episode.players.get_through_model()]
models = [Season, Episode, Player, Drink, Enemy, Death, Victory, Penalty, Episode.players.get_through_model()]
for model in models:
model.create_table()
def drop_tables():
models = [Season, Episode, Player, Drink, Enemy, Death, Victory, Penalty, Episode.players.get_through_model()]
connection.drop_tables(models)