1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-15 02:54:09 -04:00

Compare commits

..

No commits in common. "2c16d5773dc5ee6ffb3c59bd175bc5da6b6f5dc0" and "78c7e333c4f52f49b93b88f4848388ba78689c6e" have entirely different histories.

105 changed files with 21318 additions and 22839 deletions

View file

@ -8,7 +8,15 @@ 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
- python3 -mpip install Pillow
- python3 -mpip install flake8
- python3 -mpip install flake8-import-order
- python3 -mpip install py2exe
- python3 -mpip install pycotap
- python3 -mpip install pygame
- python3 -mpip install pysol-cards
- python3 -mpip install random2
- python3 -mpip install 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%
@ -56,6 +64,6 @@ artifacts:
- path: dist\PySolFC_*_setup.exe
name: pysol_win_installer
cache:
# - C:\_P5 -> .appveyor.yml
# - C:\strawberry -> .appveyor.yml
- C:\_P5 -> .appveyor.yml
- C:\strawberry -> .appveyor.yml
shallow_clone: true

12
.gitignore vendored
View file

@ -1,7 +1,6 @@
*.pyc
/.tidyall.d/
/MANIFEST
/_Inline/
/build/*
/data/cardsets/*
/data/html/*
@ -11,16 +10,15 @@
/html-src/html/*
/images
/locale/*
/po/de.po
/po/it.po
/po/pl.po
/po/ru.po
/tests/individually-importing/*.py
/tests/unit-generated/*.py
PySolFC-Cardsets--Minimal-2.0.*
# output of min card actions
# mask out folder/archives
PySolFC-Cardsets--Minimal-2.0/
PySolFC-Cardsets-2.0.*
PySolFC-Cardsets--Minimal-2.0.*
PySolFC-Cardsets-2.0/
android/*.apk
android/*.zip
android/bin/keystore
PySolFC-Cardsets-2.0.*

View file

@ -1,4 +1,20 @@
addons:
apt:
packages:
- cpanminus
- libperl-dev
- make
- perl
- python-glade2
- python-gnome2
- python-gnome2-dev
- python-gtk2
- python-setuptools
- python-tk
- python3
- python3-pip
- python3-setuptools
- python3-tk
homebrew:
update: true
brewfile: true
@ -16,34 +32,32 @@ deploy:
repo: shlomif/PySolFC
tags: true
skip_cleanup: true
dist: bionic
dist: trusty
before_install:
- if test "$TRAVIS_OS_NAME" = "osx" ; then export CPPFLAGS="$CPPFLAGS -I$(brew --prefix openssl)/include" PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig:$PKG_CONFIG_PATH" LDFLAGS="$LDFLAGS -L$(brew --prefix openssl)/lib" ;fi
- if test "$TRAVIS_OS_NAME" = "osx" ; then wget --content-disposition https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/minimal/PySolFC-Cardsets--Minimal-2.0.tar.xz/download && tar xJf PySolFC-Cardsets--Minimal-2.0.tar.xz && mv PySolFC-Cardsets--Minimal-2.0/cardset-* data ; fi
install:
# Tests are failing for them sometimes
- sudo cpanm --notest Capture::Tiny IPC::System::Simple
- sudo cpanm --notest Capture::Tiny
- sudo cpanm Code::TidyAll::Plugin::Flake8 Perl::Tidy Test::Code::TidyAll Test::Differences Test::TrailingSpace
- export PY_MODS='attrs configobj pycotap pysol-cards random2 setuptools six'
- sudo pip3 install --upgrade $PY_MODS flake8 flake8-import-order
- sudo pip2 install --upgrade $PY_MODS
language: generic
- export PY_MODS='pycotap pysol-cards random2 six'
- "`which python3` -m pip install --upgrade flake8 flake8-import-order $PY_MODS"
- "sudo /usr/bin/python3 -m pip install --upgrade $PY_MODS || true"
- "sudo `which python2` -m pip install --upgrade $PY_MODS"
- which python
- which python2
language: python
python: "3.6"
matrix:
include:
- os: linux
before_install:
- sudo apt-get install -y
cpanminus
python-glade2
python-gnome2
python-gnome2-dev
python-gtk2
python-pip
python-setuptools
python-tk
python3-pip
python3-setuptools
python3-tk
- os: osx
language: generic
env:
- TOXENV=py35
- PATH="/usr/local/opt/openssl/bin:$PATH:/usr/local/bin"
- DYLD_LIBRARY_PATH="/usr/local/opt/curl/lib:/usr/local/opt/openssl/lib:${DYLD_LIBRARY_PATH}"
- LDFLAGS="$LDFLAGS -L/usr/local/opt/openssl/lib"
- CPPFLAGS="$CPPFLAGS -I/usr/local/opt/openssl/include"
script:
- export TIDYALL_DATA_DIR="$HOME/tidyall_d"
- bash -x scripts/travis-ci-build

View file

@ -12,7 +12,6 @@ for general guidelines for contributing to open source.
# How you can contribute
- Translate PySol to a human language you know.
- Test the "master" branch version of the version control repository or other prereleases.
- Try to reproduce [open issues](https://github.com/shlomif/PySolFC/issues)
- Try to fix bugs.
- Add new games.
@ -21,7 +20,6 @@ for general guidelines for contributing to open source.
- Add new features.
- Contribute graphics
- Improve the site
- Package PySol for a new package repository or OS, or update existing packages.
- Make a monetary donation.
- [Star](https://help.github.com/articles/about-stars/) or [Watch](https://help.github.com/articles/watching-and-unwatching-repositories/) the repository on GitHub

View file

@ -7,10 +7,9 @@ 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 pysollib/macosx/*.py pysollib/configobj/*.py
include pysollib/winsystems/*.py
include pysollib/tk/*.py pysollib/tile/*.py pysollib/pysolgtk/*.py
include pysollib/game/*.py
include pysollib/games/*.py pysollib/games/special/*.py
include pysollib/games/ultra/*.py pysollib/games/mahjongg/*.py
include data/tcl/*.tcl
@ -19,8 +18,8 @@ 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/all_games.py scripts/cardset_viewer.py
include scripts/cardconv
include scripts/pygettext.py scripts/all_games.py scripts/cardset_viewer.py
include scripts/cardconv scripts/cardsetsgiftobmp
include scripts/gen_individual_importing_tests.py
include tests/individually-importing/PLACEHOLDER
recursive-include tests/lib *.pm *.py
@ -30,8 +29,6 @@ include tests/unit-generated/PLACEHOLDER
include .tidyallrc
include android/*.py
include android/mk*
include android/initsdk
include android/initsupport
include android/debian/*
#graft data/plugins
##

View file

@ -1,73 +1,82 @@
# Makefile for PySolFC
ifeq ($(OS),Windows_NT)
path_sep = ;
else
path_sep = :
endif
export PYTHONPATH := $(PYTHONPATH)$(path_sep)$(CURDIR)
override LANG=C
override PYSOL_DEBUG=1
.PHONY: all install dist rpm all_games_html rules pot mo pretest test runtest
PYSOLLIB_FILES=pysollib/tk/*.py pysollib/tile/*.py pysollib/*.py \
pysollib/games/*.py pysollib/games/special/*.py \
pysollib/games/ultra/*.py pysollib/games/mahjongg/*.py \
pysollib/kivy/*.py
.PHONY : all install dist all_games_html rules pot mo
all:
@echo "No default target"
install:
python3 setup.py install
python setup.py install
dist: all_games_html rules mo
python3 setup.py sdist
rpm: all_games_html rules mo
python3 setup.py bdist_rpm
python setup.py bdist_rpm
DOCS_DIR = docs
HTML_DIR = data/html
ALL_GAMES_HTML_BASE = all_games.html
ALL_GAMES_HTML = $(HTML_DIR)/$(ALL_GAMES_HTML_BASE)
ALL_GAMES_HTML__FOR_WEBSITE = $(DOCS_DIR)/$(ALL_GAMES_HTML_BASE)
all_games_html: $(ALL_GAMES_HTML)
$(ALL_GAMES_HTML) $(ALL_GAMES_HTML__FOR_WEBSITE): rules
cd $(HTML_DIR) && $(CURDIR)/scripts/all_games.py html id rules > $(ALL_GAMES_HTML_BASE)
./scripts/all_games.py html id doc/rules bare > $(ALL_GAMES_HTML__FOR_WEBSITE)
all_games_html:
PYTHONPATH=`pwd` ./scripts/all_games.py html id doc/rules bare > docs/all_games.html
rules:
cd html-src && ./gen-html.py
export PYTHONPATH=`pwd`; (cd html-src && ./gen-html.py)
cp -r html-src/images html-src/html
rm -rf data/html
mv html-src/html data
pot:
./scripts/all_games.py gettext > po/games.pot
xgettext --keyword=n_ --add-comments=TRANSLATORS: -o po/pysol.pot \
pysollib/*.py pysollib/*/*.py pysollib/*/*/*.py data/pysolfc.glade
set -e; \
for lng in ru de pl it; do \
msgmerge --update --quiet --backup=none po/$${lng}_pysol.po po/pysol.pot; \
msgmerge --update --quiet --backup=none po/$${lng}_games.po po/games.pot; \
PYTHONPATH=`pwd` ./scripts/all_games.py gettext > po/games.pot
PYTHONPATH=`pwd` ./scripts/pygettext.py -k n_ --ngettext-keyword ungettext -o po/pysol-1.pot $(PYSOLLIB_FILES)
xgettext -L C --keyword=N_ -o po/pysol-2.pot data/glade-translations
msgcat po/pysol-1.pot po/pysol-2.pot > po/pysol.pot
rm -f po/pysol-1.pot po/pysol-2.pot
for lng in ru pl; do \
mv -f po/$${lng}_pysol.po po/$${lng}_pysol.old.po; \
msgmerge po/$${lng}_pysol.old.po po/pysol.pot > po/$${lng}_pysol.po; \
rm -f po/$${lng}_pysol.old.po; \
mv -f po/$${lng}_games.po po/$${lng}_games.old.po; \
msgmerge po/$${lng}_games.old.po po/games.pot > po/$${lng}_games.po; \
rm -f po/$${lng}_games.old.po; \
done
mo:
set -e; \
for lang in ru de pl it; do \
mkdir -p locale/$${lang}/LC_MESSAGES; \
msgcat --use-first po/$${lang}_games.po po/$${lang}_pysol.po > po/$${lang}.po; \
msgfmt --check -o locale/$${lang}/LC_MESSAGES/pysol.mo po/$${lang}.po; \
for loc in ru ru_RU de de_AT de_BE de_DE de_LU de_CH pl pl_PL it it_IT; do \
test -d locale/$${loc}/LC_MESSAGES || mkdir -p locale/$${loc}/LC_MESSAGES; \
done
for lang in ru pl it; do \
msgcat --use-first po/$${lang}_games.po po/$${lang}_pysol.po > po/$${lang}.po 2>/dev/null; \
done
for lang in ru de pl it; do \
msgfmt -o locale/$${lang}/LC_MESSAGES/pysol.mo po/$${lang}.po; \
done
cp -f locale/ru/LC_MESSAGES/pysol.mo locale/ru_RU/LC_MESSAGES/pysol.mo
for dir in de_AT de_BE de_DE de_LU de_CH; do \
cp -f locale/de/LC_MESSAGES/pysol.mo locale/$${dir}/LC_MESSAGES/pysol.mo; \
done
cp -f locale/pl/LC_MESSAGES/pysol.mo locale/pl_PL/LC_MESSAGES/pysol.mo
cp -f locale/it/LC_MESSAGES/pysol.mo locale/it_IT/LC_MESSAGES/pysol.mo
pretest:
rm -f tests/individually-importing/*.py tests/unit-generated/*.py # To avoid stray files
@rm -f tests/individually-importing/*.py # To avoid stray files
python3 scripts/gen_individual_importing_tests.py
TEST_ENV_PATH = $(CURDIR)$(path_sep)$(CURDIR)/tests/lib
TEST_ENV_PATH = "`pwd`:`pwd`/tests/lib"
TEST_ENV = PYTHONPATH="$$PYTHONPATH:"$(TEST_ENV_PATH) PERL5LIB="$$PERL5LIB:"$(TEST_ENV_PATH)
TEST_FILES = tests/style/*.t tests/unit-generated/*.py tests/individually-importing/*.py
test runtest: export PYTHONPATH := $(PYTHONPATH)$(path_sep)$(TEST_ENV_PATH)
test runtest: export PERL5LIB := $(PERL5LIB)$(path_sep)$(TEST_ENV_PATH)
define RUN_TESTS
$(TEST_ENV) $1 $(TEST_FILES)
endef
test: pretest
prove $(TEST_FILES)
$(call RUN_TESTS,prove)
runtest: pretest
runprove $(TEST_FILES)
$(call RUN_TESTS,runprove)

View file

@ -45,15 +45,14 @@ Prerequisites (needs root):
Build with 'python-for-android' (as user):
Use the cloned repo or an unpacked distribution tarball.
go to the android directory, then
$ ./mkp4a.init # prepare sdk and p4a installation
$ ./mkp4a.init [<sdkdir>] [<ndkdir>] # prepare sdk and p4a installation
$ ./mkkeystore # if you want to build a release version.
$ ./mkp4a.debug # build debug apk
$ ./mkp4a.release <passwd1> [<passwd2>] # build release apk
$ ./mkp4a.unsigned # build an unsigned release apk
The build system will download all required additional
packages (such as the android sdk and more). Do the first build will
@ -69,22 +68,11 @@ Build with 'python-for-android' (as user):
Cardsets:
The Apk includes a minimal set of cards for playing.
Additional cardsets can be installed in ${HOME}/.PySolFC/cardsets/.
On an android device this is equivalent to /sdcard/.PySolFC/cardsets/.
Cardsets must use the bmp image format. Use scripts/cardconv
Cardsets should be installed in ${HOME}/.PySolFC/cardsets/. On an
android device this is equivalent to /sdcard/.PySolFC/cardsets/.
Cardsets must use the bmp image format. Use scripts/cardsetsgiftobmp
(on a linux system) to convert them, before copying to the device.
Important Notice on python3/kivy 1.11.x (pysol verson 2.6.4 ff):
In kivy, using python3, the support for bmp images depends on OpenGL.
On fairly up to date Android OpenGL ES 3.x is available. ES (Embedded
System) release is a subset of the full OpenGL. Due to this, bmp image
support will be broken on android, but not on up to date workstations.
As gif images are still slow and error prone, the best we can do is to
use png images instead of bmp (as noted above).
Possible known build issues:
2) for android ndk: needs a Version <=13 (because needs ant support).

View file

@ -39,7 +39,7 @@ kivy version.
Additional cardsets are available from the SourceForge
project. To use them with kivy, they need to be converted to
the BMP format. A shell script, 'cardconv' , has been added
the BMP format. A shell script, 'cardsetsgiftobmp' , has been added
to the scripts directory (it requires Bash and ImageMagick).
For all GIF images in the directories data/images and data/tiles ,

View file

@ -96,14 +96,13 @@ per the instructions above.
At the moment, this only works on POSIX (Linux, FreeBSD and similar) systems.
Windows and Mac users - you'll need to chip in with a script for your system.
#### 1 - Install build prerequisites: six, random2 and pysol-cards
#### 1 - Install build prerequisites: six and random2
This is kind of stupid and maybe it can be fixed in the future, but for now:
```
pip install six
pip install random2
pip install pysol-cards
```
You may want to use your OS distribution package system instead, for example:
@ -113,12 +112,6 @@ sudo apt-get install python-six
sudo apt-get install python-random2
```
For Pillow compilation, libjpeg headers and libraries need to be available:
```
sudo apt-get install libjpeg-dev
```
#### 2 - Clone the source from version control
```
@ -129,10 +122,10 @@ cd PySolFC
#### 3 - Create your virtual environment.
```
PKGTREE=/usr/local/packages/PySolFC # or whatever
export PKGTREE
mkdir -p "$PKGTREE"
( cd "$PKGTREE" && python -m venv ./env )
PKGDIR=/usr/local/packages/PySolFC # or whatever
export PKGDIR
mkdir -p "$PKGDIR"
( cd "$PKGDIR" && python -m venv ./env )
```
#### 4 - Run the install script
@ -146,11 +139,12 @@ mkdir -p "$PKGTREE"
#### 6 - Enjoy playing
```
"$PKGTREE"/env/bin/pysol.py
"$PKGDIR"/env/bin/pysol.py
```
## Alternate toolkit.
- Python2 (2.7 or later)
- Kivy (10.0 or later)
- Features:
@ -160,7 +154,7 @@ mkdir -p "$PKGTREE"
- Running from source without installation:
```
python pysol.py --kivy
python2 pysol.py --kivy
```
### Configuring Freecell Solver

View file

@ -10,6 +10,9 @@ root$ ./apt-install.sh
root$ exit
user$ ./pip-install.sh
- .....some output.
Now all required packages are installed to proceed with the
android build.

View file

@ -1,20 +1,12 @@
#!/bin/sh
set -e
#!/bin/bash
# als root ausführen!
# install as root
apt-get install -y \
git \
openjdk-8-jdk \
cython3 \
python3-pip \
python3-yaml \
virtualenv \
pkg-config \
automake autoconf libtool \
zlib1g-dev \
libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \
libtinfo5 \
lld
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
apt-get install -y mercurial git default-jdk
apt-get install -y cython cython3
apt-get install -y python3-pip
apt-get install -y python3-yaml
apt-get install -y virtualenv
apt-get install -y pkg-config
apt-get install -y automake autoconf libtool
apt-get install -y zlib1g-dev
apt-get install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev

8
android/debian/pip-installs.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
# als user installieren !
python3 -m pip install --user pyasn1
python3 -m pip install --user pyasn1_modules
python3 -m pip install --user requests
python3 -m pip install --user clint

View file

@ -1,26 +0,0 @@
#!/bin/bash
set -eux
# This script mimics the instructions laid out in the p4a documentation:
# https://python-for-android.readthedocs.io/en/latest/quickstart/
. mkp4a.common
if [[ -d $sdkdir && -d $ndkdir ]]; then
echo "Skipping SDK and NDK installation: SDK and NDK directories already exist."
exit
fi
urlbase=https://dl.google.com/android/repository/
tools_zip=sdk-tools-linux-4333796.zip
ndk_zip=android-ndk-r17c-linux-x86_64.zip
mkdir -p $sdkdir $ndkdir
[ -a $ndk_zip ] || wget $urlbase/$ndk_zip
unzip -d $(dirname $ndkdir) $ndk_zip
[ -a $tools_zip ] || wget $urlbase/$tools_zip
unzip -d $sdkdir $tools_zip
$sdkdir/tools/bin/sdkmanager 'platforms;android-27'
$sdkdir/tools/bin/sdkmanager 'build-tools;29.0.1'

243
android/initsdk.py Executable file
View file

@ -0,0 +1,243 @@
#! /usr/bin/env python3
# -*- coding: iso-8859-1 -*-
import glob
import hashlib
import logging
import os
import sys
from zipfile import ZipFile, ZipInfo
from clint.textui import progress
import requests
cachefiles = [
('https://dl.google.com/android/repository/platform-tools-latest-linux.zip',
'',
'platform-tools'),
('https://dl.google.com/android/repository/tools_r25.2.5-linux.zip',
'577516819c8b5fae680f049d39014ff1ba4af870b687cab10595783e6f22d33e',
'tools'),
('https://dl.google.com/android/repository/android-19_r04.zip',
'5efc3a3a682c1d49128daddb6716c433edf16e63349f32959b6207524ac04039',
'platform'),
('https://dl.google.com/android/repository/build-tools_r26-linux.zip',
'7422682f92fb471d4aad4c053c9982a9a623377f9d5e4de7a73cd44ebf2f3c61',
'build-tools'),
('https://dl.google.com/'
'android/repository/android-ndk-r12b-linux-x86_64.zip',
'eafae2d614e5475a3bcfd7c5f201db5b963cc1290ee3e8ae791ff0c66757781e',
'ndk'),
]
# https://stackoverflow.com/questions/39296101:
class MyZipFile(ZipFile):
def extract(self, member, path=None, pwd=None):
if not isinstance(member, ZipInfo):
member = self.getinfo(member)
if path is None:
path = os.getcwd()
ret_val = self._extract_member(member, path, pwd)
attr = member.external_attr >> 16
os.chmod(ret_val, attr)
return ret_val
# Reused from fdroidserver:
def sha256_for_file(path):
with open(path, 'rb') as f:
s = hashlib.sha256()
while True:
data = f.read(4096)
if not data:
break
s.update(data)
return s.hexdigest()
# Adapted from fdroidserver:
def update_cache(cachedir, cachefiles):
for srcurl, shasum, typ in cachefiles:
filename = os.path.basename(srcurl)
local_filename = os.path.join(cachedir, filename)
if os.path.exists(local_filename):
local_length = os.path.getsize(local_filename)
else:
local_length = -1
if (typ == 'ndk') and (ndkloc is not None):
continue
elif (typ != 'tools') and (sdkloc is not None):
continue
resume_header = {}
download = True
try:
r = requests.head(srcurl, allow_redirects=True, timeout=60)
if r.status_code == 200:
content_length = int(r.headers.get('content-length'))
else:
content_length = local_length # skip the download
except requests.exceptions.RequestException as e:
content_length = local_length # skip the download
logger.warn('%s', e)
if local_length == content_length:
download = False
elif local_length > content_length:
logger.info('deleting corrupt file from cache: %s',
local_filename)
os.remove(local_filename)
logger.info("Downloading %s to cache", filename)
elif local_length > -1 and local_length < content_length:
logger.info("Resuming download of %s", local_filename)
resume_header = {
'Range': 'bytes=%d-%d' % (local_length, content_length)}
else:
logger.info("Downloading %s to cache", filename)
if download:
r = requests.get(srcurl, headers=resume_header,
stream=True, verify=False, allow_redirects=True)
content_length = int(r.headers.get('content-length'))
with open(local_filename, 'ab') as f:
for chunk in progress.bar(
r.iter_content(chunk_size=65536),
expected_size=(content_length / 65536) + 1):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
if not shasum == '':
v = sha256_for_file(local_filename)
if v == shasum:
logger.info("Shasum verified for %s", local_filename)
else:
logger.critical(
"Invalid shasum of '%s' detected for %s", v, local_filename)
os.remove(local_filename)
sys.exit(1)
# Build the sdk from zips.
def build_sdk(sdkdir, cachedir, cachfiles):
for srcurl, shasum, typ in cachefiles:
filename = os.path.basename(srcurl)
local_filename = os.path.join(cachedir, filename)
if typ == 'tools':
if os.path.exists(local_filename):
print('Extract: %s' % local_filename)
zf = MyZipFile(local_filename)
zf.extractall(sdkdir)
elif typ == 'platform-tools':
if (sdkloc is None) and (os.path.exists(local_filename)):
print('Extract: %s' % local_filename)
zf = MyZipFile(local_filename)
zf.extractall(sdkdir)
else:
print('Link to: %s' % sdkloc)
os.symlink(sdkloc + '/platform-tools',
sdkdir + '/platform-tools')
elif typ == 'platform':
if (sdkloc is None) and (os.path.exists(local_filename)):
print('Extract: %s' % local_filename)
zf = MyZipFile(local_filename)
zf.extractall(sdkdir + '/platforms')
else:
print('Link to: %s' % sdkloc)
os.symlink(sdkloc + '/platforms', sdkdir + '/platforms')
elif typ == 'build-tools':
if (sdkloc is None) and (os.path.exists(local_filename)):
print('Extract: %s' % local_filename)
zf = MyZipFile(local_filename)
zf.extractall(sdkdir + '/build-tools')
else:
print('Link to: %s' % sdkloc)
os.symlink(sdkloc + '/build-tools', sdkdir + '/build-tools')
elif typ == 'ndk':
if ndkloc is None:
print('Extract: %s' % local_filename)
zf = MyZipFile(local_filename)
zf.extractall(sdkdir)
lst = glob.glob(sdkdir + '/*-ndk-*')
print(lst)
os.rename(lst[0], sdkdir + '/ndk-bundle')
else:
print('Link to: %s' % ndkloc)
os.symlink(ndkloc, sdkdir + '/ndk-bundle')
logger = logging.getLogger('prepare-fdroid-build')
logging.basicConfig(format='%(message)s', level=logging.INFO)
logger.setLevel(logging.INFO)
# command line arguments
sdkloc = None
ndkloc = None
if len(sys.argv) > 1:
sdkloc = sys.argv[1]
if (len(sdkloc) > 0) and (sdkloc[-1] == '/'):
sdkloc = sdkloc[:-1]
if not os.path.isdir(sdkloc):
sdkloc = None
if len(sys.argv) > 2:
ndkloc = sys.argv[2]
if (len(ndkloc) > 0) and (ndkloc[-1] == '/'):
ndkloc = ndkloc[:-1]
if not os.path.isdir(ndkloc):
ndkloc = None
fdroidmode = None
if len(sys.argv) > 3:
fdroidmode = sys.argv[3]
if (len(fdroidmode) > 0):
fdroidmode = '1'
if sdkloc == "":
sdkloc = None
if ndkloc == "":
ndkloc = None
logger.info('sdkloc = %s' % sdkloc)
logger.info('ndkloc = %s' % ndkloc)
# sdkloc and ndkloc already set by the user and fdroidmode:
# nothing to do.
if (sdkloc is not None) and (ndkloc is not None) and (fdroidmode is not None):
sys.exit(0)
# cache dir (using the same as in fdroidserver/buildserver)
cachedir = os.path.join(os.getenv('HOME'), '.cache', 'fdroidserver')
logger.info('cachedir name is: %s', cachedir)
if not os.path.exists(cachedir):
os.makedirs(cachedir, 0o755)
logger.info('created cachedir %s', cachedir)
# sdkdir location
sdkdir = os.path.join(os.getenv('HOME'), '.cache', 'sdk-for-p4a')
logger.info('sdkdir name is: %s', sdkdir)
if not os.path.exists(sdkdir):
os.makedirs(sdkdir, 0o755)
logger.debug('created sdkdir %s', sdkdir)
update_cache(cachedir, cachefiles)
build_sdk(sdkdir, cachedir, cachefiles)
else:
logger.info('sdkdir %s already exists', sdkdir)

View file

@ -1,10 +0,0 @@
#!/bin/bash
set -eux
# Download android support library from maven
. mkp4a.common
liburl="https://maven.google.com/com/android/support/support-v4/24.1.1"
libname="support-v4-24.1.1.aar"
. mkp4a.preload supportlib ${liburl} ${libname}

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python2.7
# ---------------------------------------------------------------------------
#
# PySol -- a Python Solitaire game

View file

@ -1,27 +1,46 @@
#!/bin/bash
set -eux
. mkp4a.common
echo '### prepare cardsets'
if [ ! -f ${cardsets_file} ]; then
echo '### downloading cardsets'
wget https://netix.dl.sourceforge.net/project/pysolfc/PySolFC-Cardsets/minimal/${cardsets_file}
if [ ! -f ./PySolFC-Cardsets-2.0.tar.bz2 ]
then
echo '### downloading cardets'
# wget http://downloads.sourceforge.net/pysolfc/PySolFC-Cardsets-2.0.tar.bz2
wget https://netix.dl.sourceforge.net/project/pysolfc/PySolFC-Cardsets/PySolFC-Cardsets-2.0/PySolFC-Cardsets-2.0.tar.bz2
fi
if [ ! -d ${cardsets_dir} ]; then
echo '### extracting cardsets'
tar -xf ${cardsets_file}
fi
if [ -f ./PySolFC-Cardsets-2.0.tar.bz2 ]
then
if [ ! -d ./PySolFC-Cardsets-2.0 ]
then
echo '### extracting selected cardets'
tar -xjvf PySolFC-Cardsets-2.0.tar.bz2 \
PySolFC-Cardsets-2.0/cardset-crystal-mahjongg \
PySolFC-Cardsets-2.0/cardset-dashavatara-ganjifa \
PySolFC-Cardsets-2.0/cardset-dondorf \
PySolFC-Cardsets-2.0/cardset-hexadeck \
PySolFC-Cardsets-2.0/cardset-kintengu \
PySolFC-Cardsets-2.0/cardset-matrix \
PySolFC-Cardsets-2.0/cardset-mughal-ganjifa \
PySolFC-Cardsets-2.0/cardset-oxymoron \
PySolFC-Cardsets-2.0/cardset-standard \
PySolFC-Cardsets-2.0/cardset-vienna-2k \
PySolFC-Cardsets-2.0/cardset-greywyvern
fi
echo '### processing cardsets'
(
cd ${cardsets_dir}
../../scripts/cardconv gif png
for i in cardset-*-png; do
rm -rf `basename $i -png`
done
)
if [ -d ./PySolFC-Cardsets-2.0 ]
then
echo '### processing cardets'
cd PySolFC-Cardsets-2.0
../../scripts/cardsetsgiftobmp
for i in cardset-*-bmp
do
rm -rf `basename $i -bmp`
done
cd ..
fi
else
echo '### error downloading cardsets'
fi
echo '### end cardsets'

View file

@ -1,12 +1,16 @@
#!/bin/bash
set -eux
# memo:
# keytool -genkey -v -keystore my-release-keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 12000
mkdir -p bin
if [ ! -d bin ]
then
echo "mkdir bin"
mkdir bin
fi
if [ -f ./bin/keystore ]; then
if [ -f ./bin/keystore ]
then
echo "keystore is already defined"
else
keytool -genkey -v -keystore ./bin/keystore -alias python -keyalg RSA -keysize 2048 -validity 12000

View file

@ -1,8 +1,8 @@
#!/bin/bash
set -eux
rm -rf tmp
python3 -m pythonforandroid.toolchain clean_dists
python3 -m pythonforandroid.toolchain clean_builds
rm -f *.apk
rm -rf PySolFC-Cardsets--Minimal-2.0.1
rm -rf PySolFC-Cardsets-2.0

View file

@ -1,5 +1,4 @@
#!/bin/bash
set -e
rm -rf tmp
rm -f *.apk

View file

@ -1,33 +0,0 @@
# Common constants for various scripts in this directory.
version=$(PYTHONPATH=.. python3 -c \
'from pysollib.settings import VERSION; print(VERSION)')
tmpdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
cardsets_dir='PySolFC-Cardsets--Minimal-2.0.1'
cardsets_file="${cardsets_dir}.tar.xz"
sdkdir="${HOME}/.cache/sdk-for-p4a/sdk"
ndkdir="${HOME}/.cache/sdk-for-p4a/android-ndk-r17c"
pkgdir="${HOME}/.local/share/python-for-android/packages"
# gradle may need this.
export TERM="xterm"
p4a_options="\
--sdk-dir ${sdkdir} \
--ndk-dir ${ndkdir} \
--dist-name pysolfc \
--name PySolFC \
--package org.lufebe16.pysolfc \
--version ${version} \
--bootstrap sdl2 \
--requirements python3,attrs,configobj,kivy,pysol-cards,random2,six \
--private ${tmpdir} \
--orientation sensor \
--icon ${tmpdir}/data/images/icons/48x48/pysol.png \
--presplash ${tmpdir}/data/images/icons/1024x1024/pysol.png \
--copy-libs \
--add-jar ${tmpdir}/support-v4-24.1.1.aar \
--color always"

View file

@ -1,11 +1,32 @@
#!/bin/bash
set -eux
. mkp4a.common
package='org.lufebe16.pysolfc'
version=`./version.py`
name='PySolFC'
tmpdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
new_options=${p4a_options}
new_options=${new_options/PySolFC/PySolFCdbg}
new_options=${new_options/org.lufebe16.pysolfc/org.lufebe16.pysolfc.dbg}
if [ "$1" ]
then
package=${package}.dbg
name=${name}dbg
fi
python3 -m pythonforandroid.toolchain apk \
${new_options}
--sdk-dir ${HOME}/.cache/sdk-for-p4a \
--ndk-dir ${HOME}/.cache/sdk-for-p4a/ndk-bundle \
--android-api 19 \
--ndk-version r12b \
--arch armeabi-v7a \
--dist-name pysolfc \
--name ${name} \
--bootstrap=sdl2 \
--requirements kivy,hostpython2,random2 \
--minsdk 14 \
--private ${tmpdir} \
--package ${package} \
--version ${version} \
--orientation sensor \
--color=always \
--icon ${tmpdir}/data/images/misc/pysol01.png \
--presplash ${tmpdir}/data/images/misc/pysol06.png \
--copy-libs

View file

@ -1,62 +1,56 @@
#!/bin/bash
set -eux
. mkp4a.common
# NOTE: $1 will be set with fdroid builds only.
echo '### prepare sdk'
if [[ $# == 0 ]]
then
./initsupport
./initsdk
fi
./initsdk.py $1 $2 $3
echo '### install p4a'
if [[ $# == 0 ]]
p4adir=${HOME}/.cache/tmp-for-p4a
mkdir -p ${p4adir}
p4aversion='0.5.3'
if [ ! -f ${p4adir}/${p4aversion}.zip ]
then
python3 -m pip install -q --user python-for-android
wget "https://github.com/kivy/python-for-android/archive/${p4aversion}.zip"
cp -a ./${p4aversion}.zip ${p4adir}/${p4aversion}.zip
rm -f ./${p4aversion}.zip
fi
if [ -f ${p4adir}/${p4aversion}.zip ]
then
python3 -m pip install -q --user "${p4adir}/${p4aversion}.zip"
else
echo "### download of ${p4aversion}.zip failed"
fi
echo '### prepare source'
(cd .. && make rules && make all_games_html && make mo)
srcdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
mkdir -p ${tmpdir}
rm -rf ${tmpdir}
cp -a .. ${tmpdir}
rm -rf ${tmpdir}/android
rm -rf ${tmpdir}/src
# remove useless load from the app
rm -rf ${tmpdir}/.git
rm -rf ${tmpdir}/.gitignore
rm -rf ${tmpdir}/Screenshots
rm -rf ${tmpdir}/build
rm -rf ${tmpdir}/contrib
rm -rf ${tmpdir}/dist
rm -rf ${tmpdir}/runtests.pl
rm -rf ${tmpdir}/tests
rm -rf ${tmpdir}/Brewfile
rm -rf ${tmpdir}/.appveyor.yml
rm -rf ${tmpdir}/.perltidyrc
rm -rf ${tmpdir}/.travis.yml
rm -rf ${tmpdir}/setup.py
rm -rf ${tmpdir}/setup_osx.py
rm -rf ${tmpdir}/setup.cfg
cp -a ${pkgdir}/supportlib/support-v4-24.1.1.aar ${tmpdir}
cp -a main.py ${tmpdir}
mkdir -p ${tmpdir}/data/images/cards/bottoms/trumps-only
echo "" > ${tmpdir}/data/images/cards/bottoms/trumps-only/.keep
mkdir -p ${srcdir}
rm -rf ${srcdir}
cp -a .. ${srcdir}
rm -rf ${srcdir}/android
rm -rf ${srcdir}/src
cp -a main.py ${srcdir}/main.py
mkdir -p ${srcdir}/data/images/cards/bottoms/trumps-only
echo "" > ${srcdir}/data/images/cards/bottoms/trumps-only/.keep
echo '### prepare cardsets'
./mkcards
cardsdir=${HOME}/.cache/tmp-for-p4a/pysolfc
cp -a ${cardsets_dir}/* ${tmpdir}/data
if [ ! -d ${cardsdir}/PySolFC-Cardsets-2.0 ]
then
./mkcards
mv PySolFC-Cardsets-2.0 ${cardsdir}/
rm -f PySolFC-Cardsets-2.0.tar.bz2
fi
if [ -d ${cardsdir}/PySolFC-Cardsets-2.0 ]
then
echo '### copying cardsets'
cp -a ${cardsdir}/PySolFC-Cardsets-2.0/* ${srcdir}/data
fi
echo '### end init'

View file

@ -1,30 +0,0 @@
#!/bin/bash
# package preload helper for fdroid build.
set -eux
if [[ $# < 3 ]]
then
exit 1
fi
packagebase=${HOME}'/.local/share/python-for-android/packages'
packagedir=${packagebase}/$1
packageurl=$2
packagename=$3
packagemark='.mark-'${packagename}
if [[ $# == 4 ]]
then
packagemark='.mark'$4
fi
mkdir -p ${packagedir}
cd ${packagedir}
if [ ! -f ${packagemark} ]
then
wget -nv ${packageurl}/${packagename}
touch ${packagemark}
fi

View file

@ -1,13 +1,11 @@
#!/bin/bash
set -e
. mkp4a.common
pass1=""
pass2=""
keyalias="python"
keystore="${PWD}/bin/keystore"
if [ $1 ]; then
if [ $1 ]
then
pass1=$1
pass2=$1
else
@ -15,13 +13,16 @@ else
echo " (use ./mkkeystore to create one in default location)"
exit
fi
if [ $2 ]; then
if [ $2 ]
then
pass2=$2
fi
if [ $3 ]; then
if [ $3 ]
then
keyalias=$3
fi
if [ $4 ]; then
if [ $4 ]
then
keystore=$4
fi
@ -30,10 +31,30 @@ export P4A_RELEASE_KEYSTORE_PASSWD="$pass1"
export P4A_RELEASE_KEYALIAS_PASSWD="$pass2"
export P4A_RELEASE_KEYALIAS="$keyalias"
version=`./version.py`
tmpdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
python3 -m pythonforandroid.toolchain apk \
${p4a_options} \
--sdk-dir ${HOME}/.cache/sdk-for-p4a \
--ndk-dir ${HOME}/.cache/sdk-for-p4a/ndk-bundle \
--android-api 19 \
--ndk-version r12b \
--arch armeabi-v7a \
--dist-name pysolfc \
--name PySolFC \
--bootstrap=sdl2 \
--requirements kivy,hostpython2,random2 \
--release \
--sign
--sign \
--minsdk 14 \
--private ${tmpdir} \
--package org.lufebe16.pysolfc \
--version ${version} \
--orientation sensor \
--color=always \
--icon ${tmpdir}/data/images/misc/pysol01.png \
--presplash ${tmpdir}/data/images/misc/pysol06.png \
--copy-libs
# keystore options (instead environment vars):
#

View file

@ -1,21 +1,47 @@
#!/bin/bash
set -eux
. mkp4a.common
echo '### p4a started'
# NOTE: $1 and $2 (sdk and ndk) used with fdroid build only.
# sdk-dir and nkd-dir from command line (fdroid mode)
if [[ $# == 2 ]]
sdkdir="${HOME}/.cache/sdk-for-p4a"
ndkdir="${HOME}/.cache/sdk-for-p4a/ndk-bundle"
if [ $1 ]
then
sdkdir=$1
ndkdir=$2
echo "set sdk to: $1"
sdkdir="$1"
fi
if [ $2 ]
then
echo "set ndk to: $2"
ndkdir="$2"
fi
echo '### run toolchain'
version=`./version.py`
tmpdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
python3 -m pythonforandroid.toolchain apk \
${p4a_options} \
--sdk-dir ${sdkdir} \
--ndk-dir ${ndkdir} \
--release
--android-api 19 \
--ndk-version r12b \
--arch armeabi-v7a \
--dist-name pysolfc \
--name PySolFC \
--bootstrap=sdl2 \
--requirements kivy,hostpython2,random2 \
--release \
--minsdk 14 \
--private ${tmpdir} \
--package org.lufebe16.pysolfc \
--version ${version} \
--orientation sensor \
--color=always \
--icon ${tmpdir}/data/images/misc/pysol01.png \
--presplash ${tmpdir}/data/images/misc/pysol06.png \
--copy-libs
# python3 -m pythonforandroid.toolchain apk
# ...
@ -27,3 +53,5 @@ python3 -m pythonforandroid.toolchain apk \
# ohne: -> debug version
# 1: -> release unsigned
# 1 und 2: -> release version.
echo '### p4a finished'

View file

@ -1,8 +1,7 @@
#!/bin/bash
set -Cefu
#! /bin/sh -Cefu
: ${PKGTREE:=/usr/local/packages/PySolFC}
PIP=("${PKGTREE}/env/bin/pip" install --no-binary :all:)
PIP="$(printf '%s/env/bin/pip install --no-binary :all: ' "$PKGTREE")"
PYPROG="$(printf '%s/env/bin/python' "$PKGTREE")"
VERSION="$(env PYTHONPATH=`pwd` "$PYPROG" -c 'from pysollib.settings import VERSION ; print(VERSION)')"
XZBALL="$(printf 'dist/PySolFC-%s.tar.xz' "$VERSION")"
@ -11,6 +10,6 @@ reqs='six random2 pillow'
make dist
for req in $reqs
do
"${PIP[@]}" "$req"
"$PIP" "$req"
done
"${PIP[@]}" --upgrade "$XZBALL"
"$PIP" --upgrade "$XZBALL"

76
data/glade-translations Normal file
View file

@ -0,0 +1,76 @@
/*
* Translatable strings file generated by Glade.
* Add this file to your project's POTFILES.in.
* DO NOT compile it as part of your application.
*/
gchar *s = N_("Game Statistics");
gchar *s = N_("Game:");
gchar *s = N_("Won:");
gchar *s = N_("Total:");
gchar *s = N_("Lost:");
gchar *s = N_("Current session");
gchar *s = N_("Won:");
gchar *s = N_("Lost:");
gchar *s = N_("Total:");
gchar *s = N_("Total");
gchar *s = N_("Current game");
gchar *s = N_("Playing time:");
gchar *s = N_("Moves:");
gchar *s = N_("Total moves:");
gchar *s = N_("Minimum");
gchar *s = N_("Maximum");
gchar *s = N_("Average");
gchar *s = N_("Summary");
gchar *s = N_("Playing time");
gchar *s = N_("Moves");
gchar *s = N_("Total moves");
gchar *s = N_("Game:");
gchar *s = N_("Top 10");
gchar *s = N_("All games");
gchar *s = N_("Full log");
gchar *s = N_("Session log");
gchar *s = N_("Set timeouts");
gchar *s = N_("Demo:");
gchar *s = N_("Hint:");
gchar *s = N_("Raise card:");
gchar *s = N_("Highlight piles:");
gchar *s = N_("Highlight cards:");
gchar *s = N_("Highlight same rank:");
gchar *s = N_("Set colors");
gchar *s = N_("Highlight piles:");
gchar *s = N_("Highlight cards 1:");
gchar *s = N_("Highlight cards 2:");
gchar *s = N_("Highlight same rank 1:");
gchar *s = N_("Highlight same rank 2:");
gchar *s = N_("Hint arrow:");
gchar *s = N_("Highlight not matching:");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Text foreground:");
gchar *s = N_("Set font");
gchar *s = N_("HTML: ");
gchar *s = N_("Small: ");
gchar *s = N_("Fixed: ");
gchar *s = N_("Tableau default: ");
gchar *s = N_("Tableau fixed: ");
gchar *s = N_("Tableau small: ");
gchar *s = N_("Tableau large: ");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Change...");
gchar *s = N_("Sound settings");
gchar *s = N_("Sound enabled");
gchar *s = N_("Sample volume:");
gchar *s = N_("Music volume:");
gchar *s = N_("Enable samles");

View file

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View file

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

View file

@ -1,6 +1,4 @@
#!/bin/bash
set -e
# convert gif to png - dir recursive
# scharf !!!!

View file

@ -1,10 +1,8 @@
[Desktop Entry]
Encoding=UTF-8
Name=PySol Fan Club Edition
Comment=More than 1000 solitaire card games
Exec=pysol.py
StartupWMClass=Pysol
Terminal=false
Type=Application
Categories=Game;CardGame;
Keywords=solitaire;patience;cards;pysolfc;klondike;
Icon=pysol
Icon=/usr/share/icons/pysol01.png

View file

@ -1,5 +1,4 @@
#!/bin/sh
set -e
from_dir=images
to_dir=clearlooks

View file

@ -69,9 +69,9 @@ the current directory
.br
/usr/local/share/PySolFC
.br
/usr/share/games/PySolFC
/usr/games/PySolFC
.br
/usr/local/share/games/PySolFC
/usr/local/games/PySolFC
.PP
Options are saved in \fB~/.PySolFC/options.cfg\fR
.PP

View file

@ -6,11 +6,8 @@ traditionally been individually hand painted. There are any where from eight
to twelve or more suits per deck, each suit having usually twelve ranks. The
two most common Ganjifa decks are the Mughal which has eight suits and the
Dashavatara which has ten. The suits have pip cards numbered from Ace through
ten and two court cards, the Wazir and the Mir. The order of the suits
is: Matsya, Kuchha, Varaha, Narsingha, Vamana, Parashurama, Rama,
Krishna, Buddha, and Kalanki. Ganjifa solitaire games play the same
as games that use the standard deck but the larger number of different
cards in a deck (96 or 120) adds an element of complexity. The fact
that each suit has it's own color makes things quite interesting in
games that use "Alternate Color" row stacks.
<img alt="" src="images/ganjifa.gif">
ten and two court cards, the Wazir and the Mir. Ganjifa solitaire games play
the same as games that use the standard deck but the larger number of different
cards in a deck (96 or 120) adds an element of complexity. The fact that each
suit has it's own color makes things quite interesting in games that use
"Alternate Color" row stacks.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

View file

@ -10,7 +10,7 @@ Move all cards to the foundations.
<p>
This is a Freecell type of game. Cards on the tableau build down in rank
by suit. Cards build up in rank on the foundations.
A stack can be moved if the cards are in descending rank order
A stack can be moved if the cards are in decending rank order
regardless of the suit. Only a King or the highest trump can be played
on an empty row.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PySol 0.0.1\n"
"POT-Creation-Date: Wed Sep 25 11:43:34 2019\n"
"POT-Creation-Date: Mon Mar 7 21:38:07 2011\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -702,9 +702,6 @@ msgstr ""
msgid "Czarina"
msgstr ""
msgid "Daddy Longlegs"
msgstr ""
msgid "Danda"
msgstr ""
@ -1275,12 +1272,6 @@ msgstr ""
msgid "FreeCell"
msgstr ""
msgid "FreeCell with Two Reserves"
msgstr ""
msgid "FreeCell with Zero Reserves"
msgstr ""
msgid "Frog"
msgstr ""

View file

@ -5,16 +5,14 @@
msgid ""
msgstr ""
"Project-Id-Version: it_games\n"
"POT-Creation-Date: Thu Jul 18 18:43:59 2019\n"
"POT-Creation-Date: Thu Sep 6 15:06:46 2007\n"
"PO-Revision-Date: 2011-05-12 18:46+0200\n"
"Last-Translator: Giuliano Colla <giuliano.colla@gmail.com>\n"
"Language-Team: Italiano <it@li.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: ./scripts/all_games.py 0.1\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: KBabel 1.11.4\n"
msgid " 3x3 Matrix"
@ -77,9 +75,6 @@ msgstr "Conoscenti"
msgid "Adela"
msgstr "Adelina"
msgid "Aglet"
msgstr ""
msgid "Agnes Bernauer"
msgstr "Agnese Bernauer"
@ -248,12 +243,6 @@ msgstr ""
msgid "Bavarian Patience"
msgstr ""
msgid "Bayan"
msgstr ""
msgid "Beacon"
msgstr ""
msgid "Beak and Flipper"
msgstr ""
@ -533,9 +522,6 @@ msgstr ""
msgid "Cat's Tail"
msgstr ""
msgid "Catherine the Great"
msgstr ""
msgid "Cavalier"
msgstr ""
@ -704,9 +690,6 @@ msgstr ""
msgid "Czarina"
msgstr ""
msgid "Daddy Longlegs"
msgstr ""
msgid "Danda"
msgstr ""
@ -821,9 +804,6 @@ msgstr ""
msgid "Double Bisley"
msgstr ""
msgid "Double Blue Moon"
msgstr ""
msgid "Double Canfield"
msgstr ""
@ -896,18 +876,12 @@ msgstr ""
msgid "Double Measure"
msgstr ""
msgid "Double Montana"
msgstr ""
msgid "Double Pyramid"
msgstr ""
msgid "Double Rail"
msgstr ""
msgid "Double Red Moon"
msgstr ""
msgid "Double Russian Solitaire"
msgstr ""
@ -968,9 +942,6 @@ msgstr ""
msgid "Dutch Solitaire"
msgstr ""
msgid "Dutchess"
msgstr ""
msgid "Eagle Wing"
msgstr ""
@ -1001,9 +972,6 @@ msgstr ""
msgid "Eight Off"
msgstr ""
msgid "Eight Packs"
msgstr ""
msgid "Eight Sages"
msgstr ""
@ -1190,9 +1158,6 @@ msgstr ""
msgid "Flying Dragon"
msgstr ""
msgid "Foothold"
msgstr ""
msgid "Footling"
msgstr ""
@ -1277,12 +1242,6 @@ msgstr ""
msgid "FreeCell"
msgstr ""
msgid "FreeCell with Two Reserves"
msgstr ""
msgid "FreeCell with Zero Reserves"
msgstr ""
msgid "Frog"
msgstr ""
@ -1466,9 +1425,6 @@ msgstr ""
msgid "Hanoi Puzzle 6"
msgstr ""
msgid "Hanoi Sequence"
msgstr ""
msgid "Happy New Year"
msgstr ""
@ -1682,9 +1638,6 @@ msgstr ""
msgid "Katrina's Game Relaxed"
msgstr ""
msgid "Kentish"
msgstr ""
msgid "Khadga"
msgstr ""
@ -2357,7 +2310,7 @@ msgstr ""
msgid "Mahjongg Stargate"
msgstr ""
msgid "Mahjongg Steps Pyramid"
msgid "Mahjongg Step Pyramid"
msgstr ""
msgid "Mahjongg Stonehenge"
@ -2699,15 +2652,6 @@ msgstr ""
msgid "Northwest Territory"
msgstr ""
msgid "Not Shisen-Sho 14x6"
msgstr ""
msgid "Not Shisen-Sho 18x8"
msgstr ""
msgid "Not Shisen-Sho 24x12"
msgstr ""
msgid "Number Ten"
msgstr ""
@ -2960,9 +2904,6 @@ msgstr ""
msgid "Puss in the Corner"
msgstr ""
msgid "Putt Putt"
msgstr ""
msgid "Pyramid"
msgstr ""
@ -2984,18 +2925,12 @@ msgstr ""
msgid "Quadrangle"
msgstr ""
msgid "Quadrille"
msgstr ""
msgid "Quadruple Alliance"
msgstr ""
msgid "Quads"
msgstr ""
msgid "Quads +"
msgstr ""
msgid "Quartets"
msgstr ""
@ -3065,10 +3000,6 @@ msgstr ""
msgid "Relax"
msgstr ""
#, fuzzy
msgid "Relaxed Accordion"
msgstr "Fisarmonica"
msgid "Relaxed FreeCell"
msgstr ""
@ -3084,9 +3015,6 @@ msgstr ""
msgid "Relaxed Spider"
msgstr ""
msgid "Relaxed Three Fir-trees"
msgstr ""
msgid "Repair"
msgstr ""
@ -3300,13 +3228,13 @@ msgstr ""
msgid "Shifting"
msgstr ""
msgid "Shisen-Sho (No Gravity) 14x6"
msgid "Shisen-Sho (No Gra) 14x6"
msgstr ""
msgid "Shisen-Sho (No Gravity) 18x8"
msgid "Shisen-Sho (No Gra) 18x8"
msgstr ""
msgid "Shisen-Sho (No Gravity) 24x12"
msgid "Shisen-Sho (No Gra) 24x12"
msgstr ""
msgid "Shisen-Sho 14x6"
@ -3495,15 +3423,15 @@ msgstr ""
msgid "Stargate"
msgstr ""
msgid "Step Pyramid"
msgstr ""
msgid "Step-Up"
msgstr ""
msgid "Steps"
msgstr ""
msgid "Steps Pyramid"
msgstr ""
msgid "Steve"
msgstr ""
@ -3669,9 +3597,6 @@ msgstr ""
msgid "Thieves of Egypt"
msgstr ""
msgid "Thirteen Packs"
msgstr ""
msgid "Thirteen Up"
msgstr ""
@ -3939,9 +3864,6 @@ msgstr ""
msgid "Waning Moon"
msgstr ""
msgid "Wasatch"
msgstr ""
msgid "Washington's Favorite"
msgstr ""
@ -4046,3 +3968,4 @@ msgstr ""
msgid "Zodiac"
msgstr ""

File diff suppressed because it is too large Load diff

View file

@ -4,11 +4,10 @@
msgid ""
msgstr ""
"Project-Id-Version: PySol 0.0.1\n"
"POT-Creation-Date: Thu Jul 18 18:43:59 2019\n"
"POT-Creation-Date: Mon Mar 7 21:38:07 2011\n"
"PO-Revision-Date: 2010-12-16 23:56+0100\n"
"Last-Translator: Jerzy Trzeciak <artusek@wp.pl>\n"
"Language-Team: Polish <pl@li.org>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -706,9 +705,6 @@ msgstr ""
msgid "Czarina"
msgstr "Czarina"
msgid "Daddy Longlegs"
msgstr ""
msgid "Danda"
msgstr "Danda"
@ -1281,12 +1277,6 @@ msgstr "Free Napoleon"
msgid "FreeCell"
msgstr "FreeCell"
msgid "FreeCell with Two Reserves"
msgstr ""
msgid "FreeCell with Zero Reserves"
msgstr ""
msgid "Frog"
msgstr "Żaba"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,17 +5,14 @@
msgid ""
msgstr ""
"Project-Id-Version: PySol 0.0.1\n"
"POT-Creation-Date: Thu Jul 18 18:43:59 2019\n"
"POT-Creation-Date: Mon Mar 7 21:38:07 2011\n"
"PO-Revision-Date: 2007-09-05 17:43+0400\n"
"Last-Translator: Скоморох <skomoroh@gmail.com>\n"
"Language-Team: Russian <ru@li.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: utf-8\n"
"Generated-By: ./scripts/all_games.py 0.1\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
msgid " 3x3 Matrix"
msgstr "Матрица 3x3"
@ -710,10 +707,6 @@ msgstr "Творог и сыворотка"
msgid "Czarina"
msgstr "Царевна"
#, fuzzy
msgid "Daddy Longlegs"
msgstr "Тенистые аллеи"
#, fuzzy
msgid "Danda"
msgstr "Алмаз"
@ -1296,12 +1289,6 @@ msgstr "Свободный Наполеон"
msgid "FreeCell"
msgstr "Свободная ячейка"
msgid "FreeCell with Two Reserves"
msgstr ""
msgid "FreeCell with Zero Reserves"
msgstr ""
msgid "Frog"
msgstr "Лягушка"

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,7 @@ from pysollib.pysoltk import create_find_card_dialog
from pysollib.pysoltk import create_solver_dialog
from pysollib.settings import DEBUG
from pysollib.settings import PACKAGE_URL, TITLE
from pysollib.settings import TOP_SIZE
from pysollib.settings import TOP_TITLE
from pysollib.stats import FileStatsFormatter
@ -381,7 +381,7 @@ class PysolMenubar(PysolMenubarTk):
if self._cancelDrag():
return
if self.changed():
if not self.game.areYouSure(_("Quit %s") % TITLE):
if not self.game.areYouSure(_("Quit ") + TITLE):
return
self.game.endGame()
self.game.quitGame()
@ -445,7 +445,7 @@ class PysolMenubar(PysolMenubarTk):
if not self.game.gsaveinfo.bookmarks:
return
if not self.game.areYouSure(_("Clear bookmarks"),
_("Clear all bookmarks?")):
_("Clear all bookmarks ?")):
return
self.game.gsaveinfo.bookmarks = {}
self.game.updateMenus()
@ -457,7 +457,7 @@ class PysolMenubar(PysolMenubarTk):
return
if self.changed(restart=1):
if not self.game.areYouSure(_("Restart game"),
_("Restart this game?")):
_("Restart this game ?")):
return
self.game.restartGame()
@ -501,11 +501,10 @@ class PysolMenubar(PysolMenubarTk):
if self._cancelDrag(break_pause=False):
return
game, gi = self.game, self.game.gameinfo
kw = {'game': gi.name,
'id': game.getGameNumber(format=1)}
cc = _("Comments for %(game)s %(id)s:\n\n") % kw
t = " " + game.getGameNumber(format=1)
cc = _("Comments for %s:\n\n") % (gi.name + t)
c = game.gsaveinfo.comment or cc
d = EditTextDialog(game.top, _("Comments for %(id)s") % kw, text=c)
d = EditTextDialog(game.top, _("Comments for ")+t, text=c)
if d.status == 0 and d.button == 0:
text = d.text
if text.strip() == cc.strip():
@ -526,9 +525,8 @@ class PysolMenubar(PysolMenubarTk):
text=_("Error while writing to file"))
else:
d = MfxMessageDialog(
self.top, title=_("%s Info") % TITLE, bitmap="info",
text=_("Comments were appended to\n\n%(filename)s")
% {'filename': fn})
self.top, title=TITLE+_(" Info"), bitmap="info",
text=_("Comments were appended to\n\n") + fn)
self._setCommentMenu(bool(game.gsaveinfo.comment))
#
@ -537,10 +535,10 @@ class PysolMenubar(PysolMenubarTk):
def _mStatsSave(self, player, filename, write_method):
if player is None:
text = _("Demo statistics were appended to\n\n%(filename)s")
text = _("Demo statistics")
filename = filename + "_demo"
else:
text = _("Your statistics were appended to\n\n%(filename)s")
text = _("Your statistics")
filename = os.path.join(self.app.dn.config, filename + ".txt")
filename = os.path.normpath(filename)
try:
@ -551,8 +549,8 @@ class PysolMenubar(PysolMenubarTk):
text=_("Error while writing to file"))
else:
MfxMessageDialog(
self.top, title=_("%s Info") % TITLE, bitmap="info",
text=text % {'filename': filename})
self.top, title=TITLE+_(" Info"), bitmap="info",
text=text + _(" were appended to\n\n") + filename)
def mPlayerStats(self, *args, **kw):
mode = kw.get("mode", 101)
@ -566,40 +564,31 @@ class PysolMenubar(PysolMenubarTk):
d = Struct(status=-1, button=-1)
if demo:
player = None
p0, p1, p2 = TITLE+_(" Demo"), TITLE+_(" Demo "), ""
else:
player = self.app.opt.player
p0, p1, p2 = player, "", _(" for ") + player
n = self.game.gameinfo.name
# translation keywords
transkw = {'app': TITLE,
'player': player,
'game': n,
'tops': TOP_SIZE}
#
if mode == 100:
d = Status_StatsDialog(self.top, game=self.game)
elif mode == 101:
header = (_("%(app)s Demo Statistics for %(game)s") if demo
else _("Statistics for %(game)s")) % transkw
header = p1 + _("Statistics for ") + n
d = SingleGame_StatsDialog(
self.top, header, self.app, player, gameid=self.game.id)
gameid = d.selected_game
elif mode == 102:
header = (_("%(app)s Demo Statistics") if demo
else _("Statistics for %(player)s")) % transkw
header = p1 + _("Statistics") + p2
d = AllGames_StatsDialog(self.top, header, self.app, player)
gameid = d.selected_game
elif mode == 103:
header = (_("%(app)s Demo Full log") if demo
else _("Full log for %(player)s")) % transkw
header = p1 + _("Full log") + p2
d = FullLog_StatsDialog(self.top, header, self.app, player)
elif mode == 104:
header = (_("%(app)s Demo Session log") if demo
else _("Session log for %(player)s")) % transkw
header = p1 + _("Session log") + p2
d = SessionLog_StatsDialog(self.top, header, self.app, player)
elif mode == 105:
# TRANSLATORS: eg. top 10 or top 5 results for a certain game
header = (_("%(app)s Demo Top %(tops)d for %(game)s") if demo
else _("Top %(tops)d for %(game)s")) % transkw
header = p1 + TOP_TITLE + _(" for ") + n
d = Top_StatsDialog(
self.top, header, self.app, player, gameid=self.game.id)
elif mode == 106:
@ -625,8 +614,7 @@ class PysolMenubar(PysolMenubarTk):
# reset all player stats
if self.game.areYouSure(
_("Reset all statistics"),
_("Reset ALL statistics and logs for player\n" +
"%(player)s?") % transkw,
_("Reset ALL statistics and logs for player\n%s ?") % p0,
confirm=1, default=1
):
self.app.stats.resetStats(player, 0)
@ -636,8 +624,8 @@ class PysolMenubar(PysolMenubarTk):
# reset player stats for current game
if self.game.areYouSure(
_("Reset game statistics"),
_('Reset statistics and logs for player\n%(player)s\n'
'and game\n%(game)s?') % transkw,
_('Reset statistics and logs ' +
'for player\n%s\nand game\n%s ?') % (p0, n),
confirm=1, default=1
):
self.app.stats.resetStats(player, self.game.id)

View file

@ -60,7 +60,7 @@ from pysollib.resource import Tile, TileManager
from pysollib.settings import DEBUG
from pysollib.settings import PACKAGE, VERSION_TUPLE, WIN_SYSTEM
from pysollib.settings import TOOLKIT
from pysollib.util import IMAGE_EXTENSIONS
from pysollib.util import CARDSET, IMAGE_EXTENSIONS
from pysollib.winsystems import TkSettings
if TOOLKIT == 'tk':
from pysollib.ui.tktile.solverdialog import destroy_solver_dialog
@ -329,8 +329,7 @@ class Application:
elif self.commandline.game is not None:
gameid = self.gdb.getGameByName(self.commandline.game)
if gameid is None:
print_err(_("can't find game: %(game)s") % {
'game': self.commandline.game})
print_err(_("can't find game: ") + self.commandline.game)
sys.exit(-1)
else:
self.nextgame.id = gameid
@ -669,7 +668,7 @@ class Application:
if progress is None:
self.wm_save_state()
self.wm_withdraw()
title = _("Loading cardset %s...") % cs.name
title = _("Loading %s %s...") % (CARDSET, cs.name)
color = self.opt.colors['table']
if self.tabletile_index > 0:
color = "#008200"
@ -679,7 +678,7 @@ class Application:
images = Images(self.dataloader, cs)
try:
if not images.load(app=self, progress=progress):
raise Exception("Invalid or damaged cardset")
raise Exception("Invalid or damaged "+CARDSET)
simages = SubsampledImages(images)
if self.opt.save_cardsets:
c = self.cardsets_cache.get(cs.type)
@ -711,8 +710,8 @@ class Application:
# images.destruct()
destruct(images)
MfxExceptionDialog(
self.top, ex, title=_("Cardset load error"),
text=_("Error while loading cardset"))
self.top, ex, title=CARDSET+_(" load error"),
text=_("Error while loading ")+CARDSET)
self.intro.progress = progress
if r and self.menubar is not None:
self.menubar.updateBackgroundImagesMenu()
@ -807,14 +806,14 @@ class Application:
#
t = self.checkCompatibleCardsetType(gi, self.cardset)
MfxMessageDialog(
self.top, title=_("Incompatible cardset"),
self.top, title=_("Incompatible ")+CARDSET,
bitmap="warning",
text=_('''The currently selected cardset %(cardset)s
text=_('''The currently selected %s %s
is not compatible with the game
%(game)s
%s
Please select a %(correct_type)s type cardset.
''') % {'cardset': self.cardset.name, 'game': gi.name, 'correct_type': t[0]},
Please select a %s type %s.
''') % (CARDSET, self.cardset.name, gi.name, t[0], CARDSET),
strings=(_("&OK"),), default=0)
cs = self.__selectCardsetDialog(t)
if cs is None:
@ -853,7 +852,7 @@ Please select a %(correct_type)s type cardset.
def __selectCardsetDialog(self, t):
cs = self.selectCardset(
_("Please select a %s type cardset") % t[0],
_("Please select a %s type %s") % (t[0], CARDSET),
self.cardset.index)
return cs
@ -1061,8 +1060,7 @@ Please select a %(correct_type)s type cardset.
except Exception as ex:
if DEBUG:
traceback.print_exc()
print_err(_("error loading plugin %(file)s: %(err)s") %
{'file': n, 'err': ex})
print_err(_("error loading plugin %s: %s") % (n, ex))
#
# init cardsets
@ -1213,10 +1211,11 @@ Please select a %(correct_type)s type cardset.
d = os.path.join(dirname, name)
if not os.path.isdir(d):
continue
f = os.path.join(d, "config.txt")
if os.path.isfile(f):
f1 = os.path.join(d, "config.txt")
f2 = os.path.join(d, "COPYRIGHT")
if os.path.isfile(f1) and os.path.isfile(f2):
try:
cs = self._readCardsetConfig(d, f)
cs = self._readCardsetConfig(d, f1)
if cs:
# from pprint import pprint
# print cs.name
@ -1233,7 +1232,7 @@ Please select a %(correct_type)s type cardset.
fnames[cs.name] = 1
else:
print_err('fail _readCardsetConfig: %s %s'
% (d, f))
% (d, f1))
pass
except Exception:
# traceback.print_exc()

View file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,55 +0,0 @@
# 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.pysolrandom import random__str2long
from pysollib.settings import PACKAGE
from pysollib.settings import VERSION, VERSION_TUPLE
def pysolDumpGame(game_, p, bookmark=0):
game_.updateTime()
assert 0 <= bookmark <= 2
p.dump(PACKAGE)
p.dump(VERSION)
p.dump(VERSION_TUPLE)
p.dump(bookmark)
p.dump(game_.GAME_VERSION)
p.dump(game_.id)
#
p.dump(random__str2long(game_.random.getSeedStr()))
p.dump(game_.random.getstate())
#
p.dump(len(game_.allstacks))
for stack in game_.allstacks:
p.dump(len(stack.cards))
for card in stack.cards:
p.dump(card.id)
p.dump(card.face_up)
p.dump(game_.s.talon.round)
p.dump(game_.finished)
if 0 <= bookmark <= 1:
p.dump(game_.saveinfo)
p.dump(game_.gsaveinfo)
p.dump(game_.moves)
p.dump(game_.snapshots)
if 0 <= bookmark <= 1:
if bookmark == 0:
game_.gstats.saved += 1
p.dump(game_.gstats)
p.dump(game_.stats)
game_._saveGameHook(p)
p.dump("EOF")

View file

@ -27,7 +27,6 @@ from . import bakersdozen # noqa: F401
from . import bakersgame # noqa: F401
from . import beleagueredcastle # noqa: F401
from . import bisley # noqa: F401
from . import bisley13 # noqa: F401
from . import braid # noqa: F401
from . import bristol # noqa: F401
from . import buffalobill # noqa: F401

View file

@ -1,89 +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
# Copyright (C) 2020 qunka
# Modified by Shlomi Fish, 2020, while disclaiming all copyrights.
#
# 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.gamedb import GI, GameInfo, registerGame
from pysollib.games.bisley import Bisley
from pysollib.layout import Layout
from pysollib.stack import \
InitialDealTalonStack, \
SS_FoundationStack, \
UD_SS_RowStack
from pysollib.util import KING, NO_RANK
# ************************************************************************
# * Bisley 13
# ************************************************************************
class Bisley13(Bisley):
#
# game layout
#
def createGame(self):
# create layout
l, s = Layout(self), self.s
# set window
w, h = 2*l.XM+9*l.XS, max(2*(l.YM+l.YS+8*l.YOFFSET), l.YM+5*l.YS)
self.setSize(w, h)
# create stacks
x, y = l.XM, l.YM
for i in range(7):
s.rows.append(UD_SS_RowStack(x, y, self, base_rank=NO_RANK))
x += l.XS
x, y = l.XM, l.YM+l.YS+8*l.YOFFSET
for i in range(6):
s.rows.append(UD_SS_RowStack(x, y, self, base_rank=NO_RANK))
x += l.XS
y = l.YM
for i in range(4):
x = l.XM+7*l.XS+l.XM
s.foundations.append(SS_FoundationStack(x, y, self, i, max_move=0))
x += l.XS
s.foundations.append(SS_FoundationStack(x, y, self, i,
base_rank=KING, max_move=0, dir=-1))
y += l.YS
s.talon = InitialDealTalonStack(w-l.XS, h-l.YS, self)
# default
l.defaultAll()
#
# game overrides
#
def startGame(self):
self._startDealNumRows(3)
self.s.talon.dealRow(rows=self.s.rows[4:13])
self.s.talon.dealRow(rows=self.s.foundations[::2])
# register the game
registerGame(GameInfo(343001, Bisley13, "Bisley 13",
GI.GT_1DECK_TYPE | GI.GT_OPEN, 1, 0, GI.SL_MOSTLY_SKILL))

View file

@ -120,8 +120,7 @@ class Matriarchy_Talon(WasteTalonStack):
return
WasteTalonStack.updateText(self, update_rounds=0)
# t = "Round %d" % self.round
t = _("Round %(round)d/%(max_rounds)d") % {
'round': self.round, 'max_rounds': self.max_rounds}
t = _("Round %d/%d") % (self.round, self.max_rounds)
self.texts.rounds.config(text=t)
t = _("Deal %d") % self.DEAL[self.round-1]
self.texts.misc.config(text=t)

View file

@ -286,9 +286,6 @@ class Hanafuda_SequenceStack(Flower_OpenStack):
return cards[0].rank == 0 or self.cap.base_rank == ANY_RANK
return self.isHanafudaSequence([stackcards[-1], cards[0]])
def canMoveCards(self, cards):
return self.basicCanMoveCards(cards) and self.isHanafudaSequence(cards)
class Oonsoo_SequenceStack(Flower_OpenStack):
@ -301,10 +298,6 @@ class Oonsoo_SequenceStack(Flower_OpenStack):
return cards[0].rank == 0 or self.cap.base_rank == ANY_RANK
return self.isHanafudaSequence([stackcards[-1], cards[0]], 0)
def canMoveCards(self, cards):
return (self.basicCanMoveCards(cards) and
self.isHanafudaSequence(cards, 0))
class FlowerClock_RowStack(Flower_OpenStack):

View file

@ -40,18 +40,17 @@ from pysollib.settings import PACKAGE_URL, TITLE, TOOLKIT, VERSION
def help_about(app, timeout=0, sound=True):
if sound:
app.audio.playSample("about")
t = _("A Python Solitaire Game Collection")
t = _("A Python Solitaire Game Collection\n")
if app.miscrandom.random() < 0.8:
t = _("A World Domination Project")
t = _("A World Domination Project\n")
strings = (_("&Nice"), _("&Credits..."))
if timeout:
strings = (_("&Enjoy"),)
version = _("Version %s") % VERSION
d = PysolAboutDialog(app, app.top, title=_("About %s") % TITLE,
d = PysolAboutDialog(app, app.top, title=_("About ") + TITLE,
timeout=timeout,
text=_('''PySol Fan Club edition
%(description)s
%(versioninfo)s
%s%s
Copyright (C) 1998 - 2003 Markus F.X.J. Oberhumer.
Copyright (C) 2003 Mt. Hood Playing Card Co.
@ -61,8 +60,7 @@ All Rights Reserved.
PySol is free software distributed under the terms
of the GNU General Public License.
For more information about this application visit''') %
{'description': t, 'versioninfo': version},
For more information about this application visit''') % (t, version),
url=PACKAGE_URL,
image=app.gimages.logos[2],
strings=strings, default=0,
@ -88,7 +86,7 @@ def help_credits(app, timeout=0, sound=True):
t = "kivy"
d = MfxMessageDialog(
app.top, title=_("Credits"), timeout=timeout,
text=_('''%(app)s credits go to:
text=TITLE+_(''' credits go to:
Volker Weidner for getting me into Solitaire
Guido van Rossum for the initial example program
@ -97,8 +95,8 @@ Carl Larsson for the background music
The Gnome AisleRiot team for parts of the documentation
Natascha
The Python, %(gui_library)s, SDL & Linux crews
for making this program possible''') % {'app': TITLE, 'gui_library': t},
The Python, %s, SDL & Linux crews
for making this program possible''') % t,
image=app.gimages.logos[3], image_side="right",
separator=True)
return d.status
@ -124,8 +122,8 @@ def help_html(app, document, dir_, top=None):
document, dir_ = "index.html", "html"
help_html_index = app.dataloader.findFile(document, dir_)
except EnvironmentError:
MfxMessageDialog(app.top, title=_("%s HTML Problem") % TITLE,
text=_("Cannot find help document\n%s") % document,
MfxMessageDialog(app.top, title=TITLE + _(" HTML Problem"),
text=_("Cannot find help document\n") + document,
bitmap="warning")
return None
# print doc, help_html_index
@ -138,7 +136,7 @@ def help_html(app, document, dir_, top=None):
viewer.display(doc, relpath=0)
except Exception:
# traceback.print_exc()
top = make_help_toplevel(app, title=_("%s Help") % TITLE)
top = make_help_toplevel(app, title=TITLE+_(" Help"))
if top.winfo_screenwidth() < 800 or top.winfo_screenheight() < 600:
# maximized = 1
top.wm_minsize(300, 150)

View file

@ -27,11 +27,6 @@ import os
import subprocess
import sys
try:
import jnius
except ImportError:
jnius = None
import pysollib.settings
# ************************************************************************
@ -41,31 +36,27 @@ import pysollib.settings
def init():
if 'LANG' not in os.environ:
if os.name == 'nt':
lang, enc = locale.getdefaultlocale()
os.environ['LANG'] = lang
elif jnius: # android
Locale = jnius.autoclass('java.util.Locale')
os.environ['LANG'] = Locale.getDefault().getLanguage()
locale.setlocale(locale.LC_ALL, '')
if os.name == 'nt' and 'LANG' not in os.environ:
try:
loc = locale.getdefaultlocale()
os.environ['LANG'] = loc[0]
except Exception:
pass
# locale.setlocale(locale.LC_ALL, '')
# install gettext
locale_locations = (
# locale/ next to the pysol.py script
sys.path[0],
# locale/ next to library.zip (py2exe)
os.path.dirname(sys.path[0]),
# locale/ in curdir (works for e.g. py2app)
os.curdir)
# leaving the domain unbound means sys.prefix+'/share/locale'
for par in locale_locations:
locale_dir = os.path.join(par, 'locale')
if os.path.isdir(locale_dir):
gettext.bindtextdomain('pysol', locale_dir)
break
# locale_dir = 'locale'
locale_dir = None
if os.path.isdir(sys.path[0]):
d = os.path.join(sys.path[0], 'locale')
else:
# i.e. library.zip
d = os.path.join(os.path.dirname(sys.path[0]), 'locale')
if os.path.exists(d) and os.path.isdir(d):
locale_dir = d
# if locale_dir: locale_dir = os.path.normpath(locale_dir)
# gettext.install('pysol', locale_dir, unicode=True) # ngettext don't work
gettext.bindtextdomain('pysol', locale_dir)
gettext.textdomain('pysol')
# debug

View file

@ -52,8 +52,6 @@ from kivy.uix.treeview import TreeViewLabel
from kivy.uix.widget import Widget
from kivy.utils import platform
from pysollib.kivy.androidperms import requestStoragePerm
# =============================================================================
@ -673,10 +671,7 @@ class LRectangle(Widget, LBase):
event = LEvent()
event.x = ppos[0]
event.y = ppos[1]
if touch.is_double_tap:
self.group.bindings['<Double-1>'](event)
else:
self.group.bindings['<1>'](event)
self.group.bindings['<1>'](event)
return True
return False
@ -717,10 +712,6 @@ class LImageItem(BoxLayout, LBase):
if self.group and '<1>' in self.group.bindings:
self.group.bindings['<1>'](event)
def send_event_pressed_double_1(self, event):
if self.group and '<Double-1>' in self.group.bindings:
self.group.bindings['<Double-1>'](event)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
@ -743,10 +734,7 @@ class LImageItem(BoxLayout, LBase):
event.y = ppos[1]
self.dragstart = touch.pos
event.cardid = i
if touch.is_double_tap:
self.send_event_pressed_double_1(event)
else:
self.send_event_pressed_1(event)
self.send_event_pressed_1(event)
return True
if self.group is not None:
@ -1180,7 +1168,7 @@ class LMenu(ActionView, LBase):
class MyActionPrev(ActionPrevious, LBase):
pass
kw['app_icon'] = 'data/images/icons/48x48/pysol.png'
kw['app_icon'] = 'data/images/misc/pysol01.png'
kw['with_previous'] = prev
kw['size_hint'] = (.01, 1)
self.ap = MyActionPrev(**kw)
@ -1553,12 +1541,6 @@ class LMainWindow(BoxLayout, LTkBase):
self.workStack = LStack()
self.app = None
'''
from kivy.graphics import opengl_utils
print('OPENGL support:')
print(opengl_utils.gl_get_extensions())
'''
# self.touches = []
# beispiel zu canvas (hintergrund)
@ -1797,8 +1779,6 @@ class LApp(App):
self.mainloop = self.app.mainproc() # Einrichten
self.mainloop.send(None) # Spielprozess starten
logging.info("LApp: on_start processed")
# Android: Request missing android permissions.
requestStoragePerm()
def on_stop(self):
# Achtung wird u.U. 2 mal aufgerufen !!!
@ -1852,6 +1832,12 @@ class LApp(App):
except Exception:
traceback.print_exc()
pass
# save comments
try:
app.saveComments()
except Exception:
traceback.print_exc()
pass
logging.info("LApp: on_pause - gamesaved")
logging.info("LApp: on_pause, Window.size=%s" % str(Window.size))

View file

@ -1,64 +0,0 @@
import logging
try:
import jnius
except ImportError:
jnius = None
# link address of related support library:
# https://maven.google.com/com/android/support/support-v4/24.1.1/support-v4-24.1.1.aar
# inspired by stackoverflow.com/questions/47510030/
# as functools (reduce,partial,map) do not seem to work in python3 on android,
# implemented in a classic functional way.
# LB190927.
# wait loop removed. (Implement it in external code if needed.)
# LB191011.
class AndroidPerms(object):
def __init__(self):
if jnius is None:
return
self.PythonActivity = jnius.autoclass(
'org.kivy.android.PythonActivity')
self.Compat = jnius.autoclass(
'android.support.v4.content.ContextCompat')
self.currentActivity = jnius.cast(
'android.app.Activity', self.PythonActivity.mActivity)
def getPerm(self, permission):
if jnius is None:
return True
p = self.Compat.checkSelfPermission(self.currentActivity, permission)
return p == 0
# check actual permissions
def getPerms(self, permissions):
if jnius is None:
return True
haveperms = True
for perm in permissions:
haveperms = haveperms and self.getPerm(perm)
return haveperms
# invoke the permissions dialog
def requestPerms(self, permissions):
if jnius is None:
return True
logging.info("androidperms: invoke permission dialog")
self.currentActivity.requestPermissions(permissions, 0)
return
def getStoragePerm():
ap = AndroidPerms()
return ap.getPerms(
["android.permission.WRITE_EXTERNAL_STORAGE"])
def requestStoragePerm():
ap = AndroidPerms()
# ap.requestPerms(
# ["android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE"])
ap.requestPerms(
["android.permission.WRITE_EXTERNAL_STORAGE"])

View file

@ -48,10 +48,10 @@ from pysollib.kivy.tkutil import after_idle
from pysollib.kivy.tkutil import bind
from pysollib.mfxutil import Struct
from pysollib.mygettext import _
from pysollib.pysoltk import MfxMessageDialog
from pysollib.pysoltk import connect_game_find_card_dialog
from pysollib.settings import SELECT_GAME_MENU
from pysollib.settings import TITLE
from pysollib.util import CARDSET
# ************************************************************************
@ -177,34 +177,34 @@ class MainMenuDialog(LMenuDialog):
def buildTree(self, tv, node):
rg = tv.add_node(
LTreeNode(
text=_("File"),
text="File",
command=self.make_game_command(self.menubar.mFileMenuDialog)))
rg = tv.add_node(
LTreeNode(
text=_("Games"),
text="Games",
command=self.make_game_command(
self.menubar.mSelectGameDialog)))
rg = tv.add_node(
LTreeNode(
text=_("Tools"),
text="Tools",
command=self.make_game_command(self.menubar.mEditMenuDialog)))
rg = tv.add_node(
LTreeNode(
text=_("Statistics"),
text="Statistics",
command=self.make_game_command(self.menubar.mGameMenuDialog)))
rg = tv.add_node(
LTreeNode(
text=_("Assist"),
text="Assist",
command=self.make_game_command(
self.menubar.mAssistMenuDialog)))
rg = tv.add_node(
LTreeNode(
text=_("Options"),
text="Options",
command=self.make_game_command(
self.menubar.mOptionsMenuDialog)))
rg = tv.add_node(
LTreeNode(
text=_("Help"),
text="Help",
command=self.make_game_command(self.menubar.mHelpMenuDialog)))
del rg
@ -225,7 +225,7 @@ class FileMenuDialog(LMenuDialog):
def buildTree(self, tv, node):
rg = tv.add_node(
LTreeNode(text=_('Recent games')))
LTreeNode(text='Recent games'))
# Recent Liste
recids = self.app.opt.recent_gameid
# recgames = []
@ -238,12 +238,12 @@ class FileMenuDialog(LMenuDialog):
LTreeNode(text=gi.name, command=command), rg)
rg = tv.add_node(
LTreeNode(text=_('Favorite games')))
LTreeNode(text='Favorite games'))
if rg:
tv.add_node(LTreeNode(
text=_('<Add>'), command=self.menubar.mAddFavor), rg)
text='<Add>', command=self.menubar.mAddFavor), rg)
tv.add_node(LTreeNode(
text=_('<Remove>'), command=self.menubar.mDelFavor), rg)
text='<Remove>', command=self.menubar.mDelFavor), rg)
# Recent Liste
favids = self.app.opt.favorite_gameid
@ -257,12 +257,12 @@ class FileMenuDialog(LMenuDialog):
LTreeNode(text=gi.name, command=command), rg)
tv.add_node(LTreeNode(
text=_('Load'), command=self.menubar.mOpen))
text='Load', command=self.menubar.mOpen))
tv.add_node(LTreeNode(
text=_('Save'), command=self.menubar.mSaveAs))
text='Save', command=self.menubar.mSaveAs))
tv.add_node(LTreeNode(
text=_('Quit'), command=self.menubar.mHoldAndQuit))
text='Quit', command=self.menubar.mHoldAndQuit))
# ************************************************************************
@ -289,36 +289,36 @@ class EditMenuDialog(LMenuDialog): # Tools
def buildTree(self, tv, node):
tv.add_node(LTreeNode(
text=_('New game'), command=self.menubar.mNewGame))
text='New game', command=self.menubar.mNewGame))
tv.add_node(LTreeNode(
text=_('Restart game'), command=self.menubar.mRestart))
text='Restart game', command=self.menubar.mRestart))
tv.add_node(LTreeNode(
text=_('Undo'), command=self.menubar.mUndo))
text='Undo', command=self.menubar.mUndo))
tv.add_node(LTreeNode(
text=_('Redo'), command=self.menubar.mRedo))
text='Redo', command=self.menubar.mRedo))
tv.add_node(LTreeNode(
text=_('Redo all'), command=self.menubar.mRedoAll))
text='Redo all', command=self.menubar.mRedoAll))
tv.add_node(LTreeNode(
text=_('Auto drop'), command=self.menubar.mDrop))
text='Auto drop', command=self.menubar.mDrop))
tv.add_node(LTreeNode(
text=_('Shuffle tiles'), command=self.menubar.mShuffle))
text='Shuffle tiles', command=self.menubar.mShuffle))
tv.add_node(LTreeNode(
text=_('Deal cards'), command=self.menubar.mDeal))
text='Deal cards', command=self.menubar.mDeal))
self.addCheckNode(tv, None,
_('Pause'),
'Pause',
self.menubar.tkopt.pause,
self.menubar.mPause)
tv.add_node(LTreeNode(
text=_('Load game'), command=self.menubar.mOpen))
text='Load game', command=self.menubar.mOpen))
tv.add_node(LTreeNode(
text=_('Save game'), command=self.menubar.mSaveAs))
text='Save game', command=self.menubar.mSaveAs))
tv.add_node(LTreeNode(
text=_('Help'), command=self.menubar.mHelpRules))
text='Help', command=self.menubar.mHelpRules))
# -------------------------------------------
# TBD ?
@ -369,7 +369,7 @@ class GameMenuDialog(LMenuDialog):
def buildTree(self, tv, node):
tv.add_node(LTreeNode(
text=_('Current game...'),
text='Current game ...',
command=self.make_command(101, self.menubar.mPlayerStats)), None)
# tv.add_node(LTreeNode(
@ -432,16 +432,16 @@ class AssistMenuDialog(LMenuDialog):
def buildTree(self, tv, node):
tv.add_node(LTreeNode(
text=_('Hint'), command=self.menubar.mHint))
text='Hint', command=self.menubar.mHint))
tv.add_node(LTreeNode(
text=_('Highlight piles'), command=self.menubar.mHighlightPiles))
text='Highlight piles', command=self.menubar.mHighlightPiles))
# tv.add_node(LTreeNode(
# text='Find Card', command=self.menubar.mFindCard))
tv.add_node(LTreeNode(
text=_('Demo'), command=self.menubar.mDemo))
text='Demo', command=self.menubar.mDemo))
# -------------------------------------------
# TBD. How ?
@ -507,27 +507,27 @@ class OptionsMenuDialog(LMenuDialog):
# Automatic play settings
rg = tv.add_node(
LTreeNode(text=_('Automatic play')))
LTreeNode(text='Automatic play'))
if rg:
self.addCheckNode(tv, rg,
_('Auto face up'),
'Auto face up',
self.menubar.tkopt.autofaceup,
self.menubar.mOptAutoFaceUp)
self.addCheckNode(tv, rg,
_('Auto drop'),
'Auto drop',
self.menubar.tkopt.autodrop,
self.menubar.mOptAutoDrop)
self.addCheckNode(tv, rg,
_('Auto deal'),
'Auto deal',
self.menubar.tkopt.autodeal,
self.menubar.mOptAutoDeal)
# submenu.add_separator()
self.addCheckNode(tv, rg,
_('Quick play'),
'Quick play',
self.menubar.tkopt.quickplay,
self.menubar.mOptQuickPlay)
@ -535,245 +535,214 @@ class OptionsMenuDialog(LMenuDialog):
# Player assistance
rg = tv.add_node(
LTreeNode(text=_('Assist level')))
LTreeNode(text='Assist level'))
if rg:
self.addCheckNode(tv, rg,
_('Enable undo'),
'Enable undo',
self.menubar.tkopt.undo,
self.menubar.mOptEnableUndo)
self.addCheckNode(tv, rg,
_('Enable bookmarks'),
'Enable bookmarks',
self.menubar.tkopt.bookmarks,
self.menubar.mOptEnableBookmarks)
self.addCheckNode(tv, rg,
_('Enable hint'),
'Enable hint',
self.menubar.tkopt.hint,
self.menubar.mOptEnableHint)
self.addCheckNode(tv, rg,
_('Enable shuffle'),
'Enable shuffle',
self.menubar.tkopt.shuffle,
self.menubar.mOptEnableShuffle)
self.addCheckNode(tv, rg,
_('Enable highlight piles'),
'Enable highlight piles',
self.menubar.tkopt.highlight_piles,
self.menubar.mOptEnableHighlightPiles)
self.addCheckNode(tv, rg,
_('Enable highlight cards'),
'Enable highlight cards',
self.menubar.tkopt.highlight_cards,
self.menubar.mOptEnableHighlightCards)
self.addCheckNode(tv, rg,
_('Enable highlight same rank'),
'Enable highlight same rank',
self.menubar.tkopt.highlight_samerank,
self.menubar.mOptEnableHighlightSameRank)
self.addCheckNode(tv, rg,
_('Highlight no matching'),
'Highlight no matching',
self.menubar.tkopt.highlight_not_matching,
self.menubar.mOptEnableHighlightNotMatching)
# submenu.add_separator()
self.addCheckNode(tv, rg,
_('Show removed tiles (in Mahjongg games)'),
'Show removed tiles (in Mahjongg games)',
self.menubar.tkopt.mahjongg_show_removed,
self.menubar.mOptMahjonggShowRemoved)
self.addCheckNode(tv, rg,
_('Show hint arrow (in Shisen-Sho games)'),
'Show hint arrow (in Shisen-Sho games)',
self.menubar.tkopt.shisen_show_hint,
self.menubar.mOptShisenShowHint)
# submenu.add_separator()
# -------------------------------------------
# Language options
rg = tv.add_node(
LTreeNode(text=_('Language')))
if rg:
self.addRadioNode(tv, rg,
_('Default'),
self.menubar.tkopt.language, '',
self.menubar.mOptLanguage)
self.addRadioNode(tv, rg,
_('English'),
self.menubar.tkopt.language, 'en',
self.menubar.mOptLanguage)
self.addRadioNode(tv, rg,
_('German'),
self.menubar.tkopt.language, 'de',
self.menubar.mOptLanguage)
self.addRadioNode(tv, rg,
_('Italian'),
self.menubar.tkopt.language, 'it',
self.menubar.mOptLanguage)
self.addRadioNode(tv, rg,
_('Polish'),
self.menubar.tkopt.language, 'pl',
self.menubar.mOptLanguage)
self.addRadioNode(tv, rg,
_('Russian'),
self.menubar.tkopt.language, 'ru',
self.menubar.mOptLanguage)
# -------------------------------------------
# Sound options
rg = tv.add_node(
LTreeNode(text=_('Sound')))
LTreeNode(text='Sound'))
if rg:
self.addCheckNode(tv, rg,
_('Enable'),
'Enable',
self.menubar.tkopt.sound,
self.menubar.mOptSoundDialog)
rg1 = tv.add_node(
LTreeNode(text=_('Volume')), rg)
LTreeNode(text='Volume'), rg)
if rg1:
self.addRadioNode(tv, rg1,
_('100%'),
'100%',
self.menubar.tkopt.sound_sample_volume, 100,
self.menubar.mOptSoundSampleVol)
self.addRadioNode(tv, rg1,
_('75%'),
'75%',
self.menubar.tkopt.sound_sample_volume, 75,
self.menubar.mOptSoundSampleVol)
self.addRadioNode(tv, rg1,
_('50%'),
'50%',
self.menubar.tkopt.sound_sample_volume, 50,
self.menubar.mOptSoundSampleVol)
self.addRadioNode(tv, rg1,
_('25%'),
'25%',
self.menubar.tkopt.sound_sample_volume, 25,
self.menubar.mOptSoundSampleVol)
rg1 = tv.add_node(
LTreeNode(text=_('Samples')), rg)
LTreeNode(text='Samples'), rg)
if rg1:
key = 'areyousure'
self.addCheckNode(
tv, rg1,
_('are you sure'),
'are you sure',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'autodrop'
self.addCheckNode(
tv, rg1,
_('auto drop'),
'auto drop',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'autoflip'
self.addCheckNode(
tv, rg1,
_('auto flip'),
'auto flip',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'autopilotlost'
self.addCheckNode(
tv, rg1,
_('auto pilot lost'),
'auto pilot lost',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'autopilotwon'
self.addCheckNode(
tv, rg1,
_('auto pilot won'),
'auto pilot won',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'deal'
self.addCheckNode(
tv, rg1,
_('deal'),
'deal',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'dealwaste'
self.addCheckNode(
tv, rg1,
_('deal waste'),
'deal waste',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'droppair'
self.addCheckNode(
tv, rg1,
_('drop pair'),
'drop pair',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'drop'
self.addCheckNode(
tv, rg1,
_('drop'),
'drop',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'flip'
self.addCheckNode(
tv, rg1,
_('flip'),
'flip',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'move'
self.addCheckNode(
tv, rg1,
_('move'),
'move',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'nomove'
self.addCheckNode(
tv, rg1,
_('no move'),
'no move',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'redo'
self.addCheckNode(
tv, rg1,
_('redo'),
'redo',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'startdrag'
self.addCheckNode(
tv, rg1,
_('start drag'),
'start drag',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'turnwaste'
self.addCheckNode(
tv, rg1,
_('turn waste'),
'turn waste',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'undo'
self.addCheckNode(
tv, rg1,
_('undo'),
'undo',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'gamefinished'
self.addCheckNode(
tv, rg1,
_('game finished'),
'game finished',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'gamelost'
self.addCheckNode(
tv, rg1,
_('game lost'),
'game lost',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'gameperfect'
self.addCheckNode(
tv, rg1,
_('game perfect'),
'game perfect',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
key = 'gamewon'
self.addCheckNode(
tv, rg1,
_('game won'),
'game won',
self.menubar.tkopt.sound_sample_vars[key],
self.make_vars_command(self.menubar.mOptSoundSample, key))
@ -781,7 +750,7 @@ class OptionsMenuDialog(LMenuDialog):
# Cardsets and card backside options
rg = tv.add_node(
LTreeNode(text=_('Cardsets')))
LTreeNode(text='Cardsets'))
if rg:
self.menubar.tkopt.cardset.set(self.app.cardset.index)
@ -821,45 +790,45 @@ class OptionsMenuDialog(LMenuDialog):
# Table background settings
rg = tv.add_node(
LTreeNode(text=_('Table')))
LTreeNode(text='Table'))
if rg:
rg1 = tv.add_node(
LTreeNode(text=_('Solid colors')), rg)
LTreeNode(text='Solid colors'), rg)
if rg1:
key = 'table'
self.addRadioNode(
tv, rg1,
_('Blue'),
'Blue',
self.menubar.tkopt.color_vars[key], '#0082df',
self.menubar.mOptTableColor)
self.addRadioNode(
tv, rg1,
_('Green'),
'Green',
self.menubar.tkopt.color_vars[key], '#008200',
self.menubar.mOptTableColor)
self.addRadioNode(
tv, rg1,
_('Navy'),
'Navy',
self.menubar.tkopt.color_vars[key], '#000086',
self.menubar.mOptTableColor)
self.addRadioNode(
tv, rg1,
_('Olive'),
'Olive',
self.menubar.tkopt.color_vars[key], '#868200',
self.menubar.mOptTableColor)
self.addRadioNode(
tv, rg1,
_('Orange'),
'Orange',
self.menubar.tkopt.color_vars[key], '#f79600',
self.menubar.mOptTableColor)
self.addRadioNode(
tv, rg1,
_('Teal'),
'Teal',
self.menubar.tkopt.color_vars[key], '#008286',
self.menubar.mOptTableColor)
rg1 = tv.add_node(
LTreeNode(text=_('Tiles and Images')), rg)
LTreeNode(text='Tiles and Images'), rg)
if rg1:
tm = self.app.tabletile_manager
@ -879,30 +848,30 @@ class OptionsMenuDialog(LMenuDialog):
# Card view options
rg = tv.add_node(
LTreeNode(text=_('Card view')))
LTreeNode(text='Card view'))
if rg:
self.addCheckNode(tv, rg,
_('Card shadow'),
'Card shadow',
self.menubar.tkopt.shadow,
self.menubar.mOptShadow)
self.addCheckNode(tv, rg,
_('Shade legal moves'),
'Shade legal moves',
self.menubar.tkopt.shade,
self.menubar.mOptShade)
self.addCheckNode(tv, rg,
_('Negative cards bottom'),
'Negative cards bottom',
self.menubar.tkopt.negative_bottom,
self.menubar.mOptNegativeBottom)
self.addCheckNode(tv, rg,
_('Shrink face-down cards'),
'Shrink face-down cards',
self.menubar.tkopt.shrink_face_down,
self.menubar.mOptShrinkFaceDown)
self.addCheckNode(tv, rg,
_('Shade filled stacks'),
'Shade filled stacks',
self.menubar.tkopt.shade_filled_stacks,
self.menubar.mOptShadeFilledStacks)
@ -910,47 +879,47 @@ class OptionsMenuDialog(LMenuDialog):
# Animation settins
rg = tv.add_node(
LTreeNode(text=_('Animations')))
LTreeNode(text='Animations'))
if rg:
self.addRadioNode(tv, rg,
_('None'),
'None',
self.menubar.tkopt.animations, 0,
self.menubar.mOptAnimations)
self.addRadioNode(tv, rg,
_('Very fast'),
'Very fast',
self.menubar.tkopt.animations, 1,
self.menubar.mOptAnimations)
self.addRadioNode(tv, rg,
_('Fast'),
'Fast',
self.menubar.tkopt.animations, 2,
self.menubar.mOptAnimations)
self.addRadioNode(tv, rg,
_('Medium'),
'Medium',
self.menubar.tkopt.animations, 3,
self.menubar.mOptAnimations)
self.addRadioNode(tv, rg,
_('Slow'),
'Slow',
self.menubar.tkopt.animations, 4,
self.menubar.mOptAnimations)
self.addRadioNode(tv, rg,
_('Very slow'),
'Very slow',
self.menubar.tkopt.animations, 5,
self.menubar.mOptAnimations)
# submenu.add_separator()
self.addCheckNode(tv, rg,
_('Redeal animation'),
'Redeal animation',
self.menubar.tkopt.redeal_animation,
self.menubar.mRedealAnimation)
self.addCheckNode(tv, rg,
_('Winning animation'),
'Winning animation',
self.menubar.tkopt.win_animation,
self.menubar.mWinAnimation)
@ -958,15 +927,15 @@ class OptionsMenuDialog(LMenuDialog):
# Touch mode settings
rg = tv.add_node(
LTreeNode(text=_('Touch mode')))
LTreeNode(text='Touch mode'))
if rg:
self.addRadioNode(tv, rg,
_('Drag-and-Drop'),
'Drag-and-Drop',
self.menubar.tkopt.mouse_type, 'drag-n-drop',
self.menubar.mOptMouseType)
self.addRadioNode(tv, rg,
_('Point-and-Click'),
'Point-and-Click',
self.menubar.tkopt.mouse_type, 'point-n-click',
self.menubar.mOptMouseType)
@ -1000,10 +969,10 @@ class OptionsMenuDialog(LMenuDialog):
# Toolbar options
rg = tv.add_node(
LTreeNode(text=_('Toolbar')))
LTreeNode(text='Toolbar'))
if rg:
self.addRadioNode(tv, rg,
_('Hide'),
'Hide',
self.menubar.tkopt.toolbar, 0,
self.menubar.mOptToolbar)
@ -1018,11 +987,11 @@ class OptionsMenuDialog(LMenuDialog):
# self.menubar.mOptToolbar)
self.addRadioNode(tv, rg,
_('Left'),
'Left',
self.menubar.tkopt.toolbar, 3,
self.menubar.mOptToolbar)
self.addRadioNode(tv, rg,
_('Right'),
'Right',
self.menubar.tkopt.toolbar, 4,
self.menubar.mOptToolbar)
@ -1059,12 +1028,12 @@ class OptionsMenuDialog(LMenuDialog):
# self.menubar.mOptDemoLogo)
self.addCheckNode(tv, None,
_('Startup splash screen'),
'Startup splash screen',
self.menubar.tkopt.splashscreen,
self.menubar.mOptSplashscreen)
self.addCheckNode(tv, None,
_('Winning splash'),
'Winning splash',
self.menubar.tkopt.display_win_message,
self.menubar.mWinDialog)
@ -1087,23 +1056,23 @@ class HelpMenuDialog(LMenuDialog):
def buildTree(self, tv, node):
tv.add_node(
LTreeNode(
text=_('Contents'),
text='Contents',
command=self.make_help_command(self.menubar.mHelp)))
tv.add_node(
LTreeNode(
text=_('How to play'),
text='How to play',
command=self.make_help_command(self.menubar.mHelpHowToPlay)))
tv.add_node(
LTreeNode(
text=_('Rules for this game'),
text='Rules for this game',
command=self.make_help_command(self.menubar.mHelpRules)))
tv.add_node(
LTreeNode(
text=_('License terms'),
text='License terms',
command=self.make_help_command(self.menubar.mHelpLicense)))
tv.add_node(
LTreeNode(
text=_('About %s...') % TITLE,
text='About' + TITLE + '...',
command=self.make_help_command(self.menubar.mHelpAbout)))
# tv.add_node(LTreeNode(
@ -1265,7 +1234,6 @@ class PysolMenubarTk:
toolbar_vars={},
sound_sample_vars={},
color_vars={},
language=StringVar(),
)
for w in TOOLBAR_BUTTONS:
self.tkopt.toolbar_vars[w] = BooleanVar()
@ -1320,7 +1288,6 @@ class PysolMenubarTk:
tkopt.negative_bottom.set(opt.negative_bottom)
tkopt.display_win_message.set(opt.display_win_message)
tkopt.cardset.set(self.app.cardset_manager.getSelected())
tkopt.language.set(opt.language)
for w in TOOLBAR_BUTTONS:
tkopt.toolbar_vars[w].set(opt.toolbar_vars.get(w, False))
@ -1379,7 +1346,7 @@ class PysolMenubarTk:
# LMainMenuDialog()
LMenuItem(self.__menubar.menu,
text=_("Menu"), command=self.mMainMenuDialog)
text="Menu", command=self.mMainMenuDialog)
MfxMenubar.addPath = None
@ -1607,8 +1574,7 @@ class PysolMenubarTk:
menu.delete(0, 'last')
if len(games) == 0:
menu.add_radiobutton(label=_('<none>'), name=None,
state='disabled')
menu.add_radiobutton(label='<none>', name=None, state='disabled')
elif len(games) > self.__cb_max * 4:
games.sort(lambda a, b: cmp2(a.name, b.name))
self._addSelectAllGameSubMenu(games, menu,
@ -1825,9 +1791,8 @@ class PysolMenubarTk:
#
DEFAULTEXTENSION = ".pso"
# TRANSLATORS: Usually, 'PySol files'
FILETYPES = ((_("%s files") % TITLE, "*" + DEFAULTEXTENSION),
(_("All files"), "*"))
FILETYPES = ((TITLE + " files", "*" + DEFAULTEXTENSION),
("All files", "*"))
def mAddFavor(self, *event):
gameid = self.app.game.id
@ -1905,16 +1870,6 @@ class PysolMenubarTk:
self.game.doPause()
self.tkopt.pause.set(self.game.pause)
def mOptLanguage(self, *args):
if self._cancelDrag(break_pause=False):
return
self.app.opt.language = self.tkopt.language.get()
MfxMessageDialog(
self.app.top, title=_("Note"),
text=_("""\
These settings will take effect
the next time you restart the %(app)s""") % {'app': TITLE})
def mOptSoundDialog(self, *args):
if self._cancelDrag(break_pause=False):
return
@ -2111,9 +2066,10 @@ the next time you restart the %(app)s""") % {'app': TITLE})
# if os.name == "posix":
strings, default = (None, _("&Load"), _(
"&Cancel"), _("&Info..."), ), 1
t = CARDSET
key = self.app.nextgame.cardset.index
d = SelectCardsetDialogWithPreview(
self.top, title=_("Select cardset"),
self.top, title=_("Select ") + t,
app=self.app, manager=self.app.cardset_manager, key=key,
strings=strings, default=default)

View file

@ -35,13 +35,17 @@ class SelectCardsetDialogWithPreview(MfxDialog):
_cardset_store = None
def __init__(self, parent, title, app, manager, key=None, **kw):
kw = self.initKw(kw)
MfxDialog.__init__(self, parent, title, **kw)
#
if key is None:
key = 1
self.status = -1
self.key = key
key = manager.getSelected()
self.app = app
self.manager = manager
return
self.key = key
self.preview_key = -1
self.all_keys = []
self.status = -1
def getSelected(self):
return None

View file

@ -165,7 +165,7 @@ class SelectGameData(SelectDialogTreeData):
if name is None or not list(filter(
select_func, self.all_games_gi)):
continue
name = _("New games in v. %(version)s") % {'version': name}
name = _("New games in v. ") + name
gg.append(SelectGameNode(None, name, select_func))
if 1 and gg:
s_by_pysol_version = SelectGameNode(None, _("by PySol version"),

View file

@ -406,7 +406,7 @@ class HTMLViewer:
# self.defcursor = 'xterm'
self.handcursor = "hand2"
self.title = _("Browser")
self.title = "Browser"
self.window = None
self.running = False
@ -431,11 +431,11 @@ class HTMLViewer:
# BoxLayout(orientation='horizontal', size_hint=(1.0, 0.1))
# create buttons
self.homeButton = HTMLButton(text=_("Index"), on_release=self.goHome)
self.backButton = HTMLButton(text=_("Back"), on_release=self.goBack)
self.homeButton = HTMLButton(text="Index", on_release=self.goHome)
self.backButton = HTMLButton(text="Back", on_release=self.goBack)
self.forwardButton = HTMLButton(
text=_("Forward"), on_release=self.goForward)
self.closeButton = HTMLButton(text=_("Close"), on_release=self.goHome)
text="Forward", on_release=self.goForward)
self.closeButton = HTMLButton(text="Close", on_release=self.goHome)
'''
buttonline.add_widget(self.homeButton)
@ -683,8 +683,7 @@ class HTMLViewer:
self.display(self.home, relpath=0)
def errorDialog(self, msg):
MfxMessageDialog(self.parent,
title=_("%s HTML Problem") % TITLE,
MfxMessageDialog(self.parent, title=TITLE + " HTML Problem",
text=msg,
# bitmap="warning"
# FIXME: this interp don't have images

View file

@ -172,11 +172,8 @@ class SingleGame_StatsDialog(MfxDialog):
print('Stats(p): won=%s, lost=%s' % (won, lost))
text1 = _('Total:\n' +
' won: %(won)s ... %(percentwon)s%%\n' +
' lost: %(lost)s ... %(percentlost)s%%\n\n') % dict(
won=won, percentwon=int(round(100.0 * pwon)),
lost=lost, percentlost=int(round(100.0 * plost)))
text1 = 'Total:\n won: %s ... %s%%\n lost: %s ... %s%%\n\n' % (
won, int(round(100.0 * pwon)), lost, int(round(100.0 * plost)))
# createChart(app, won, lost, _("Total"))
won, lost = app.stats.getSessionStats(player, gameid)
@ -184,11 +181,9 @@ class SingleGame_StatsDialog(MfxDialog):
print('Stats(s): won=%s, lost=%s' % (won, lost))
text2 = _('Current Session:\n' +
' won: %(won)s ... %(percentwon)s%%\n' +
' lost: %(lost)s ... %(percentlost)s%%\n') % dict(
won=won, percentwon=(round(100.0 * pwon)),
lost=lost, percentlost=int(round(100.0 * plost)))
text2 = \
'Current Session:\n won: %s ... %s%%\n lost: %s ... %s%%\n' % \
(won, int(round(100.0 * pwon)), lost, int(round(100.0 * plost)))
# text2 = 'Current Session:\n won=%s, lost=%s\n' % (won, lost)
# createChart(app, won, lost, _("Current session"))

View file

@ -167,10 +167,10 @@ class MfxMessageDialog(MfxDialog):
# LB
# nicht automatisch ein neues spiel laden.
if (title == _("Game won")):
if (title == "Game won"):
self.status = 1
# self.button = 0
if (title == _("Game finished")):
if (title == "Game finished"):
self.status = 1
# self.button =
@ -180,7 +180,7 @@ class MfxMessageDialog(MfxDialog):
class MfxExceptionDialog(MfxMessageDialog):
def __init__(self, parent, ex, title=_("Error"), **kw):
def __init__(self, parent, ex, title="Error", **kw):
kw = KwStruct(kw, bitmap="error")
text = kw.get("text", "")
if not text.endswith("\n"):
@ -221,7 +221,7 @@ class PysolAboutDialog(object):
logging.info('PysolAboutDialog: txt=%s' % text)
text = text + '\n\n' + 'Adaptation to Kivy/Android\n' + \
' Copyright (C) (2016-19) LB'
' Copyright (C) (2016-17) LB'
self.parent = parent
self.app = app
@ -261,6 +261,13 @@ class PysolAboutDialog(object):
label = FText(text=text, halign='center', size_hint=(1, 1))
window.content.add_widget(label)
'''
label = LLabel(text=text)
label.texture_update()
label.size = label.texture_size
image = LImage(texture=label.texture)
window.content.add_widget(image)
'''
# ************************************************************************
# * a simple tooltip
@ -630,8 +637,53 @@ class MfxScrolledCanvas(object):
def scroll_bottom(self, *event):
return self._yview('moveto', 1)
# ************************************************************************
# *
# ************************************************************************
# not used witch kivy. would not nun as it refers TkInter.
'''
class StackDesc:
def __init__(self, game, stack):
self.game = game
self.stack = stack
self.canvas = game.canvas
self.bindings = []
font = game.app.getFont('canvas_small')
# print self.app.cardset.CARDW, self.app.images.CARDW
cardw = game.app.images.CARDW
x, y = stack.x + cardw / 2, stack.y
text = stack.getHelp() + '\n' + stack.getBaseCard()
text = text.strip()
if text:
frame = Tkinter.Frame(self.canvas)
self.frame = frame
label = Tkinter.Message(frame, font=font, text=text,
width=cardw - 8, relief='solid',
fg='#000000', bg='#ffffe0', bd=1)
label.pack()
self.label = label
self.id = self.canvas.create_window(
x, y, window=frame, anchor='n')
self.bindings.append(label.bind(
'<ButtonPress>', self._buttonPressEvent))
# self.bindings.append(label.bind('<Enter>', self._enterEvent))
else:
self.id = None
def _buttonPressEvent(self, *event):
# self.game.deleteStackDesc()
self.frame.tkraise()
def _enterEvent(self, *event):
self.frame.tkraise()
def delete(self):
if self.id:
self.canvas.delete(self.id)
for b in self.bindings:
self.label.unbind('<ButtonPress>', b)
'''

View file

@ -203,7 +203,7 @@ class PysolToolbarTk(BoxLayout):
# (n_("Statistics"), self.mPlayerStats, _("View statistics")),
(n_("Rules"), self.mHelpRules, _("Rules for this game")),
(None, None, None),
(n_("Quit"), self.mHoldAndQuit, _("Quit %s") % TITLE),
(n_("Quit"), self.mHoldAndQuit, _("Quit ") + TITLE),
):
if label is None:
# sep = self._createSeparator()

View file

@ -56,25 +56,25 @@ if TOOLKIT == 'kivy':
def fatal_no_cardsets(app):
app.wm_withdraw()
MfxMessageDialog(app.top, title=_("%s installation error") % TITLE,
text=_('''No cardsets were found!!!
text=_('''No cardsets were found !!!
Cardsets should be installed into:
%(dir)s
%s/cardsets/
Please check your %(app)s installation.
''') % {'dir': getprefdir(PACKAGE) + '/cardsets/', 'app': TITLE},
Please check your %s installation.
''') % (getprefdir(PACKAGE), TITLE),
bitmap="error", strings=(_("&Quit"),))
else:
def fatal_no_cardsets(app):
app.wm_withdraw()
MfxMessageDialog(app.top, title=_("%s installation error") % TITLE,
text=_('''No cardsets were found!!!
text=_('''No cardsets were found !!!
Main data directory is:
%(dir)s
%s
Please check your %(app)s installation.
''') % {'dir': app.dataloader.dir, 'app': TITLE},
Please check your %s installation.
''') % (app.dataloader.dir, TITLE),
bitmap="error", strings=(_("&Quit"),))
@ -93,8 +93,8 @@ def parse_option(argv):
"sound-mod=",
"help"])
except getopt.GetoptError as err:
print_err(err + "\n" + _("try %s --help for more information") %
prog_name, 0)
print_err(_("%s\ntry %s --help for more information") %
(err, prog_name), 0)
return None
opts = {"help": False,
"deal": None,
@ -303,14 +303,13 @@ def pysol_init(app, args):
app.intro.progress.destroy()
d = MfxMessageDialog(top, title=_("%s installation error") % TITLE,
text=_('''
No games were found!!!
No games were found !!!
Main data directory is:
%(dir)s
%s
Please check your %(app)s installation.
''') % {'dir': app.dataloader.dir, 'app': TITLE},
bitmap="error", strings=(_("&Quit"),))
Please check your %s installation.
''') % (app.dataloader.dir, TITLE), bitmap="error", strings=(_("&Quit"),))
return 1
# init cardsets

View file

@ -143,11 +143,7 @@ def getprefdir(package):
# high resolution clock() and sleep()
try:
uclock = time.perf_counter
except Exception:
uclock = time.clock
uclock = time.clock
usleep = time.sleep
if os.name == "posix":
uclock = time.time

View file

@ -4,46 +4,40 @@ import sys
import six
class myLocalGettext(object):
def __init__(self, lang):
self.language = lang
def n_(x):
return x
def translation(self):
domain = gettext._current_domain
localedir = gettext._localedirs.get(domain, None)
if self.language == "":
t = gettext.translation(domain, localedir)
def ungettext(msgid1, msgid2, n):
# unicoded ngettext
if not isinstance(msgid1, six.text_type):
msgid1 = six.text_type(msgid1, 'utf-8')
if not isinstance(msgid2, six.text_type):
msgid2 = six.text_type(msgid2, 'utf-8')
domain = gettext._current_domain
try:
t = gettext.translation(domain,
gettext._localedirs.get(domain, None))
except IOError:
if n == 1:
return msgid1
else:
t = gettext.translation(
domain, localedir, languages=[self.language])
return t
return msgid2
if sys.version_info >= (3, 0):
return t.ngettext(msgid1, msgid2, n)
else:
return t.ungettext(msgid1, msgid2, n)
def maketext(self, msg):
if not isinstance(msg, six.text_type):
return six.text_type(msg, 'utf-8')
return msg
def ungettext(self, msgid1, msgid2, n):
# unicoded ngettext
msgid1 = self.maketext(msgid1)
msgid2 = self.maketext(msgid2)
try:
t = self.translation()
except IOError:
if n == 1:
return msgid1
else:
return msgid2
if sys.version_info >= (3, 0):
return t.ngettext(msgid1, msgid2, n)
else:
return t.ungettext(msgid1, msgid2, n)
def ugettext(self, message):
def fix_gettext():
def ugettext(message):
# unicoded gettext
message = self.maketext(message)
if not isinstance(message, six.text_type):
message = six.text_type(message, 'utf-8')
domain = gettext._current_domain
try:
t = self.translation()
t = gettext.translation(domain,
gettext._localedirs.get(domain, None))
except IOError:
return message
if sys.version_info >= (3, 0):
@ -51,20 +45,10 @@ class myLocalGettext(object):
else:
return t.ugettext(message)
gettext.ugettext = ugettext
myGettext = myLocalGettext('')
def n_(x):
return x
def fix_gettext():
gettext.ugettext = myGettext.ugettext
gettext.ungettext = myGettext.ungettext
gettext.ungettext = ungettext
fix_gettext()
_ = gettext.ugettext
ungettext = gettext.ungettext

View file

@ -25,20 +25,16 @@ import os
import sys
import traceback
import configobj
import pysollib.settings
from pysollib.configobj import configobj, validate
from pysollib.mfxutil import print_err
from pysollib.mygettext import _
from pysollib.mygettext import myGettext
from pysollib.pysoltk import TOOLBAR_BUTTONS, TOOLKIT
from pysollib.resource import CSI
import six
import validate
# ************************************************************************
# * Options
# ************************************************************************
@ -115,7 +111,6 @@ solver_max_iterations = integer
solver_iterations_output_step = integer
solver_preset = string
display_win_message = boolean
language = string
[sound_samples]
move = boolean
@ -257,7 +252,6 @@ class Options:
# ('recent_gameid', 'list'),
# ('favorite_gameid', 'list'),
('display_win_message', 'bool'),
('language', 'str'),
]
def __init__(self):
@ -325,7 +319,6 @@ class Options:
self.negative_bottom = True
self.translate_game_names = True
self.display_win_message = True
self.language = ''
# sound
self.sound = True
self.sound_mode = 1
@ -670,8 +663,6 @@ class Options:
for key in TOOLBAR_BUTTONS:
self.toolbar_vars[key] = (key in visible_buttons)
myGettext.language = self.language
# solver
solver_presets = self._getOption('general', 'solver_presets', 'list')
if solver_presets is not None:

View file

@ -290,7 +290,7 @@ class SelectGameDialogWithPreview(MfxDialog):
for version, vg in GI.GAMES_BY_PYSOL_VERSION:
def selecter(gi, vg=vg):
return gi.id in vg
label = _("New games in v. %(version)s") % {'version': version}
label = _("New games in v. ") + version
data.append((label, selecter))
self._addGamesFromData(data, store, None,
_("by PySol version"), all_games)
@ -423,7 +423,7 @@ class SelectGameDialogWithPreview(MfxDialog):
# self.top.wm_title(
# "Select Game - " + self.app.getGameTitleName(gameid))
title = self.app.getGameTitleName(gameid)
self.set_title(_("Playable Preview - %(game)s") % {'game': title})
self.set_title(_("Playable Preview - ") + title)
#
self.preview_game = gi.gameclass(gi)
self.preview_game.createPreview(self.preview_app)

View file

@ -434,13 +434,13 @@ class HTMLViewer:
for p in REMOTE_PROTOCOLS:
if url.startswith(p):
if not openURL(url):
self.errorDialog(_('''%(app)s HTML limitation:
The %(protocol)s protocol is not supported yet.
self.errorDialog(TITLE + _('''HTML limitation:
The %s protocol is not supported yet.
Please use your standard web browser
to open the following URL:
%(url)s
''') % {'app': TITLE, 'protocol': p, 'url': url})
%s
''') % (p, url))
return
# locate the file relative to the current url

View file

@ -67,8 +67,7 @@ class StatsFormatter(PysolStatsFormatter):
6, result[6],
7, result[7])
total, played, won, lost, time, moves, perc = self.getStatSummary()
text = _("Total (%(played)d out of %(total)d games)") % {
'played': played, 'total': total}
text = _("Total (%d out of %d games)") % (played, total)
iter = self.store.append(None)
self.store.set(iter,
0, text,

View file

@ -24,12 +24,95 @@
# imports
import re
import time
import pysol_cards
assert getattr(pysol_cards, 'VERSION', (0, 0, 0)) >= (0, 8, 7), (
"Newer version of https://pypi.org/project/pysol-cards is required.")
from pysol_cards.random_base import RandomBase # noqa: I100
from pysol_cards.random import MTRandom, match_ms_deal_prefix # noqa: I100
from pysollib.mfxutil import SubclassResponsibility
try:
import random2
except ImportError:
raise ImportError(
"You need to install " +
"https://pypi.python.org/pypi/random2 using pip or similar.")
from pysol_cards.random import RandomBase # noqa: I100
# ************************************************************************
# * Abstract class for PySol Random number generator.
# *
# * We use a seed of type int in the range [0, MAX_SEED].
# ************************************************************************
class BasicRandom(RandomBase):
# MAX_SEED = 0L
# MAX_SEED = 0xffffffffffffffffL # 64 bits
MAX_SEED = int('100000000000000000000') # 20 digits
ORIGIN_UNKNOWN = 0
ORIGIN_RANDOM = 1
ORIGIN_PREVIEW = 2 # random from preview
ORIGIN_SELECTED = 3 # manually entered
ORIGIN_NEXT_GAME = 4 # "Next game number"
def __init__(self):
self.seed_as_string = None
def getSeedStr(self):
return str(self.initial_seed)
def __str__(self):
return self.str(self.initial_seed)
def str(self, seed):
return '%020d' % seed
def reset(self):
raise SubclassResponsibility
def copy(self):
random = self.__class__(0)
random.__dict__.update(self.__dict__)
return random
def increaseSeed(self, seed):
if seed < self.MAX_SEED:
return seed + 1
return 0
def _getRandomSeed(self):
t = int(time.time() * 256.0)
t = (t ^ (t >> 24)) % (self.MAX_SEED + 1)
return t
def setSeedAsStr(self, new_s):
self.seed_as_string = new_s
def getSeedAsStr(self):
if self.seed_as_string:
return self.seed_as_string
else:
return str(self)
# ************************************************************************
# * Mersenne Twister random number generator
# * uses the standard python module `random'
# ************************************************************************
class MTRandom(BasicRandom, random2.Random):
def __init__(self, seed=None):
if seed is None:
seed = self._getRandomSeed()
BasicRandom.__init__(self)
random2.Random.__init__(self, seed)
self.initial_seed = seed
self.initial_state = self.getstate()
self.origin = self.ORIGIN_UNKNOWN
def reset(self):
self.setstate(self.initial_state)
# ************************************************************************
@ -37,12 +120,12 @@ from pysol_cards.random import MTRandom, match_ms_deal_prefix # noqa: I100
# * uses the standard python module `random'
# ************************************************************************
# class WHRandom(RandomBase, random.WichmannHill):
# class WHRandom(BasicRandom, random.WichmannHill):
#
# def __init__(self, seed=None):
# if seed is None:
# seed = self._getRandomSeed()
# RandomBase.__init__(self)
# BasicRandom.__init__(self)
# random.WichmannHill.__init__(self, seed)
# self.initial_seed = seed
# self.initial_state = self.getstate()
@ -56,10 +139,10 @@ from pysol_cards.random import MTRandom, match_ms_deal_prefix # noqa: I100
# ************************************************************************
class MFXRandom(RandomBase):
class MFXRandom(BasicRandom):
def __init__(self, seed=None):
RandomBase.__init__(self)
BasicRandom.__init__(self)
if seed is None:
seed = self._getRandomSeed()
self.initial_seed = self.setSeed(seed)
@ -114,7 +197,7 @@ MS_LONG_BIT = (1 << 1000)
CUSTOM_BIT = (1 << 999)
class CustomRandom(RandomBase):
class CustomRandom(BasicRandom):
def __init__(self):
self.initial_seed = self.seed = MS_LONG_BIT | CUSTOM_BIT
self.origin = self.ORIGIN_UNKNOWN
@ -150,9 +233,7 @@ class LCRandom31(MFXRandom):
return "ms" + str(self.initial_seed)
def str(self, seed):
if match_ms_deal_prefix("{}".format(seed)) is None:
return "%05d" % int(seed)
return seed
return "%05d" % int(seed) if not _match_ms(seed) else seed
def setSeed(self, seed):
seed = int(seed)
@ -194,14 +275,18 @@ PysolRandom = MTRandom
# * PySol support code
# ************************************************************************
def _match_ms(s):
"""match an ms based seed string."""
return re.match(r"ms([0-9]+)\n?\Z", s)
# construct Random from seed string
def constructRandom(s):
if s == 'Custom':
return CustomRandom()
m = match_ms_deal_prefix(s)
if m is not None:
seed = m
m = _match_ms(s)
if m:
seed = int(m.group(1))
if 0 <= seed <= LCRandom31.MAX_SEED:
ret = LCRandom31(seed)
ret.setSeedAsStr(s)
@ -222,9 +307,9 @@ def constructRandom(s):
def random__str2long(s):
if s == 'Custom':
return CUSTOM_BIT | MS_LONG_BIT
m = match_ms_deal_prefix(s)
if m is not None:
return (m | MS_LONG_BIT)
m = _match_ms(s)
if m:
return (int(m.group(1)) | MS_LONG_BIT)
else:
return int(s)

View file

@ -63,8 +63,8 @@ if os.name == 'posix':
DATA_DIRS = [
'/usr/share/PySolFC',
'/usr/local/share/PySolFC',
'/usr/share/games/PySolFC',
'/usr/local/share/games/PySolFC',
'/usr/games/PySolFC',
'/usr/local/games/PySolFC',
]
if os.name == 'nt':
pass

View file

@ -1945,7 +1945,7 @@ class TalonStack(Stack,
nredeals = _('Unlimited redeals.')
else:
n = self.max_rounds-1
nredeals = ungettext('%d redeal', '%d redeals', n) % n
nredeals = ungettext('%d readeal', '%d redeals', n) % n
# round = _('Round #%d.') % self.round
return _('Talon.')+' '+nredeals # +' '+round

View file

@ -199,7 +199,7 @@ class FileStatsFormatter(PysolStatsFormatter):
def writeStats(self, player, sort_by='name'):
if player is None:
player = _('Demo')
header = _("Statistics for %(player)s") % {'player': player}
header = _("Statistics for ") + player
self.writeHeader(header, 62)
header = self.getStatHeader()
self.pstats(*header)
@ -209,8 +209,7 @@ class FileStatsFormatter(PysolStatsFormatter):
self.pstats(gameid=gameid, *result)
self.nl()
total, played, won, lost, time, moves, perc = self.getStatSummary()
self.pstats(_("Total (%(played)d out of %(total)d games)") %
{'played': played, 'total': total},
self.pstats(_("Total (%d out of %d games)") % (played, total),
won+lost, won, lost, time, moves, perc)
self.nl(2)
return played
@ -232,14 +231,14 @@ class FileStatsFormatter(PysolStatsFormatter):
def writeFullLog(self, player):
if player is None:
player = _('Demo')
header = _("Full log for %(player)s") % {'player': player}
header = _("Full log for ") + player
prev_games = self.app.stats.prev_games.get(player)
return self.writeLog(player, header, prev_games)
def writeSessionLog(self, player):
if player is None:
player = _('Demo')
header = _("Session log for %(player)s") % {'player': player}
header = _("Session log for ") + player
prev_games = self.app.stats.session_games.get(player)
return self.writeLog(player, header, prev_games)

View file

@ -1,25 +0,0 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2019 Shlomi Fish <shlomif@cpan.org>
#
# Distributed under terms of the MIT license.
"""
"""
class NewStruct(object):
"""docstring for NewStruct"""
def copy(self):
ret = self.__class__()
ret.__dict__.update(self.__dict__)
return ret
def addattr(self, **kw):
for k in kw.keys():
if k in self.__dict__:
raise AttributeError(k)
self.__dict__.update(kw)

View file

@ -105,8 +105,8 @@ class PysolMenubarTk(PysolMenubarTkCommon):
self._calc_MfxMessageDialog()(
self.top, title=_("Change theme"),
text=_("""\
These settings will take effect
the next time you restart %(app)s""") % {'app': TITLE},
This settings will take effect
the next time you restart """)+TITLE,
bitmap="warning",
default=0, strings=(_("&OK"),))

View file

@ -21,6 +21,7 @@
#
# ---------------------------------------------------------------------------
import os
from pysollib.gamedb import GI
@ -79,8 +80,7 @@ class SelectGameData(SelectDialogTreeData):
def __init__(self, app):
SelectDialogTreeData.__init__(self)
self.all_games_gi = list(map(
app.gdb.get,
app.gdb.getGamesIdSortedByName()))
app.gdb.get, app.gdb.getGamesIdSortedByName()))
self.no_games = [SelectGameLeaf(None, None, _("(no games)"), None), ]
#
s_by_type = s_oriental = s_special = s_original = s_contrib = \
@ -144,7 +144,7 @@ class SelectGameData(SelectDialogTreeData):
if name is None or not list(filter(
select_func, self.all_games_gi)):
continue
name = _("New games in v. %(version)s") % {'version': name}
name = _("New games in v. ") + name
gg.append(SelectGameNode(None, name, select_func))
if 1 and gg:
s_by_pysol_version = SelectGameNode(None, _("by PySol version"),
@ -230,6 +230,8 @@ class SelectGameData(SelectDialogTreeData):
lambda gi: gi.si.redeals == 3),
SelectGameNode(None, _("Unlimited redeals"),
lambda gi: gi.si.redeals == -1),
# SelectGameNode(None, "Variable redeals",
# lambda gi: gi.si.redeals == -2),
SelectGameNode(
None, _("Other number of redeals"),
lambda gi: gi.si.redeals not in (-1, 0, 1, 2, 3)),
@ -319,7 +321,7 @@ class SelectGameDialog(MfxDialog):
if button == 0: # Ok or double click
self.gameid = self.tree.selection_key
self.tree.n_expansions = 1 # save xyview in any case
if button == 1: # Rules
if button == 10: # Rules
doc = self.app.getGameRulesFilename(self.tree.selection_key)
if not doc:
return
@ -513,7 +515,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
# self.top.wm_title("Select Game - " +
# self.app.getGameTitleName(gameid))
title = self.app.getGameTitleName(gameid)
self.top.wm_title(_("Playable Preview - %(game)s") % {'game': title})
self.top.wm_title(_("Playable Preview - ") + title)
#
self.preview_game = gi.gameclass(gi)
self.preview_game.createPreview(self.preview_app)

View file

@ -368,8 +368,7 @@ class TreeFormatter(PysolStatsFormatter):
self.parent_window.games[id] = t8
total, played, won, lost, time_, moves, perc = self.getStatSummary()
text = _("Total (%(played)d out of %(total)d games)") % {
'played': played, 'total': total}
text = _("Total (%d out of %d games)") % (played, total)
id = self.tree.insert("", "end", text=text,
values=(won+lost, won, lost, time_, moves, perc))
self.parent_window.tree_items.append(id)

View file

@ -188,7 +188,7 @@ class PysolToolbarTk:
(n_("Statistics"), self.mPlayerStats, _("View statistics")),
(n_("Rules"), self.mHelpRules, _("Rules for this game")),
(None, None, None),
(n_("Quit"), self.mQuit, _("Quit %s") % TITLE),
(n_("Quit"), self.mQuit, _("Quit ")+TITLE),
):
if label is None:
sep = self._createSeparator()

View file

@ -24,6 +24,7 @@
import os
from pysollib.gamedb import GI
from pysollib.help import help_html
from pysollib.mfxutil import KwStruct, Struct, destruct
from pysollib.mfxutil import format_time
from pysollib.mygettext import _
@ -38,11 +39,11 @@ from .selecttree import SelectDialogTreeCanvas
from .selecttree import SelectDialogTreeLeaf, SelectDialogTreeNode
from .tkwidget import MfxDialog, MfxScrolledCanvas
# ************************************************************************
# * Nodes
# ************************************************************************
class SelectGameLeaf(SelectDialogTreeLeaf):
pass
@ -136,6 +137,7 @@ class SelectGameData(SelectDialogTreeData):
if 1 and gg:
s_by_compatibility = SelectGameNode(None, _("by Compatibility"),
tuple(gg))
pass
#
s_by_pysol_version, gg = None, []
for name, games in GI.GAMES_BY_PYSOL_VERSION:
@ -144,7 +146,7 @@ class SelectGameData(SelectDialogTreeData):
if name is None or not list(filter(
select_func, self.all_games_gi)):
continue
name = _("New games in v. %(version)s") % {'version': name}
name = _("New games in v. ") + name
gg.append(SelectGameNode(None, name, select_func))
if 1 and gg:
s_by_pysol_version = SelectGameNode(None, _("by PySol version"),
@ -165,16 +167,16 @@ class SelectGameData(SelectDialogTreeData):
list(app.gdb.getGamesTuplesSortedByAlternateName()))
#
self.rootnodes = [_f for _f in (
SelectGameNode(None, _("All Games"), None, expanded=0),
SelectGameNode(None, _("All Games"), None),
SelectGameNode(None, _("Alternate Names"), ul_alternate_names),
SelectGameNode(None, _("Popular Games"),
lambda gi: gi.si.game_flags & GI.GT_POPULAR),
s_by_type,
s_mahjongg,
s_oriental,
s_special,
SelectGameNode(None, _("Custom Games"),
lambda gi: gi.si.game_type == GI.GT_CUSTOM),
s_by_type,
SelectGameNode(None, _('by Skill Level'), (
SelectGameNode(None, _('Luck only'),
lambda gi: gi.skill_level == GI.SL_LUCK),
@ -230,6 +232,8 @@ class SelectGameData(SelectDialogTreeData):
lambda gi: gi.si.redeals == 3),
SelectGameNode(None, _("Unlimited redeals"),
lambda gi: gi.si.redeals == -1),
SelectGameNode(None, "Variable redeals",
lambda gi: gi.si.redeals == -2),
SelectGameNode(
None, _("Other number of redeals"),
lambda gi: gi.si.redeals not in (-1, 0, 1, 2, 3)),
@ -304,8 +308,8 @@ class SelectGameDialog(MfxDialog):
def initKw(self, kw):
kw = KwStruct(kw,
strings=(None, None, _("&Cancel"),), default=0,
resizable=True,
separator=True,
resizable=True,
padx=10, pady=10,
buttonpadx=10, buttonpady=5,
)
@ -318,15 +322,14 @@ class SelectGameDialog(MfxDialog):
MfxDialog.destroy(self)
def mDone(self, button):
if button == 0: # Ok or double click
if button == 0: # Ok or double click
self.gameid = self.tree.selection_key
self.tree.n_expansions = 1 # save xyview in any case
if button == 1: # Rules
if button == 1: # Rules
doc = self.app.getGameRulesFilename(self.tree.selection_key)
if not doc:
return
dir = os.path.join("html", "rules")
from pysollib.help import help_html
help_html(self.app, doc, dir, self.top)
return
MfxDialog.mDone(self, button)
@ -433,8 +436,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
def initKw(self, kw):
kw = KwStruct(kw,
strings=((_("&Rules"), 10), 'sep',
_("&Select"), _("&Cancel"),),
strings=(_("&Select"), _("&Rules"), _("&Cancel"),),
default=0,
)
return SelectGameDialog.initKw(self, kw)
@ -514,7 +516,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
# self.top.wm_title("Select Game - " +
# self.app.getGameTitleName(gameid))
title = self.app.getGameTitleName(gameid)
self.top.wm_title(_("Playable Preview - %(game)s") % {'game': title})
self.top.wm_title(_("Playable Preview - ") + title)
#
self.preview_game = gi.gameclass(gi)
self.preview_game.createPreview(self.preview_app)
@ -543,7 +545,7 @@ class SelectGameDialogWithPreview(SelectGameDialog):
#
self.updateInfo(gameid)
#
rules_button = self.buttons[0]
rules_button = self.buttons[1]
if self.app.getGameRulesFilename(gameid):
rules_button.config(state="normal")
else:

View file

@ -410,8 +410,7 @@ class CanvasFormatter(PysolStatsFormatter):
#
y += self.h
total, played, won, lost, time_, moves, perc = self.getStatSummary()
s = _("Total (%(played)d out of %(total)d games)") % {
'played': played, 'total': total}
s = _("Total (%d out of %d games)") % (played, total)
self.pstats(y, (s, won+lost, won, lost, time_, moves, perc))
def writeLog(self, player, prev_games):

View file

@ -188,7 +188,7 @@ class PysolToolbarTk:
(n_("Statistics"), self.mPlayerStats, _("View statistics")),
(n_("Rules"), self.mHelpRules, _("Rules for this game")),
(None, None, None),
(n_("Quit"), self.mQuit, _("Quit %s") % TITLE),
(n_("Quit"), self.mQuit, _("Quit ")+TITLE),
):
if label is None:
sep = self._createSeparator()

View file

@ -293,7 +293,7 @@ class PysolMenubarTkCommon:
if WIN_SYSTEM == "aqua":
applemenu = MfxMenu(self.menubar, "apple")
applemenu.add_command(
label=_("&About %s") % TITLE, command=self.mHelpAbout)
label=_("&About ")+TITLE, command=self.mHelpAbout)
menu = MfxMenu(self.menubar, n_("&File"))
menu.add_command(
@ -663,7 +663,7 @@ class PysolMenubarTkCommon:
if WIN_SYSTEM != "aqua":
menu.add_separator()
menu.add_command(
label=_("&About %s...") % TITLE,
label=n_("&About ")+TITLE+"...",
command=self.mHelpAbout)
MfxMenubar.addPath = None
@ -968,8 +968,7 @@ class PysolMenubarTkCommon:
def updateGamesMenu(self, menu, games):
menu.delete(0, 'last')
if len(games) == 0:
menu.add_radiobutton(label=_('<none>'), name=None,
state='disabled')
menu.add_radiobutton(label='<none>', name=None, state='disabled')
elif len(games) > self.cb_max*4:
games.sort(key=lambda x: x.name)
self._addSelectAllGameSubMenu(games, menu,
@ -1133,8 +1132,7 @@ class PysolMenubarTkCommon:
#
DEFAULTEXTENSION = ".pso"
FILETYPES = ((_("%s files") % TITLE, "*" + DEFAULTEXTENSION),
(_("All files"), "*"))
FILETYPES = ((TITLE+" files", "*"+DEFAULTEXTENSION), ("All files", "*"))
def mAddFavor(self, *event):
gameid = self.app.game.id

View file

@ -25,7 +25,7 @@ class BaseSolverDialog:
def __init__(self, parent, app, **kw):
self.parent = parent
self.app = app
title = _('%(app)s - FreeCell Solver') % {'app': TITLE}
title = TITLE+' - FreeCell Solver'
kw = self.initKw(kw)
self._calc_MfxDialog().__init__(
self, parent, title, kw.resizable, kw.default)

View file

@ -311,13 +311,13 @@ class Base_HTMLViewer:
for p in REMOTE_PROTOCOLS:
if url.startswith(p):
if not openURL(url):
self.errorDialog(_('''%(app)s HTML limitation:
The %(protocol)s protocol is not supported yet.
self.errorDialog(TITLE + _('''HTML limitation:
The %s protocol is not supported yet.
Please use your standard web browser
to open the following URL:
%(url)s
''') % {'app': TITLE, 'protocol': p, 'url': url})
%s
''') % (p, url))
return
# locate the file relative to the current url
@ -429,7 +429,7 @@ to open the following URL:
def errorDialog(self, msg):
self._calc_MfxMessageDialog()(
self.parent, title="%(app)s HTML Problem" % {'app': TITLE},
self.parent, title=TITLE+" HTML Problem",
text=msg,
# bitmap="warning", # FIXME: this interp don't have images
strings=(_("&OK"),), default=0)

View file

@ -150,7 +150,7 @@ def all_games(sort_by='id'):
if gt == 'French':
gt = 'French (%s)' % GAME_BY_TYPE[gi.si.game_type]
name = gi.name
altnames = '<br/>'.join(gi.altnames)
altnames = '<br>'.join(gi.altnames)
fn = os.path.join(rules_dir, rules_fn)
if 1 and os.path.exists(fn):
print('''<tr>

View file

@ -1,61 +1,39 @@
#!/bin/bash
set -eu
# Converts cardset images and config files in subdirs of the current
# directory from input-format to output-format (default: gif to bmp).
# converts cardset images and config files in current
# directory from input-format to output-format.
#
# Example to convert from gif format to png:
# example to convert from gif format to png:
#
# $> cardconv gif png
#
# Needs package 'ImageMagick' being installed.
# needs package 'ImageMagick' beeing installed.
ifo='gif'
ofo='bmp'
if [ $# -eq 2 ]; then
ifo=''
if [ $1 ]
then
ifo=$1
ofo=$2
elif [ $# -ne 0 ]; then
echo "Usage: cardconv [INPUTFORMAT OUTPUTFORMAT]"
echo "If formats are not specified, converts $ifo to $ofo."
exit 1
else
echo 'use: cardconv <input-format> <output-format>'
exit
fi
# Returns true if $1/config.txt exists and contains a mention of the input format
# file extension.
chkdir() {
grep -qi "\.${ifo}" "${1}/config".txt
return $?
}
ofo=''
if [ $2 ]
then
ofo=$2
else
echo 'use: cardconv <input-format> <output-format>'
exit
fi
# Usage: convdir in_dir out_dir
convdir() {
mkdir -p "$2"
# alle images.
for i in *.${ifo}; do convert $i `basename $i .${ifo}`.${ofo}; rm -f $i; done
# Convert all images
if [ $ofo == 'png' ]; then
for i in $1/*.$ifo; do
convert "$i" "-matte" "-quality" "95" "png32:$2/$(basename $i .$ifo).$ofo"
done
else
for i in $1/*.$ifo; do
convert "$i" "$2/$(basename $i .$ifo).$ofo"
done
fi
# Convert config.txt
if [ -f $1/config.txt ]; then
sed "s/\.${ifo}/.${ofo}/g" $1/config.txt > $2/config.txt
fi
}
# Check all cardsets.
for in_dir in cardset-*; do
out_dir=${in_dir}-${ofo}
if [[ ! $in_dir =~ -$ofo$ ]] && [ ! -d $out_dir ] && chkdir $in_dir; then
convdir $in_dir $out_dir
echo "$out_dir created"
fi
done
# config.txt
if [ -f config.txt ]
then
cp -a config.txt tmp.txt
cat tmp.txt | sed "s/.${ifo}/.${ofo}/g" >config.txt
rm -f tmp.txt
fi

77
scripts/cardsetsgiftobmp Executable file
View file

@ -0,0 +1,77 @@
#!/bin/bash
# creates a bmp copy off all gif cardsets in the current dir.
# uses package 'ImageMagick'
ifo='gif'
if [ $1 ]
then
ifo=$1
fi
ofo='bmp'
if [ $2 ]
then
ofo=$2
fi
function chkdir()
{
# convert all images
cd $1
if [ -f config.txt ]
then
g=`grep -i ".${ifo}" config.txt`
#echo $g
if [[ $g == "" ]]
then
cd ..
return 1
else
cd ..
return 0
fi
fi
cd ..
return 0
}
function convdir()
{
# convert all images
for i in *.${ifo}; do convert $i `basename $i .${ifo}`.${ofo}; rm -f $i; done
# convert config.txt
if [ -f config.txt ]
then
cp -a config.txt tmp.txt
cat tmp.txt | sed "s/.${ifo}/.${ofo}/g" >config.txt
rm -f tmp.txt
fi
}
# check all cardsets.
for k in cardset-*
do
x=${k%-bmp}
y=$x-${ofo}
if chkdir $k
then
if [ $k != $y ]
then
if [ -a $y ]
then
echo "$y exists already - skipped"
else
echo "$y processing ..."
cp -a $k $y
cd $y
convdir
cd ..
echo "$y created"
fi
fi
fi
done

View file

@ -7,22 +7,14 @@ import re
from sys import platform
IS_MAC = (platform == "darwin")
TEST_TAGS = os.getenv('TEST_TAGS', '')
def _has_tag(tag):
return re.search("\\b{}\\b".format(tag), TEST_TAGS)
PY_VERS = ([] if _has_tag('SKIP_PY2') else [2])+[3]
SKIP_GTK = _has_tag('SKIP_GTK')
PY_VERS = ([] if re.search("\\bSKIP_PY2\\b",
os.getenv('TEST_TAGS', '')) else [2])+[3]
module_names = []
for d, _, files in os.walk("pysollib"):
for f in files:
if re.search("\\.py$", f):
module_names.append(
(d + "/" + re.sub("\\.py$", "", f))
.replace("/", ".").replace(os.sep, "."))
(d + "/" + re.sub("\\.py$", "", f)).replace("/", "."))
module_names.sort()
for module_name in module_names:
@ -30,7 +22,7 @@ for module_name in module_names:
continue
is_gtk = ("gtk" in module_name)
for ver in PY_VERS:
if ((not is_gtk) or (ver == 2 and (not IS_MAC) and (not SKIP_GTK))):
if ((not is_gtk) or (ver == 2 and (not IS_MAC))):
def fmt(s):
return s % {'module_name': module_name, 'ver': ver}
open(os.path.join(".", "tests", "individually-importing", fmt("import_v%(ver)d_%(module_name)s.py")), 'w').write(fmt('''#!/usr/bin/env python%(ver)d
@ -44,7 +36,6 @@ print('ok 1 - imported')
for ver in PY_VERS:
for mod in [
'pysol_tests.acard_unit',
'pysol_tests.game_drag',
'pysol_tests.hint',
'pysol_tests.import_file1',
'pysol_tests.kpat_load_save',

725
scripts/pygettext.py Executable file
View file

@ -0,0 +1,725 @@
#! /usr/bin/env python3
# -*- coding: iso-8859-1 -*-
# Originally written by Barry Warsaw <barry@zope.com>
#
# Minimally patched to make it even more xgettext compatible
# by Peter Funk <pf@artcom-gmbh.de>
#
# 2002-11-22 Jürgen Hermann <jh@web.de>
# Added checks that _() only contains string literals, and
# command line args are resolved to module lists, i.e. you
# can now pass a filename, a module or package name, or a
# directory (including globbing chars, important for Win32).
# Made docstring fit in 80 chars wide displays using pydoc.
#
# 2007-05-11 Scomoroh <scomoroh@gmail.com>
# Added very simple support for ngettext
#
import functools
import getopt
import glob
import imp
import operator
import os
import sys
import time
import token
import tokenize
from six import PY2, print_
# for selftesting
try:
import fintl
_ = fintl.gettext
except ImportError:
def _(s):
return s
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
internationalization of C programs. Most of these tools are independent of
the programming language and can be used from within Python programs.
Martin von Loewis' work[1] helps considerably in this regard.
There's one problem though; xgettext is the program that scans source code
looking for message strings, but it groks only C (or C++). Python
introduces a few wrinkles, such as dual quoting characters, triple quoted
strings, and raw strings. xgettext understands none of this.
Enter pygettext, which uses Python's standard tokenize module to scan
Python source code, generating .pot files identical to what GNU xgettext[2]
generates for C and C++ code. From there, the standard GNU tools can be
used.
A word about marking Python strings as candidates for translation. GNU
xgettext recognizes the following keywords: gettext, dgettext, dcgettext,
and gettext_noop. But those can be a lot of text to include all over your
code. C and C++ have a trick: they use the C preprocessor. Most
internationalized C source includes a #define for gettext() to _() so that
what has to be written in the source is much less. Thus these are both
translatable strings:
gettext("Translatable String")
_("Translatable String")
Python of course has no preprocessor so this doesn't work so well. Thus,
pygettext searches only for _() by default, but see the -k/--keyword flag
below for how to augment this.
[1] http://www.python.org/workshops/1997-10/proceedings/loewis.html
[2] http://www.gnu.org/software/gettext/gettext.html
NOTE: pygettext attempts to be option and feature compatible with GNU
xgettext where ever possible. However some options are still missing or are
not fully implemented. Also, xgettext's use of command line switches with
option arguments is broken, and in these cases, pygettext just defines
additional switches.
Usage: pygettext [options] inputfile ...
Options:
-a
--extract-all
Extract all strings.
-d name
--default-domain=name
Rename the default output file from messages.pot to name.pot.
-E
--escape
Replace non-ASCII characters with octal escape sequences.
-D
--docstrings
Extract module, class, method, and function docstrings. These do
not need to be wrapped in _() markers, and in fact cannot be for
Python to consider them docstrings. (See also the -X option).
-h
--help
Print this help message and exit.
-k word
--keyword=word
Keywords to look for in addition to the default set, which are:
%(DEFAULTKEYWORDS)s
You can have multiple -k flags on the command line.
-K
--no-default-keywords
Disable the default set of keywords (see above). Any keywords
explicitly added with the -k/--keyword option are still recognized.
--no-location
Do not write filename/lineno location comments.
-n
--add-location
Write filename/lineno location comments indicating where each
extracted string is found in the source. These lines appear before
each msgid. The style of comments is controlled by the -S/--style
option. This is the default.
-o filename
--output=filename
Rename the default output file from messages.pot to filename. If
filename is `-' then the output is sent to standard out.
-p dir
--output-dir=dir
Output files will be placed in directory dir.
-S stylename
--style stylename
Specify which style to use for location comments. Two styles are
supported:
Solaris # File: filename, line: line-number
GNU #: filename:line
The style name is case insensitive. GNU style is the default.
-v
--verbose
Print the names of the files being processed.
-V
--version
Print the version of pygettext and exit.
-w columns
--width=columns
Set width of output to columns.
-x filename
--exclude-file=filename
Specify a file that contains a list of strings that are not be
extracted from the input files. Each string to be excluded must
appear on a line by itself in the file.
-X filename
--no-docstrings=filename
Specify a file that contains a list of files (one per line) that
should not have their docstrings extracted. This is only useful in
conjunction with the -D option above.
If `inputfile' is -, standard input is read.
""")
__version__ = '1.6con'
default_keywords = ['_']
DEFAULTKEYWORDS = ', '.join(default_keywords)
default_ngettext_keywords = ['ngettext']
EMPTYSTRING = ''
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
# there.
pot_header = _('''\
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\\n"
"POT-Creation-Date: %(time)s\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=CHARSET\\n"
"Content-Transfer-Encoding: ENCODING\\n"
"Generated-By: pygettext.py %(version)s\\n"
''')
def usage(code, msg=''):
print_(__doc__ % globals(), file=sys.stderr)
if msg:
print_(msg, file=sys.stderr)
sys.exit(code)
escapes = []
def make_escapes(pass_iso8859):
global escapes
if pass_iso8859:
# Allow iso-8859 characters to pass through so that e.g. 'msgid
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
# escape any character outside the 32..126 range.
mod = 128
else:
mod = 256
for i in range(256):
if 32 <= (i % mod) <= 126:
escapes.append(chr(i))
else:
escapes.append("\\%03o" % i)
escapes[ord('\\')] = '\\\\'
escapes[ord('\t')] = '\\t'
escapes[ord('\r')] = '\\r'
escapes[ord('\n')] = '\\n'
escapes[ord('\"')] = '\\"'
def escape(s):
global escapes
s = list(s)
for i in range(len(s)):
s[i] = escapes[ord(s[i])]
return EMPTYSTRING.join(s)
def safe_eval(s):
# unwrap quotes, safely
return eval(s, {'__builtins__': {}}, {})
def normalize(s):
# This converts the various Python string types into a format that is
# appropriate for .po files, namely much closer to C style.
lines = s.split('\n')
if len(lines) == 1:
s = '"' + escape(s) + '"'
else:
if not lines[-1]:
del lines[-1]
lines[-1] = lines[-1] + '\n'
for i in range(len(lines)):
lines[i] = escape(lines[i])
lineterm = '\\n"\n"'
s = '""\n"' + lineterm.join(lines) + '"'
return s
def containsAny(str, set):
"""Check whether 'str' contains ANY of the chars in 'set'"""
return 1 in [c in str for c in set]
def _visit_pyfiles(list, dirname, names):
"""Helper for getFilesForName()."""
# get extension for python source files
if '_py_ext' not in globals():
global _py_ext
_py_ext = [triple[0] for triple in imp.get_suffixes()
if triple[2] == imp.PY_SOURCE][0]
# don't recurse into CVS directories
if 'CVS' in names:
names.remove('CVS')
# add all *.py files to list
list.extend(
[os.path.join(dirname, file) for file in names
if os.path.splitext(file)[1] == _py_ext]
)
def _get_modpkg_path(dotted_name, pathlist=None):
"""Get the filesystem path for a module or a package.
Return the file system path to a file for a module, and to a directory for
a package. Return None if the name is not found, or is a builtin or
extension module.
"""
# split off top-most name
parts = dotted_name.split('.', 1)
if len(parts) > 1:
# we have a dotted path, import top-level package
try:
file, pathname, description = imp.find_module(parts[0], pathlist)
if file:
file.close()
except ImportError:
return None
# check if it's indeed a package
if description[2] == imp.PKG_DIRECTORY:
# recursively handle the remaining name parts
pathname = _get_modpkg_path(parts[1], [pathname])
else:
pathname = None
else:
# plain name
try:
file, pathname, description = imp.find_module(
dotted_name, pathlist)
if file:
file.close()
if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]:
pathname = None
except ImportError:
pathname = None
return pathname
def getFilesForName(name):
"""Get a list of module files for a filename, a module or package name,
or a directory.
"""
if not os.path.exists(name):
# check for glob chars
if containsAny(name, "*?[]"):
files = glob.glob(name)
list = []
for file in files:
list.extend(getFilesForName(file))
return list
# try to find module or package
name = _get_modpkg_path(name)
if not name:
return []
if os.path.isdir(name):
# find all python files in directory
list = []
os.path.walk(name, _visit_pyfiles, list)
return list
elif os.path.exists(name):
# a single file
return [name]
return []
class TokenEater:
def __init__(self, options):
self.__options = options
self.__messages = {}
self.__state = self.__waiting
self.__data = []
self.__lineno = -1
self.__freshmodule = 1
self.__curfile = None
self.__ngettext = False
def __call__(self, ttype, tstring, stup, etup, line):
# dispatch
# import token
# print >> sys.stderr, 'ttype:', token.tok_name[ttype], \
# 'tstring:', tstring
self.__state(ttype, tstring, stup[0])
def __waiting(self, ttype, tstring, lineno):
opts = self.__options
# Do docstring extractions, if enabled
if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
# module docstring?
if self.__freshmodule:
if ttype == tokenize.STRING:
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
self.__freshmodule = 0
elif ttype not in (tokenize.COMMENT, tokenize.NL):
self.__freshmodule = 0
return
# class docstring?
if ttype == tokenize.NAME and tstring in ('class', 'def'):
self.__state = self.__suiteseen
return
if ttype == tokenize.NAME and tstring in opts.keywords:
self.__state = self.__keywordseen
self.__ngettext = tstring in opts.ngettext_keywords
def __suiteseen(self, ttype, tstring, lineno):
# ignore anything until we see the colon
if ttype == tokenize.OP and tstring == ':':
self.__state = self.__suitedocstring
def __suitedocstring(self, ttype, tstring, lineno):
# ignore any intervening noise
if ttype == tokenize.STRING:
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
self.__state = self.__waiting
elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
tokenize.COMMENT):
# there was no class docstring
self.__state = self.__waiting
def __keywordseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == '(':
self.__data = []
self.__lineno = lineno
self.__state = self.__openseen
else:
self.__state = self.__waiting
def __openseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == ')':
# We've seen the last of the translatable strings. Record the
# line number of the first line of the strings and update the list
# of messages seen. Reset state for the next batch. If there
# were no strings inside _(), then just ignore this entry.
if self.__data:
if self.__ngettext:
data = []
msg = []
for s in self.__data:
if s is not None:
msg.append(s)
else:
data.append(EMPTYSTRING.join(msg))
msg = []
if len(data) == 2 and data[0] and data[1]:
self.__addentry(tuple(data))
elif self.__options.verbose:
print_(_(
'*** %(file)s:%(lineno)s: incorrect '
'ngettext format'
) % {
'file': self.__curfile,
'lineno': self.__lineno}, file=sys.stderr)
else:
self.__addentry(EMPTYSTRING.join(self.__data))
self.__state = self.__waiting
elif ttype == tokenize.STRING:
self.__data.append(safe_eval(tstring))
elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT,
token.NEWLINE, tokenize.NL]:
if self.__ngettext and ttype == tokenize.OP and tstring == ',':
self.__data.append(None)
elif self.__ngettext: # and ttype == tokenize.NUMBER:
pass
else:
# warn if we see anything else than STRING or whitespace
if self.__options.verbose:
print_(_(
'*** %(file)s:%(lineno)s: Seen unexpected '
'token "%(token)s"'
) % {
'token': tstring,
'file': self.__curfile,
'lineno': self.__lineno
}, file=sys.stderr)
self.__state = self.__waiting
def __addentry(self, msg, lineno=None, isdocstring=0):
if lineno is None:
lineno = self.__lineno
if msg not in self.__options.toexclude:
entry = (self.__curfile, lineno)
self.__messages.setdefault(msg, {})[entry] = isdocstring
def set_filename(self, filename):
self.__curfile = filename
self.__freshmodule = 1
def write(self, fp):
options = self.__options
timestamp = time.ctime(time.time())
# The time stamp in the header doesn't have the same format as that
# generated by xgettext...
print_(pot_header % {'time': timestamp, 'version': __version__},
file=fp)
# Sort the entries. First sort each particular entry's keys, then
# sort all the entries by their first item.
reverse = {}
for k, v in self.__messages.items():
keys = list(v.keys())
keys.sort()
reverse.setdefault(tuple(keys), []).append((k, v))
rkeys = list(reverse.keys())
rkeys.sort()
for rkey in rkeys:
rentries = reverse[rkey]
rentries.sort()
for k, v in rentries:
isdocstring = 0
# If the entry was gleaned out of a docstring, then add a
# comment stating so. This is to aid translators who may wish
# to skip translating some unimportant docstrings.
if functools.reduce(operator.__add__, v.values()):
isdocstring = 1
# k is the message string, v is a dictionary-set of (filename,
# lineno) tuples. We want to sort the entries in v first by
# file name and then by line number.
v = list(v.keys())
v.sort()
if not options.writelocations:
pass
# location comments are different b/w Solaris and GNU:
elif options.locationstyle == options.SOLARIS:
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
print_(_('# File: %(filename)s, line: %(lineno)d') % d,
file=fp)
elif options.locationstyle == options.GNU:
# fit as many locations on one line, as long as the
# resulting line length doesn't exceeds 'options.width'
locline = '#:'
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
s = _(' %(filename)s:%(lineno)d') % d
if len(locline) + len(s) <= options.width:
locline = locline + s
else:
print_(locline, file=fp)
locline = "#:" + s
if len(locline) > 2:
print_(locline, file=fp)
if isdocstring:
print_('#, docstring', file=fp)
if isinstance(k, str):
print_('msgid', normalize(k), file=fp)
print_('msgstr ""\n', file=fp)
else:
# ngettext
assert isinstance(k, tuple)
assert len(k) == 2
print_('msgid', normalize(k[0]), file=fp)
print_('msgid_plural', normalize(k[1]), file=fp)
print_('msgstr[0] ""', file=fp)
print_('msgstr[1] ""\n', file=fp)
def main():
global default_keywords
try:
opts, args = getopt.getopt(
sys.argv[1:],
'ad:DEhk:Kno:p:S:Vvw:x:X:',
['extract-all', 'default-domain=', 'escape', 'help',
'keyword=', 'no-default-keywords', 'ngettext-keyword=',
'add-location', 'no-location', 'output=', 'output-dir=',
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
'docstrings', 'no-docstrings',
])
except getopt.error as msg:
usage(1, msg)
# for holding option values
class Options:
# constants
GNU = 1
SOLARIS = 2
# defaults
extractall = 0 # FIXME: currently this option has no effect at all.
escape = 0
keywords = []
ngettext_keywords = []
outpath = ''
outfile = 'messages.pot'
writelocations = 1
locationstyle = GNU
verbose = 0
width = 78
excludefilename = ''
docstrings = 0
nodocstrings = {}
options = Options()
locations = {'gnu': options.GNU,
'solaris': options.SOLARIS,
}
# parse options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-a', '--extract-all'):
options.extractall = 1
elif opt in ('-d', '--default-domain'):
options.outfile = arg + '.pot'
elif opt in ('-E', '--escape'):
options.escape = 1
elif opt in ('-D', '--docstrings'):
options.docstrings = 1
elif opt in ('-k', '--keyword'):
options.keywords.append(arg)
elif opt in ('--ngettext-keyword'):
options.ngettext_keywords.append(arg)
elif opt in ('-K', '--no-default-keywords'):
default_keywords = []
elif opt in ('-n', '--add-location'):
options.writelocations = 1
elif opt in ('--no-location',):
options.writelocations = 0
elif opt in ('-S', '--style'):
options.locationstyle = locations.get(arg.lower())
if options.locationstyle is None:
usage(1, _('Invalid value for --style: %s') % arg)
elif opt in ('-o', '--output'):
options.outfile = arg
elif opt in ('-p', '--output-dir'):
options.outpath = arg
elif opt in ('-v', '--verbose'):
options.verbose = 1
elif opt in ('-V', '--version'):
print(_('pygettext.py (xgettext for Python) %s') % __version__)
sys.exit(0)
elif opt in ('-w', '--width'):
try:
options.width = int(arg)
except ValueError:
usage(1, _('--width argument must be an integer: %s') % arg)
elif opt in ('-x', '--exclude-file'):
options.excludefilename = arg
elif opt in ('-X', '--no-docstrings'):
fp = open(arg)
try:
while 1:
line = fp.readline()
if not line:
break
options.nodocstrings[line[:-1]] = 1
finally:
fp.close()
# calculate escapes
make_escapes(options.escape)
# calculate all keywords
options.keywords.extend(default_keywords)
options.ngettext_keywords.extend(default_ngettext_keywords)
options.keywords.extend(options.ngettext_keywords)
# initialize list of strings to exclude
if options.excludefilename:
try:
fp = open(options.excludefilename)
options.toexclude = fp.readlines()
fp.close()
except IOError:
print_(_("Can't read --exclude-file: %s") %
options.excludefilename, file=sys.stderr)
sys.exit(1)
else:
options.toexclude = []
# resolve args to module lists
expanded = []
for arg in args:
if arg == '-':
expanded.append(arg)
else:
expanded.extend(getFilesForName(arg))
args = expanded
# slurp through all the files
eater = TokenEater(options)
for filename in args:
if filename == '-':
if options.verbose:
print(_('Reading standard input'))
fp = sys.stdin
closep = 0
else:
if options.verbose:
print(_('Working on %s') % filename)
fp = open(filename, 'rb')
closep = 1
try:
eater.set_filename(filename)
try:
if PY2:
for token_info in tokenize.generate_tokens(fp.readline):
eater(*token_info)
else:
for token_info in tokenize.tokenize(fp.readline):
eater(*token_info)
except tokenize.TokenError as e:
print_('%s: %s, line %d, column %d' % (
e[0], filename, e[1][0], e[1][1]), file=sys.stderr)
except tokenize.StopTokenizing:
pass
finally:
if closep:
fp.close()
# write the output
if options.outfile == '-':
fp = sys.stdout
closep = 0
else:
if options.outpath:
options.outfile = os.path.join(options.outpath, options.outfile)
fp = open(options.outfile, 'w')
closep = 1
try:
eater.write(fp)
finally:
if closep:
fp.close()
if __name__ == '__main__':
main()
# some more test strings
_('a unicode string')
# this one creates a warning
_('*** Seen unexpected token "%(token)s"') % {'token': 'test'}
_('more' 'than' 'one' 'string')

5
scripts/repack-min-cardsets.bash Executable file → Normal file
View file

@ -10,9 +10,9 @@ set -e -x
src_base="PySolFC-Cardsets"
dest_base="$src_base--Minimal"
ver="2.0.1"
ver="2.0"
src_vbase="$src_base-2.0"
dest_vbase="$dest_base-2.0.1"
dest_vbase="$dest_base-2.0"
src_arc="$src_vbase.tar.bz2"
if ! test -f "$src_arc"
@ -21,7 +21,6 @@ then
fi
tar -xvf "$src_arc"
rm -rf "$dest_vbase"
mkdir -p "$dest_vbase"
cat scripts/cardsets_to_bundle | (while read b
do

View file

@ -1,6 +1,4 @@
#! /bin/sh
set -e
#
# y.sh
# Copyright (C) 2018 shlomif <shlomif@cpan.org>

Some files were not shown because too many files have changed in this diff Show more