mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-15 02:54:09 -04:00
Compare commits
18 commits
dfff276fc1
...
7255ad9e68
Author | SHA1 | Date | |
---|---|---|---|
|
7255ad9e68 | ||
|
451700aefa | ||
|
97e981d900 | ||
|
d3faa78e75 | ||
|
07aac001b7 | ||
|
278b3261d9 | ||
|
755b1d51d3 | ||
|
cb0ddeeccd | ||
|
dda2f3b520 | ||
|
d145642a9b | ||
|
12601364dc | ||
|
0be465dea1 | ||
|
0f15613a15 | ||
|
1b14baf856 | ||
|
da5b85c064 | ||
|
a8a262a68c | ||
|
95a0d7d007 | ||
|
bf9ce90a5b |
27 changed files with 312 additions and 281 deletions
|
@ -1,23 +1,25 @@
|
|||
---
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: "C:\\PYTHON34"
|
||||
- PYTHON: "C:\\Python37"
|
||||
# Shamelessly taken from https://github.com/plicease/Dist-Zilla-PluginBundle-Author-Plicease/blob/master/.appveyor.yml
|
||||
# Thanks!
|
||||
install:
|
||||
- choco install strawberryperl
|
||||
- copy %PYTHON%\python.exe %PYTHON%\python3.exe
|
||||
- SET PATH=%PYTHON%;C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%
|
||||
- python3 -mpip install Pillow attrs configobj flake8 flake8-import-order py2exe pycotap pygame pysol-cards random2 setuptools six
|
||||
- SET PATH=%PYTHON%;%PYTHON%\Scripts;C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%
|
||||
- python3 -mpip install Pillow attrs configobj flake8 flake8-import-order
|
||||
pycotap pygame pyinstaller pysol-cards random2 setuptools six
|
||||
- perl -v
|
||||
- copy C:\msys64\mingw64\bin\mingw32-make.exe C:\msys64\mingw64\bin\make.exe
|
||||
- SET PATH=C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%
|
||||
- SET PERL5LIB=C:/_P5/lib/perl5
|
||||
- SET PERL_LOCAL_LIB_ROOT=C:/_P5
|
||||
- SET PERL_MB_OPT=--install_base C:/_P5
|
||||
- SET PERL_MM_OPT=INSTALL_BASE=C:/_P5
|
||||
- perl -v
|
||||
- cpanm --notest Code::TidyAll::Plugin::Flake8 File::Find::Object Perl::Tidy Task::FreecellSolver::Testing Test::Code::TidyAll Test::TrailingSpace
|
||||
- cpanm --notest Code::TidyAll::Plugin::Flake8 File::Find::Object
|
||||
Perl::Tidy Task::FreecellSolver::Testing Test::Code::TidyAll
|
||||
Test::TrailingSpace
|
||||
- echo %PATH%
|
||||
build: off
|
||||
test_script:
|
||||
|
@ -30,13 +32,14 @@ test_script:
|
|||
- gmake rules
|
||||
- gmake pot
|
||||
- gmake mo
|
||||
- python3 setup.py py2exe
|
||||
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/PySolFC-Cardsets-2.0/PySolFC-Cardsets-2.0.tar.bz2/download -FileName cardsets.tar.bz2
|
||||
- tar xf cardsets.tar.bz2
|
||||
- xargs -ta scripts\cardsets_to_bundle -I file cp -rt dist\data\ PySolFC-Cardsets-2.0\file
|
||||
- pyinstaller pysol.py --windowed --icon=data\pysol.ico
|
||||
- python3 setup.py install_data -d dist\pysol
|
||||
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/minimal/PySolFC-Cardsets--Minimal-2.0.1.tar.xz/download -FileName cardsets.tar.xz
|
||||
- 7z x cardsets.tar.xz -so | 7z x -si -ttar
|
||||
- mv PySolFC-Cardsets--Minimal-2.0.1/cardset-* dist/pysol/data
|
||||
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySol-Music/PySol-Music-4.50/pysol-music-4.50.tar.xz/download -FileName music.tar.xz
|
||||
- 7z x music.tar.xz -so | 7z x -si -ttar
|
||||
- move pysol-music-4.50\data\music dist\data\music
|
||||
- move pysol-music-4.50\data\music dist\pysol\data\music
|
||||
# - ps: |
|
||||
# $apiUrl = 'https://ci.appveyor.com/api'
|
||||
# $project = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/shlomif/fc-solve"
|
||||
|
@ -48,8 +51,8 @@ test_script:
|
|||
- SET FC_SOLVE_VER=5.20.0
|
||||
- appveyor DownloadFile https://netix.dl.sourceforge.net/project/fc-solve/fc-solve/DO-NOT-USE--fc-solve-for-pysol/fc-solve-for-pysol--v%FC_SOLVE_VER%.zip -FileName fc-solve.zip
|
||||
- 7z x fc-solve.zip
|
||||
- move fcs-pysol dist\freecell-solver
|
||||
- 7z a -r pysol_win_dist.7z dist\
|
||||
- move fcs-pysol dist\pysol\freecell-solver
|
||||
- 7z a -r pysol_win_dist.7z dist\pysol\
|
||||
- SET PYTHONPATH=%cd%
|
||||
- python3 scripts\create_iss.py
|
||||
- appveyor DownloadFile https://download.microsoft.com/download/C/6/D/C6D0FD4E-9E53-4897-9B91-836EBA2AACD3/vcredist_x86.exe -FileName vcredist_x86.exe
|
||||
|
@ -58,7 +61,7 @@ test_script:
|
|||
artifacts:
|
||||
- path: pysol_win_dist.7z
|
||||
name: pysol_win_dist
|
||||
- path: dist\PySolFC_*_setup.exe
|
||||
- path: dist\pysol\PySolFC_*_setup.exe
|
||||
name: pysol_win_installer
|
||||
cache:
|
||||
# - C:\_P5 -> .appveyor.yml
|
||||
|
|
17
.travis.yml
17
.travis.yml
|
@ -11,7 +11,7 @@ deploy:
|
|||
api_key:
|
||||
secure: SrKnXigL/oUHNbqpbGx0DB1o+LAEkfPA2QTBllXxg4V+1vGAHBT9FRecp8Do+no/zSPRttH+sPDEPBXMMAV0BWVKKw5Mxas/S5ulVkNdfxpTq1bKjI3EjZbVsS1zZlHe0P77TDFDAj8zyeiYecBM08suhd9OvScieiPlpFPE1UYp9vvNKaBgc66IRNnIDRBdktW4YLsgvkrpXnxGPy8gGwylsTeOzNs5/r5dzHswGdksJl46kqCIbV+s4/Xcx+BEnfibWzEFZmLQoGKhoukbSis3YXGIlERcgiVU6v7S2D4wbwUXSAKOj/Io7z/88Co2P3Qbm538kf/pjeR9+DaM1HsHQQcL0detCjjLog+ekKr2fM00QI1yRmqOiZtuXxTMpneYX73EBmPt4la4rjKmnlhS+NTxrynHcPZD8QopCPvoZ3sUD6dQCrbi8kcGxe13srfdJ3KjuWZXdedLIOgNELbj5o6GNivsanWna59yoJzChC5/H5Jjllncvzbp56TZfEkM1NJkE84jjSS8Sn2KLXjD0woHIsuUSkRNExrCt/6QmIub/QxZPUhwQ2J0xCv1IJPdd0XvO3gCqasG3UA2Q0OlP172x92ocOV/wm1/4wfoG6v/mn+bX5ZwvrsMmm+r3FKKlM8L3T33yFjMzgG/YMoRN8w7pXUIkdtZK8EEDVg=
|
||||
# file: dist/PySolFC.app
|
||||
file: PySolFC.app.tar.xz
|
||||
file: PySolFC.dmg
|
||||
on:
|
||||
repo: shlomif/PySolFC
|
||||
tags: true
|
||||
|
@ -24,8 +24,8 @@ before_install:
|
|||
mv PySolFC-Cardsets--Minimal-2.0/cardset-* data ;
|
||||
fi
|
||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then
|
||||
PYVER=3.8.2 &&
|
||||
PYVER_SHORT=3.8 &&
|
||||
PYVER=3.9.0 &&
|
||||
PYVER_SHORT=3.9 &&
|
||||
wget -O python.pkg "https://www.python.org/ftp/python/${PYVER}/python-${PYVER}-macosx10.9.pkg" &&
|
||||
sudo installer -pkg python.pkg -target / &&
|
||||
export PATH="/Library/Frameworks/Python.framework/Versions/${PYVER_SHORT}/bin:${PATH}" ;
|
||||
|
@ -61,6 +61,11 @@ script:
|
|||
- export TIDYALL_DATA_DIR="$HOME/tidyall_d"
|
||||
- bash -x scripts/travis-ci-build
|
||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then PYTHONPATH="." python3 setup_osx.py py2app ; fi
|
||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then find . -iname '*.app' ; fi
|
||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then (cd dist && tar -cvf ../PySolFC.app.tar PySolFC.app/) && xz PySolFC.app.tar ; fi
|
||||
|
||||
- if test "$TRAVIS_OS_NAME" = "osx" ; then
|
||||
create-dmg --volname "Install PySolFC"
|
||||
--volicon data/PySol.icns
|
||||
--background html-src/images/pysollogo01.png
|
||||
--window-size 800 400
|
||||
--icon PySolFC.app 200 185
|
||||
--app-drop-link 600 185
|
||||
PySolFC.dmg dist ; fi
|
||||
|
|
1
Brewfile
1
Brewfile
|
@ -1,5 +1,6 @@
|
|||
brew "perl"
|
||||
brew "cpanminus"
|
||||
brew "create-dmg"
|
||||
brew "gettext", link: true
|
||||
brew "gnutls"
|
||||
brew "jpeg"
|
||||
|
|
|
@ -7,7 +7,7 @@ include pysol.py setup.py setup_osx.py setup.cfg MANIFEST.in Makefile
|
|||
include COPYING README.md AUTHORS.md README.android README.kivy
|
||||
include NEWS.asciidoc
|
||||
#recursive-include pysollib *.py
|
||||
include pysollib/*.py pysollib/macosx/*.py
|
||||
include pysollib/*.py
|
||||
include pysollib/winsystems/*.py
|
||||
include pysollib/tk/*.py pysollib/tile/*.py pysollib/pysolgtk/*.py
|
||||
include pysollib/game/*.py
|
||||
|
@ -18,7 +18,7 @@ include data/pysol.desktop
|
|||
include data/pysolfc.glade
|
||||
graft data/themes
|
||||
recursive-exclude data/themes *.py
|
||||
include scripts/build.bat scripts/create_iss.py scripts/mahjongg_utils.py
|
||||
include scripts/create_iss.py scripts/mahjongg_utils.py
|
||||
include scripts/all_games.py scripts/cardset_viewer.py
|
||||
include scripts/cardconv
|
||||
include scripts/gen_individual_importing_tests.py
|
||||
|
|
|
@ -19,7 +19,9 @@ back01.ext;back02.ext;back03.ext
|
|||
Line 1
|
||||
------
|
||||
|
||||
*$A:* The number of fields in first line (e.g. `.gif;1;78;8,1016` -> `$A=4`)
|
||||
*$A:* The cardset version number that belongs to the number of fields divided through ";" on the first line (e.g. `.gif;1;78;8,1016` -> `$A=4`)
|
||||
|
||||
( *WARNING:* For Mahjongg, $A must always be 6 and the $F field must be included in the line; however, you can put `0` in `$F` if you wish, in that case. )
|
||||
|
||||
( *NOTE:* $D and $E are comma separated and count for one field )
|
||||
|
||||
|
@ -154,6 +156,10 @@ You are welcome to send any suggestions to: mailto:neelix570@gmail.com[the Autho
|
|||
https://github.com/shlomif/PySolFC/issues[PySol FC's GitHub issue tracker] or
|
||||
https://sourceforge.net/p/pysolfc/_list/tickets[PySol FC's Sourceforge issue tracker].
|
||||
|
||||
*NOTE 2:*
|
||||
You should also place a file called `COPYRIGHT` in the same directory as `config.txt`,
|
||||
containing the text that can be accessed via `Info/Settings`.
|
||||
|
||||
License:
|
||||
~~~~~~~~
|
||||
|
||||
|
@ -162,3 +168,12 @@ version 3 or later. You can redistribute it as is and/or modify it.
|
|||
|
||||
Shlomi Fish, hereby puts his modifications to this document under
|
||||
https://github.com/shlomif/shlomif-computer-settings/blob/master/shlomif-settings/git/commit-messages/cc0-copyright-disclaimer.txt[CC0 / Public Domain / MIT License / GPL terms]
|
||||
|
||||
Credits:
|
||||
~~~~~~~~
|
||||
|
||||
Credits go to:
|
||||
|
||||
mailto:andsa@web.de[Andreas Sauer] for clarifying certain points +
|
||||
|
||||
https://www.shlomifish.org/[Shlomi Fish] for making some improvements to this tutorial
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
set -Cefu
|
||||
|
||||
: ${PKGTREE:=/usr/local/packages/PySolFC}
|
||||
PIP=("${PKGTREE}/env/bin/pip" install --no-binary :all:)
|
||||
PYPROG="$(printf '%s/env/bin/python' "$PKGTREE")"
|
||||
PIP="${PKGTREE}/env/bin/pip"
|
||||
PYPROG="${PKGTREE}/env/bin/python"
|
||||
VERSION="$(env PYTHONPATH=`pwd` "$PYPROG" -c 'from pysollib.settings import VERSION ; print(VERSION)')"
|
||||
XZBALL="$(printf 'dist/PySolFC-%s.tar.xz' "$VERSION")"
|
||||
reqs='six random2 pillow'
|
||||
XZBALL="dist/PySolFC-${VERSION}.tar.xz"
|
||||
reqs=(pillow pygame random2 six)
|
||||
|
||||
make dist
|
||||
for req in $reqs
|
||||
do
|
||||
"${PIP[@]}" "$req"
|
||||
done
|
||||
"${PIP[@]}" --upgrade "$XZBALL"
|
||||
|
||||
"$PIP" install wheel
|
||||
"$PIP" install "${reqs[@]}"
|
||||
|
||||
"$PIP" install --upgrade "$XZBALL"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
modifications from repoB
|
|
@ -519,7 +519,8 @@ class PysolMenubar(PysolMenubarTk):
|
|||
text += os.linesep
|
||||
enc = locale.getpreferredencoding()
|
||||
try:
|
||||
open(fn, 'a').write(text.encode(enc, 'replace'))
|
||||
with open(fn, 'at') as fh:
|
||||
fh.write(text.encode(enc, 'replace'))
|
||||
except Exception as err:
|
||||
d = MfxExceptionDialog(
|
||||
self.top, err,
|
||||
|
|
129
pysollib/app.py
129
pysollib/app.py
|
@ -33,6 +33,7 @@ from pysollib.actions import PysolMenubar
|
|||
from pysollib.actions import PysolToolbar
|
||||
from pysollib.app_stat_result import GameStatResult
|
||||
from pysollib.app_statistics import Statistics
|
||||
from pysollib.cardsetparser import read_cardset_config
|
||||
from pysollib.gamedb import GAME_DB, GI, loadGame
|
||||
from pysollib.help import destroy_help_html, help_about
|
||||
from pysollib.images import Images, SubsampledImages
|
||||
|
@ -53,7 +54,7 @@ from pysollib.pysoltk import SelectCardsetDialogWithPreview
|
|||
from pysollib.pysoltk import SelectDialogTreeData
|
||||
from pysollib.pysoltk import destroy_find_card_dialog
|
||||
from pysollib.pysoltk import loadImage, wm_withdraw
|
||||
from pysollib.resource import CSI, Cardset, CardsetConfig, CardsetManager
|
||||
from pysollib.resource import CSI, CardsetManager
|
||||
from pysollib.resource import Music, MusicManager
|
||||
from pysollib.resource import Sample, SampleManager
|
||||
from pysollib.resource import Tile, TileManager
|
||||
|
@ -1070,125 +1071,14 @@ Please select a %(correct_type)s type cardset.
|
|||
|
||||
# read & parse a cardset config.txt file - see class Cardset in resource.py
|
||||
def _readCardsetConfig(self, dirname, filename):
|
||||
with open(filename, "r") as f:
|
||||
lines = f.readlines()
|
||||
lines = [line.strip() for line in lines]
|
||||
if not lines[0].startswith("PySol"):
|
||||
return None
|
||||
config = CardsetConfig()
|
||||
if not self._parseCardsetConfig(config, lines):
|
||||
# print filename, 'invalid config'
|
||||
return None
|
||||
if config.CARDD > self.top.winfo_screendepth():
|
||||
return None
|
||||
cs = Cardset()
|
||||
cs.dir = dirname
|
||||
cs.update(config.__dict__)
|
||||
return cs
|
||||
|
||||
def _parseCardsetConfig(self, cs, line):
|
||||
def perr(line, field=None, msg=''):
|
||||
if not DEBUG:
|
||||
return
|
||||
if field:
|
||||
print_err('_parseCardsetConfig error: line #%d, field #%d %s'
|
||||
% (line, field, msg))
|
||||
else:
|
||||
print_err('_parseCardsetConfig error: line #%d: %s'
|
||||
% (line, msg))
|
||||
if len(line) < 6:
|
||||
perr(1, msg='number of lines')
|
||||
return 0
|
||||
# line[0]: magic identifier, possible version information
|
||||
fields = [f.strip() for f in line[0].split(';')]
|
||||
if len(fields) >= 2:
|
||||
m = re.search(r"^(\d+)$", fields[1])
|
||||
if m:
|
||||
cs.version = int(m.group(1))
|
||||
if cs.version >= 3:
|
||||
if len(fields) < 5:
|
||||
perr(1, msg='number of fields')
|
||||
return 0
|
||||
cs.ext = fields[2]
|
||||
m = re.search(r"^(\d+)$", fields[3])
|
||||
if not m:
|
||||
perr(1, 3, 'not integer')
|
||||
return 0
|
||||
cs.type = int(m.group(1))
|
||||
m = re.search(r"^(\d+)$", fields[4])
|
||||
if not m:
|
||||
perr(1, 4, 'not integer')
|
||||
return 0
|
||||
cs.ncards = int(m.group(1))
|
||||
if cs.version >= 4:
|
||||
if len(fields) < 6:
|
||||
perr(1, msg='number of fields')
|
||||
return 0
|
||||
styles = fields[5].split(",")
|
||||
for s in styles:
|
||||
m = re.search(r"^\s*(\d+)\s*$", s)
|
||||
if not m:
|
||||
perr(1, 5, 'not integer')
|
||||
return 0
|
||||
s = int(m.group(1))
|
||||
if s not in cs.styles:
|
||||
cs.styles.append(s)
|
||||
if cs.version >= 5:
|
||||
if len(fields) < 7:
|
||||
perr(1, msg='number of fields')
|
||||
return 0
|
||||
m = re.search(r"^(\d+)$", fields[6])
|
||||
if not m:
|
||||
perr(1, 6, 'not integer')
|
||||
return 0
|
||||
cs.year = int(m.group(1))
|
||||
if len(cs.ext) < 2 or cs.ext[0] != ".":
|
||||
perr(1, msg='invalid extention')
|
||||
return 0
|
||||
# line[1]: identifier/name
|
||||
if not line[1]:
|
||||
perr(2, msg='empty line')
|
||||
return 0
|
||||
cs.ident = line[1]
|
||||
m = re.search(r"^(.*;)?([^;]+)$", cs.ident)
|
||||
if not m:
|
||||
perr(2, msg='invalid format')
|
||||
return 0
|
||||
cs.name = m.group(2).strip()
|
||||
# line[2]: CARDW, CARDH, CARDD
|
||||
m = re.search(r"^(\d+)\s+(\d+)\s+(\d+)", line[2])
|
||||
if not m:
|
||||
perr(3, msg='invalid format')
|
||||
return 0
|
||||
cs.CARDW, cs.CARDH, cs.CARDD = \
|
||||
int(m.group(1)), int(m.group(2)), int(m.group(3))
|
||||
# line[3]: CARD_UP_YOFFSET, CARD_DOWN_YOFFSET,
|
||||
# SHADOW_XOFFSET, SHADOW_YOFFSET
|
||||
m = re.search(r"^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", line[3])
|
||||
if not m:
|
||||
perr(4, msg='invalid format')
|
||||
return 0
|
||||
cs.CARD_XOFFSET = int(m.group(1))
|
||||
cs.CARD_YOFFSET = int(m.group(2))
|
||||
cs.SHADOW_XOFFSET = int(m.group(3))
|
||||
cs.SHADOW_YOFFSET = int(m.group(4))
|
||||
# line[4]: default background
|
||||
back = line[4]
|
||||
if not back:
|
||||
perr(5, msg='empty line')
|
||||
return 0
|
||||
# line[5]: all available backgrounds
|
||||
cs.backnames = [f.strip() for f in line[5].split(';')]
|
||||
if back in cs.backnames:
|
||||
cs.backindex = cs.backnames.index(back)
|
||||
else:
|
||||
cs.backnames.insert(0, back)
|
||||
cs.backindex = 0
|
||||
cs = read_cardset_config(dirname, filename)
|
||||
# set offsets from options.cfg
|
||||
if cs.ident in self.opt.offsets:
|
||||
cs.CARD_XOFFSET, cs.CARD_YOFFSET = self.opt.offsets[cs.ident]
|
||||
# if cs.type != 1: print cs.type, cs.name
|
||||
return 1
|
||||
|
||||
if cs.CARDD > self.top.winfo_screendepth():
|
||||
return None
|
||||
return cs
|
||||
|
||||
def initCardsets(self):
|
||||
manager = self.cardset_manager
|
||||
|
@ -1232,9 +1122,8 @@ Please select a %(correct_type)s type cardset.
|
|||
# print '+', cs.name
|
||||
fnames[cs.name] = 1
|
||||
else:
|
||||
print_err('fail _readCardsetConfig: %s %s'
|
||||
% (d, f))
|
||||
pass
|
||||
print_err('failed to parse cardset file: %s'
|
||||
% f)
|
||||
except Exception:
|
||||
# traceback.print_exc()
|
||||
pass
|
||||
|
|
148
pysollib/cardsetparser.py
Normal file
148
pysollib/cardsetparser.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- mode: python; coding: utf-8; -*-
|
||||
# ---------------------------------------------------------------------------##
|
||||
#
|
||||
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
||||
# Copyright (C) 2003 Mt. Hood Playing Card Co.
|
||||
# Copyright (C) 2005-2009 Skomoroh
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# ---------------------------------------------------------------------------##
|
||||
|
||||
from pysollib.mfxutil import print_err
|
||||
from pysollib.resource import Cardset, CardsetConfig
|
||||
|
||||
|
||||
def _perr(line_no, field=None, msg=''):
|
||||
if field:
|
||||
print_err('cannot parse cardset config: line #%d, field #%d: %s'
|
||||
% (line_no, field, msg))
|
||||
else:
|
||||
print_err('cannot parse cardset config: line #%d: %s' % (line_no, msg))
|
||||
|
||||
|
||||
def read_cardset_config(dirname, filename):
|
||||
"""Parse a cardset config file and produce a Cardset object.
|
||||
|
||||
This function returns None if any errors occurred.
|
||||
"""
|
||||
with open(filename, "rt") as f:
|
||||
lines_list = f.readlines()
|
||||
lines_list = [line.strip() for line in lines_list]
|
||||
if not lines_list[0].startswith("PySol"):
|
||||
return None
|
||||
config = parse_cardset_config(lines_list)
|
||||
if not config:
|
||||
print_err('invalid cardset: %s' % filename)
|
||||
return None
|
||||
cs = Cardset()
|
||||
cs.dir = dirname
|
||||
cs.update(config.__dict__)
|
||||
return cs
|
||||
|
||||
|
||||
def parse_cardset_config(lines_list):
|
||||
cs = CardsetConfig()
|
||||
if len(lines_list) < 6:
|
||||
_perr(1, msg='not enough lines in file')
|
||||
return None
|
||||
# lines_list[0]: magic identifier, possible version information
|
||||
fields = [f.strip() for f in lines_list[0].split(';')]
|
||||
if len(fields) >= 2:
|
||||
try:
|
||||
cs.version = int(fields[1])
|
||||
except ValueError:
|
||||
# version 1 is implied
|
||||
cs.version = 1
|
||||
if cs.version >= 3:
|
||||
if len(fields) < 5:
|
||||
_perr(1, msg='not enough fields')
|
||||
return None
|
||||
cs.ext = fields[2]
|
||||
try:
|
||||
cs.type = int(fields[3])
|
||||
except ValueError:
|
||||
_perr(1, 3, 'not integer')
|
||||
return None
|
||||
try:
|
||||
cs.ncards = int(fields[4])
|
||||
except ValueError:
|
||||
_perr(1, 4, 'not integer')
|
||||
return None
|
||||
if cs.version >= 4:
|
||||
if len(fields) < 6:
|
||||
_perr(1, msg='not enough fields')
|
||||
return None
|
||||
try:
|
||||
styles = (int(s.strip()) for s in fields[5].split(","))
|
||||
cs.styles = list(set(styles))
|
||||
except ValueError:
|
||||
_perr(1, 5, 'not integer')
|
||||
return None
|
||||
if cs.version >= 5:
|
||||
if len(fields) < 7:
|
||||
_perr(1, msg='not enough fields')
|
||||
return None
|
||||
try:
|
||||
cs.year = int(fields[6])
|
||||
except ValueError:
|
||||
_perr(1, 6, 'not integer')
|
||||
return None
|
||||
if len(cs.ext) < 2 or cs.ext[0] != ".":
|
||||
_perr(1, msg='specifies an invalid file extension')
|
||||
return None
|
||||
# lines_list[1]: identifier/name
|
||||
if not lines_list[1]:
|
||||
_perr(2, msg='unexpected empty line')
|
||||
return None
|
||||
cs.ident = lines_list[1]
|
||||
split_ident = cs.ident.split(';')
|
||||
if len(split_ident) == 1:
|
||||
cs.name = cs.ident
|
||||
elif len(split_ident) == 2:
|
||||
cs.name = split_ident[1].strip()
|
||||
else:
|
||||
_perr(2, msg='invalid format')
|
||||
return None
|
||||
# lines_list[2]: CARDW, CARDH, CARDD
|
||||
try:
|
||||
cs.CARDW, cs.CARDH, cs.CARDD = (int(x) for x in lines_list[2].split())
|
||||
except ValueError:
|
||||
_perr(3, msg='invalid format')
|
||||
return None
|
||||
# lines_list[3]: CARD_UP_YOFFSET, CARD_DOWN_YOFFSET,
|
||||
# SHADOW_XOFFSET, SHADOW_YOFFSET
|
||||
try:
|
||||
(cs.CARD_XOFFSET, cs.CARD_YOFFSET,
|
||||
cs.SHADOW_XOFFSET, cs.SHADOW_YOFFSET) = \
|
||||
(int(x) for x in lines_list[3].split())
|
||||
except ValueError:
|
||||
_perr(4, msg='invalid format')
|
||||
return None
|
||||
# lines_list[4]: default background
|
||||
back = lines_list[4]
|
||||
if not back:
|
||||
_perr(5, msg='unexpected empty line')
|
||||
return None
|
||||
# lines_list[5]: all available backgrounds
|
||||
cs.backnames = [f.strip() for f in lines_list[5].split(';')]
|
||||
if back in cs.backnames:
|
||||
cs.backindex = cs.backnames.index(back)
|
||||
else:
|
||||
cs.backnames.insert(0, back)
|
||||
cs.backindex = 0
|
||||
|
||||
# if cs.type != 1: print cs.type, cs.name
|
||||
return cs
|
|
@ -498,19 +498,15 @@ def test(args=None):
|
|||
fn = 'test.html'
|
||||
|
||||
if fn == '-':
|
||||
f = sys.stdin
|
||||
data = sys.stdin.read()
|
||||
else:
|
||||
try:
|
||||
f = open(fn, 'r')
|
||||
with open(fn, 'rt') as fh:
|
||||
data = fh.read()
|
||||
except IOError as msg:
|
||||
print(fn, ":", msg)
|
||||
sys.exit(1)
|
||||
|
||||
data = f.read()
|
||||
|
||||
if f is not sys.stdin:
|
||||
f.close()
|
||||
|
||||
if silent:
|
||||
f = formatter.NullFormatter()
|
||||
else:
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
import os
|
||||
|
||||
from pysollib.mfxutil import Image, ImageTk, USE_PIL
|
||||
from pysollib.mfxutil import Image, ImageTk, USE_PIL, print_err
|
||||
from pysollib.pysoltk import copyImage, createBottom, createImage, loadImage
|
||||
from pysollib.pysoltk import shadowImage
|
||||
from pysollib.resource import CSI
|
||||
|
@ -80,7 +80,7 @@ class Images:
|
|||
# print '__loadCard:', filename
|
||||
f = os.path.join(self.cs.dir, filename)
|
||||
if not os.path.exists(f):
|
||||
print('card image path %s does not exist' % (f))
|
||||
print_err('card image path %s does not exist' % f)
|
||||
return None
|
||||
try:
|
||||
img = loadImage(file=f)
|
||||
|
@ -180,7 +180,12 @@ class Images:
|
|||
for name in self.cs.backnames:
|
||||
if name:
|
||||
im = self.__loadCard(name)
|
||||
self.__addBack(im, name)
|
||||
if im:
|
||||
self.__addBack(im, name)
|
||||
else:
|
||||
print_err('in {cs_dir}/config.txt: card back "{fname}" '
|
||||
'does not exist'.format(
|
||||
cs_dir=self.cs.dir, fname=name))
|
||||
if progress:
|
||||
progress.update(step=1)
|
||||
# load bottoms
|
||||
|
|
|
@ -106,11 +106,6 @@ def init():
|
|||
sys.exit("%s needs Tcl/Tk 8.4 or better (you have %s)" %
|
||||
(pysollib.settings.TITLE, str(tkinter.TkVersion)))
|
||||
pysollib.settings.WIN_SYSTEM = root.tk.call('tk', 'windowingsystem')
|
||||
if pysollib.settings.WIN_SYSTEM == 'aqua':
|
||||
# TkAqua displays the console automatically in application
|
||||
# bundles, so we hide it here.
|
||||
from pysollib.macosx.appSupport import hideTkConsole
|
||||
hideTkConsole(root)
|
||||
#
|
||||
if pysollib.settings.USE_TILE == 'auto':
|
||||
# check Tile
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- mode: python; coding: utf-8; -*-
|
||||
# ---------------------------------------------------------------------------##
|
||||
#
|
||||
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
|
||||
# Copyright (C) 2003 Mt. Hood Playing Card Co.
|
||||
# Copyright (C) 2005-2009 Skomoroh
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# ---------------------------------------------------------------------------##
|
||||
"""
|
||||
A number of function that enhance PySol on MacOSX when it used as a normal
|
||||
GUI application (as opposed to an X11 application).
|
||||
"""
|
||||
import sys
|
||||
|
||||
from six.moves.tkinter import TclError
|
||||
|
||||
|
||||
def runningAsOSXApp():
|
||||
""" Returns True if-and-only-if running from the
|
||||
PySol.app bundle on OSX """
|
||||
return (sys.platform == 'darwin' and 'PySol.app' in sys.argv[0])
|
||||
|
||||
|
||||
def hideTkConsole(root):
|
||||
try:
|
||||
root.tk.call('console', 'hide')
|
||||
except TclError:
|
||||
pass
|
||||
|
||||
|
||||
def setupApp(app):
|
||||
"""
|
||||
Perform setup for the OSX application bundle.
|
||||
"""
|
||||
if not runningAsOSXApp():
|
||||
return
|
||||
hideTkConsole(app.top)
|
|
@ -285,30 +285,23 @@ class KwStruct:
|
|||
# ************************************************************************
|
||||
|
||||
def pickle(obj, filename, protocol=0):
|
||||
f = None
|
||||
try:
|
||||
f = open(filename, "wb")
|
||||
Pickler(f, protocol).dump(obj)
|
||||
f.close()
|
||||
f = None
|
||||
with open(filename, "wb") as fh:
|
||||
Pickler(fh, protocol).dump(obj)
|
||||
# print "Pickled", filename
|
||||
finally:
|
||||
if f:
|
||||
f.close()
|
||||
pass
|
||||
|
||||
|
||||
def unpickle(filename):
|
||||
f, obj = None, None
|
||||
obj = None
|
||||
try:
|
||||
f = open(filename, "rb")
|
||||
x = Unpickler(f).load()
|
||||
f.close()
|
||||
f = None
|
||||
with open(filename, "rb") as fh:
|
||||
x = Unpickler(fh).load()
|
||||
obj = x
|
||||
# print "Unpickled", filename
|
||||
finally:
|
||||
if f:
|
||||
f.close()
|
||||
pass
|
||||
return obj
|
||||
|
||||
|
||||
|
|
|
@ -524,9 +524,10 @@ class CardsetInfoDialog(MfxDialog):
|
|||
frame.rowconfigure(1, weight=1)
|
||||
#
|
||||
text = ''
|
||||
f = os.path.join(cardset.dir, "COPYRIGHT")
|
||||
fn = os.path.join(cardset.dir, "COPYRIGHT")
|
||||
try:
|
||||
text = open(f).read()
|
||||
with open(fn, "rt") as fh:
|
||||
text = fh.read()
|
||||
except Exception:
|
||||
pass
|
||||
if text:
|
||||
|
|
|
@ -487,9 +487,10 @@ class CardsetInfoDialog(MfxDialog):
|
|||
frame.rowconfigure(1, weight=1)
|
||||
#
|
||||
text = ''
|
||||
f = os.path.join(cardset.dir, "COPYRIGHT")
|
||||
fn = os.path.join(cardset.dir, "COPYRIGHT")
|
||||
try:
|
||||
text = open(f).read()
|
||||
with open(fn, "rt") as fh:
|
||||
text = fh.read()
|
||||
except Exception:
|
||||
pass
|
||||
if text:
|
||||
|
|
|
@ -295,7 +295,8 @@ class Base_HTMLViewer:
|
|||
import codecs
|
||||
return codecs.open(url, encoding='utf-8')
|
||||
else:
|
||||
return open(url, "rb")
|
||||
with open(url, "rb") as fh:
|
||||
return fh
|
||||
return my_open(url), url
|
||||
|
||||
def display(self, url, add=1, relpath=1, xview=0, yview=0):
|
||||
|
|
|
@ -21,22 +21,11 @@
|
|||
#
|
||||
# ---------------------------------------------------------------------------##
|
||||
|
||||
from pysollib.macosx.appSupport import hideTkConsole
|
||||
from pysollib.settings import TOOLKIT, USE_TILE
|
||||
from pysollib.winsystems.common import BaseTkSettings, base_init_root_window
|
||||
|
||||
|
||||
def init_root_window(root, app):
|
||||
base_init_root_window(root, app)
|
||||
if TOOLKIT == 'tk':
|
||||
hideTkConsole(root)
|
||||
if TOOLKIT == 'gtk':
|
||||
pass
|
||||
elif USE_TILE:
|
||||
pass
|
||||
else: # pure Tk
|
||||
# root.option_add(...)
|
||||
pass
|
||||
|
||||
|
||||
class TkSettings(BaseTkSettings):
|
||||
|
|
|
@ -106,16 +106,10 @@ def base_init_root_window(root, app):
|
|||
else:
|
||||
root.wm_minsize(520, 360)
|
||||
|
||||
if TOOLKIT == 'gtk':
|
||||
pass
|
||||
if TOOLKIT == 'kivy':
|
||||
pass
|
||||
elif USE_TILE:
|
||||
if TOOLKIT == 'tk' and USE_TILE:
|
||||
theme = app.opt.tile_theme
|
||||
init_tile(app, root)
|
||||
set_theme(app, root, theme)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
class BaseTkSettings:
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
rem simple script for building windows package
|
||||
|
||||
cd ..
|
||||
rm -rf dist
|
||||
mkdir dist
|
||||
cp -r locale dist
|
||||
cp -r freecell-solver dist
|
||||
python setup.py py2exe
|
||||
cp -r d:\Python\tcl\tile0.7.8 dist\tcl
|
||||
cp -r data\music dist\data
|
||||
python scripts\create_iss.py
|
||||
"d:\Program Files\Inno Setup 5\ISCC.exe" setup.iss
|
||||
pause
|
|
@ -14,7 +14,7 @@ prog_name = 'PySol Fan Club edition'
|
|||
|
||||
dirs_list = []
|
||||
files_list = []
|
||||
for root, dirs, files in os.walk('dist'):
|
||||
for root, dirs, files in os.walk(os.path.join('dist', 'pysol')):
|
||||
if files:
|
||||
files_list.append(root)
|
||||
dirs_list.append(root)
|
||||
|
@ -32,7 +32,7 @@ DefaultGroupName=%(prog_name)s
|
|||
UninstallDisplayIcon={app}\\pysol.exe
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
SourceDir=dist
|
||||
SourceDir=dist\\pysol
|
||||
OutputDir=.
|
||||
OutputBaseFilename=PySolFC_%(prog_version)s_setup
|
||||
DisableWelcomePage=no
|
||||
|
@ -47,16 +47,17 @@ Name: "{userdesktop}\\%(prog_name)s"; Filename: "{app}\\pysol.exe"
|
|||
|
||||
print('[Dirs]', file=out)
|
||||
for d in dirs_list[1:]:
|
||||
print('Name: "{app}%s"' % d.replace('dist', ''), file=out)
|
||||
print('Name: "{app}%s"' % d.replace(os.path.join('dist', 'pysol'), ''),
|
||||
file=out)
|
||||
|
||||
print(file=out)
|
||||
print('[Files]', file=out)
|
||||
print('Source: "*"; DestDir: "{app}"', file=out)
|
||||
for d in files_list[1:]:
|
||||
d = d.replace('dist\\', '')
|
||||
d = d.replace(os.path.join('dist', 'pysol', ''), '')
|
||||
print('Source: "%s\\*"; DestDir: "{app}\\%s"' % (d, d), file=out)
|
||||
|
||||
print('Source: "..\\vcredist_x86.exe"; DestDir: {tmp}; \
|
||||
print('Source: "..\\..\\vcredist_x86.exe"; DestDir: {tmp}; \
|
||||
Flags: deleteafterinstall', file=out)
|
||||
print('[Run]\n\
|
||||
Filename: {tmp}\\vcredist_x86.exe; \
|
||||
|
|
|
@ -44,6 +44,7 @@ print('ok 1 - imported')
|
|||
for ver in PY_VERS:
|
||||
for mod in [
|
||||
'pysol_tests.acard_unit',
|
||||
'pysol_tests.cardsetparser',
|
||||
'pysol_tests.game_drag',
|
||||
'pysol_tests.hint',
|
||||
'pysol_tests.import_file1',
|
||||
|
|
6
setup.py
6
setup.py
|
@ -8,9 +8,6 @@ from pysollib.settings import VERSION
|
|||
|
||||
from setuptools import setup
|
||||
|
||||
if os.name == 'nt':
|
||||
import py2exe # noqa: F401
|
||||
|
||||
|
||||
def get_data_files(source, destination):
|
||||
"""Iterates over all files under the given tree, to install them to the
|
||||
|
@ -86,7 +83,6 @@ kw = {
|
|||
'license': 'GPL',
|
||||
'scripts': ['pysol.py'],
|
||||
'packages': ['pysollib',
|
||||
'pysollib.macosx',
|
||||
'pysollib.winsystems',
|
||||
'pysollib.tk',
|
||||
'pysollib.tile',
|
||||
|
@ -103,8 +99,6 @@ kw = {
|
|||
}
|
||||
|
||||
if os.name == 'nt':
|
||||
kw['windows'] = [{'script': 'pysol.py',
|
||||
'icon_resources': [(1, 'data/pysol.ico')], }]
|
||||
kw['packages'].remove('pysollib.pysolgtk')
|
||||
|
||||
setup(**kw)
|
||||
|
|
|
@ -56,7 +56,8 @@ DATA_FILES = ['docs', 'data', 'locale', 'scripts', 'COPYING', 'README.md',
|
|||
] + SOLVER
|
||||
RESOURCES = []
|
||||
FRAMEWORKS = [SOLVER_LIB_PATH] if SOLVER_LIB_PATH else []
|
||||
OPTIONS = dict(argv_emulation=True,
|
||||
# with argv_emulation=True, the app window is not shown when launched
|
||||
OPTIONS = dict(argv_emulation=False,
|
||||
plist=PLIST,
|
||||
iconfile=ICON_FILE,
|
||||
resources=RESOURCES,
|
||||
|
|
62
tests/lib/pysol_tests/cardsetparser.py
Normal file
62
tests/lib/pysol_tests/cardsetparser.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
# Written by Juhani Numminen, under the MIT Expat License.
|
||||
|
||||
import unittest
|
||||
|
||||
from pysollib.cardsetparser import parse_cardset_config
|
||||
from pysollib.resource import CSI, CardsetConfig
|
||||
|
||||
|
||||
class MyTests(unittest.TestCase):
|
||||
|
||||
def _assertCcEqual(self, a, b, msg=None):
|
||||
"""Assert that CardsetConfig objects a and b have equal attributes."""
|
||||
return self.assertDictEqual(a.__dict__, b.__dict__, msg)
|
||||
|
||||
def test_good_cardset(self):
|
||||
config_txt = """\
|
||||
PySolFC solitaire cardset;4;.gif;1;52;7
|
||||
123-dondorf;Dondorf
|
||||
79 123 8
|
||||
16 25 7 7
|
||||
back01.gif
|
||||
back01.gif
|
||||
"""
|
||||
|
||||
reference = CardsetConfig()
|
||||
reference.update(dict(
|
||||
version=4,
|
||||
ext='.gif',
|
||||
type=CSI.TYPE_FRENCH,
|
||||
ncards=52,
|
||||
styles=[7],
|
||||
ident='123-dondorf;Dondorf',
|
||||
name='Dondorf',
|
||||
CARDW=79,
|
||||
CARDH=123,
|
||||
CARDD=8,
|
||||
CARD_XOFFSET=16,
|
||||
CARD_YOFFSET=25,
|
||||
SHADOW_XOFFSET=7,
|
||||
SHADOW_YOFFSET=7,
|
||||
backindex=0,
|
||||
backnames=['back01.gif'],
|
||||
))
|
||||
self._assertCcEqual(
|
||||
parse_cardset_config(config_txt.split('\n')),
|
||||
reference,
|
||||
'parse_cardset_config should parse well-formed v4 config.txt ' +
|
||||
'correctly')
|
||||
|
||||
def test_reject_too_few_fields(self):
|
||||
config_txt = """\
|
||||
PySolFC solitaire cardset;4;.gif;1;52
|
||||
123-dondorf;Dondorf
|
||||
79 123 8
|
||||
16 25 7 7
|
||||
back01.gif
|
||||
back01.gif
|
||||
"""
|
||||
self.assertIsNone(
|
||||
parse_cardset_config(config_txt.split('\n')),
|
||||
'parse_cardset_config should reject v4 config.txt with ' +
|
||||
'a missing field on the first line')
|
Loading…
Add table
Reference in a new issue