mirror of
https://github.com/shlomif/PySolFC.git
synced 2025-04-15 02:54:09 -04:00
Compare commits
14 commits
2983648a4c
...
dc86d9338d
Author | SHA1 | Date | |
---|---|---|---|
|
dc86d9338d | ||
|
12ca8c5535 | ||
|
6016a6a5c1 | ||
|
300d5dca7a | ||
|
0d98da15e6 | ||
|
e5e60d3232 | ||
|
f5b1cf0eea | ||
|
a34e169031 | ||
|
e09efe375e | ||
|
1365523131 | ||
|
864e7b9b52 | ||
|
25f1b222a1 | ||
|
ad79d2429f | ||
|
11aff68af1 |
17 changed files with 129 additions and 43 deletions
|
@ -37,11 +37,16 @@ test_script:
|
||||||
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySol-Music/PySol-Music-4.50/pysol-music-4.50.tar.xz/download -FileName music.tar.xz
|
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySol-Music/PySol-Music-4.50/pysol-music-4.50.tar.xz/download -FileName music.tar.xz
|
||||||
- 7z x music.tar.xz -so | 7z x -si -ttar
|
- 7z x music.tar.xz -so | 7z x -si -ttar
|
||||||
- move pysol-music-4.50\data\music dist\data\music
|
- move pysol-music-4.50\data\music dist\data\music
|
||||||
- ps: |
|
# - ps: |
|
||||||
$apiUrl = 'https://ci.appveyor.com/api'
|
# $apiUrl = 'https://ci.appveyor.com/api'
|
||||||
$project = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/shlomif/fc-solve"
|
# $project = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/shlomif/fc-solve"
|
||||||
$jobId = $project.build.jobs[0].jobId
|
# $jobId = $project.build.jobs[0].jobId
|
||||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/fc-solve/pkg-build/fc-solve-for-pysol.zip" -OutFile fc-solve.zip
|
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/fc-solve/pkg-build/fc-solve-for-pysol.zip" -OutFile fc-solve.zip
|
||||||
|
#
|
||||||
|
# For reproducible builds:
|
||||||
|
# See: https://reproducible-builds.org/ .
|
||||||
|
- SET FC_SOLVE_VER=5.20.0
|
||||||
|
- appveyor DownloadFile https://netix.dl.sourceforge.net/project/fc-solve/fc-solve/DO-NOT-USE--fc-solve-for-pysol/fc-solve-for-pysol--v%FC_SOLVE_VER%.zip -FileName fc-solve.zip
|
||||||
- 7z x fc-solve.zip
|
- 7z x fc-solve.zip
|
||||||
- move fcs-pysol dist\freecell-solver
|
- move fcs-pysol dist\freecell-solver
|
||||||
- 7z a -r pysol_win_dist.7z dist\
|
- 7z a -r pysol_win_dist.7z dist\
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
[[news]]
|
[[news]]
|
||||||
=== News
|
=== News
|
||||||
|
|
||||||
|
* _TODO, 2020:_ There is a new stable release
|
||||||
|
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.8.0/[PySolFC
|
||||||
|
v2.8.0]. New in this release:
|
||||||
|
** Better kivy/Android support
|
||||||
|
** Using ttk and configobj as shipped in the python dist (instead of forked versions)
|
||||||
|
** Requiring https://pypi.org/project/attrs/[attrs] and https://pypi.org/project/pysol-cards/[pysol-cards] from PyPI
|
||||||
|
** Added tests, bug fixes and refactorings.
|
||||||
|
** Add the +-g+ and +--deal+ command line options.
|
||||||
* _25 April, 2019:_ There is a new stable release
|
* _25 April, 2019:_ There is a new stable release
|
||||||
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.6.4/[PySolFC
|
https://sourceforge.net/projects/pysolfc/files/PySolFC/PySolFC-2.6.4/[PySolFC
|
||||||
v2.6.4]. New in this release:
|
v2.6.4]. New in this release:
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
|
||||||
Prerequisites (needs root):
|
Prerequisites (needs root):
|
||||||
|
|
||||||
|
(For updated information on these subjects please consult the scripts in
|
||||||
|
android/debian).
|
||||||
|
|
||||||
On a 'freshly installed' Ubuntu 16.04 (32bit), the following
|
On a 'freshly installed' Ubuntu 16.04 (32bit), the following
|
||||||
additional packages had to be installed:
|
additional packages had to be installed:
|
||||||
|
|
||||||
|
|
|
@ -18,3 +18,17 @@ apt-get install -y \
|
||||||
lld
|
lld
|
||||||
|
|
||||||
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
|
update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
|
||||||
|
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
imagemagick \
|
||||||
|
python3-tk \
|
||||||
|
ccache \
|
||||||
|
libltdl-dev
|
||||||
|
|
||||||
|
# set python3 as default.
|
||||||
|
# make python alternatives selectable.
|
||||||
|
# (debian stretch, adapt for different versions)
|
||||||
|
|
||||||
|
update-alternatives --install /usr/bin/python python /usr/bin/python2.7 1
|
||||||
|
update-alternatives --install /usr/bin/python python /usr/bin/python3.5 2
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,27 @@ set -eux
|
||||||
|
|
||||||
. mkp4a.common
|
. mkp4a.common
|
||||||
|
|
||||||
if [[ -d $sdkdir && -d $ndkdir ]]; then
|
urlbase=https://dl.google.com/android/repository/
|
||||||
echo "Skipping SDK and NDK installation: SDK and NDK directories already exist."
|
|
||||||
exit
|
if [[ -d $ndkdir ]]; then
|
||||||
|
echo "Skipping NDK installation: NDK directory already exists."
|
||||||
|
else
|
||||||
|
mkdir -p $ndkdir
|
||||||
|
ndk_zip=android-ndk-${ndkver}-linux-x86_64.zip
|
||||||
|
[ -a $ndk_zip ] || wget $urlbase/$ndk_zip
|
||||||
|
unzip -d $(dirname $ndkdir) $ndk_zip
|
||||||
fi
|
fi
|
||||||
|
|
||||||
urlbase=https://dl.google.com/android/repository/
|
if [[ -d $sdkdir ]]; then
|
||||||
tools_zip=sdk-tools-linux-4333796.zip
|
echo "Skipping SDK installation: SDK directory already exists."
|
||||||
ndk_zip=android-ndk-r17c-linux-x86_64.zip
|
else
|
||||||
|
mkdir -p $sdkdir
|
||||||
|
tools_zip=sdk-tools-linux-4333796.zip
|
||||||
|
[ -a $tools_zip ] || wget $urlbase/$tools_zip
|
||||||
|
unzip -d $sdkdir $tools_zip
|
||||||
|
|
||||||
mkdir -p $sdkdir $ndkdir
|
$sdkdir/tools/bin/sdkmanager 'platforms;android-27'
|
||||||
|
$sdkdir/tools/bin/sdkmanager 'build-tools;29.0.1'
|
||||||
|
fi
|
||||||
|
|
||||||
[ -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'
|
|
||||||
|
|
|
@ -8,8 +8,11 @@ tmpdir=${HOME}/.cache/tmp-for-p4a/pysolfc/src
|
||||||
cardsets_dir='PySolFC-Cardsets--Minimal-2.0.1'
|
cardsets_dir='PySolFC-Cardsets--Minimal-2.0.1'
|
||||||
cardsets_file="${cardsets_dir}.tar.xz"
|
cardsets_file="${cardsets_dir}.tar.xz"
|
||||||
|
|
||||||
|
p4aver="2019.10.6"
|
||||||
|
ndkver="r19c"
|
||||||
|
|
||||||
sdkdir="${HOME}/.cache/sdk-for-p4a/sdk"
|
sdkdir="${HOME}/.cache/sdk-for-p4a/sdk"
|
||||||
ndkdir="${HOME}/.cache/sdk-for-p4a/android-ndk-r17c"
|
ndkdir="${HOME}/.cache/sdk-for-p4a/android-ndk-${ndkver}"
|
||||||
pkgdir="${HOME}/.local/share/python-for-android/packages"
|
pkgdir="${HOME}/.local/share/python-for-android/packages"
|
||||||
|
|
||||||
# gradle may need this.
|
# gradle may need this.
|
||||||
|
@ -27,7 +30,7 @@ p4a_options="\
|
||||||
--private ${tmpdir} \
|
--private ${tmpdir} \
|
||||||
--orientation sensor \
|
--orientation sensor \
|
||||||
--icon ${tmpdir}/data/images/icons/48x48/pysol.png \
|
--icon ${tmpdir}/data/images/icons/48x48/pysol.png \
|
||||||
--presplash ${tmpdir}/data/images/icons/1024x1024/pysol.png \
|
--presplash ${tmpdir}/data/images/logo-with-margin-1024.png \
|
||||||
--copy-libs \
|
--copy-libs \
|
||||||
--add-jar ${tmpdir}/support-v4-24.1.1.aar \
|
--add-jar ${tmpdir}/support-v4-24.1.1.aar \
|
||||||
--color always"
|
--color always"
|
||||||
|
|
|
@ -17,7 +17,16 @@ echo '### install p4a'
|
||||||
|
|
||||||
if [[ $# == 0 ]]
|
if [[ $# == 0 ]]
|
||||||
then
|
then
|
||||||
python3 -m pip install -q --user python-for-android
|
if not python3 -m pip install -q --user "python-for-android==${p4aver}"
|
||||||
|
then
|
||||||
|
echo "obviously inside a virtualenv, so omit --user"
|
||||||
|
if python3 -m pip install -q "python-for-android==${p4aver}"
|
||||||
|
then
|
||||||
|
echo "done"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "done"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo '### prepare source'
|
echo '### prepare source'
|
||||||
|
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
@ -31,6 +31,7 @@ from kivy.base import EventLoop
|
||||||
from kivy.base import stopTouchApp
|
from kivy.base import stopTouchApp
|
||||||
from kivy.cache import Cache
|
from kivy.cache import Cache
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
from kivy.config import Config
|
||||||
from kivy.core.audio import SoundLoader
|
from kivy.core.audio import SoundLoader
|
||||||
from kivy.core.window import Window
|
from kivy.core.window import Window
|
||||||
from kivy.graphics import Color
|
from kivy.graphics import Color
|
||||||
|
@ -54,6 +55,9 @@ from kivy.utils import platform
|
||||||
|
|
||||||
from pysollib.kivy.androidperms import requestStoragePerm
|
from pysollib.kivy.androidperms import requestStoragePerm
|
||||||
|
|
||||||
|
if platform != 'android':
|
||||||
|
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@ -713,13 +717,27 @@ class LImageItem(BoxLayout, LBase):
|
||||||
# ev. noch globales cache für stacks->game und cards->stack
|
# ev. noch globales cache für stacks->game und cards->stack
|
||||||
# einrichten. Aber: stacks hängt vom jeweiligen spiel ab.
|
# einrichten. Aber: stacks hängt vom jeweiligen spiel ab.
|
||||||
|
|
||||||
def send_event_pressed_1(self, event):
|
def send_event_pressed_n(self, event, n):
|
||||||
if self.group and '<1>' in self.group.bindings:
|
if self.group and n in self.group.bindings:
|
||||||
self.group.bindings['<1>'](event)
|
self.group.bindings[n](event)
|
||||||
|
|
||||||
def send_event_pressed_double_1(self, event):
|
def send_event_pressed(self, touch, event):
|
||||||
if self.group and '<Double-1>' in self.group.bindings:
|
|
||||||
self.group.bindings['<Double-1>'](event)
|
if touch.is_double_tap:
|
||||||
|
self.send_event_pressed_n(event, '<Double-1>')
|
||||||
|
else:
|
||||||
|
button = 'left'
|
||||||
|
if 'button' in touch.profile:
|
||||||
|
button = touch.button
|
||||||
|
if button == 'left':
|
||||||
|
self.send_event_pressed_n(event, '<1>')
|
||||||
|
return
|
||||||
|
if button == 'middle':
|
||||||
|
self.send_event_pressed_n(event, '<2>')
|
||||||
|
return
|
||||||
|
if button == 'right':
|
||||||
|
self.send_event_pressed_n(event, '<3>')
|
||||||
|
return
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
def on_touch_down(self, touch):
|
||||||
|
|
||||||
|
@ -743,10 +761,7 @@ class LImageItem(BoxLayout, LBase):
|
||||||
event.y = ppos[1]
|
event.y = ppos[1]
|
||||||
self.dragstart = touch.pos
|
self.dragstart = touch.pos
|
||||||
event.cardid = i
|
event.cardid = i
|
||||||
if touch.is_double_tap:
|
self.send_event_pressed(touch, event)
|
||||||
self.send_event_pressed_double_1(event)
|
|
||||||
else:
|
|
||||||
self.send_event_pressed_1(event)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if self.group is not None:
|
if self.group is not None:
|
||||||
|
@ -1777,10 +1792,9 @@ class LApp(App):
|
||||||
|
|
||||||
def doSize(self, obj, val):
|
def doSize(self, obj, val):
|
||||||
mval = self.mainWindow.size
|
mval = self.mainWindow.size
|
||||||
logging.info("LApp: size changed %s - %s (%s)" % (obj, val, mval))
|
if (val[0] != mval[0] and val[1] != mval[1]):
|
||||||
# Clock.schedule_once(self.delayedRebuild, 0.01)
|
logging.info("LApp: size changed %s - %s (%s)" % (obj, val, mval))
|
||||||
Clock.schedule_once(self.makeDelayedRebuild(), 0.01)
|
Clock.schedule_once(self.makeDelayedRebuild(), 0.01)
|
||||||
# self.mainWindow.rebuildContainer()
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
|
|
|
@ -93,7 +93,7 @@ def parse_option(argv):
|
||||||
"sound-mod=",
|
"sound-mod=",
|
||||||
"help"])
|
"help"])
|
||||||
except getopt.GetoptError as err:
|
except getopt.GetoptError as err:
|
||||||
print_err(err + "\n" + _("try %s --help for more information") %
|
print_err(str(err) + "\n" + _("try %s --help for more information") %
|
||||||
prog_name, 0)
|
prog_name, 0)
|
||||||
return None
|
return None
|
||||||
opts = {"help": False,
|
opts = {"help": False,
|
||||||
|
|
|
@ -393,7 +393,6 @@ class SelectGameDialogWithPreview(MfxDialog):
|
||||||
audio=self.app.audio,
|
audio=self.app.audio,
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
cardset=self.app.cardset.copy(),
|
cardset=self.app.cardset.copy(),
|
||||||
comments=self.app.comments.new(),
|
|
||||||
gamerandom=self.app.gamerandom,
|
gamerandom=self.app.gamerandom,
|
||||||
gdb=self.app.gdb,
|
gdb=self.app.gdb,
|
||||||
gimages=self.app.gimages,
|
gimages=self.app.gimages,
|
||||||
|
|
|
@ -32,7 +32,7 @@ PACKAGE = 'PySolFC'
|
||||||
TITLE = 'PySol'
|
TITLE = 'PySol'
|
||||||
PACKAGE_URL = 'http://pysolfc.sourceforge.net/'
|
PACKAGE_URL = 'http://pysolfc.sourceforge.net/'
|
||||||
|
|
||||||
VERSION_TUPLE = (2, 6, 4)
|
VERSION_TUPLE = (2, 8, 0)
|
||||||
VERSION = '.'.join(map(str, VERSION_TUPLE))
|
VERSION = '.'.join(map(str, VERSION_TUPLE))
|
||||||
|
|
||||||
# Tk windowing system (auto set up in init.py)
|
# Tk windowing system (auto set up in init.py)
|
||||||
|
|
|
@ -319,13 +319,14 @@ class SelectGameDialog(MfxDialog):
|
||||||
if button == 0: # Ok or double click
|
if button == 0: # Ok or double click
|
||||||
self.gameid = self.tree.selection_key
|
self.gameid = self.tree.selection_key
|
||||||
self.tree.n_expansions = 1 # save xyview in any case
|
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)
|
doc = self.app.getGameRulesFilename(self.tree.selection_key)
|
||||||
if not doc:
|
if not doc:
|
||||||
return
|
return
|
||||||
dir = os.path.join("html", "rules")
|
dir = os.path.join("html", "rules")
|
||||||
from pysollib.help import help_html
|
from pysollib.help import help_html
|
||||||
help_html(self.app, doc, dir, self.top)
|
help_html(self.app, doc, dir, self.top)
|
||||||
|
self.top.grab_release() # Don't want the help window appear frozen
|
||||||
return
|
return
|
||||||
MfxDialog.mDone(self, button)
|
MfxDialog.mDone(self, button)
|
||||||
|
|
||||||
|
@ -483,7 +484,6 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
audio=self.app.audio,
|
audio=self.app.audio,
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
cardset=self.app.cardset.copy(),
|
cardset=self.app.cardset.copy(),
|
||||||
comments=self.app.comments.new(),
|
|
||||||
gamerandom=self.app.gamerandom,
|
gamerandom=self.app.gamerandom,
|
||||||
gdb=self.app.gdb,
|
gdb=self.app.gdb,
|
||||||
gimages=self.app.gimages,
|
gimages=self.app.gimages,
|
||||||
|
|
|
@ -484,7 +484,6 @@ class SelectGameDialogWithPreview(SelectGameDialog):
|
||||||
audio=self.app.audio,
|
audio=self.app.audio,
|
||||||
canvas=canvas,
|
canvas=canvas,
|
||||||
cardset=self.app.cardset.copy(),
|
cardset=self.app.cardset.copy(),
|
||||||
comments=self.app.comments.new(),
|
|
||||||
gamerandom=self.app.gamerandom,
|
gamerandom=self.app.gamerandom,
|
||||||
gdb=self.app.gdb,
|
gdb=self.app.gdb,
|
||||||
gimages=self.app.gimages,
|
gimages=self.app.gimages,
|
||||||
|
|
|
@ -110,7 +110,7 @@ def makeToplevel(parent, title=None):
|
||||||
def make_help_toplevel(app, title=None):
|
def make_help_toplevel(app, title=None):
|
||||||
# Create an independent Toplevel window.
|
# Create an independent Toplevel window.
|
||||||
from pysollib.winsystems import init_root_window
|
from pysollib.winsystems import init_root_window
|
||||||
window = tkinter.Tk(className=TITLE)
|
window = tkinter.Toplevel(class_=TITLE)
|
||||||
init_root_window(window, app)
|
init_root_window(window, app)
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
|
|
@ -167,5 +167,22 @@ class DataLoader:
|
||||||
filename += ('.ico' if os.name == 'nt' else '.xbm')
|
filename += ('.ico' if os.name == 'nt' else '.xbm')
|
||||||
return self.findFile(filename, subdirs)
|
return self.findFile(filename, subdirs)
|
||||||
|
|
||||||
|
def findAllIconSizes(self, filename='pysol.png'):
|
||||||
|
try:
|
||||||
|
icondir = self.findDir(os.path.join('images', 'icons'))
|
||||||
|
icons = [os.path.join(icondir, subdir, filename) for subdir in
|
||||||
|
os.listdir(icondir)]
|
||||||
|
except OSError:
|
||||||
|
try:
|
||||||
|
# pysol06.png is known to have transparent borders around it
|
||||||
|
# which is unsuitable for a window icon
|
||||||
|
icon_blacklist = ('pysol06.png',)
|
||||||
|
miscdir = self.findDir(os.path.join('images', 'misc'))
|
||||||
|
icons = [os.path.join(miscdir, f) for f in os.listdir(miscdir)
|
||||||
|
if f not in icon_blacklist]
|
||||||
|
except OSError:
|
||||||
|
icons = []
|
||||||
|
return filter(os.path.isfile, icons)
|
||||||
|
|
||||||
def findDir(self, filename, subdirs=None):
|
def findDir(self, filename, subdirs=None):
|
||||||
return self.__findFile(os.path.isdir, filename, subdirs)
|
return self.__findFile(os.path.isdir, filename, subdirs)
|
||||||
|
|
|
@ -32,6 +32,7 @@ from pysollib.settings import TOOLKIT, USE_TILE
|
||||||
from pysollib.settings import VERSION
|
from pysollib.settings import VERSION
|
||||||
|
|
||||||
if TOOLKIT == 'tk':
|
if TOOLKIT == 'tk':
|
||||||
|
from pysollib.ui.tktile.tkutil import loadImage
|
||||||
if USE_TILE:
|
if USE_TILE:
|
||||||
from six.moves import tkinter_ttk as ttk
|
from six.moves import tkinter_ttk as ttk
|
||||||
|
|
||||||
|
@ -89,6 +90,15 @@ def base_init_root_window(root, app):
|
||||||
# root.wm_group(root)
|
# root.wm_group(root)
|
||||||
root.wm_title(TITLE + ' ' + VERSION)
|
root.wm_title(TITLE + ' ' + VERSION)
|
||||||
root.wm_iconname(TITLE + ' ' + VERSION)
|
root.wm_iconname(TITLE + ' ' + VERSION)
|
||||||
|
|
||||||
|
if TOOLKIT == 'tk':
|
||||||
|
icons = [loadImage(img) for img in app.dataloader.findAllIconSizes()]
|
||||||
|
if icons:
|
||||||
|
try:
|
||||||
|
root.wm_iconphoto(True, *icons)
|
||||||
|
except AttributeError:
|
||||||
|
root.tk.call('wm', 'iconphoto', root, '-default', *icons)
|
||||||
|
|
||||||
# set minsize
|
# set minsize
|
||||||
sw, sh = (root.winfo_screenwidth(), root.winfo_screenheight())
|
sw, sh = (root.winfo_screenwidth(), root.winfo_screenheight())
|
||||||
if sw < 640 or sh < 480:
|
if sw < 640 or sh < 480:
|
||||||
|
|
Loading…
Add table
Reference in a new issue