diff options
Diffstat (limited to 'macros/latex/contrib/wargame/source/utils/wgexport.py')
-rwxr-xr-x | macros/latex/contrib/wargame/source/utils/wgexport.py | 971 |
1 files changed, 849 insertions, 122 deletions
diff --git a/macros/latex/contrib/wargame/source/utils/wgexport.py b/macros/latex/contrib/wargame/source/utils/wgexport.py index a09a7e4257..d573b63d36 100755 --- a/macros/latex/contrib/wargame/source/utils/wgexport.py +++ b/macros/latex/contrib/wargame/source/utils/wgexport.py @@ -208,6 +208,8 @@ CTRL_SHIFT = CTRL+SHIFT ALT_SHIFT = ALT+SHIFT NONE = '\ue004' NONE_MOD = 0 + +# -------------------------------------------------------------------- def key(let,mod=CTRL): '''Encode a key sequence @@ -220,6 +222,8 @@ def key(let,mod=CTRL): Modifier mask ''' return f'{ord(let)},{mod}' + +# -------------------------------------------------------------------- # def hexcolor(s): if isinstance(s,str): @@ -241,6 +245,7 @@ def hexcolor(s): return rgb(int(r*256),int(g*256),int(b*256)) +# -------------------------------------------------------------------- # Colour encoding def rgb(r,g,b): '''Encode RGB colour @@ -261,6 +266,7 @@ def rgb(r,g,b): ''' return ','.join([str(r),str(g),str(b)]) +# -------------------------------------------------------------------- def rgba(r,g,b,a): '''Encode RGBA colour @@ -282,6 +288,7 @@ def rgba(r,g,b,a): ''' return ','.join([str(r),str(g),str(b),str(a)]) +# -------------------------------------------------------------------- def dumpTree(node,ind=''): '''Dump the tree of nodes @@ -296,6 +303,12 @@ def dumpTree(node,ind=''): for c in node.childNodes: dumpTree(c,ind+' ') +# -------------------------------------------------------------------- +def registerElement(cls): + + Element.known_tags[cls.TAG] = cls + + # # EOF # @@ -310,6 +323,8 @@ class Element: MAP = MODULE + 'map.' PICKER = MAP + 'boardPicker.' BOARD = PICKER + 'board.' + known_tags = {} + def __init__(self,parent,tag,node=None,**kwargs): '''Create a new element @@ -429,9 +444,14 @@ class Element: return {c[key] : c for c in cand} return cand - def getParent(self,cls,checkTag=True): + def getParent(self,cls=None,checkTag=True): if self._node.parentNode is None: return None + if cls is None: + cls = self.getTagClass(self._node.parentNode.tagName) + checkTag = False + if cls is None: + return None if checkTag and self._node.parentNode.tagName != cls.TAG: return None return cls(self,node=self._node.parentNode) @@ -440,6 +460,10 @@ class Element: '''Searches back until we find the parent with the right class, or none ''' + try: + iter(cls) + except: + cls = [cls] t = {c.TAG: c for c in cls} p = self._node.parentNode while p is not None: @@ -447,6 +471,11 @@ class Element: if c is not None: return c(self,node=p) p = p.parentNode return None + + def getTagClass(self,tag): + '''Get class corresponding to the tag''' + if tag not in self.known_tags: return None; + return self.known_tags[tag] # ---------------------------------------------------------------- # Adders @@ -518,7 +547,83 @@ class DummyElement(Element): ''' super(DummyElement,self).__init__(parent,'Dummy',node=node) +# -------------------------------------------------------------------- +class ToolbarElement(Element): + def __init__(self, + parent, + tag, + node = None, + name = '', # Toolbar element name + tooltip = '', # Tool tip + text = '', # Button text + icon = '', # Button icon, + hotkey = '', # Named key or key stroke + canDisable = False, + propertyGate = '', + disabledIcon = '', + **kwargs): + '''Base class for toolbar elements. + Parameters + ---------- + parent : Element + Parent element if any + tag : str + Element tag + node : XMLNode + Possible node - when reading back + name : str + Name of element (user reminder). If not set, and tooltip is set, + set to tooltip + toolttip : str + Tool tip when hovering. If not set, and name is set, then + use name as tooltip. + text : str + Text of button + icon : str + Image path for button image + hotkey : str + Named key or key-sequence + canDisable : bool + If true, then the element can be disabled + propertyGate : str + Name of a global property. When this property is `true`, + then this element is _disabled_. Note that this _must_ be + the name of a property - it cannot be a BeanShell + expression. + disabledIcon : str + Path to image to use when the element is disabled. + kwargs : dict + Other attributes to set on the element + ''' + if name == '' and tooltip != '': name = tooltip + if name != '' and tooltip == '': tooltip = name + + # Build arguments for super class + args = { + 'node': node, + 'name': name, + 'icon': icon, + 'tooltip': tooltip, + 'hotkey': hotkey, + 'canDisable': canDisable, + 'propertyGate': propertyGate, + 'disabledIcon': disabledIcon } + bt = kwargs.pop('buttonText',None) + # If the element expects buttonText attribute, then do not set + # the text attribute - some elements interpret that as a + # legacy name attribute, + if bt is not None: + args['buttonText'] = bt + else: + args['text'] = text + args.update(kwargs) + + super(ToolbarElement,self).__init__(parent, + tag, + **args) + # print('Attributes\n','\n'.join([f'- {k}="{v}"' for k,v in self._node.attributes.items()])) + # # EOF # @@ -526,26 +631,28 @@ class DummyElement(Element): # From globalkey.py # -------------------------------------------------------------------- -class GlobalKey(Element): +class GlobalKey(ToolbarElement): SELECTED = 'MAP|false|MAP|||||0|0||true|Selected|true|EQUALS' def __init__(self, parent, tag, node = None, name = '', + icon = '', + tooltip = '', buttonHotkey = '', - hotkey = '', buttonText = '', canDisable = False, + propertyGate = '', + disabledIcon = '', + # Local + hotkey = '', deckCount = '-1', filter = '', - propertyGate = '', reportFormat = '', reportSingle = False, singleMap = True, - target = SELECTED, - tooltip = '', - icon = ''): + target = SELECTED): ''' Parameters ---------- @@ -569,28 +676,26 @@ class GlobalKey(Element): Default targets are selected units ''' - nme = (name if len(name) > 0 else - tooltip if len(tooltip) > 0 else '') - tip = (tooltip if len(tooltip) > 0 else - name if len(name) > 0 else '') + super(GlobalKey,self).\ __init__(parent, tag, node = node, - name = nme, + name = name, + icon = icon, + tooltip = tooltip, buttonHotkey = buttonHotkey, # This hot key - hotkey = hotkey, # Target hot key buttonText = buttonText, canDisable = canDisable, + propertyGate = propertyGate, + disabledIcon = disabledIcon, + hotkey = hotkey, # Target hot key deckCount = deckCount, filter = filter, - propertyGate = propertyGate, reportFormat = reportFormat, reportSingle = reportSingle, singleMap = singleMap, - target = target, - tooltip = tip, - icon = icon) + target = target) # # EOF # @@ -600,7 +705,7 @@ class GlobalKey(Element): # -------------------------------------------------------------------- class GameElementService: def getGame(self): - return self.getParent(Game) + return self.getParentOfClass(Game) # -------------------------------------------------------------------- class GameElement(Element,GameElementService): @@ -608,23 +713,34 @@ class GameElement(Element,GameElementService): super(GameElement,self).__init__(game,tag,node=node,**kwargs) # -------------------------------------------------------------------- -class Notes(GameElement): +class Notes(ToolbarElement,GameElementService): TAG = Element.MODULE+'NotesWindow' def __init__(self,elem,node=None, - name = 'Notes', - buttonText = '', - hotkey = key('N',ALT), - icon = '/images/notes.gif', - tooltip = 'Show notes window'): - super(Notes,self).__init__(elem,self.TAG,node=node, - name = name, - buttonText = buttonText, - hotkey = hotkey, - icon = icon, - tooltip = tooltip) + name = 'Notes', # Toolbar element name + tooltip = 'Show notes window', # Tool tip + text = '', # Button text + icon = '/images/notes.gif', # Button icon, + hotkey = key('N',ALT), # Named key or key stroke + canDisable = False, + propertyGate = '', + disabledIcon = '', + description = ''): + super(Notes,self).__init__(elem,self.TAG, + node = node, + name = name, + tooltip = tooltip, + text = text, + icon = icon, + hotkey = hotkey, + canDisable = canDisable, + propertyGate = propertyGate, + disabledIcon = disabledIcon, + description = description) def encode(self): return ['NOTES\t\\','PNOTES'] +registerElement(Notes) + # -------------------------------------------------------------------- class PredefinedSetup(GameElement): TAG = Element.MODULE+'PredefinedSetup' @@ -673,6 +789,7 @@ class PredefinedSetup(GameElement): +registerElement(PredefinedSetup) # -------------------------------------------------------------------- class GlobalTranslatableMessages(GameElement): @@ -690,11 +807,15 @@ class GlobalTranslatableMessages(GameElement): super(GlobalTranslatableMessages,self).\ __init__(elem,self.TAG,node=node) +registerElement(GlobalTranslatableMessages) + # -------------------------------------------------------------------- class Language(GameElement): TAG = 'VASSAL.i18n.Language' def __init__(self,elem,node=None,**kwargs): super(Languate,self).__init__(sele,self.TAG,node=none,**kwargs) + +registerElement(Language) # -------------------------------------------------------------------- class Chatter(GameElement): @@ -712,6 +833,8 @@ class Chatter(GameElement): Attributes ''' super(Chatter,self).__init__(elem,self.TAG,node=node,**kwargs) + +registerElement(Chatter) # -------------------------------------------------------------------- class KeyNamer(GameElement): @@ -730,6 +853,8 @@ class KeyNamer(GameElement): ''' super(KeyNamer,self).__init__(elem,self.TAG,node=node,**kwargs) +registerElement(KeyNamer) + # -------------------------------------------------------------------- # <VASSAL.build.module.GlobalOptions @@ -883,6 +1008,7 @@ class GlobalOptions(GameElement): return retd +registerElement(GlobalOptions) # -------------------------------------------------------------------- class Option(Element): @@ -894,6 +1020,8 @@ class Option(Element): def getGlobalOptions(self): return self.getParent(GlobalOptions) +registerElement(Option) + # -------------------------------------------------------------------- class Preference(Element): PREFS = 'VASSAL.preferences.' @@ -947,6 +1075,9 @@ class IntPreference(Preference): default = str(default), desc = desc, tab = tab) + +registerElement(IntPreference) + # -------------------------------------------------------------------- class FloatPreference(Preference): TAG = Preference.PREFS+'DoublePreference' @@ -964,6 +1095,9 @@ class FloatPreference(Preference): default = str(default), desc = desc, tab = tab) + +registerElement(FloatPreference) + # -------------------------------------------------------------------- class BoolPreference(Preference): TAG = Preference.PREFS+'BooleanPreference' @@ -982,6 +1116,9 @@ class BoolPreference(Preference): else 'false'), desc = desc, tab = tab) + +registerElement(BoolPreference) + # -------------------------------------------------------------------- class StrPreference(Preference): TAG = Preference.PREFS+'StringPreference' @@ -999,6 +1136,9 @@ class StrPreference(Preference): default = default, desc = desc, tab = tab) + +registerElement(StrPreference) + # -------------------------------------------------------------------- class TextPreference(Preference): TAG = Preference.PREFS+'TextPreference' @@ -1017,6 +1157,9 @@ class TextPreference(Preference): .replace('\n',' ')), desc = desc, tab = tab) + +registerElement(TextPreference) + # -------------------------------------------------------------------- class EnumPreference(Preference): TAG = Preference.PREFS+'EnumPreference' @@ -1042,39 +1185,42 @@ class EnumPreference(Preference): tab = tab, list = sl) + +registerElement(EnumPreference) + # -------------------------------------------------------------------- # CurrentMap == "Board" -class Inventory(GameElement): +class Inventory(ToolbarElement,GameElementService): TAG = Element.MODULE+'Inventory' def __init__(self,doc,node=None, - canDisable = False, - centerOnPiece = True, - disabledIcon = '', - drawPieces = True, - foldersOnly = False, - forwardKeystroke = True, - groupBy = '', - hotkey = key('I',ALT), - icon = '/images/inventory.gif', - include = '{}', - launchFunction = 'functionHide', - leafFormat = '$PieceName$', - name = '', - nonLeafFormat = '$PropertyValue$', - pieceZoom = '0.33', - pieceZoom2 = '0.5', - pieceZoom3 = '0.6', - propertyGate = '', - refreshHotkey = key('I',ALT_SHIFT), - showMenu = True, - sides = '', - sortFormat = '$PieceName$', - sortPieces = True, - sorting = 'alpha', - text = '', - tooltip = 'Show inventory of all pieces', - zoomOn = False): + name = '', + icon = '/images/inventory.gif', + text = '', + tooltip = 'Show inventory of all pieces', + hotkey = key('I',ALT), + canDisable = False, + propertyGate = '', + disabledIcon = '', + centerOnPiece = True, + drawPieces = True, + foldersOnly = False, + forwardKeystroke = True, + groupBy = '', + include = '{}', + launchFunction = 'functionHide', + leafFormat = '$PieceName$', + nonLeafFormat = '$PropertyValue$', + pieceZoom = '0.33', + pieceZoom2 = '0.5', + pieceZoom3 = '0.6', + refreshHotkey = key('I',ALT_SHIFT), + showMenu = True, + sides = '', + sortFormat = '$PieceName$', + sortPieces = True, + sorting = 'alpha', + zoomOn = False): super(Inventory,self).__init__(doc,self.TAG,node=node, canDisable = canDisable, centerOnPiece = centerOnPiece, @@ -1104,16 +1250,7 @@ class Inventory(GameElement): tooltip = tooltip, zoomOn = zoomOn) - - - - - - - - - - +registerElement(Inventory) # -------------------------------------------------------------------- class Prototypes(GameElement): @@ -1149,17 +1286,21 @@ class Prototypes(GameElement): ''' return self.getElementsByKey(Prototype,'name',asdict=asdict) - - +registerElement(Prototypes) # -------------------------------------------------------------------- -class DiceButton(GameElement): +class DiceButton(ToolbarElement,GameElementService): TAG=Element.MODULE+'DiceButton' def __init__(self,elem,node=None, - addToTotal = 0, - canDisable = False, - hotkey = key('6',ALT), + name = '1d6', + tooltip = 'Roll a 1d6', + text = '1d6', icon = '/images/die.gif', + hotkey = key('6',ALT), + canDisable = False, + propertyGate = '', + disabledIcon = '', + addToTotal = 0, keepCount = 1, keepDice = False, keepOption = '>', @@ -1169,19 +1310,16 @@ class DiceButton(GameElement): lockSides = False, nDice = 1, nSides = 6, - name = '1d6', plus = 0, prompt = False, - propertyGate = '', - reportFormat = '** $name$ = $result$ *** <$PlayerName$>;', + reportFormat = '$name$ = $result$', reportTotal = False, - sortDice = False, - text = '1d6', - tooltip = 'Roll a 1d6'): + sortDice = False): super(DiceButton,self).\ __init__(elem,self.TAG,node=node, addToTotal = addToTotal, canDisable = canDisable, + disabledIcon = disabledIcon, hotkey = hotkey, icon = icon, keepCount = keepCount, @@ -1203,24 +1341,27 @@ class DiceButton(GameElement): text = text, tooltip = tooltip) +registerElement(DiceButton) + # -------------------------------------------------------------------- class GameMassKey(GlobalKey,GameElementService): TAG = Element.MODULE+'GlobalKeyCommand' def __init__(self,map,node=None, name = '', - buttonHotkey = '', - hotkey = '', buttonText = '', + tooltip = '', + icon = '', canDisable = False, + propertyGate = '', + disabledIcon = '', + buttonHotkey = '', + hotkey = '', deckCount = '-1', filter = '', - propertyGate = '', reportFormat = '', reportSingle = False, singleMap = True, - target = GlobalKey.SELECTED, - tooltip = '', - icon = ''): + target = GlobalKey.SELECTED): '''Default targets are selected units''' super(GameMassKey,self).\ __init__(map, @@ -1241,6 +1382,8 @@ class GameMassKey(GlobalKey,GameElementService): tooltip = tooltip, icon = icon) +registerElement(GameMassKey) + # -------------------------------------------------------------------- class StartupMassKey(GlobalKey,GameElementService): TAG = Element.MODULE+'StartupGlobalKeyCommand' @@ -1287,21 +1430,24 @@ class StartupMassKey(GlobalKey,GameElementService): if node is None: self['whenToApply'] = whenToApply +registerElement(StartupMassKey) + # -------------------------------------------------------------------- class Menu(GameElement): TAG = Element.MODULE+'ToolbarMenu' def __init__(self, game, node = None, + name = '', + tooltip = '', + text = '', # Menu name canDisable = False, - description = '', + propertyGate = '', disabledIcon = '', + description = '', hotkey = '', icon = '', - menuItems = [],# Button texts - propertyGate = '', - text = '',# Menu name - tooltip = ''): + menuItems = []): if len(description) <= 0 and len(tooltip) > 0: description = tooltip if len(tooltip) <= 0 and len(description) > 0: @@ -1310,6 +1456,7 @@ class Menu(GameElement): __init__(game, self.TAG, node = node, + name = name, canDisable = canDisable, description = description, disabledIcon = disabledIcon, @@ -1320,6 +1467,8 @@ class Menu(GameElement): text = text, tooltip = tooltip) +registerElement(Menu) + # -------------------------------------------------------------------- class SymbolicDice(GameElement): @@ -1370,6 +1519,8 @@ class SymbolicDice(GameElement): def getSymbolicDice(self): return self.getParent(SymbolicDice) +registerElement(SymbolicDice) + # -------------------------------------------------------------------- class SpecialDie(GameElement): @@ -1399,8 +1550,7 @@ class SpecialDie(GameElement): def getSymbolicDice(self): return self.getParent(SymbolicDice) - - +registerElement(SpecialDie) # -------------------------------------------------------------------- class DieFace(GameElement): @@ -1421,6 +1571,9 @@ class DieFace(GameElement): def getSpecialDie(self): return self.getParent(SpecialDie) + +registerElement(DieFace) + # # EOF # @@ -1451,6 +1604,223 @@ class MapElement(Element,MapElementService): # -------------------------------------------------------------------- +class PieceLayers(MapElement): + TAG=Element.MAP+'LayeredPieceCollection' + def __init__(self,map,node=None, + property = 'PieceLayer', + description = '', + layerOrder = []): + super(PieceLayers,self).__init__(map,self.TAG,node=node, + property = property, + description = description, + layerOrder = ','.join(layerOrder)) + + def addControl(self,**kwargs): + '''Add `LayerControl` element to this + + Parameters + ---------- + kwargs : dict + Dictionary of attribute key-value pairs + Returns + ------- + element : LayerControl + The added element + ''' + return self.add(LayerControl,**kwargs) + def getControls(self,asdict=True): + '''Get all `LayerControl` element(s) from this + + Parameters + ---------- + asdict : bool + If `True`, return a dictonary that maps name to + `LayerControl` elements. If `False`, return a list of all + `LayerControl` children. + + Returns + ------- + children : dict or list + Dictionary or list of `LayerControl` children + + ''' + return self.getElementsByKey(LayerControl,'name',asdict) + +registerElement(PieceLayers) + +# -------------------------------------------------------------------- +class LayerControl(MapElement): + TAG=Element.MAP+'LayerControl' + CYCLE_UP='Rotate Layer Order Up' + CYCLE_DOWN='Rotate Layer Order Down' + ENABLE='Make Layer Active' + DISABLE='Make Layer Inactive' + TOGGLE='Switch Layer between Active and Inactive' + RESET='Reset All Layers' + def __init__(self,col,node=None, + name = '', + tooltip = '', + text = '', + hotkey = '', + icon = '', + canDisable = False, + propertyGate = '', #Property name, disable when property false + disabledIcon = '', + command = TOGGLE, + skip = False, + layers = [], + description = ''): + super(LayerControl,self).__init__(col,self.TAG,node=node, + name = name, + tooltip = tooltip, + text = text, + buttonText = text, + hotkey = hotkey, + icon = icon, + canDisable = canDisable, + propertyGate = propertyGate, + disabledIcon = disabledIcon, + command = command, + skip = skip, + layers = ','.join(layers), + description = description) + + def getLayers(self): + '''Get map - either a Map or WidgetMap''' + return self.getParentOfClass([PieceLayers]) + +registerElement(LayerControl) + + +# -------------------------------------------------------------------- +class LineOfSight(MapElement): + TAG=Element.MAP+'LOS_Thread' + ROUND_UP = 'Up' + ROUND_DOWN = 'Down' + ROUND_NEAREST = 'Nearest whole number' + FROM_LOCATION = 'FromLocation' + TO_LOCATION = 'ToLocation' + CHECK_COUNT = 'NumberOfLocationsChecked' + CHECK_LIST = 'AllLocationsChecked' + RANGE = 'Range' + NEVER = 'Never' + ALWAYS = 'Always' + WHEN_PERSISTENT = 'When persistent' + CTRL_CLICK = 'Cltr-Click & Drag' + + def __init__(self,map, + node=None, + threadName = 'LOS', + hotkey = key('L',ALT), + tooltip = 'Trace line of sight', + iconName = '/images/thread.gif', #'los-icon.png', + label = '', + snapLOS = False, + snapStart = True, + snapEnd = True, + report = (f'{{"Range from "+{FROM_LOCATION}' + f'+" to "+{TO_LOCATION}+" is "' + f'+{RANGE}+" (via "+{CHECK_LIST}+")"}}'), + persistent = CTRL_CLICK, + persistentIconName = '/images/thread.gif', + globl = ALWAYS, + losThickness = 3, + threadColor = rgb(255,0,0), + drawRange = True, + # rangeBg = rgb(255,255,255), + # rangeFg = rgb(0,0,0), + rangeScale = 0, + hideCounters = True, + hideOpacity = 50, + round = ROUND_UP, + canDisable = False, + propertyGate = '', + disabledIcon = ''): + '''Make Line of Sight interface + + Parameters + ---------- + threadName : str + Name of interface + hotkey : str + Start LOS key + tooltip : str + Tool tip text + iconName : str + Path to button icon + label : str + Button text + snapLOS : bool + Wether to snap both ends + snapStart : bool + Snap to start + snapEnd: bool + Snap to end + report : str + Report format + persistent : str + When persistent + persistentIconName : str + Icon when persistent(?) + globl : str + Visisble to opponents + losThickness : int + Thickness in pixels + losColor : str + Colour of line + drawRange : bool + Draw the range next to LOST thread + rangeBg : str + Range backgroung colour + rangeFg : str + Range foregrond colour + rangeScale : int + Scale of range - pixels per unit + round : str + How to round range + hideCounters :bool + If true, hide counters while making thread + hideOpacity : int + Opacity of hidden counters (percent) + canDisable : bool + IF true, then can be hidden + propertyGate : str + Name of property. When that property is TRUE, then the + interface is disabled. Must be a property name, not an expression. + disabledIcon : str + Icon to use when disabled + ''' + super(LineOfSight,self).__init__(map,self.TAG, + node = node, + threadName = threadName, + hotkey = hotkey, + tooltip = tooltip, + iconName = iconName, + label = label, + snapLOS = snapLOS, + snapStart = snapStart, + snapEnd = snapEnd, + report = report, + persistent = persistent, + persistentIconName = persistentIconName, + losThickness = losThickness, + threadColor = threadColor, + drawRange = drawRange, + #rangeBg = rangeBg, + #rangeFg = rangeFg, + rangeScale = rangeScale, + hideCounters = hideCounters, + hideOpacity = hideOpacity, + round = round, + canDisable = canDisable, + propertyGate = propertyGate, + disabledIcon = disabledIcon) + self.setAttribute('global',globl) + + +registerElement(LineOfSight) + +# -------------------------------------------------------------------- class StackMetrics(MapElement): TAG=Element.MAP+'StackMetrics' def __init__(self,map,node=None, @@ -1474,6 +1844,8 @@ class StackMetrics(MapElement): unexSepY = unexSepY, up = up) +registerElement(StackMetrics) + # -------------------------------------------------------------------- class ImageSaver(MapElement): TAG=Element.MAP+'ImageSaver' @@ -1491,6 +1863,9 @@ class ImageSaver(MapElement): icon = icon, propertyGate = propertyGate, tooltip = tooltip) + +registerElement(ImageSaver) + # -------------------------------------------------------------------- class TextSaver(MapElement): TAG=Element.MAP+'TextSaver' @@ -1509,6 +1884,7 @@ class TextSaver(MapElement): propertyGate = propertyGate, tooltip = tooltip) +registerElement(TextSaver) # -------------------------------------------------------------------- class ForwardToChatter(MapElement): @@ -1516,30 +1892,40 @@ class ForwardToChatter(MapElement): def __init__(self,map,node=None,**kwargs): super(ForwardToChatter,self).__init__(map,self.TAG,node=node,**kwargs) +registerElement(ForwardToChatter) + # -------------------------------------------------------------------- class MenuDisplayer(MapElement): TAG=Element.MAP+'MenuDisplayer' def __init__(self,map,node=None,**kwargs): super(MenuDisplayer,self).__init__(map,self.TAG,node=node,**kwargs) +registerElement(MenuDisplayer) + # -------------------------------------------------------------------- class MapCenterer(MapElement): TAG=Element.MAP+'MapCenterer' def __init__(self,map,node=None,**kwargs): super(MapCenterer,self).__init__(map,self.TAG,node=node,**kwargs) +registerElement(MapCenterer) + # -------------------------------------------------------------------- class StackExpander(MapElement): TAG=Element.MAP+'StackExpander' def __init__(self,map,node=None,**kwargs): super(StackExpander,self).__init__(map,self.TAG,node=node,**kwargs) +registerElement(StackExpander) + # -------------------------------------------------------------------- class PieceMover(MapElement): TAG=Element.MAP+'PieceMover' def __init__(self,map,node=None,**kwargs): super(PieceMover,self).__init__(map,self.TAG,node=node,**kwargs) +registerElement(PieceMover) + # -------------------------------------------------------------------- class SelectionHighlighters(MapElement): TAG=Element.MAP+'SelectionHighlighters' @@ -1547,12 +1933,16 @@ class SelectionHighlighters(MapElement): super(SelectionHighlighters,self).\ __init__(map,self.TAG,node=node,**kwargs) +registerElement(SelectionHighlighters) + # -------------------------------------------------------------------- class KeyBufferer(MapElement): TAG=Element.MAP+'KeyBufferer' def __init__(self,map,node=None,**kwargs): super(KeyBufferer,self).__init__(map,self.TAG,node=node,**kwargs) +registerElement(KeyBufferer) + # -------------------------------------------------------------------- class HighlightLastMoved(MapElement): TAG=Element.MAP+'HighlightLastMoved' @@ -1565,6 +1955,8 @@ class HighlightLastMoved(MapElement): enabled = enabled, thickness = thickness) +registerElement(HighlightLastMoved) + # -------------------------------------------------------------------- class CounterDetailViewer(MapElement): TAG=Element.MAP+'CounterDetailViewer' @@ -1587,7 +1979,7 @@ class CounterDetailViewer(MapElement): extraTextPadding = 0, fgColor = rgb(0,0,0), fontSize = 9, - graphicsZoom = 1.0, + graphicsZoom = 1.0,# Zoom on counters hotkey = key('\n',0), layerList = '', minDisplayPieces = 2, @@ -1649,6 +2041,8 @@ class CounterDetailViewer(MapElement): verticalTopText = verticalTopText, zoomlevel = zoomlevel) +registerElement(CounterDetailViewer) + # -------------------------------------------------------------------- class GlobalMap(MapElement): TAG=Element.MAP+'GlobalMap' @@ -1668,6 +2062,8 @@ class GlobalMap(MapElement): scale = scale, tooltip = 'Show/Hide overview window') +registerElement(GlobalMap) + # -------------------------------------------------------------------- class Zoomer(MapElement): TAG = Element.MAP+'Zoomer' @@ -1687,6 +2083,7 @@ class Zoomer(MapElement): zoomOutKey = key('-'), zoomPickKey = key('='), zoomStart = 3): + '''Zoom start is counting from the back (with default zoom levels, and zoom start, the default zoom is 1''' lvls = ','.join([str(z) for z in zoomLevels]) @@ -1707,6 +2104,8 @@ class Zoomer(MapElement): zoomPickKey = zoomPickKey, zoomStart = zoomStart) +registerElement(Zoomer) + # -------------------------------------------------------------------- class HidePiecesButton(MapElement): TAG=Element.MAP+'HidePiecesButton' @@ -1724,6 +2123,8 @@ class HidePiecesButton(MapElement): showingIcon = showingIcon, tooltip = tooltip) +registerElement(HidePiecesButton) + # -------------------------------------------------------------------- class MassKey(GlobalKey,MapElementService): TAG = Element.MAP+'MassKeyCommand' @@ -1760,6 +2161,7 @@ class MassKey(GlobalKey,MapElementService): tooltip = tooltip, icon = icon) +registerElement(MassKey) # -------------------------------------------------------------------- class Flare(MapElement): @@ -1783,10 +2185,13 @@ class Flare(MapElement): flarePulsesPerSec = flarePulsesPerSec, reportFormat = '') +registerElement(Flare) + # -------------------------------------------------------------------- class AtStart(MapElement): TAG = Element.MODULE+'map.SetupStack' - def __init__(self,map,node=None, + def __init__(self,map, + node = None, name = '', location = '', useGridLocation = True, @@ -1861,6 +2266,8 @@ class AtStart(MapElement): ''' return self.getElementsWithKey(PieceSlot,'entryName',asdict) +registerElement(AtStart) + # # EOF # @@ -1894,6 +2301,7 @@ class GlobalProperties(Element): def getProperties(self): return getElementsByKey(GlobalProperty,'name') +registerElement(GlobalProperties) # -------------------------------------------------------------------- class GlobalProperty(Element): @@ -1919,6 +2327,7 @@ class GlobalProperty(Element): def getGlobalProperties(self): return self.getParent(GlobalProperties) +registerElement(GlobalProperty) # # EOF @@ -2099,7 +2508,8 @@ class TurnTrack(TurnLevel): return [] - +registerElement(TurnTrack) + # -------------------------------------------------------------------- class TurnCounter(TurnLevel): TAG = Element.MODULE+"turn.CounterTurnLevel" @@ -2118,6 +2528,8 @@ class TurnCounter(TurnLevel): loopLimit = loopLimit, turnFormat = turnFormat) +registerElement(TurnCounter) + # -------------------------------------------------------------------- class TurnList(TurnLevel): TAG = Element.MODULE+"turn.ListTurnLevel" @@ -2135,6 +2547,8 @@ class TurnList(TurnLevel): configList = configList, turnFormat = turnFormat) +registerElement(TurnList) + # -------------------------------------------------------------------- class TurnGlobalHotkey(Element): TAG = Element.MODULE+'turn.TurnGlobalHotkey' @@ -2172,6 +2586,8 @@ class TurnGlobalHotkey(Element): '''Get the turn track''' return self.getParent(TurnTrack) +registerElement(TurnGlobalHotkey) + # # EOF # @@ -2316,6 +2732,7 @@ class Documentation(GameElement): return txt +registerElement(Documentation) # -------------------------------------------------------------------- class AboutScreen(Element): @@ -2343,6 +2760,8 @@ class AboutScreen(Element): '''Get Parent element''' return self.getParent(Documentation) +registerElement(AboutScreen) + # -------------------------------------------------------------------- class BrowserPDFFile(Element): TAG = Element.MODULE+'documentation.BrowserPDFFile' @@ -2368,6 +2787,8 @@ class BrowserPDFFile(Element): '''Get Parent element''' return self.getParent(Documentation) +registerElement(BrowserPDFFile) + # -------------------------------------------------------------------- class HelpFile(Element): TAG = Element.MODULE+'documentation.HelpFile' @@ -2400,6 +2821,8 @@ class HelpFile(Element): '''Get Parent element''' return self.getParent(Documentation) +registerElement(HelpFile) + # -------------------------------------------------------------------- class BrowserHelpFile(Element): TAG = Element.MODULE+'documentation.BrowserHelpFile' @@ -2427,7 +2850,9 @@ class BrowserHelpFile(Element): def getDocumentation(self): '''Get Parent element''' return self.getParent(Documentation) - + +registerElement(BrowserHelpFile) + # -------------------------------------------------------------------- class Tutorial(Element): TAG = Element.MODULE+'documentation.Tutorial' @@ -2468,6 +2893,8 @@ class Tutorial(Element): '''Get Parent element''' return self.getParent(Documentation) +registerElement(Tutorial) + # # EOF @@ -2517,6 +2944,8 @@ class PlayerRoster(GameElement): '''Encode for save''' return ['PLAYER\ta\ta\t<observer>'] +registerElement(PlayerRoster) + # -------------------------------------------------------------------- class PlayerSide(Element): TAG = 'entry' @@ -2540,6 +2969,8 @@ class PlayerSide(Element): '''Get Parent element''' return self.getParent(PlayerRoster) +registerElement(PlayerSide) + # # EOF @@ -2614,7 +3045,9 @@ class ChessClock(Element): def getControl(self): '''Get Parent element''' return self.getParent(ChessClockControl) - + +registerElement(ChessClock) + # ==================================================================== class ChessClockControl(GameElement): TAG=Element.MODULE+'ChessClockControl' @@ -2727,6 +3160,7 @@ class ChessClockControl(GameElement): '''Return dictionary of clocs''' return self.getElementsByKey(ChessClock,'side',asdict) +registerElement(ChessClockControl) # # EOF @@ -2961,6 +3395,8 @@ class PieceWindow(GameElement,WidgetElement): tooltip = tooltip, icon = icon) +registerElement(PieceWindow) + # -------------------------------------------------------------------- class ComboWidget(Element,WidgetElement): TAG=Element.WIDGET+'BoxWidget' @@ -2972,6 +3408,8 @@ class ComboWidget(Element,WidgetElement): width = width, height = height) +registerElement(ComboWidget) + # -------------------------------------------------------------------- class TabWidget(Element,WidgetElement): TAG=Element.WIDGET+'TabWidget' @@ -2981,6 +3419,8 @@ class TabWidget(Element,WidgetElement): node = node, entryName = entryName) +registerElement(TabWidget) + # -------------------------------------------------------------------- class ListWidget(Element,WidgetElement): TAG=Element.WIDGET+'ListWidget' @@ -2997,6 +3437,8 @@ class ListWidget(Element,WidgetElement): scale = scale, divider = divider) +registerElement(ListWidget) + # -------------------------------------------------------------------- class PanelWidget(Element,WidgetElement): TAG=Element.WIDGET+'PanelWidget' @@ -3011,6 +3453,8 @@ class PanelWidget(Element,WidgetElement): nColumns = nColumns, vert = vert) +registerElement(PanelWidget) + # -------------------------------------------------------------------- class MapWidget(Element): TAG=Element.WIDGET+'MapWidget' @@ -3046,6 +3490,8 @@ class MapWidget(Element): ''' return self.getElementsByKey(WidgetMap,'mapName',asdict=asdict) +registerElement(MapWidget) + # # EOF # @@ -3258,6 +3704,8 @@ class HexGrid(BaseGrid): width = self.getZone().getWidth() return floor(width / self.getDeltaY() + .5) +registerElement(HexGrid) + # -------------------------------------------------------------------- class SquareGrid(BaseGrid): TAG = Element.BOARD+'SquareGrid' @@ -3307,6 +3755,8 @@ class SquareGrid(BaseGrid): width = self.getZone().getWidth() return floor(width / self.getDeltaX() + .5) +registerElement(SquareGrid) + # -------------------------------------------------------------------- class HexNumbering(BaseNumbering): TAG = Element.BOARD+'mapgrid.HexGridNumbering' @@ -3368,6 +3818,8 @@ class HexNumbering(BaseNumbering): return x,y +registerElement(HexNumbering) + # -------------------------------------------------------------------- class SquareNumbering(BaseNumbering): TAG = Element.BOARD+'mapgrid.SquareGridNumbering' @@ -3395,6 +3847,7 @@ class SquareNumbering(BaseNumbering): return x,y +registerElement(SquareNumbering) # -------------------------------------------------------------------- class RegionGrid(Element): @@ -3452,6 +3905,8 @@ class RegionGrid(Element): return None +registerElement(RegionGrid) + # -------------------------------------------------------------------- class Region(Element): TAG = Element.BOARD+'Region' @@ -3527,6 +3982,8 @@ class Region(Element): return b.getMap() return None +registerElement(Region) + # # EOF # @@ -3579,7 +4036,7 @@ class ZonedGrid(Element): children : list List of `Highligter` children (even if `single=True`) ''' - return self.getAllElements(ZonedGridHighliger,single=single) + return self.getAllElements(ZonedGridHighlighter,single=single) def addZone(self,**kwargs): '''Add a `Zone` element to this @@ -3607,6 +4064,8 @@ class ZonedGrid(Element): ''' return self.getElementsByKey(Zone,'name',asdict=asdict) +registerElement(ZonedGrid) + # -------------------------------------------------------------------- class ZonedGridHighlighter(Element): TAG=Element.BOARD+'mapgrid.ZonedGridHighlighter' @@ -3614,6 +4073,96 @@ class ZonedGridHighlighter(Element): super(ZonedGridHighlighter,self).__init__(zoned,self.TAG,node=node) def getZonedGrid(self): return self.getParent(ZonedGrid) + def addZoneHighlight(self,**kwargs): + '''Add a `ZoneHighlight` element to this + + Parameters + ---------- + kwargs : dict + Dictionary of attribute key-value pairs + Returns + ------- + element : ZoneHighlight + The added element + ''' + return self.add(ZoneHighlight,**kwargs) + def getZoneHighlights(self,asdict=True): + '''Get all ZoneHighlight element(s) from this + + Parameters + ---------- + asdict : bool + If `True`, return a dictonary that maps key to `Zone` elements. If `False`, return a list of all Zone` children. + Returns + ------- + children : dict or list + Dictionary or list of `Zone` children + ''' + return self.getElementsByKey(ZoneHighlight,'name',asdict=asdict) + +registerElement(ZonedGridHighlighter) + +# -------------------------------------------------------------------- +class ZoneHighlight(Element): + TAG=Element.BOARD+'mapgrid.ZoneHighlight' + FULL='Entire Zone', + BORDER='Zone Border', + PLAIN='Plain', + STRIPED='Striped' + CROSS='Crosshatched', + TILES='Tiled Image' + def __init__(self, + highlighters, + node = None, + name = '', + color = rgb(255,0,0), + coverage = FULL, + width = 1, + style = PLAIN, + image = '', + opacity = 50): + super(ZoneHighlight,self).__init__(highlighters, + self.TAG, + node = node, + name = name, + color = color, + coverage = coverage, + width = width, + style = style, + image = image, + opacity = int(opacity)) + def getZonedGridHighlighter(self): + return self.getParent(ZonedGridHighlighter) + + +registerElement(ZoneHighlight) + + +# -------------------------------------------------------------------- +class ZoneProperty(Element): + TAG = Element.MODULE+'properties.ZoneProperty' + def __init__(self,zone,node=None, + name = '', + initialValue = '', + isNumeric = False, + min = "null", + max = "null", + wrap = False, + description = ""): + super(ZoneProperty,self).__init__(zone,self.TAG, + node = node, + name = name, + initialValue = initialValue, + isNumeric = isNumeric, + min = min, + max = max, + wrap = wrap, + description = description) + + def getZone(self): + return self.getParent(Zone) + +registerElement(ZoneProperty) # -------------------------------------------------------------------- class Zone(Element): @@ -3693,6 +4242,19 @@ class Zone(Element): The added element ''' return self.add(RegionGrid,**kwargs) + def addProperty(self,**kwargs): + '''Add a `Property` element to this + + Parameters + ---------- + kwargs : dict + Dictionary of attribute key-value pairs + Returns + ------- + element : Property + The added element + ''' + return self.add(ZoneProperty,**kwargs) def getHexGrids(self,single=True): '''Get all or a sole `HexGrid` element(s) from this @@ -3758,6 +4320,17 @@ class Zone(Element): if g is not None: return g return g + def getProperties(self): + '''Get all `Property` element from this + + Parameters + ---------- + Returns + ------- + children : dict + dict of `Property` children + ''' + return getElementsByKey(ZoneProperty,'name') def getPath(self): p = self['path'].split(';') @@ -3785,6 +4358,8 @@ class Zone(Element): def getYOffset(self): return self.getBB()[1] +registerElement(Zone) + # # EOF # @@ -3879,6 +4454,8 @@ class BoardPicker(MapElement): return ret +registerElement(BoardPicker) + # -------------------------------------------------------------------- class Setup(Element): TAG = 'setup' @@ -3901,7 +4478,9 @@ class Setup(Element): self.addText(txt) def getPicker(self): return self.getParent(BoardPicker) - + +registerElement(Setup) + # -------------------------------------------------------------------- class Board(Element): TAG = Element.PICKER+'Board' @@ -3982,6 +4561,7 @@ class Board(Element): return int(self['height']) return 0 +registerElement(Board) # # EOF @@ -4340,6 +4920,57 @@ class BaseMap(Element): picker = self.getPicker() if picker is None: return None return picker[0].getBoards(asdict=asdict) + def getLayers(self,asdict=True): + '''Get all `PieceLayer` element(s) from this + + Parameters + ---------- + asdict : bool + If `True`, return a dictonary that maps property name + `PieceLayers` elements. If `False`, return a list of all + `PieceLayers` children. + + Returns + ------- + children : dict or list + Dictionary or list of `PieceLayers` children + + ''' + return self.getElementsByKey(PieceLayers,'property',asdict) + def getMenus(self,asdict=True): + '''Get all Menu element(s) from this + + Parameters + ---------- + asdict : bool + If `True`, return a dictonary that maps key to `Board` + elements. If `False`, return a list of all Board` + children. + + Returns + ------- + children : dict or list + Dictionary or list of `Board` children + + ''' + return self.getElementsByKey(Menu,'name',asdict) + def getLOSs(self,asdict=True): + '''Get all Menu element(s) from this + + Parameters + ---------- + asdict : bool + If `True`, return a dictonary that maps key to `Board` + elements. If `False`, return a list of all Board` + children. + + Returns + ------- + children : dict or list + Dictionary or list of `Board` children + + ''' + return self.getElementsByKey(LineOfSight,'threadName',asdict) def addBoardPicker(self,**kwargs): '''Add a `BoardPicker` element to this @@ -4600,6 +5231,47 @@ class BaseMap(Element): The added element ''' return self.add(AtStart,**kwargs) + + + def addLayers(self,**kwargs): + '''Add `PieceLayers` element to this + + Parameters + ---------- + kwargs : dict + Dictionary of attribute key-value pairs + Returns + ------- + element : PieceLayers + The added element + ''' + return self.add(PieceLayers,**kwargs) + def addMenu(self,**kwargs): + '''Add a `Menu` element to this + + Parameters + ---------- + kwargs : dict + Dictionary of attribute key-value pairs + Returns + ------- + element : Menu + The added element + ''' + return self.add(Menu,**kwargs) + def addLOS(self,**kwargs): + '''Add a `Menu` element to this + + Parameters + ---------- + kwargs : dict + Dictionary of attribute key-value pairs + Returns + ------- + element : Menu + The added element + ''' + return self.add(LineOfSight,**kwargs) # -------------------------------------------------------------------- class Map(BaseMap): @@ -4657,7 +5329,9 @@ class Map(BaseMap): def getGame(self): return self.getParent(Game) - + +registerElement(Map) + # -------------------------------------------------------------------- class WidgetMap(BaseMap): TAG = Element.WIDGET+'WidgetMap' @@ -4669,6 +5343,8 @@ class WidgetMap(BaseMap): def getMapWidget(self): return self.getParent(MapWidget) +registerElement(WidgetMap) + # # EOF @@ -4721,7 +5397,7 @@ class ChartWindow(GameElement,WidgetElement): ''' return self.getElementsById(Chart,'chartName',asdict=asdict) - +registerElement(ChartWindow) # -------------------------------------------------------------------- class Chart(Element): @@ -4735,6 +5411,8 @@ class Chart(Element): description = description, fileName = fileName) +registerElement(Chart) + # # EOF # @@ -4766,7 +5444,7 @@ class Trait: this actually holds state that isn't reflected elsewhere in the DOM. This means that the data here is local to the object. So when we do - + piece = foo.getPieceSlots()[0] traits = p.getTraits() for trait in traits: @@ -5040,6 +5718,15 @@ class WithTraits(Element): Identifier ''' + last = traits[-1] + # A little hackish to use the name of the class, but needed + # because of imports into patch scripts. + if not isinstance(last,BasicTrait) and \ + not last.__class__.__name__.endswith('BasicTrait'): + from sys import stderr + print(f'Warning - last trait NOT a BasicTrait, but a {type(last)}', + file=stderr) + types = [] states = [] for trait in traits: @@ -5165,7 +5852,9 @@ class DummyWithTraits(WithTraits): if parent is not None: parent.remove(self) - + +registerElement(DummyWithTraits) + # -------------------------------------------------------------------- class PieceSlot(WithTraits): TAG = Element.WIDGET+'PieceSlot' @@ -5226,6 +5915,7 @@ class PieceSlot(WithTraits): piece.setTraits(*traits) return piece +registerElement(PieceSlot) # -------------------------------------------------------------------- class Prototype(WithTraits): @@ -5255,6 +5945,8 @@ class Prototype(WithTraits): name = name, description = description) +registerElement(Prototype) + # # EOF # @@ -5262,16 +5954,21 @@ class Prototype(WithTraits): # From traits/dynamicproperty.py # -------------------------------------------------------------------- -# Base class for property (piece or global) change traits. Encodes -# constraints and commands. +# +# class ChangePropertyTrait(Trait): DIRECT = 'P' + INCREMENT = 'I' def __init__(self, *commands, numeric = False, min = 0, max = 100, wrap = False): + '''Base class for property (piece or global) change traits. + + Encodes constraints and commands. + ''' # assert name is not None and len(name) > 0, \ # 'No name specified for ChangePropertyTriat' super(ChangePropertyTrait,self).__init__() @@ -5293,8 +5990,11 @@ class ChangePropertyTrait(Trait): # print(cmd) com = cmd[0] + ':' + cmd[1].replace(',',r'\,') + ':' + cmd[2] if cmd[2] == self.DIRECT: - com += f'\,'+cmd[3].replace(':',r'\:') + com += f'\,'+cmd[3].replace(',',r'\\,').replace(':',r'\:') + elif cmd[2] == self.INCREMENT: + com += f'\,'+cmd[3].replace(',',r'\\,').replace(':',r'\:') cmds.append(com) + # print(cmds) return ','.join(cmds) def decodeCommands(self,commands): @@ -5305,6 +6005,8 @@ class ChangePropertyTrait(Trait): # print('parts',parts) if parts[-1][0] == self.DIRECT: parts = parts[:-1]+Trait.decodeKeys(parts[-1],',') + if parts[-1][0] == self.INCREMENT: + parts = parts[:-1]+Trait.decodeKeys(parts[-1],',') ret.append(parts) # print(commands,parts) return ret @@ -5840,7 +6542,7 @@ class NoStackTrait(Trait): canStack = False, ignoreGrid = False, description = ''): - + '''No stacking trait''' selectionOptions = (select + (self.IGNORE_GRID if ignoreGrid else '') + bandSelect) @@ -7319,6 +8021,7 @@ class Game(Element): ''' return self.getAllElements(AtStart,single) +registerElement(Game) # -------------------------------------------------------------------- class BasicCommandEncoder(GameElement): @@ -7326,6 +8029,8 @@ class BasicCommandEncoder(GameElement): def __init__(self,doc,node=None): super(BasicCommandEncoder,self).__init__(doc,self.TAG,node=node) +registerElement(BasicCommandEncoder) + # # EOF # @@ -8446,7 +9151,8 @@ class LaTeXExporter(Exporter): vassalVersion = '3.6.7', nonato = False, nochit = False, - counterScale = 1): + counterScale = 1, + resolution = 150): '''Exports a PDF and associated JSON files to a VASSAL module. Parameters @@ -8473,6 +9179,8 @@ class LaTeXExporter(Exporter): Make grids visible vassalVersion : str VASSAL version to encode this module for + resolution : int + Resolution for images (default 150) ''' self._vmodname = vmodname self._pdfname = pdfname @@ -8487,6 +9195,7 @@ class LaTeXExporter(Exporter): self._vassalVersion = vassalVersion self._nonato = nonato self._nochit = nochit + self._resolution = resolution self._counterScale = counterScale self._battleMark = 'wgBattleMarker' self._battleMarks = [] @@ -8572,6 +9281,7 @@ class LaTeXExporter(Exporter): v(f'Tutorial log: {self._tutorial}') v(f'Patch scripts: {self._patch}') v(f'Visible grids: {self._visible}') + v(f'Resolution: {self._resolution}') v(f'Scale of counters: {self._counterScale}') def setup(self): @@ -8704,6 +9414,7 @@ class LaTeXExporter(Exporter): args = ['pdftocairo', '-transp', '-singlefile', + '-r', str(self._resolution), '-f', str(page), '-l', str(page), '-png' ] @@ -8772,9 +9483,9 @@ class LaTeXExporter(Exporter): imgsinfo = self.getImagesInfo() if len(imgsinfo) - 1 != docinfo['Pages']: - raise RuntimeError(f'Number of pages in {pdfname} ' - f'(doc["Pages"]) not matched in JSON ' - f'{self._infoname} -> {len(imagesinfo)}') + raise RuntimeError(f'Number of pages in {self._pdfname} ' + f'{docinfo["Pages"]} not matched in JSON ' + f'{self._infoname} -> {len(imgsinfo)}') with VerboseGuard(f'Converting {docinfo["Pages"]} ' f'pages in {self._pdfname}') as v: @@ -9126,10 +9837,16 @@ class LaTeXExporter(Exporter): 'property': 'Phase', 'names': self._sides } }) turns.addHotkey(hotkey = self._clearMoved+'Phase', - name = 'Clear moved markers') + name = 'Clear moved markers', + reportFormat = (f'{{{self._verbose}?(' + f'"`Clear all moved markers, "+' + f'""):""}}')) if len(self._battleMarks) > 0: turns.addHotkey(hotkey = self._clearBattlePhs, - name = 'Clear battle markers') + name = 'Clear battle markers', + reportFormat = (f'{{{self._verbose}?(' + f'"`Clear all battle markers, "+' + f'""):""}}')) self._dice = self._categories\ .get('die-roll',{}) @@ -9153,7 +9870,9 @@ class LaTeXExporter(Exporter): # f'+" <img src=\'{die}-"+result1' # f'+".png\' width=24 height=24>"' f'}}'), - resultWindow = True); + resultWindow = True, + windowX = str(int(67 * self._resolution/150)), + windowY = str(int(65 * self._resolution/150))); sdie = symb.addDie(name = die); for face, fdata in faces.items(): fn = fdata['filename'] @@ -10186,13 +10905,14 @@ class LaTeXExporter(Exporter): # ---------------------------------------------------------------- def factionTraits(self,faction): - traits = [ReportTrait(self._eliminateKey, - self._restoreKey, - self._trailKey), + offX = 36 * self._counterScale * self._resolution/150 + offY = -38 * self._counterScale * self._resolution/150 + traits = [#ReportTrait(self._eliminateKey, + # self._restoreKey, + # self._trailKey), TrailTrait(), RotateTrait(), - MovedTrait(xoff = int( 36 * self._counterScale), - yoff = int(-38 * self._counterScale)), + MovedTrait(xoff = int(offX),yoff = int(offY)), DeleteTrait(), SendtoTrait(mapName = 'DeadMap', boardName = f'{faction} pool', @@ -11308,7 +12028,10 @@ class LaTeXExporter(Exporter): pc = p["coords"] if j == 0: vv(f'',end='') vv(f'[{pn}] ',end='',flush=True,noindent=True) - + + if pn.endswith(' flipped'): + pn = pn[:-len(' flipped')] + x, y = tran(*pc) r = grid.addRegion(name = pn, originx = x, @@ -11499,7 +12222,7 @@ class LaTeXExporter(Exporter): def addDie(self): '''Add a `Die` element to the module ''' - if self._dice is not None: + if self._dice is not None and len(self._dice) > 0: return self._game.addDiceButton(name = '1d6', hotkey = self._diceKey) @@ -11568,6 +12291,9 @@ if __name__ == '__main__': ap.add_argument('-S','--counter-scale', type=float, default=1, help='Scale counters by factor') + ap.add_argument('-R','--resolution', + type=int, default=150, + help='Resolution of images') args = ap.parse_args() @@ -11600,6 +12326,7 @@ if __name__ == '__main__': vassalVersion = args.vassal_version, nonato = args.no_nato_prototypes, nochit = args.no_chit_information, + resolution = args.resolution, counterScale = args.counter_scale) exporter.run() except Exception as e: |