Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 88 KiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 811 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 29 KiB |
@ -0,0 +1,93 @@ |
||||
<html> <!-- vasl-templates:id {{SNIPPET_ID}} --> |
||||
|
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<style> {{CSS:common}} </style> |
||||
|
||||
<style> |
||||
|
||||
td { |
||||
width: 50px ; min-width: 50px ; |
||||
height: {%if TURN_TRACK_PREVIEW_MODE%} 50px {%else%} 43px {%endif%} ; |
||||
padding: 2px ; |
||||
border: 1px solid black ; |
||||
} |
||||
{% set RESET_TD = "min-width: unset ; height: unset ; padding: 0 ; border: none" %} |
||||
td.turn-no { |
||||
{{RESET_TD}} ; width: unset ; |
||||
text-align: center ; vertical-align: center ; font-size: 18px ; font-weight: bold ; |
||||
} |
||||
td.no-reinforce { {{RESET_TD}} ; width: 13px ; } |
||||
{# NOTE: We do the reinforcement flags as CSS backgrounds, since VASSAL is incredibly slow downloading normal images. #} |
||||
td.reinforce1 { {{RESET_TD}} ; width: 13px ; background: url("{{TURN_TRACK_FLAG_1}}") top left no-repeat ; vertical-align: top ; } |
||||
td.reinforce2 { {{RESET_TD}} ; width: 13px ; background: url("{{TURN_TRACK_FLAG_2}}") bottom right no-repeat ; vertical-align: bottom ; } |
||||
td.half-turn { |
||||
background: url("{{IMAGES_BASE_URL}}/turn-track-half-turn.png") bottom right no-repeat ; |
||||
background-size: contain ; {# nb: doesn't work in VASSAL, the image file needs to be the correct size :-/ #} |
||||
} |
||||
|
||||
{% if TURN_TRACK_PREVIEW_MODE %} |
||||
body { margin: 0 ; } |
||||
.reinforce1, .reinforce2 { opacity: 0 ; } |
||||
.click { width: 13px ; height: 13px ; cursor: pointer ; } |
||||
{%endif%} |
||||
|
||||
</style> |
||||
|
||||
</head> |
||||
|
||||
{% if TURN_TRACK_PREVIEW_MODE %} |
||||
<script> |
||||
// notify the parent window of a click on a reinforcement flag |
||||
function onFlagClick( turnNo, playerNo ) { |
||||
window.parent.postMessage( { |
||||
type: "FlagClick", |
||||
turnNo: turnNo, uiPlayerNo: playerNo |
||||
}, "*" ) ; |
||||
} |
||||
</script> |
||||
{%endif%} |
||||
|
||||
<table class="turn-track"> |
||||
|
||||
{% for row in TURN_TRACK_SQUARES %} |
||||
<tr> |
||||
|
||||
{% for turnSquare in row %} |
||||
<td {%if turnSquare[0] == TURN_TRACK_HALF_TURN%} class="half-turn" {%endif%} > |
||||
|
||||
<table style="width:100%;height:100%;"> <tr> |
||||
|
||||
<td id="flag-{{turnSquare[0]}}_1" width="100%" |
||||
class = {% if turnSquare[1] %} "reinforce1" {%else%} "no-reinforce" {%endif%} |
||||
> |
||||
{% if TURN_TRACK_PREVIEW_MODE %} |
||||
<div class="click" |
||||
onclick = "onFlagClick( {{turnSquare[0]}}, 1 )" |
||||
> </div> |
||||
{%endif%} |
||||
</td> |
||||
|
||||
<td class="turn-no"> {{turnSquare[0]}} </td> |
||||
|
||||
<td id="flag-{{turnSquare[0]}}_2" width="100%" |
||||
class = {% if turnSquare[2] and turnSquare[0] != TURN_TRACK_HALF_TURN %} "reinforce2" {%else%} "no-reinforce" {%endif%} |
||||
> |
||||
{% if TURN_TRACK_PREVIEW_MODE and turnSquare[0] != TURN_TRACK_HALF_TURN %} |
||||
<div class="click" |
||||
onclick = "onFlagClick( {{turnSquare[0]}}, 2 )" |
||||
> </div> |
||||
{%endif%} |
||||
</td> |
||||
|
||||
</tr> </table> |
||||
|
||||
</td> |
||||
{%endfor%} |
||||
|
||||
</tr> |
||||
{%endfor%} |
||||
|
||||
</table> |
||||
|
||||
</html> |
@ -0,0 +1,27 @@ |
||||
#turn-track { display: flex ; overflow: hidden ; } |
||||
.ui-dialog.turn-track .ui-dialog-titlebar { background: #80d0ff ; } |
||||
.ui-dialog.turn-track .ui-dialog-buttonpane { border: none ; margin-top: 0 !important ; padding-top: 0 !important ; } |
||||
|
||||
.ui-dialog.turn-track .controls { display: flex ; } |
||||
.ui-dialog.turn-track .controls .row { display: flex ; align-items: center ; } |
||||
.ui-dialog.turn-track .controls .select2 { margin: -1px 0 0 0.5em ; } |
||||
.ui-dialog.turn-track .controls input { margin-top: 0.25em ; } |
||||
.ui-dialog.turn-track .controls button.reset { |
||||
height: 26px ; width: 4.5em ; |
||||
margin-top: 1em ; padding: 2px 10px 2px 5px ; |
||||
display: none ; |
||||
} |
||||
|
||||
.ui-dialog.turn-track iframe { margin: -4px ; border: 0 ; overflow: scroll ; } |
||||
|
||||
/* special layout settings for a horizontal turn track */ |
||||
#turn-track.horz { flex-direction: column ; } |
||||
#turn-track.horz .controls { flex-direction: row ; } |
||||
#turn-track.horz .controls>div { margin: 0 1em 0 0 ; } |
||||
#turn-track.horz .preview { height: auto ; width: 100% ; margin: 10px 0 0 0 ; padding-bottom: 15px ; } |
||||
|
||||
/* special layout settings for a vertical turn track */ |
||||
#turn-track.vert { flex-direction: row ; } |
||||
#turn-track.vert .controls { flex-direction: column ; } |
||||
#turn-track.vert .controls>div { margin: 0 0 1em 0 ; } |
||||
#turn-track.vert .preview { height: 100% ; width: auto ; margin: 0 0 0 10px ; padding-right: 15px ; } |
After Width: | Height: | Size: 1.9 KiB |
@ -0,0 +1,309 @@ |
||||
DEFAULT_TURN_TRACK_TURNS_MIN = 6 ; |
||||
DEFAULT_TURN_TRACK_TURNS_MAX = 10 ; |
||||
|
||||
// NOTE: Reinforcement flags get clipped on turn 100, but this is unlikely to be an issue :-/
|
||||
_MAX_TURN_TRACK_TURNS = 100 ; |
||||
|
||||
gTurnTrackReinforcements = null ; |
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
function editTurnTrackSettings() |
||||
{ |
||||
// initialize
|
||||
var $dlg, $iframe, iframeSeqNo=0 ; |
||||
// FUDGE! This should work as a local variable, but causes a weird problem where it doesn't get reset properly :-/
|
||||
gTurnTrackReinforcements = null ; |
||||
|
||||
function loadControls() { |
||||
// load the dialog controls
|
||||
$dlg.find( "select[name='nturns']" ).val( |
||||
$panel.find( "select[name='TURN_TRACK_NTURNS'].param" ).val() |
||||
).trigger("change" ) ; |
||||
var width = $panel.find( "input[name='TURN_TRACK_WIDTH']" ).val() ; |
||||
$dlg.find( "select[name='width']" ).val( |
||||
isNaN( parseInt( width ) ) ? "" : width |
||||
).trigger( "change" ) ; |
||||
$dlg.find( "input[name='vertical']" ).prop( "checked", |
||||
$panel.find( "input[name='TURN_TRACK_VERTICAL']" ).prop( "checked" ) |
||||
) ; |
||||
$dlg.find( "input[name='swap-players']" ).prop( "checked", |
||||
$panel.find( "input[name='TURN_TRACK_SWAP_PLAYERS']" ).prop( "checked" ) |
||||
) ; |
||||
// load the reinforcements
|
||||
var params = updatePreview( false ) ; |
||||
var args = parseTurnTrackParams( params ) ; |
||||
gTurnTrackReinforcements = { 1: args.reinforce1, 2: args.reinforce2 } ; |
||||
// update the UI
|
||||
updateUI() ; |
||||
} |
||||
|
||||
function onResetControls() { |
||||
// reset all the controls
|
||||
ask( "Reset turn track", "Do you want to reset the turn track?", { |
||||
ok: function() { |
||||
setTurnTrackNTurns( DEFAULT_TURN_TRACK_TURNS_MIN ) ; |
||||
$panel.find( "input[name='TURN_TRACK_WIDTH']" ).val( "" ) ; |
||||
$panel.find( "input[name='TURN_TRACK_VERTICAL']" ).prop( "checked", false ) ; |
||||
$panel.find( "input[name='TURN_TRACK_SWAP_PLAYERS']" ).prop( "checked", false ) ; |
||||
$panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_1']" ).val( "" ) ; |
||||
$panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_2']" ).val( "" ) ; |
||||
gTurnTrackReinforcements = null ; |
||||
loadControls() ; |
||||
} |
||||
} ) ; |
||||
} |
||||
|
||||
function initTurnCountSelect2( $sel ) { |
||||
// initialize the TURN COUNT droplist
|
||||
init_select2( |
||||
$sel, "4em", false, formatTurnTrackOption |
||||
).on( "select2:open", function() { |
||||
restrict_droplist_height( $(this) ) ; |
||||
} ).on( "change", function() { |
||||
setTurnTrackNTurns( $(this).val() ) ; |
||||
if ( $dlg ) |
||||
updateUI() ; |
||||
} ) ; |
||||
for ( var nTurns=1 ; nTurns <= _MAX_TURN_TRACK_TURNS ; nTurns += 0.5 ) |
||||
$sel.append( $( "<option value='" + nTurns + "'>" + nTurns + "</option>" ) ) ; |
||||
} |
||||
function initWidthSelect2( $sel ) { |
||||
// initialize the WIDTH droplist
|
||||
init_select2( |
||||
$sel, "3.5em", false, null |
||||
).on( "select2:open", function() { |
||||
restrict_droplist_height( $(this) ) ; |
||||
} ).on( "change", function() { |
||||
$panel.find( "input[name='TURN_TRACK_WIDTH']" ).val( $(this).val() ) ; |
||||
if ( $dlg ) |
||||
updateUI() ; |
||||
} ) ; |
||||
$sel.append( $( "<option value=''>-</option>" ) ) ; |
||||
for ( var i=1 ; i <= 30 ; ++i ) |
||||
$sel.append( $( "<option value='" + i + "'>" + i + "</option>" ) ) ; |
||||
} |
||||
|
||||
function syncCheckbox( $elem, $target ) { |
||||
// sync the target checkbox in the SCENARIO panel with the one in this dialog
|
||||
$target.prop( "checked", $elem.prop("checked") ) ; |
||||
updateUI() ; |
||||
} |
||||
|
||||
function updatePreview( showAllFlags ) { |
||||
|
||||
// generate the turn track snippet
|
||||
var params = unload_snippet_params( true, "turn_track" ) ; |
||||
if ( showAllFlags ) |
||||
params.TURN_TRACK.REINFORCEMENTS_1 = params.TURN_TRACK.REINFORCEMENTS_2 = makeCommaList( _MAX_TURN_TRACK_TURNS ) ; |
||||
params.TURN_TRACK_PREVIEW_MODE = true ; |
||||
var $btn = $( "button.generate[data-id='turn_track']" ) ; |
||||
var snippet = make_snippet( $btn, params, {}, false ).content ; |
||||
|
||||
// update the preview
|
||||
// NOTE: To minimize flickering, we load the snippet into a hidden <iframe>,
|
||||
// then replace the preview <iframe> with it.
|
||||
// FUDGE! We should be able to wait until the new iframe has finished loading before removing the old one,
|
||||
// but for some inexplicable reason, the remove doesn't work on Windows, and the iframe's just build up :-/
|
||||
// Instead, we remove the old iframe here, but by fiddling with opacity, we can avoid flicker. Sigh...
|
||||
var style = $iframe.attr( "style" ) ; |
||||
style.opacity = 0 ; |
||||
var $newFrame = $( "<iframe></iframe>", { style: style, "data-seqno": ++iframeSeqNo } ) ; |
||||
$iframe.after( $newFrame ) ; |
||||
$iframe.remove() ; |
||||
$iframe = $newFrame ; |
||||
$newFrame.attr( "srcdoc", snippet ).on( "load", function() { |
||||
// update the state of each reinforcement flag
|
||||
for ( var turnNo=1 ; turnNo <= _MAX_TURN_TRACK_TURNS ; ++turnNo ) { |
||||
for ( var playerNo=1 ; playerNo <= 2 ; ++playerNo ) |
||||
updateFlag( turnNo, playerNo ) ; |
||||
} |
||||
// install the new <iframe>
|
||||
$newFrame.attr( "id", "turn-track-preview" ).css( "opacity", 1 ) ; |
||||
// FUDGE! This works around a weird problem when we load a scenario with a vertical turn track
|
||||
// and show it in a turn track dialog that was previously showing a horizontal turn track :-/
|
||||
updateLayout() ; |
||||
} ) ; |
||||
|
||||
return params ; |
||||
} |
||||
|
||||
function onFlagClick( turnNo, playerNo ) { |
||||
// NOTE: This method gets called by a click handler in the snippet HTML.
|
||||
// toggle the player turn reinforcements
|
||||
if ( gTurnTrackReinforcements[playerNo][turnNo] ) |
||||
delete gTurnTrackReinforcements[playerNo][turnNo] ; |
||||
else |
||||
gTurnTrackReinforcements[playerNo][turnNo] = true ; |
||||
$panel.find( "input[name='TURN_TRACK_REINFORCEMENTS_" + playerNo + "']" ).val( |
||||
Object.keys( gTurnTrackReinforcements[playerNo] ).join( "," ) |
||||
) ; |
||||
updateFlag( turnNo, playerNo ) ; |
||||
} |
||||
|
||||
function updateFlag( turnNo, playerNo ) { |
||||
// update the specified reinforcement flag
|
||||
$iframe.contents().find( "#flag-" + turnNo + "_" + flipPlayerNo2(playerNo) ).css( { |
||||
opacity: gTurnTrackReinforcements && gTurnTrackReinforcements[playerNo][turnNo] ? 1 : 0.4, |
||||
} ) ; |
||||
} |
||||
|
||||
function updateUI() { |
||||
// update the UI
|
||||
updateLayout() ; |
||||
updatePreview( true ) ; |
||||
} |
||||
|
||||
function updateLayout() { |
||||
// update the layout based on the direction of the turn track
|
||||
if ( $dlg.find( "input[name='vertical']" ).prop( "checked" ) ) { |
||||
// vertical layout
|
||||
$iframe.css( { position: "absolute", |
||||
top: "10px", height: "calc(100% - 20px)", left: "150px", width: "calc(100% - 160px)" |
||||
} ) ; |
||||
$dlg.addClass( "vert" ).removeClass( "horz" ) ; |
||||
$dlg.find( ".controls" ).addClass( "vert" ).removeClass( "horz" ) ; |
||||
$dlg.find( ".reset1" ).hide() ; |
||||
$dlg.find( ".reset2" ).show() ; |
||||
} else { |
||||
// horizontal layout
|
||||
$iframe.css( { position: "absolute", |
||||
top: "95px", height: "calc(100% - 105px)", left: "10px", width: "calc(100% - 20px)" |
||||
} ) ; |
||||
$dlg.addClass( "horz" ).removeClass( "vert" ) ; |
||||
$dlg.find( ".controls" ).addClass( "horz" ).removeClass( "vert" ) ; |
||||
$dlg.find( ".reset1" ).show() ; |
||||
$dlg.find( ".reset2" ).hide() ; |
||||
} |
||||
} |
||||
|
||||
// NOTE: Since Player 1 in the UI is Player 2 in the Turn Track template (by default),
|
||||
// and vice versa, we often need to flip the player numbers.
|
||||
function flipPlayerNo( playerNo ) { return parseInt(playerNo) === 1 ? 2 : 1 ; } |
||||
function flipPlayerNo2( playerNo ) { |
||||
if ( ! $panel.find("input[name='TURN_TRACK_SWAP_PLAYERS']").prop( "checked" ) ) |
||||
playerNo = flipPlayerNo( playerNo ) ; |
||||
return playerNo ; |
||||
} |
||||
|
||||
function makeCommaList( nVals ) { |
||||
// generate a comma-separated list of values
|
||||
var vals = [] ; |
||||
for ( var i=1 ; i <= nVals ; ++i ) |
||||
vals.push( i ) ; |
||||
return vals.join( "," ) ; |
||||
} |
||||
|
||||
// show the TURN TRACK dialog
|
||||
var $panel = $( "#panel-scenario" ) ; |
||||
$( "#turn-track" ).dialog( { |
||||
"title": "Turn track", |
||||
dialogClass: "turn-track", |
||||
modal: true, |
||||
minWidth: 500, minHeight: 250, |
||||
resizable: true, |
||||
create: function() { |
||||
// initialize the dialog
|
||||
init_dialog( $(this), "OK", true ) ; |
||||
initTurnCountSelect2( $(this).find( "select[name='nturns']" ) ) ; |
||||
initWidthSelect2( $(this).find( "select[name='width']" ) ) ; |
||||
$(this).find( "button.reset" ).button().on( |
||||
"click", onResetControls |
||||
) ; |
||||
// keep the settings in the SCENARIO panel in sync with the dialog
|
||||
$(this).find( "input[name='vertical']" ).on( "change", function() { |
||||
syncCheckbox( $(this), $panel.find("input[name='TURN_TRACK_VERTICAL']") ) ; |
||||
} ) ; |
||||
$(this).find( "input[name='swap-players']" ).on( "change", function() { |
||||
syncCheckbox( $(this), $panel.find("input[name='TURN_TRACK_SWAP_PLAYERS']") ) ; |
||||
} ) ; |
||||
// update the UI when the direction of the turn track is changed
|
||||
$(this).find( "input[name='vertical']" ).on( "change", function() { |
||||
updateUI() ; |
||||
} ) ; |
||||
// handle clicks on reinforcement flags in the turn track preview
|
||||
window.addEventListener( "message", function( evt ) { |
||||
if ( evt.data.type === "FlagClick" ) |
||||
onFlagClick( evt.data.turnNo, flipPlayerNo2(evt.data.uiPlayerNo) ) ; |
||||
} ) ; |
||||
|
||||
}, |
||||
open: function() { |
||||
// initialize the dialog
|
||||
var $btnPane = $( ".ui-dialog.turn-track .ui-dialog-buttonpane" ) ; |
||||
var $btn = $btnPane.find( "button.snippet" ) ; |
||||
$btn.prepend( |
||||
$( "<img src='" + gImagesBaseUrl+"/snippet.png" + "' style='height:0.9em;margin:0 0.35em -1px 0;'>" ) |
||||
) ; |
||||
$btn.css( { position: "absolute", left: 5 } ) ; |
||||
// load the dialog
|
||||
$dlg = $(this) ; |
||||
$iframe = $dlg.find( "iframe#turn-track-preview" ) ; |
||||
loadControls() ; |
||||
}, |
||||
buttons: { |
||||
Snippet: { text:" Snippet", class: "snippet", click: function( evt ) { |
||||
var $btn = $( "button.generate[data-id='turn_track']" ) ; |
||||
generate_snippet( $btn, evt.shiftKey, null ) ; |
||||
} }, |
||||
Close: function() { $(this).dialog( "close" ) ; }, |
||||
}, |
||||
} ) ; |
||||
} |
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
function setTurnTrackNTurns( nTurns ) |
||||
{ |
||||
// select the specified number of turns
|
||||
updateTurnTrackNTurns( nTurns ) ; |
||||
$( "select[name='TURN_TRACK_NTURNS']" ).val( |
||||
nTurns |
||||
).trigger( "change" ) ; |
||||
} |
||||
|
||||
function updateTurnTrackNTurns( nTurns ) |
||||
{ |
||||
function makeExtraOption( val, caption ) { |
||||
return $( "<option class='extra' value='" + val + "'>" + caption + "</option>" ) ; |
||||
} |
||||
|
||||
// initialize
|
||||
var $sel = $( "select[name='TURN_TRACK_NTURNS']" ) ; |
||||
var $extra = $sel.find( "option.extra" ) ; |
||||
|
||||
// check if the specified number of turns is already in the droplist
|
||||
var $opt = $sel.find( "option[value='" + nTurns + "']" ) ; |
||||
if ( $opt.length > 0 ) { |
||||
// yup - check if it's the special extra entry
|
||||
if ( ! $opt.hasClass( "extra" ) ) { |
||||
// nope - we don't need it any more
|
||||
$extra.remove() ; |
||||
} |
||||
// check if the turn track has been disabled
|
||||
if ( nTurns === "" ) { |
||||
// yup - add a special extra entry to open the turn track dialog
|
||||
$sel.append( makeExtraOption( "(show-dialog)", "(more)" ) ) ; |
||||
} |
||||
} else { |
||||
// nope - add it as a special extra entry
|
||||
if ( $extra.length > 0 ) { |
||||
// FUDGE! If the special entry is already there, we delete and re-create it to get the select2 to work :-/
|
||||
$extra.remove() ; |
||||
} |
||||
var $opt2 = makeExtraOption( nTurns, nTurns ) ; |
||||
if ( nTurns < DEFAULT_TURN_TRACK_TURNS_MIN ) |
||||
$sel.find( "option[value='']" ).after( $opt2 ) ; |
||||
else |
||||
$sel.append( $opt2 ) ; |
||||
} |
||||
} |
||||
|
||||
function formatTurnTrackOption( opt ) { |
||||
// format the turn track <option> element
|
||||
if ( opt.id === "(show-dialog)" ) |
||||
return $( "<span style='font-size:80%;font-style:italic;color:#666;'>" + opt.text + "</span>" ) ; |
||||
if ( opt.text.substr( opt.text.length-2 ) === ".5" ) |
||||
return $( "<span>" + opt.text.substr( 0, opt.text.length-2 ) + "½" + "</span>" ) ; |
||||
return opt.text ; |
||||
} |
@ -0,0 +1,21 @@ |
||||
<div id="turn-track" style="display:none;"> |
||||
|
||||
<div class="controls"> |
||||
|
||||
<div style="display:flex;flex-direction:column;"> |
||||
<div class="row"> Turns: <select name="nturns"></select> </div> |
||||
<button class="reset reset1"> Reset </button> |
||||
</div> |
||||
|
||||
<div style="display:flex;flex-direction:column;"> |
||||
<div class="row"> Width: <select name="width"></select> </div> |
||||
<div> <input type="checkbox" name="vertical"> Vertical </input> </div> |
||||
<div> <input type="checkbox" name="swap-players"> Swap players </input> </div> |
||||
<button class="reset reset2"> Reset </button> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<iframe id="turn-track-preview"></iframe> |
||||
|
||||
</div> |
@ -0,0 +1,4 @@ |
||||
TURN TRACK: |
||||
{% for row in TURN_TRACK_SQUARES %} |
||||
{% for turnSquare in row %}[{{turnSquare}}] {%endfor%} |
||||
{%endfor%} |
@ -0,0 +1 @@ |
||||
Customized TURN_TRACK. |
@ -0,0 +1 @@ |
||||
New default TURN_TRACK. |