From 84c21d992ebef56908ce89c0029445310920a4bb Mon Sep 17 00:00:00 2001 From: Taka Date: Sun, 23 Apr 2017 05:10:52 +0000 Subject: [PATCH] Added a skeleton GUI. --- .gitignore | 3 ++ _freeze.py | 36 +++++++++++++++++++++++ constants.py | 11 +++++++ freeze.sh | 24 ++++++++++++++++ globals.py | 7 +++++ main.py | 71 ++++++++++++++++++++++++++++++++++++++++++++++ main_window.py | 44 ++++++++++++++++++++++++++++ requirements.txt | 5 ++++ resources/app.ico | Bin 0 -> 9274 bytes 9 files changed, 201 insertions(+) create mode 100644 _freeze.py create mode 100755 constants.py create mode 100755 freeze.sh create mode 100644 globals.py create mode 100755 main.py create mode 100755 main_window.py create mode 100644 requirements.txt create mode 100755 resources/app.ico diff --git a/.gitignore b/.gitignore index f414fc8..4d9c1b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +app.ini +debug.ini + .venv-* __pycache__/ *.py[cod] diff --git a/_freeze.py b/_freeze.py new file mode 100644 index 0000000..1b2d77c --- /dev/null +++ b/_freeze.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# FIXME: Get py2exe working for Windows builds (since it produces a single EXE). + +import sys +from cx_Freeze import setup , Executable + +from constants import * + +# --------------------------------------------------------------------- + +# initialize +extra_files = [ + "resources/app.ico" +] +build_options = { + "packages": [ "os" ] , + "excludes": [ "tkinter" ] , + "include_files": extra_files , +} + +# freeze the application +# FIXME! set the app icon +target = Executable( + "main.py" , + base = "Win32GUI" if sys.platform == "win32" else None , + targetName = "asl_cards.exe" if sys.platform == "win32" else "asl_cards" , +) +setup( + name = APP_NAME , + version = APP_VERSION , + description = APP_DESCRIPTION , + options = { + APP_NAME: build_options + } , + executables = [ target ] +) diff --git a/constants.py b/constants.py new file mode 100755 index 0000000..db47598 --- /dev/null +++ b/constants.py @@ -0,0 +1,11 @@ +APP_VENDOR = "Pacman Ghost" +APP_HOME_URL = "https://github.com/pacman-ghost" +APP_NAME = "ASL Cards" +APP_VERSION = "v0.1" +APP_DESCRIPTION = "ASL Cards viewer." + +# settings file +MAINWINDOW_POSITION = "MainWindow/position" +MAINWINDOW_SIZE = "MainWindow/size" +# +CONFIRM_EXIT = "Settings/ConfirmExit" diff --git a/freeze.sh b/freeze.sh new file mode 100755 index 0000000..833eb0f --- /dev/null +++ b/freeze.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# initialize +BASE_DIR=$(readlink -f "`dirname "$0"`") +RELEASE_FILENAME="/tmp/asl_cards.tar.gz" + +# freeze the application +cd "$BASE_DIR" +rm -rf build +python _freeze.py build +if [ $? -ne 0 ] ; then + echo "ERROR: Freeze failed." + exit $? +fi + +# create the release +cd build/exe.linux-x86_64-3.6 +tar cfz "$RELEASE_FILENAME" . +echo +echo "Created release:" +ls -lh "$RELEASE_FILENAME" | sed -e "s/^/ /" + +# clean up +rm -rf "$BASE_DIR/build" diff --git a/globals.py b/globals.py new file mode 100644 index 0000000..c8e2207 --- /dev/null +++ b/globals.py @@ -0,0 +1,7 @@ +# who we are, and where we live +base_dir = None +app_name = None + +# application settings +app_settings = None +debug_settings = None diff --git a/main.py b/main.py new file mode 100755 index 0000000..4784017 --- /dev/null +++ b/main.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +import sys +import os +import getopt + +from PyQt5.QtCore import QSettings , QDir +from PyQt5.QtWidgets import QApplication + +from constants import * +import globals + +# --------------------------------------------------------------------- + +def do_main( args ) : + + # initialize + QApplication.setOrganizationName( APP_VENDOR ) + QApplication.setOrganizationDomain( APP_HOME_URL ) + QApplication.setApplicationName( APP_NAME ) + + # initialize + globals.base_dir , app_name = os.path.split( + os.path.abspath( sys.executable if hasattr(sys,"frozen") else __file__ ) + ) + globals.app_name = os.path.splitext( app_name )[ 0 ] + + # parse the command-line arguments + settings_fname = None + opts , args = getopt.getopt( args[1:] , "c:h?" , ["config=","help"] ) + for opt,val in opts : + if opt in ["-c","--config"] : + settings_fname = val + elif opt in ["-h","--help","-?"] : + print_help() + else : + raise RuntimeError( "Unknown argument: {}".format( opt ) ) + if not settings_fname : + # try to locate the settings file + settings_fname = os.path.join( globals.base_dir , globals.app_name+".ini" ) + if not os.path.isfile( settings_fname ) : + settings_fname = os.path.split(settings_fname)[ 1 ] + if sys.platform != "win32" : + settings_fname = "." + settings_fname + settings_fname = os.path.join( QDir.homePath() , settings_fname ) + + # load our settings + globals.app_settings = QSettings( settings_fname , QSettings.IniFormat ) + fname = os.path.join( os.path.split(settings_fname)[0] , "debug.ini" ) + globals.debug_settings = QSettings( fname , QSettings.IniFormat ) + + # do main processing + app = QApplication( sys.argv ) + import main_window + main_window = main_window.MainWindow() + main_window.show() + return app.exec_() + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +def print_help() : + print( "{} {{options}}".format( os.path.split(sys.argv[0])[1] ) ) # FIXME! frozen? + print( " {}".format( APP_DESCRIPTION ) ) + print() + print( " -c --config Config file." ) + sys.exit() + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +if __name__ == "__main__" : + sys.exit( do_main( sys.argv ) ) diff --git a/main_window.py b/main_window.py new file mode 100755 index 0000000..fd94b03 --- /dev/null +++ b/main_window.py @@ -0,0 +1,44 @@ +import sys +import os + +from PyQt5.QtCore import Qt , QPoint , QSize +from PyQt5.QtWidgets import QMainWindow +from PyQt5.QtWidgets import QMessageBox +from PyQt5.QtGui import QIcon + +from constants import * +import globals + +# --------------------------------------------------------------------- + +class MainWindow( QMainWindow ) : + + def __init__( self ) : + super().__init__() + # initialize the window + self.setWindowTitle( APP_NAME ) + self.setWindowIcon( QIcon("resources/app.ico") ) + # load the window settings + self.resize( globals.app_settings.value( MAINWINDOW_SIZE , QSize(500,300) ) ) + self.move( globals.app_settings.value( MAINWINDOW_POSITION , QPoint(200,200) ) ) + + def closeEvent( self , evt ) : + """Handle window close.""" + # confirm the close + if globals.app_settings.value( CONFIRM_EXIT , True , type=bool ) : + rc = QMessageBox.question( self , "Confirm close" , + "Do you want to the close the program?" , + QMessageBox.Ok | QMessageBox.Cancel , + QMessageBox.Cancel + ) + if rc != QMessageBox.Ok : + evt.ignore() + # save the window settings + # FIXME! handle fullscreen + globals.app_settings.setValue( MAINWINDOW_POSITION , self.pos() ) + globals.app_settings.setValue( MAINWINDOW_SIZE , self.size() ) + + def keyPressEvent( self , evt ) : + """Handle key-presses.""" + if evt.key() == Qt.Key_Escape and globals.debug_settings.value("Debug/AllowEscapeToClose",type=bool) : + self.close() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ccccc6f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +# python == 3.6.1 + +# NOTE: There are additional requirements for the asl_cards module (see its requirements.txt). +PyQt5 == 5.8.2 +cx-Freeze == 5.0.1 diff --git a/resources/app.ico b/resources/app.ico new file mode 100755 index 0000000000000000000000000000000000000000..c3e3649f2d1ade6ab15fd2f79113475803ebbb66 GIT binary patch literal 9274 zcmeI&zpoWV7{>9Xv;Y$e3N0YvCek1Ug_Q}V78JC^SP3*(nOH~xB@`Bx(2^K?8ap&0 zp)z*<0VYC2ODrTD&*$KCGuiCfot-^iImScgzB|9(`M%G*GkbC`U3YB#@BI00{quBp zaL{!pyRJLCF6*Z5vvtw#^YTpBJwEZeY#P=-R_hP5PX)8jFAuKnUHMz`)t|pTTD|!B z+r29E#y`dW^H7lJUjPtm^P4zNz5CASxG^7d`^MP$!V)g$b;!T-n=#_uHg0I{lC~-KPcMDA zxnF26cZSw-4#Ft*65B|zVJ5V@{4CNX%&wM3*toBabdgk+~F2?w)(cM`7_@Qh3dd?o;POfA>vPO-~IWNa1 zp0r`dk$MfgoS`jtcV^h}YU5MUjyo}AjT(zR8fQGMbFS!Zjq<%$!=C(2zD18P$7&Z_ z&U6@RZ1k{~$r;-4M~`S%`kG?rC;7{-xnjY~@*j3}{H6ceXLks`_!_ePT%2OZlN`gP zo;kMtTiL~k-@Q`CU@h8}xe`6b*o~(vo;;U+J(uidobkWZ4l&2)7`rjp%Dljf zk>=WIA}8siFMfAnaof{vXMc)4I%CAEuHY7zIMn&qpFGmOlwYo5&-=CSZ;CzVKibpR zJ%W+miA8MXS<=^EYi@lhd+w*?HFgY`J@c-NuVEjvaU)17azVAXD49+nUOJ+suu@(*q-$Ji$(n zvM+1Nr;?%O*&J;0#l4bxbZcdgCU~R2SeygC#Y6k#X4b1=&Y0|D_KoE~_hT!2aw2+K z2cNna#D-s?Tg&%%F+}S=x4u?(ta5`-ez0N3Y(393YGsc0tk}zYCVlj$Q|fHZ9cd0m ztQh5nx-(=?l+x!>J=d^f!I!*Gj%06->i3U*O={WAOHSlWvi89q4DEA&tzFmWuxD*K zB>&x!*qw)cVUO