Compare commits

...

81 Commits
v1.9 ... master

Author SHA1 Message Date
Pacman Ghost 19734ac076 Updated for VASSAL 3.6.7 and VASL 6.6.5. 5 months ago
Pacman Ghost 85b625d54e Updated links to point to pacman-ghost.com. 5 months ago
Pacman Ghost 446a53b32f Fixed a possible timing error during startup. 5 months ago
Pacman Ghost c7a002b1c6 Fixed a test to work inside a Docker container with no internet access. 5 months ago
Pacman Ghost 8172fa7070 Allow the Canadians to generate a PIAT snippet. 5 months ago
Pacman Ghost 330d05e47d Don't show the loading spinner if Javascript is disabled. 5 months ago
Pacman Ghost b285a044ab Updated the documentation. 6 months ago
Pacman Ghost c555614ac6 Updated the examples. 6 months ago
Pacman Ghost 618fe3bd68 Tweaked a log message. 6 months ago
Pacman Ghost 0b720dc8bc Automatically set up basic logging for the desktop app. 6 months ago
Pacman Ghost 499e5645bc When loading a scenario, forget the previous .vsav file used. 6 months ago
Pacman Ghost fc3e1110f8 Worked around a layout problem when the Victory Conditions are long. 6 months ago
Pacman Ghost 8388cec67e Added large flags to the WYSIWYG editor's dropdown. 6 months ago
Pacman Ghost 569edbc48a Added shortcuts for Alt-Shift-< and >. 7 months ago
Pacman Ghost db7fecbc39 Optimized searching for scenarios. 7 months ago
Pacman Ghost 380dae5559 Merged the Extras templates for Kampfgruppe Scherer. 7 months ago
Pacman Ghost e5ad66658a Set focus to the correct default button if there are nested dialogs. 7 months ago
Pacman Ghost c5e1e53df4 Extended the files/directories monitored for Flask hot-reloading. 7 months ago
Pacman Ghost d00d809877 Don't reset the current directory for saving/loading files on "new scenario". 7 months ago
Pacman Ghost c4c2010170 Updated the National Capabilities label for the Free French. 7 months ago
Pacman Ghost c2e0b48343 Added Alt-Click handlers. 7 months ago
Pacman Ghost 0e0df4e3a6 Tightened up some tests. 7 months ago
Pacman Ghost d78ac34c1f Handle missing landing craft Chapter H notes. 7 months ago
Pacman Ghost 05933ad753 Reset the HTML editor controls each time they are used. 7 months ago
Pacman Ghost f6e5081605 Adjusted the layout of the SCENARIO panel. 7 months ago
Pacman Ghost b31f64ed7f Show an indicator when an HTML textbox goes multi-line. 7 months ago
Pacman Ghost 2d317c57bd Moved the "edit template" buttons into a drop-down menu. 7 months ago
Pacman Ghost 941439a2ae Allowed Extras templates to set the width of their dropdown's. 7 months ago
Pacman Ghost 071b6f587d Stopped incorrectly detecting "split MG" v/o comments as having been changed. 7 months ago
Pacman Ghost 437865b47d Improved time-based comments in the Axis Minor nat.caps. snippets. 7 months ago
Pacman Ghost 650a6f86d4 Grouped notes in Nationality Capabilities snippets. 7 months ago
Pacman Ghost 0682dc1dca Added an Extras template for Booby Traps. 7 months ago
Pacman Ghost 4ae19ca212 Tightened up how we detect if HTML content has been changed. 7 months ago
Pacman Ghost e7888e88e0 Cached V/O note images for extensions are now saved in their own sub-directory. 7 months ago
Pacman Ghost 1294d0e3d2 Store config and data files in the standard locations. 7 months ago
Pacman Ghost fbcf4e9184 Confirm closing the EDIT V/O dialog if changes have been made. 7 months ago
Pacman Ghost 6d261032be Improved the keyboard interface in the TURN TRACK dialog. 7 months ago
Pacman Ghost 4629b3421b Only show custom list bullets in the UI if they have been enabled. 7 months ago
Pacman Ghost 53e14f753f Allow single-line textbox's to be edited as HTML. 7 months ago
Pacman Ghost a09286bc50 Include the build git info in the SCENARIO template. 7 months ago
Pacman Ghost 4762a36eb6 Removed code supporting Internet Explorer. 7 months ago
Pacman Ghost 23256bbc63 Tightened up some tests. 7 months ago
Pacman Ghost 2628105ea9 Minor UI tweaks. 7 months ago
Pacman Ghost 77b1bc9548 Allow SSR snippets to be auto-generated. 7 months ago
Pacman Ghost ee4d8fbe02 Fixed a problem when auto-generating a simple note snippet with no content. 7 months ago
Pacman Ghost 2ee42f37b5 Tightened up the presentation of lists in the UI and snippets. 7 months ago
Pacman Ghost 15c632b522 Sanitize HTML content. 7 months ago
Pacman Ghost c420c168d1 Added a WYSIWYG editor for HTML content. 7 months ago
Pacman Ghost d5021f7960 Added the ASA and ROAR ID's to the SCENARIO template. 7 months ago
Pacman Ghost daef7c1c15 Gave VASSAL tests more time to run. 7 months ago
Pacman Ghost b10105f2a7 Improved the positioning and sizing of dialogs. 7 months ago
Pacman Ghost 6b909a37eb Changed how flags are resized. 7 months ago
Pacman Ghost 7e070c3b68 Update the UI after importing an ASA scenario. 8 months ago
Pacman Ghost 0312fa2fc7 Confirm closing the "add/edit simple note" dialog if changes have been made. 8 months ago
Pacman Ghost 95167f4888 Allow snippets to be generated from the "add/edit simple note" dialog. 8 months ago
Pacman Ghost 2a707863d2 Fixed a timing error during startup. 8 months ago
Pacman Ghost 13a1b511e6 Added splitters to make some UI elements resizable. 8 months ago
Pacman Ghost a556d22117 Got 1/2" counters showing at the smaller size again. 8 months ago
Pacman Ghost a52e7f8ba9 Added a splitter to the "edit vehicle/ordnance" dialog. 8 months ago
Pacman Ghost fa5a99e87c Changed how Java is detected (and reported) from the PATH. 8 months ago
Pacman Ghost 7f17a634eb Updated some icons, tightened up the UI. 8 months ago
Pacman Ghost fbc420d4b3 Tightened up the player flags. 8 months ago
Pacman Ghost feebe9f63c Disable snippet-width textbox's when disabling snippet buttons. 8 months ago
Pacman Ghost e479bf2a76 Removed the "Width:" labels from the UI. 8 months ago
Pacman Ghost 520ea43d9d Tidy-up strings coming from ROAR and ASA. 8 months ago
Pacman Ghost ff0f40b22b Tightened up how we map ASA theaters to our own. 8 months ago
Pacman Ghost 55c15e5157 Made the compass label part of the default template pack. 8 months ago
Pacman Ghost 757c78dbd8 Removed the text caption from some snippet buttons. 8 months ago
Pacman Ghost 1079ac7e60 Got the LFA tests going again in Firefox. 9 months ago
Pacman Ghost d165bfdefd Allow multiple levels of shading in the turn track. 9 months ago
Pacman Ghost 729c6e306d Reset the turn track when importing a scenario. 9 months ago
Pacman Ghost cd831446fd Allow turn track squares to be shaded. 9 months ago
Pacman Ghost 40c2b87cbe Added a new extras template for the compass. 9 months ago
Pacman Ghost bc724e426d Removed the option to create National Capabilities labels. 9 months ago
Pacman Ghost c850bbd281 Tweaked the presentation of the "VASSAL shim error" dialog. 9 months ago
Pacman Ghost 42cad6f87c Fixed a resizing problem in the "connect to ROAR" dialog. 9 months ago
Pacman Ghost c363acb73e Added more padding to dialogs. 9 months ago
Pacman Ghost c5cdaf27dd Return a spacer image as a flag for nationalities that don't have one. 9 months ago
Pacman Ghost 0966c08dd4 Added the turn track template. 9 months ago
Pacman Ghost 3a5e472b36 Updated dependencies. 9 months ago
Pacman Ghost f93888c51b Updated the version strings. 10 months ago
  1. 87
      .pylintrc
  2. 8
      Dockerfile
  3. 8
      README.md
  4. 9
      conftest.py
  5. 2
      docker/config/site.cfg
  6. BIN
      examples/Hill 621 (Scenario E) (online).vsav
  7. 32
      examples/Hill 621 (Scenario E).json
  8. BIN
      examples/Hill 621 (Scenario E).png
  9. BIN
      examples/Hill 621 (Scenario E).small.jpg
  10. BIN
      examples/Hill 621 (Scenario E).vsav
  11. BIN
      examples/Hube's Pocket (Scenario G) (online).vsav
  12. 30
      examples/Hube's Pocket (Scenario G).json
  13. BIN
      examples/Hube's Pocket (Scenario G).png
  14. BIN
      examples/Hube's Pocket (Scenario G).small.jpg
  15. BIN
      examples/Hube's Pocket (Scenario G).vsav
  16. 2
      examples/README.md
  17. BIN
      examples/The Streets Of Stalingrad (Scenario C) (online).vsav
  18. 30
      examples/The Streets Of Stalingrad (Scenario C).json
  19. BIN
      examples/The Streets Of Stalingrad (Scenario C).png
  20. BIN
      examples/The Streets Of Stalingrad (Scenario C).small.jpg
  21. BIN
      examples/The Streets Of Stalingrad (Scenario C).vsav
  22. 4
      freeze.py
  23. 2
      loader/freeze.py
  24. 6
      loader/main.py
  25. 10
      requirements-dev.txt
  26. 13
      requirements.txt
  27. 4
      setup.py
  28. 4
      vasl_templates/about.py
  29. 19
      vasl_templates/file_dialog.py
  30. 25
      vasl_templates/main.py
  31. 21
      vasl_templates/main_window.py
  32. 4
      vasl_templates/server_settings.py
  33. 75
      vasl_templates/tools/get_piece_info.py
  34. 27
      vasl_templates/ui/about.ui
  35. 2
      vasl_templates/ui/server_settings.ui
  36. 26
      vasl_templates/utils.py
  37. 4
      vasl_templates/web_channel.py
  38. 60
      vasl_templates/webapp/__init__.py
  39. 2
      vasl_templates/webapp/config/constants.py
  40. 4
      vasl_templates/webapp/config/logging.yaml.example
  41. 2
      vasl_templates/webapp/config/site.cfg.example
  42. 5
      vasl_templates/webapp/data/asl-scenario-archive.json
  43. 2
      vasl_templates/webapp/data/default-template-pack/common.css
  44. 5
      vasl_templates/webapp/data/default-template-pack/compass.j2
  45. 34
      vasl_templates/webapp/data/default-template-pack/extras/booby-traps.j2
  46. 2
      vasl_templates/webapp/data/default-template-pack/extras/count-remaining.j2
  47. 4
      vasl_templates/webapp/data/default-template-pack/extras/grid.j2
  48. 2
      vasl_templates/webapp/data/default-template-pack/extras/kakazu-ridge-cave-complexes.j2
  49. 36
      vasl_templates/webapp/data/default-template-pack/extras/kgs.j2
  50. 49
      vasl_templates/webapp/data/default-template-pack/extras/kgs/grenade-bundles.j2
  51. 2
      vasl_templates/webapp/data/default-template-pack/extras/victory-points.j2
  52. 15
      vasl_templates/webapp/data/default-template-pack/nat_caps.j2
  53. 217
      vasl_templates/webapp/data/default-template-pack/national-capabilities.json
  54. 5
      vasl_templates/webapp/data/default-template-pack/ob_vo_note.css
  55. 2
      vasl_templates/webapp/data/default-template-pack/player_flag.include
  56. 2
      vasl_templates/webapp/data/default-template-pack/player_flag_large.include
  57. 4
      vasl_templates/webapp/data/default-template-pack/players.j2
  58. 4
      vasl_templates/webapp/data/default-template-pack/scenario.j2
  59. 2
      vasl_templates/webapp/data/default-template-pack/ssr.j2
  60. 116
      vasl_templates/webapp/data/default-template-pack/turn_track.j2
  61. 65
      vasl_templates/webapp/data/vasl-6.6.0/piece-info.json
  62. 65
      vasl_templates/webapp/data/vasl-6.6.1/piece-info.json
  63. 65
      vasl_templates/webapp/data/vasl-6.6.2/piece-info.json
  64. 65
      vasl_templates/webapp/data/vasl-6.6.3/piece-info.json
  65. 65
      vasl_templates/webapp/data/vasl-6.6.4/piece-info.json
  66. 49
      vasl_templates/webapp/data/vasl-6.6.5/expected-multiple-images.json
  67. 2
      vasl_templates/webapp/data/vasl-6.6.5/online-counter-images.json
  68. 65
      vasl_templates/webapp/data/vasl-6.6.5/piece-info.json
  69. 147
      vasl_templates/webapp/data/vasl-6.6.5/vasl-overrides.json
  70. 8
      vasl_templates/webapp/data/vehicles/german.json
  71. 19
      vasl_templates/webapp/downloads.py
  72. 1
      vasl_templates/webapp/globvars.py
  73. 2
      vasl_templates/webapp/lfa.py
  74. 79
      vasl_templates/webapp/main.py
  75. 3
      vasl_templates/webapp/run_server.py
  76. 32
      vasl_templates/webapp/scenarios.py
  77. 64
      vasl_templates/webapp/snippets.py
  78. 1679
      vasl_templates/webapp/static/DOMPurify/purify.js
  79. 1
      vasl_templates/webapp/static/DOMPurify/purify.js.map
  80. 3
      vasl_templates/webapp/static/DOMPurify/purify.min.js
  81. 1
      vasl_templates/webapp/static/DOMPurify/purify.min.js.map
  82. 5
      vasl_templates/webapp/static/css/custom-bullets.css
  83. 11
      vasl_templates/webapp/static/css/desktop.css
  84. 4
      vasl_templates/webapp/static/css/edit-html-textbox-dialog.css
  85. 4
      vasl_templates/webapp/static/css/edit-simple-note-dialog.css
  86. 35
      vasl_templates/webapp/static/css/edit-vo-dialog.css
  87. 82
      vasl_templates/webapp/static/css/html-editor.css
  88. 3
      vasl_templates/webapp/static/css/lfa-upload.css
  89. 4
      vasl_templates/webapp/static/css/lfa.css
  90. 31
      vasl_templates/webapp/static/css/main.css
  91. 12
      vasl_templates/webapp/static/css/program-info.css
  92. 7
      vasl_templates/webapp/static/css/scenario-card.css
  93. 4
      vasl_templates/webapp/static/css/scenario-downloads-dialog.css
  94. 18
      vasl_templates/webapp/static/css/scenario-search-dialog.css
  95. 4
      vasl_templates/webapp/static/css/select-roar-scenario-dialog.css
  96. 2
      vasl_templates/webapp/static/css/select-vo-dialog.css
  97. 29
      vasl_templates/webapp/static/css/sortable.css
  98. 16
      vasl_templates/webapp/static/css/tabs-extras.css
  99. 9
      vasl_templates/webapp/static/css/tabs-ob.css
  100. 43
      vasl_templates/webapp/static/css/tabs-scenario.css
  101. Some files were not shown because too many files have changed in this diff Show More

@ -54,88 +54,14 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
invalid-unicode-literal,
disable=
raw-checker-failed,
bad-inline-option,
locally-disabled,
locally-enabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape,
bad-whitespace,
bad-continuation,
invalid-name,
wrong-import-position,
global-statement,
@ -149,7 +75,9 @@ disable=print-statement,
isinstance-second-argument-not-valid-type,
consider-using-f-string,
consider-using-max-builtin,
use-implicit-booleaness-not-comparison
use-implicit-booleaness-not-comparison,
unnecessary-lambda-assignment,
duplicate-string-formatting-argument,
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
@ -294,13 +222,6 @@ max-line-length=120
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no

@ -1,17 +1,17 @@
# NOTE: Use the run-container.sh script to build and launch this container.
# NOTE: Multi-stage builds require Docker >= 17.05.
FROM rockylinux:8 AS base
FROM rockylinux:8.5 AS base
# update packages and install requirements
RUN dnf -y upgrade-minimal && \
dnf install -y python38
dnf install -y python39
# NOTE: We don't need the following stuff for the build step, but it's nice to not have to re-install
# it all every time we change the requirements :-/
# install Java
ARG JAVA_URL=https://download.java.net/java/GA/jdk15.0.1/51f4f36ad4ef43e39d0dfdbaf6549e32/9/GPL/openjdk-15.0.1_linux-x64_bin.tar.gz
ARG JAVA_URL=https://download.oracle.com/java/17/archive/jdk-17.0.2_linux-x64_bin.tar.gz
RUN curl -s "$JAVA_URL" | tar -xz -C /usr/bin/
# install Firefox
@ -22,7 +22,7 @@ RUN dnf install -y bzip2 xorg-x11-server-Xvfb gtk3 dbus-glib && \
echo "exclude=firefox" >>/etc/dnf/dnf.conf
# install geckodriver
ARG GECKODRIVER_URL=https://github.com/mozilla/geckodriver/releases/download/v0.30.0/geckodriver-v0.30.0-linux64.tar.gz
ARG GECKODRIVER_URL=https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz
RUN curl -sL "$GECKODRIVER_URL" | tar -xz -C /usr/bin/
# clean up

@ -1,16 +1,14 @@
# VASL Templates
<a href="https://github.com/pacman-ghost/vasl-templates/raw/master/vasl_templates/webapp/static/help/images/hill-621.png" target="_blank">
<img src="https://github.com/pacman-ghost/vasl-templates/raw/master/vasl_templates/webapp/static/help/images/hill-621.small.png" width="200" align="right" hspace="10">
</a>
[<img src="vasl_templates/webapp/static/help/images/hill-621.small.png" width="200" align="right" hspace="10">](vasl_templates/webapp/static/help/images/hill-621.png)
*VASL Templates* makes it easy to set up attractive VASL scenarios, with loads of useful information embedded to assist with game play.
Simply enter the scenario information into the UI, and the program will generate HTML snippets that you can transfer into VASL labels in your scenario.
<img src="https://github.com/pacman-ghost/vasl-templates/raw/master/vasl_templates/webapp/static/help/images/ob_setup.png" width="200">
[<img src="vasl_templates/webapp/static/help/images/ob_setup.png" width="200">](vasl_templates/webapp/static/help/images/ob_setup.png)
You can find more examples of the program in action [here](https://github.com/pacman-ghost/vasl-templates/tree/master/examples/).
You can find more examples of the program in action [here](examples/).
### Documentation

@ -42,7 +42,7 @@ def pytest_addoption( parser ):
help="Run the tests headless."
)
parser.addoption(
"--window-size", action="store", dest="window_size", default="1000x700",
"--window-size", action="store", dest="window_size", default="1020x700",
help="Browser window size."
)
@ -70,6 +70,13 @@ def pytest_configure( config ):
import vasl_templates.webapp.tests
vasl_templates.webapp.tests.pytest_options = config.option
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@pytest.fixture( scope="session" )
def monkeypatch():
"""Override the default monkeypatch fixture."""
assert False, "Don't use monkeypatch!" # it won't work when testing against a remote server
# ---------------------------------------------------------------------
_webapp = None

@ -2,5 +2,5 @@
IS_CONTAINER = 1
JAVA_PATH = /usr/bin/jdk-15.0.1/bin/java
JAVA_PATH = /usr/bin/jdk-17.0.2/bin/java
WEBDRIVER_PATH = /usr/bin/geckodriver

@ -1,16 +1,12 @@
{
"SCENARIO_NAME": "Hill 621",
"SCENARIO_ID": "ASL E",
"SCENARIO_LOCATION": "Near Minsk, Russia",
"COMPASS": "right",
"SCENARIO_DATE": "1944-07-01",
"SCENARIO_WIDTH": "",
"PLAYER_1_DESCRIPTION": "Retreating elements of 170th Infantry Division",
"PLAYER_2_DESCRIPTION": "Elements of 5th Guards Army",
"ASA_ID": "56512",
"ROAR_ID": "129",
"PLAYERS_WIDTH": "",
"VICTORY_CONDITIONS_WIDTH": "240px",
"SSR_WIDTH": "500px",
"VICTORY_CONDITIONS_WIDTH": "",
"SSR_WIDTH": "400px",
"OB_VEHICLES_WIDTH_1": "",
"OB_VEHICLES_MA_NOTES_WIDTH_1": "300px",
"OB_ORDNANCE_WIDTH_1": "",
@ -19,7 +15,12 @@
"OB_VEHICLES_MA_NOTES_WIDTH_2": "300px",
"OB_ORDNANCE_WIDTH_2": "",
"OB_ORDNANCE_MA_NOTES_WIDTH_2": "300px",
"VICTORY_CONDITIONS": "The Russians win at Game End if they Control &ge; five Level 3 hill hexes on Board 2.",
"SCENARIO_NAME": "Hill 621",
"SCENARIO_ID": "ASL E",
"SCENARIO_LOCATION": "Near Minsk, Russia",
"PLAYER_1_DESCRIPTION": "Retreating elements of 170th Infantry Division",
"PLAYER_2_DESCRIPTION": "Elements of 5th Guards Army",
"VICTORY_CONDITIONS": "The Russians win at Game End if they Control<br>≥ five Level 3 hill hexes on Board 2.",
"SCENARIO_THEATER": "ETO",
"PLAYER_1": "russian",
"PLAYER_1_ELR": "4",
@ -27,6 +28,15 @@
"PLAYER_2": "german",
"PLAYER_2_ELR": "3",
"PLAYER_2_SAN": "4",
"TURN_TRACK": {
"NTURNS": "10",
"WIDTH": "",
"VERTICAL": false,
"SHADING": "",
"REINFORCEMENTS_1": "2,5",
"REINFORCEMENTS_2": "1,2,4,5,8",
"SWAP_PLAYERS": false
},
"SSR": [
"EC are Moderate, with no wind at start.",
"After \"At Start\" placement, each German infantry unit must take a TC. The only possible consequence of failure is that the unit must begin the scenario broken. Those units which break during this pre-game TC are not subject to DM in the initial German RPh.",
@ -106,7 +116,7 @@
],
"SCENARIO_NOTES": [
{
"caption": "Download the scenario card from <a href=\"http://www.multimanpublishing.com/Support/ASLASLSK/ASLOfficialDownloads/tabid/109/Default.aspx\">Multi-Man Publishing</a> (ASL Classic pack).",
"caption": "Download the scenario card from <a href=\"https://mmpgamers.com/asl-downloads-ezp-3#scenarios\">Multi-Man Publishing</a> (ASL Classic pack).",
"width": "300px",
"id": 1
}
@ -173,7 +183,7 @@
"id": 2
}
],
"_app_version": "v1.3",
"_last_update_time": "2020-09-27T04:13:08.719Z",
"_app_version": "v1.10",
"_last_update_time": "2022-09-12T02:46:18.035Z",
"_creation_time": "2020-09-27T03:46:56.089Z"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 109 KiB

@ -1,15 +1,11 @@
{
"SCENARIO_NAME": "Hube's Pocket",
"SCENARIO_ID": "ASL G",
"SCENARIO_LOCATION": "Near Buchach, Southern Russia",
"COMPASS": "down",
"SCENARIO_DATE": "1944-04-06",
"SCENARIO_WIDTH": "",
"PLAYER_1_DESCRIPTION": "Advance elements of 5th Tank Corps",
"PLAYER_2_DESCRIPTION": "10th SS Panzer Division \"Frundsberg\" and the First Panzer Army ",
"ASA_ID": "56514",
"ROAR_ID": "131",
"PLAYERS_WIDTH": "",
"VICTORY_CONDITIONS_WIDTH": "320px",
"VICTORY_CONDITIONS_WIDTH": "",
"SSR_WIDTH": "330px",
"OB_VEHICLES_WIDTH_1": "",
"OB_VEHICLES_MA_NOTES_WIDTH_1": "300px",
@ -19,7 +15,12 @@
"OB_VEHICLES_MA_NOTES_WIDTH_2": "300px",
"OB_ORDNANCE_WIDTH_2": "",
"OB_ORDNANCE_MA_NOTES_WIDTH_2": "300px",
"VICTORY_CONDITIONS": "The Germans win immediately by exiting &ge; 10 vehicles <br>\noff the west edge in either one or two Convoys (see SSR 4).",
"SCENARIO_NAME": "Hube's Pocket",
"SCENARIO_ID": "ASL G",
"SCENARIO_LOCATION": "Near Buchach, Southern Russia",
"PLAYER_1_DESCRIPTION": "Advance elements of 5th Tank Corps",
"PLAYER_2_DESCRIPTION": "10th SS Panzer Division \"Frundsberg\" and the First Panzer Army",
"VICTORY_CONDITIONS": "The Germans win immediately by exiting ≥ 10 vehicles <br>\noff the west edge in either one or two Convoys (see SSR 4).",
"SCENARIO_THEATER": "ETO",
"PLAYER_1": "german",
"PLAYER_1_ELR": "4",
@ -27,6 +28,15 @@
"PLAYER_2": "russian",
"PLAYER_2_ELR": "3",
"PLAYER_2_SAN": "2",
"TURN_TRACK": {
"NTURNS": "14",
"WIDTH": "5",
"VERTICAL": false,
"SHADING": "",
"REINFORCEMENTS_1": "1,5",
"REINFORCEMENTS_2": "1",
"SWAP_PLAYERS": true
},
"SSR": [
"The SPW 251/sMG inherent HS is a 3-4-8.",
"German inherent crews have a morale of 9.",
@ -84,7 +94,7 @@
],
"SCENARIO_NOTES": [
{
"caption": "Download the scenario card from <a href=\"http://www.multimanpublishing.com/Support/ASLASLSK/ASLOfficialDownloads/tabid/109/Default.aspx\">Multi-Man Publishing</a> (ASL Classic pack).",
"caption": "Download the scenario card from <a href=\"https://mmpgamers.com/asl-downloads-ezp-3#scenarios\">Multi-Man Publishing</a> (ASL Classic pack).",
"width": "",
"id": 1
}
@ -110,7 +120,7 @@
],
"OB_NOTES_1": [],
"OB_NOTES_2": [],
"_app_version": "v1.3",
"_last_update_time": "2020-09-27T04:33:18.643Z",
"_app_version": "v1.10",
"_last_update_time": "2022-09-12T02:22:47.511Z",
"_creation_time": "2020-09-27T04:11:07.200Z"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 79 KiB

@ -4,4 +4,4 @@ This directory contains examples of *VASL Templates* in action, with the `.json`
The online versions contain images that will be loaded from the internet, which looks much better, but there will be a short delay when you open the scenario in VASSAL as the images are downloaded.
These scenarios were taken from Multi-Man Publishing's [*ASL Classic* scenario pack](http://www.multimanpublishing.com/Support/ASLASLSK/ASLOfficialDownloads/tabid/109/Default.aspx).
These scenarios were taken from Multi-Man Publishing's [*ASL Classic* scenario pack](https://mmpgamers.com/asl-downloads-ezp-3#scenarios).

@ -1,15 +1,11 @@
{
"SCENARIO_NAME": "The Streets Of Stalingrad",
"SCENARIO_ID": "ASL C",
"SCENARIO_LOCATION": "Stalingrad, Russia",
"COMPASS": "up",
"SCENARIO_DATE": "1942-10-06",
"SCENARIO_WIDTH": "",
"PLAYER_1_DESCRIPTION": "308th Rifle Division / 295th Rifle Division / 2nd Battalion, 37th Guards Division",
"PLAYER_2_DESCRIPTION": "389th Infantry Division",
"ASA_ID": "56510",
"ROAR_ID": "127",
"PLAYERS_WIDTH": "",
"VICTORY_CONDITIONS_WIDTH": "400px",
"VICTORY_CONDITIONS_WIDTH": "450px",
"SSR_WIDTH": "500px",
"OB_VEHICLES_WIDTH_1": "",
"OB_VEHICLES_MA_NOTES_WIDTH_1": "300px",
@ -19,7 +15,12 @@
"OB_VEHICLES_MA_NOTES_WIDTH_2": "300px",
"OB_ORDNANCE_WIDTH_2": "",
"OB_ORDNANCE_MA_NOTES_WIDTH_2": "300px",
"VICTORY_CONDITIONS": "Victory is based upon satisfying the Victory Conditions of Scenarios A and B:\n<ul style=\"margin:0 0 10px 10px;\">\n<li> If each side fulfills one Victory Condition, the game is a draw.\n<li> If a player fulfills one Victory Condition and draws the other, he wnis.\n<li> A decisive victory is achieved when a player fulfills both Victory Conditions.\n</ul>\n\n<p> <b>Scenario A:</b> The Russians win at Game End if they Control &ge; 2 more buildings initially occupied by the Germans than they lose of their own initially-held stone buildings to German Control, and/or have a favorable 3:1 ratio of unbroken squad-equivalents.\n<p> <b>Scenario B:</b> At Game End, the player with undisputed control of at least 6 hexes of building X3 wins. A hex containing a Melee is controlled by neither player. If only one player has an unbroken unit in the building at Game End, that player is the winner. Any other result is a draw.\n</ul>",
"SCENARIO_NAME": "The Streets Of Stalingrad",
"SCENARIO_ID": "ASL C",
"SCENARIO_LOCATION": "Stalingrad, Russia",
"PLAYER_1_DESCRIPTION": "308th Rifle Division / 295th Rifle Division / 2nd Battalion, 37th Guards Division",
"PLAYER_2_DESCRIPTION": "389th Infantry Division",
"VICTORY_CONDITIONS": "Victory is based upon satisfying the Victory Conditions of Scenarios A and B:\n<ul style=\"margin:0 0 10px 10px;\">\n<li> If each side fulfills one Victory Condition, the game is a draw.\n</li><li> If a player fulfills one Victory Condition and draws the other, he wnis.\n</li><li> A decisive victory is achieved when a player fulfills both Victory Conditions.\n</li></ul>\n\n<p> <b>Scenario A:</b> The Russians win at Game End if they Control ≥ 2 more buildings initially occupied by the Germans than they lose of their own initially-held stone buildings to German Control, and/or have a favorable 3:1 ratio of unbroken squad-equivalents.\n</p><p> <b>Scenario B:</b> At Game End, the player with undisputed control of at least 6 hexes of building X3 wins. A hex containing a Melee is controlled by neither player. If only one player has an unbroken unit in the building at Game End, that player is the winner. Any other result is a draw.\n</p>",
"SCENARIO_THEATER": "ETO",
"PLAYER_1": "russian",
"PLAYER_1_ELR": "3",
@ -27,6 +28,15 @@
"PLAYER_2": "german",
"PLAYER_2_ELR": "4",
"PLAYER_2_SAN": "6",
"TURN_TRACK": {
"NTURNS": "7",
"WIDTH": "",
"VERTICAL": false,
"SHADING": "",
"REINFORCEMENTS_1": "2",
"REINFORCEMENTS_2": "3",
"SWAP_PLAYERS": false
},
"SSR": [
"Roll a die to determine who moves first.",
"Set up the forces of Scenario A prior to placing the units of Scenario B.",
@ -61,7 +71,7 @@
],
"SCENARIO_NOTES": [
{
"caption": "Download the scenario card from <a href=\"http://www.multimanpublishing.com/Support/ASLASLSK/ASLOfficialDownloads/tabid/109/Default.aspx\">Multi-Man Publishing</a> (ASL Classic pack).",
"caption": "Download the scenario card from <a href=\"https://mmpgamers.com/asl-downloads-ezp-3#scenarios\">Multi-Man Publishing</a> (ASL Classic pack).",
"width": "",
"id": 1
}
@ -157,7 +167,7 @@
],
"OB_NOTES_1": [],
"OB_NOTES_2": [],
"_app_version": "v1.3",
"_last_update_time": "2020-09-27T04:46:21.803Z",
"_app_version": "v1.10",
"_last_update_time": "2022-09-12T02:58:13.237Z",
"_creation_time": "2020-09-27T04:44:48.473Z"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 902 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 61 KiB

@ -95,8 +95,8 @@ def main( args ): #pylint: disable=too-many-locals
args.append( "--noconsole" )
args.extend( [ "--icon", APP_ICON ] )
# NOTE: These files are not always required but it's probably safer to always include them.
import distutils.sysconfig #pylint: disable=import-error
dname = os.path.join( distutils.sysconfig.get_python_lib() , "PyQt5/Qt5/bin" )
import sysconfig
dname = os.path.join( sysconfig.get_path("platlib") , "PyQt5/Qt5/bin" )
args.extend( [ "--add-binary", os.path.join(dname,"libEGL.dll") + os.pathsep + "PyQt5/Qt/bin" ] )
args.extend( [ "--add-binary", os.path.join(dname,"libGLESv2.dll") + os.pathsep + "PyQt5/Qt/bin" ] )
args.append( MAIN_SCRIPT )

@ -98,7 +98,7 @@ def _convert_app_icon( save_fname ):
# to an image, then insert it into the PyInstaller-generated executable (so that
# we don't have to bundle Pillow into the release).
img = Image.open( APP_ICON )
img = img.convert( "RGBA" ).resize( (64, 64) )
img = img.convert( "RGBA" ).resize( (48, 48) )
img.save( save_fname, "png" )
# ---------------------------------------------------------------------

@ -93,7 +93,7 @@ def create_window( app_icon ):
"""Create the splash window."""
# create the splash window
main_window.geometry( "290x75" )
main_window.geometry( "275x64" )
main_window.title( "vasl-templates loader" )
main_window.overrideredirect( 1 ) # nb: "-type splash" doesn't work on Windows :-/
main_window.eval( "tk::PlaceWindow . center" )
@ -103,11 +103,11 @@ def create_window( app_icon ):
# add the app icon
label = tkinter.Label( main_window, image=app_icon )
label.grid( row=0, column=0, rowspan=2, padx=5, pady=5 )
label.grid( row=0, column=0, rowspan=2, padx=8, pady=8 )
# add the caption
label = tkinter.Label( main_window, text="Loading vasl-templates...", font=("Helvetica",12) )
label.grid( row=0, column=1, padx=5, pady=(5,0) )
label.grid( row=0, column=1, padx=5, pady=(8,0) )
# add the "loading" image (we have to animate it ourself :-/)
anim_label = tkinter.Label( main_window )

@ -1,7 +1,7 @@
pytest==6.2.5
grpcio-tools==1.44.0
pytest==7.1.2
grpcio-tools==1.46.3
tabulate==0.8.9
lxml==4.8.0
pylint==2.12.2
lxml==4.9.0
pylint==2.14.1
pytest-pylint==0.18.0
pyinstaller==4.9
pyinstaller==5.1

@ -1,8 +1,9 @@
# python 3.8.7
# python 3.10.4
flask==2.0.3
flask==2.1.2
pyyaml==6.0
pillow==9.0.1
selenium==4.1.0
waitress==2.0.0
click==8.0.4
pillow==9.1.1
selenium==4.2.0
waitress==2.1.2
appdirs==1.4.4
click==8.1.3

@ -28,10 +28,10 @@ def parse_requirements( fname ):
setup(
name = "vasl_templates",
version = "1.9", # nb: also update constants.py
version = "1.10", # nb: also update constants.py
description = "Create HTML snippets for use in VASL.",
license = "AGPLv3",
url = "https://github.com/pacman-ghost/vasl-templates",
url = "https://code.pacman-ghost.com/public/vasl-templates",
packages = find_packages(),
install_requires = parse_requirements( "requirements.txt" ),
extras_require = {

@ -51,7 +51,7 @@ class AboutDialog( QDialog ):
time.strftime( "%d %B %Y %H:%M", time.localtime( build_info["timestamp"] ) )
) )
if "git_info" in build_info:
buf.write( " <small><em>({})</em></small>".format( build_info["git_info"] ) )
buf.write( " <small><tt>({})</tt></small>".format( build_info["git_info"] ) )
buf.write( "." )
self.build_info.setText( buf.getvalue() )
else:
@ -61,7 +61,7 @@ class AboutDialog( QDialog ):
APP_HOME_URL, mo.group(1) if mo else APP_HOME_URL
) )
def on_app_icon_clicked( self, event ): #pylint: disable=no-self-use,unused-argument
def on_app_icon_clicked( self, event ): #pylint: disable=unused-argument
"""Click handler."""
QDesktopServices.openUrl( QUrl( APP_HOME_URL ) )

@ -21,6 +21,9 @@ class FileDialog:
self.default_extn = default_extn
self.filters = filters
self.curr_fname = default_fname
# NOTE: We can't just use the directory of self.curr_fname, since this gets reset
# when the user chooses "new scenario", but we want to remember the current directory.
self._curr_dir = os.path.dirname( default_fname ) if default_fname else None
def load_file( self, binary ):
"""Load a file."""
@ -28,7 +31,7 @@ class FileDialog:
# ask the user which file to load
fname, _ = QFileDialog.getOpenFileName(
self.parent, "Load {}".format( self.object_name ),
self.curr_fname,
self._get_start_path(),
self.filters
)
if not fname:
@ -44,6 +47,7 @@ class FileDialog:
if not binary:
data = data.decode( "utf-8" )
self.curr_fname = fname
self._curr_dir = os.path.dirname( fname )
return data
@ -58,8 +62,8 @@ class FileDialog:
# ask the user where to save the file
fname, _ = QFileDialog.getSaveFileName(
self.parent, "Save {}".format( self.object_name),
self.curr_fname,
self.parent, "Save {}".format( self.object_name ),
self._get_start_path(),
self.filters
)
if not fname:
@ -80,4 +84,13 @@ class FileDialog:
self.parent.showErrorMsg( "Can't save the {}:\n\n{}".format( self.object_name, ex ) )
continue
self.curr_fname = fname
self._curr_dir = os.path.dirname( fname )
return True
def _get_start_path( self ):
"""Get the start filename or directory path for saving/loading files."""
if self.curr_fname and os.path.isabs( self.curr_fname ):
return self.curr_fname
if self._curr_dir and self.curr_fname:
return os.path.join( self._curr_dir, self.curr_fname )
return self.curr_fname

@ -22,6 +22,10 @@ from PyQt5.QtCore import Qt, QSettings, QDir
import PyQt5.QtCore
import click
# notify everyone that we're being run as the desktop application
os.environ[ "IS_DESKTOP_APP" ] = "1"
os.environ[ "QDIR_HOME_PATH" ] = QDir.homePath()
from vasl_templates.webapp.utils import SimpleError, is_windows
# NOTE: We're supposed to do the following to support HiDPI, but it causes the main window
@ -95,9 +99,20 @@ def _do_main( template_pack, default_scenario, remote_debugging, debug ): #pylin
# NOTE: We do these imports here (instead of at the top of the file) so that we can catch errors.
from vasl_templates.webapp import app as webapp
from vasl_templates.webapp import load_debug_config
from vasl_templates.webapp import globvars, load_debug_config
from vasl_templates.webapp import main as webapp_main, snippets as webapp_snippets
# initialize logging
# NOTE: We set up basic logging for people using the desktop app (if they are running from source,
# or using Docker, there is an expectation they can do this themselves). If logging has already
# been set up, this config is in *addition* to what's already been configured.
handler = logging.FileHandler( globvars.user_profile.default_log_fname, mode="w" )
handler.setLevel( logging.WARNING )
handler.setFormatter(
logging.Formatter( "%(asctime)s | %(message)s" )
)
logging.getLogger().addHandler( handler )
# configure the default template pack
if template_pack:
if template_pack.lower().endswith( ".zip" ):
@ -121,12 +136,12 @@ def _do_main( template_pack, default_scenario, remote_debugging, debug ): #pylin
os.environ["QTWEBENGINE_REMOTE_DEBUGGING"] = remote_debugging
# load the application settings
app_settings_fname = "vasl-templates.ini" if sys.platform == "win32" else ".vasl-templates.conf"
if not os.path.isfile( app_settings_fname ) :
app_settings_fname = os.path.join( QDir.homePath(), app_settings_fname )
# FUDGE! Declaring app_settings as global here doesn't work on Windows (?!), we have to do this weird import :-/
import vasl_templates.main #pylint: disable=import-self
vasl_templates.main.app_settings = QSettings( app_settings_fname, QSettings.IniFormat )
vasl_templates.main.app_settings = QSettings(
globvars.user_profile.desktop_settings_fname,
QSettings.IniFormat
)
# install the debug config file
if debug:

@ -14,9 +14,10 @@ from PyQt5.QtGui import QDesktopServices, QIcon
from PyQt5.QtCore import Qt, QUrl, QMargins, pyqtSlot, QVariant
from vasl_templates.webapp.config.constants import APP_NAME, APP_VERSION, IS_FROZEN
from vasl_templates.webapp import globvars
from vasl_templates.main import app_settings
from vasl_templates.web_channel import WebChannelHandler
from vasl_templates.utils import catch_exceptions
from vasl_templates.utils import catch_exceptions, launch_file
_CONSOLE_SOURCE_REGEX = re.compile( r"^http://.+?/static/(.*)$" )
@ -25,7 +26,7 @@ _CONSOLE_SOURCE_REGEX = re.compile( r"^http://.+?/static/(.*)$" )
class AppWebPage( QWebEnginePage ):
"""Application web page."""
def acceptNavigationRequest( self, url, nav_type, is_mainframe ): #pylint: disable=no-self-use,unused-argument
def acceptNavigationRequest( self, url, nav_type, is_mainframe ): #pylint: disable=unused-argument
"""Called when a link is clicked."""
if url.host() in ("localhost","127.0.0.1"):
if "/asl-rulebook2/" not in url.url(): # nb: asl-rulebook2 links are routed through our webapp
@ -39,12 +40,12 @@ class AppWebPage( QWebEnginePage ):
QDesktopServices.openUrl( url )
return False
def javaScriptConsoleMessage( self, level, msg, line_no, source_id ): #pylint: disable=unused-argument,no-self-use
def javaScriptConsoleMessage( self, level, msg, line_no, source_id ): #pylint: disable=unused-argument
"""Log a Javascript console message."""
mo = _CONSOLE_SOURCE_REGEX.search( source_id )
source = mo.group(1) if mo else source_id
logger = logging.getLogger( "javascript" )
logger.info( "%s:%d - %s", source, line_no, msg )
logger.warning( "%s:%d - %s", source, line_no, msg )
# ---------------------------------------------------------------------
@ -80,6 +81,7 @@ class MainWindow( QWidget ):
action.triggered.connect( handler )
file_menu.addAction( action )
add_action( "&Settings", "settings.png", self.on_settings )
add_action( "&Log file", "log.png", self.on_log_file )
add_action( "&About", "info.png", self.on_about )
file_menu.addSeparator()
add_action( "E&xit", "exit.png", self.on_exit )
@ -94,7 +96,10 @@ class MainWindow( QWidget ):
self.restoreGeometry( val )
else :
self.resize( 1000, 650 )
self.setMinimumSize( 1000, 620 )
# NOTE: This should be wide enough for the sortable hints to not wrap (so that
# we don't see a scrollbar when their panels are reduced to their minimum height).
# We also want the Trumbowyg button pane for the VC to wrap somewhere sensible.
self.setMinimumSize( 1030, 650 )
# initialize the layout
layout = QVBoxLayout( self )
@ -216,6 +221,10 @@ class MainWindow( QWidget ):
dlg = ServerSettingsDialog( self )
dlg.exec_()
def on_log_file( self ):
"""Menu action handler."""
launch_file( globvars.user_profile.default_log_fname )
def on_about( self ):
"""Menu action handler."""
from vasl_templates.about import AboutDialog #pylint: disable=cyclic-import
@ -308,7 +317,7 @@ class MainWindow( QWidget ):
@pyqtSlot( str )
@catch_exceptions( caption="SLOT EXCEPTION" )
def on_user_settings_change( self, user_settings ): #pylint: disable=no-self-use
def on_user_settings_change( self, user_settings ):
"""Called when the user changes the user settings."""
# delete all existing keys
for key in app_settings.allKeys():

@ -155,9 +155,9 @@ class ServerSettingsDialog( QDialog ):
app_settings.setValue( "ServerSettings/"+key, val )
try:
install_server_settings( False )
except Exception as ex: #pylint: disable=broad-except
except Exception as ex2: #pylint: disable=broad-except
logging.error( traceback.format_exc() )
MainWindow.showErrorMsg( "Couldn't rollback the server settings:\n\n{}".format( ex ) )
MainWindow.showErrorMsg( "Couldn't rollback the server settings:\n\n{}".format( ex2 ) )
return
self.close()

@ -0,0 +1,75 @@
#!/usr/bin/env python3
""" Prepare the piece info for a VASL module.
The main program used to identify 5/8" counters by reading a module's buildFile and checking the height
attribute of the PieceSlot nodes, but it turns out this is the wrong thing to do (this field actually
controls the size of the piece's entry in the counter palette):
https://github.com/vasl-developers/vasl/issues/1195
For each version of VASL supported, run vassal-shim (getPieceInfo command) to analyze the module's
buildFile and get the correct counter sizes. Then pass the output into this script, to generate
the final data file that should be saved in the $/data/vasl-$VERSION/ directory, where it will
be read by the main program.
NOTE: Introducing this process opens the possibility of also extracting the image file paths
within the .vmod file, instead of the current messy parsing of the PieceSlot CDATA... :-/
"""
import sys
import os
import json
import xml.etree.ElementTree as ET
# ---------------------------------------------------------------------
# initialize
report = {}
# figure out which GPID's we're interested in
gpids = set()
def get_gpids( vo_type ):
"""Get the GPID's from our data files."""
dname = os.path.join( os.path.dirname(__file__), "../webapp/data", vo_type )
for root,_,fnames in os.walk( dname ):
for fname in fnames:
if os.path.splitext( fname )[1] != ".json":
continue
fname = os.path.join( root, fname )
with open( fname, "r", encoding="utf-8" ) as fp:
entries = json.load( fp )
for entry in entries:
entry_gpid = entry.get( "gpid" )
if not entry_gpid:
continue
if isinstance( entry_gpid, list ):
gpids.update( str(g) for g in entry_gpid )
else:
gpids.add( str( entry_gpid ) )
get_gpids( "vehicles" )
get_gpids( "ordnance" )
# parse the piece info generated by vassal-shim
doc = ET.parse( sys.stdin )
for piece_info in doc.getroot():
gpid = piece_info.attrib["gpid"]
if gpid not in gpids:
continue
info = {}
# check if the next piece is small
# FUDGE! We used to check for <= 48, but what we get is GamePiece.boundingBox(), which is
# the click zone for the counter, not the actual size of the counter's image :-/
if int( piece_info.attrib["height"] ) <= 55:
info["is_small"] = True
if info:
report[ gpid ] = info
# output the final report
print( "{" )
lines = []
for gpid, piece_info in report.items():
lines.append( "\"{}\": {}".format(
gpid, json.dumps( piece_info )
) )
print( ",\n".join( lines ) )
print( "}" )

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>460</width>
<height>182</height>
<height>195</height>
</rect>
</property>
<property name="windowTitle">
@ -22,7 +22,7 @@
<widget class="QLabel" name="app_icon">
<property name="geometry">
<rect>
<x>10</x>
<x>15</x>
<y>10</y>
<width>64</width>
<height>64</height>
@ -39,9 +39,9 @@
<property name="geometry">
<rect>
<x>80</x>
<y>20</y>
<width>371</width>
<height>61</height>
<y>19</y>
<width>361</width>
<height>58</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -75,7 +75,6 @@
<property name="font">
<font>
<family>DejaVu Sans</family>
<italic>true</italic>
</font>
</property>
<property name="text">
@ -88,9 +87,9 @@
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<width>441</width>
<x>19</x>
<y>152</y>
<width>425</width>
<height>31</height>
</rect>
</property>
@ -129,9 +128,9 @@
<widget class="QLabel" name="home_url">
<property name="geometry">
<rect>
<x>10</x>
<y>120</y>
<width>441</width>
<x>80</x>
<y>122</y>
<width>361</width>
<height>21</height>
</rect>
</property>
@ -151,9 +150,9 @@
<widget class="QLabel" name="license">
<property name="geometry">
<rect>
<x>10</x>
<x>80</x>
<y>100</y>
<width>441</width>
<width>361</width>
<height>17</height>
</rect>
</property>

@ -509,7 +509,7 @@
<rect>
<x>650</x>
<y>230</y>
<width>164</width>
<width>173</width>
<height>31</height>
</rect>
</property>

@ -1,12 +1,15 @@
""" Miscellaneous utilities. """
import os
import platform
import subprocess
import functools
import logging
import traceback
import json
from vasl_templates.webapp.config.constants import BASE_DIR
from vasl_templates.webapp import app
from vasl_templates.webapp.config.constants import BASE_DIR,