#!/usr/bin/env python3
"""Generate resources/skins/Default/1080i/games/DialogMilionarGameModern.xml: the modern card of the Millionaire game.

The window is a large rounded translucent card over the dimmed Home screen: the backdrop of the work fades in from the
right, the screen (title, rules, intro, question, feedback, game over, win, results, error) is chosen by the property
`WCS.Game.Screen` that wcs/games/game_view.py publishes, and every screen is built from the same few components below
(panel, button, chip, answer tile ...), so shapes, radii, colours and animations stay consistent. Control ids are those
of wcs/games/designs.py (MODERN). Shapes come from existing textures (search / notification dialogs: card radius 36,
panels 24-30, buttons 20); icons are Kodi's own. Run after changing this file; never edit the XML by hand.
"""
import os
import sys
from xml.sax.saxutils import escape

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))
from wcs.games import game_settings                      # noqa: E402  (the rows of the settings screen)

OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'resources', 'skins', 'Default', '1080i',
                   'games', 'DialogMilionarGameModern.xml')
MEDIA = 'special://home/addons/plugin.video.milionar/resources/media/'


def M(name):
    """A texture of the addon's media folder (Kodi's own icons are given by their skin names instead)."""
    return MEDIA + name


CARD_TEX, CARD_STROKE_TEX = M('notif_card_fill.png'), M('notif_card_stroke.png')
PANEL_TEX, PANEL_STROKE_TEX = M('search_card_fill.png'), M('search_card_stroke.png')
BTN_TEX, BTN_STROKE_TEX = M('search_card_button_fill.png'), M('search_card_button_stroke.png')
CIRCLE_TEX, CIRCLE_STROKE_TEX, WHITE_TEX = M('search_circle_fill.png'), M('search_circle_stroke.png'), M('white.png')

# ---- design tokens
CARD_X, CARD_Y, CARD_W, CARD_H = 100, 60, 1720, 960
PAD = 56
START_ROW_Y, START_PRIMARY_W, START_BACK_W, START_GAP, START_H = 764, 640, 400, 20, 84
START_ROW_W = START_PRIMARY_W + START_GAP + START_BACK_W
START_HALF_W = (760 - START_GAP) // 2          # two buttons share the width of the primary one
COL_W = 1000                                   # the text column; the backdrop fills the rest of the card
TXT, SUB, DIM, GOLD = 'FFFBFBFD', 'FFC9CAD0', 'FF8E909A', 'FFE8B860'
GREEN, RED, INK = 'FF5BD58A', 'FFFF6B6B', 'FF14141A'
CARD_FILL, CARD_STROKE = 'FA262629', 'FF57575E'
PANEL_FILL, PANEL_STROKE = '5C0E0E12', '30FFFFFF'
SOLID_FILL, SOLID_STROKE = 'E8101014', '48FFFFFF'
GOLD_SOLID_FILL = 'EE1D1708'
BTN_FILL, BTN_STROKE, BTN_FOCUS_FILL = '12FFFFFF', '38FFFFFF', 'FFF6F0E2'
GREEN_FILL, RED_FILL = '2A5BD58A', '2AFF6B6B'
R_CARD, R_PANEL, R_BTN = 36, 30, 21           # 9-slice borders of the textures used
# question screen, top to bottom: lifelines, the help card (a tip of up to 4 lines, or the poll), two rows of answers;
# the answers end on the bottom edge of the ladder card (112 + 744)
HELP_Y, HELP_H, HELP_GAP = 408, 204, 12
ANSWER_H, ANSWER_GAP = 108, 16
ANSWER_Y1 = HELP_Y + HELP_H + HELP_GAP
ANSWER_Y2 = ANSWER_Y1 + ANSWER_H + ANSWER_GAP

SCREEN = 'Window.Property(WCS.Game.Screen)'


def localized(string_id):
    """A string of the addon's language files (cs / sk / en) as the skin XML reads it."""
    return '$ADDON[plugin.video.milionar {}]'.format(string_id)


def prop(name, namespace='WCS.Game'):
    return 'Window.Property({}.{})'.format(namespace, name)


def info(name, prefix='', suffix='', namespace='WCS.Game'):
    source = prop(name, namespace)
    return '$INFO[{},{},{}]'.format(source, prefix, suffix) if (prefix or suffix) else '$INFO[{}]'.format(source)


def is_prop(name, value, namespace='WCS.Game'):
    return 'String.IsEqual({},{})'.format(prop(name, namespace), value)


def has(name):
    return '!String.IsEmpty({})'.format(prop(name))


def empty(name):
    return 'String.IsEmpty({})'.format(prop(name))


def on_screen(*names):
    return ' | '.join('String.IsEqual({},{})'.format(SCREEN, n) for n in names)


# ---- XML building blocks
def tag(name, text, indent):
    return '{}<{}>{}</{}>'.format(indent, name, text, name)


def anims(items, indent):
    """items: (effect attributes, kind) pairs -> <animation> lines."""
    return [indent + '<animation {}>{}</animation>'.format(attrs, kind) for attrs, kind in items]


def control(kind, children, indent, **attrs):
    ident = ' id="{}"'.format(attrs['id']) if attrs.get('id') else ''
    return ['{}<control type="{}"{}>'.format(indent, kind, ident)] + children + ['{}</control>'.format(indent)]


def geometry(x, y, w, h, indent):
    return [tag('left', x, indent), tag('top', y, indent), tag('width', w, indent), tag('height', h, indent)]


def image(texture, x, y, w, h, indent, color=None, border=None, visible=None, animations=(), diffuse=None, aspect=None,
          fallback=None, flipx=False):
    inner = indent + '    '
    body = geometry(x, y, w, h, inner)
    texture_attrs = ''.join([' border="{}"'.format(border) if border else '',
                             ' colordiffuse="{}"'.format(color) if color else '',
                             ' diffuse="{}"'.format(M(diffuse)) if diffuse else '',
                             ' fallback="{}"'.format(M(fallback)) if fallback else '',
                             ' flipx="true"' if flipx else ''])
    body.append('{}<texture{}>{}</texture>'.format(inner, texture_attrs, texture))
    if aspect:
        scale = ' scalediffuse="false"' if diffuse else ''
        body.append('{}<aspectratio{}>{}</aspectratio>'.format(inner, scale, aspect))
    if visible:
        body.append(tag('visible', escape(visible), inner))
    body += anims(animations, inner)
    return control('image', body, indent)


def label(text, x, y, w, h, indent, font='font25_title', color=TXT, align='left', aligny='center', visible=None,
          scroll=False, animations=(), wrap=False):
    inner = indent + '    '
    if text.isdigit():
        text = '[B]{}[/B]'.format(text)          # a purely numeric label would be read as a string id
    body = geometry(x, y, w, h, inner) + [tag('font', font, inner), tag('textcolor', color, inner),
                                          tag('label', escape(text), inner), tag('align', align, inner),
                                          tag('aligny', aligny, inner)]
    if scroll:
        body += [tag('scroll', 'true', inner), tag('scrollspeed', '40', inner), tag('scrollsuffix', '  •  ', inner)]
    if wrap:
        body.append(tag('wrapmultiline', 'true', inner))
    if visible:
        body.append(tag('visible', escape(visible), inner))
    body += anims(animations, inner)
    return control('label', body, indent)


def textbox(text, x, y, w, h, indent, font='font27', color=SUB, visible=None, autoscroll=False):
    inner = indent + '    '
    body = geometry(x, y, w, h, inner) + [tag('font', font, inner), tag('textcolor', color, inner),
                                          tag('label', escape(text), inner), tag('align', 'left', inner)]
    if autoscroll:
        body.append(inner + '<autoscroll delay="4000" time="1500" repeat="5000">true</autoscroll>')
    if visible:
        body.append(tag('visible', escape(visible), inner))
    return control('textbox', body, indent)


def group(children, x, y, w, h, indent, visible=None, animations=(), ident=None):
    inner = indent + '    '
    body = geometry(x, y, w, h, inner)
    if visible:
        body.append(tag('visible', escape(visible), inner))
    body += anims(animations, inner)
    for child in children:
        body += child
    return control('group', body, indent, id=ident)


def nav(onup=None, ondown=None, onleft=None, onright=None, indent=''):
    body = []
    for direction, value in (('onup', onup), ('ondown', ondown), ('onleft', onleft), ('onright', onright)):
        if isinstance(value, tuple):
            for condition, target in value:
                body.append('{}<{} condition="{}">{}</{}>'.format(indent, direction, escape(condition),
                                                                  target or 'noop', direction))
        else:
            body.append(tag(direction, value or 'noop', indent))
    return body


def screen_animations(delay=60):
    """A screen fades in while it rises a little, and fades out quickly."""
    return [('effect="fade" start="0" end="100" time="360" delay="{}" tween="cubic" easing="out"'.format(delay), 'Visible'),
            ('effect="slide" start="0,26" end="0,0" time="360" delay="{}" tween="cubic" easing="out"'.format(delay), 'Visible'),
            ('effect="fade" start="100" end="0" time="140"', 'Hidden')]


def stagger(delay):
    return [('effect="fade" start="0" end="100" time="320" delay="{}" tween="cubic" easing="out"'.format(delay), 'Visible'),
            ('effect="slide" start="0,18" end="0,0" time="320" delay="{}" tween="cubic" easing="out"'.format(delay), 'Visible')]


# ---- components
def panel(x, y, w, h, indent, tone='plain', visible=None):
    """A rounded inner card; tone: plain | solid (over the backdrop) | green | red | gold."""
    fill = {'plain': PANEL_FILL, 'solid': SOLID_FILL, 'green': GREEN_FILL, 'red': RED_FILL, 'gold': '33E8B860',
            'goldsolid': GOLD_SOLID_FILL}[tone]
    stroke = {'plain': PANEL_STROKE, 'solid': SOLID_STROKE, 'green': GREEN, 'red': RED, 'gold': GOLD,
              'goldsolid': GOLD}[tone]
    return group([image(PANEL_TEX, 0, 0, w, h, indent + '    ', color=fill, border=R_PANEL),
                  image(PANEL_STROKE_TEX, 0, 0, w, h, indent + '    ', color=stroke, border=R_PANEL)],
                 x, y, w, h, indent, visible=visible)


def button_frame(focus, w, h, inner):
    """The look of a button: translucent idle, cream with a pulsing gold ring when `focus` (a condition) holds."""
    return [
        image(BTN_TEX, 0, 0, w, h, inner, color=BTN_FILL, border=R_BTN),
        image(BTN_STROKE_TEX, 0, 0, w, h, inner, color=BTN_STROKE, border=R_BTN,
              visible='!' + focus),
        image(BTN_TEX, 0, 0, w, h, inner, color=BTN_FOCUS_FILL, border=R_BTN, visible=focus,
              animations=[('effect="fade" start="0" end="100" time="140"', 'Visible')]),
        image(BTN_STROKE_TEX, 0, 0, w, h, inner, color=GOLD, border=R_BTN, visible=focus,
              animations=[('effect="fade" start="62" end="100" time="900" tween="sine" easing="inout" pulse="true"',
                           'Visible')])]


def button_target(ident, w, h, indent, links, enable=None):
    """An invisible hit target shared by the drawn buttons and mode segments."""
    inner = indent + '    '
    body = geometry(0, 0, w, h, inner) + [
        tag('label', '', inner), '{}<texturefocus>-</texturefocus>'.format(inner),
        '{}<texturenofocus>-</texturenofocus>'.format(inner)]
    if enable:
        body.append(tag('enable', escape(enable), inner))
    body += nav(*links, indent=inner)
    return control('button', body, indent, id=ident)


def button(ident, text, x, y, w, h, indent, links, icon=None, primary=False, visible=None, enable=None, font=None):
    """A rounded button: translucent idle, cream with a pulsing gold ring when focused. links: (up, down, left, right)."""
    inner = indent + '    '
    focus = 'Control.HasFocus({})'.format(ident)
    font = font or ('font32_title' if primary else 'font27')
    pad = 30
    icon_w = 44 if icon else 0
    children = button_frame(focus, w, h, inner)
    if icon:
        children.append(image(icon, pad, (h - 36) // 2, 36, 36, inner, aspect='keep', visible='!' + focus))
        children.append(image(icon, pad, (h - 36) // 2, 36, 36, inner, aspect='keep', color=INK, visible=focus))
    text_x = pad + icon_w + (14 if icon else 0)
    text_w = w - text_x - pad
    align = 'left' if icon else 'center'
    children.append(label(text, text_x, 0, text_w, h, inner, font=font, color=TXT, align=align, visible='!' + focus))
    children.append(label(text, text_x, 0, text_w, h, inner, font=font, color=INK, align=align, visible=focus))
    children.append(button_target(ident, w, h, inner, links, enable=enable))
    zoom = [('effect="zoom" start="100" end="102" center="auto" time="180" tween="cubic" easing="out" condition="{}"'
             .format(focus), 'Conditional')]
    return group(children, x, y, w, h, indent, visible=visible, animations=zoom)


def pill_note(text, x, y, w, h, indent, visible=None):
    """A non-focusable pill with a text (the disabled "preparing" button)."""
    return group([image(BTN_TEX, 0, 0, w, h, indent + '    ', color='0AFFFFFF', border=R_BTN),
                  image(BTN_STROKE_TEX, 0, 0, w, h, indent + '    ', color='24FFFFFF', border=R_BTN),
                  label(text, 0, 0, w, h, indent + '    ', font='font27', color=DIM, align='center')],
                 x, y, w, h, indent, visible=visible)


def chip(number, text, x, y, w, h, indent):
    """A fact chip: a big gold number and a caption."""
    inner = indent + '    '
    return group([panel(0, 0, w, h, inner),
                  label(number, 22, 0, 70, h, inner, font='font45_title', color=GOLD, align='center'),
                  label(text, 100, 0, w - 112, h, inner, font='font27', color=SUB)], x, y, w, h, indent)


def dots(x, y, indent, visible=None):
    """Three pulsing dots (a busy indicator made of the circle texture)."""
    inner = indent + '    '
    children = []
    for n in range(3):
        children.append(image(CIRCLE_TEX, n * 34, 0, 20, 20, inner, color=GOLD,
                              animations=[('effect="fade" start="25" end="100" time="620" delay="{}" tween="sine" '
                                           'easing="inout" pulse="true"'.format(n * 200), 'Visible')]))
    return group(children, x, y, 92, 20, indent, visible=visible)


def hint_bar(indent, visible=None, texts=None):
    inner = indent + '    '
    y = CARD_H - 70
    select, confirm, back = texts or ('Výběr', 'Potvrdit', 'Návrat')
    return group([
        image(WHITE_TEX, PAD, 0, CARD_W - 2 * PAD, 1, inner, color='1FFFFFFF'),
        label('Šipky', PAD, 12, 90, 46, inner, font='font25_title', color=TXT),
        label(select, PAD + 96, 12, 560, 46, inner, font='font25', color=DIM),
        label('OK', CARD_W // 2 - 140, 12, 60, 46, inner, font='font25_title', color=TXT, align='right'),
        label(confirm, CARD_W // 2 - 70, 12, 300, 46, inner, font='font25', color=DIM),
        label('Zpět', CARD_W - PAD - 250, 12, 100, 46, inner, font='font25_title', color=TXT, align='right'),
        label(back, CARD_W - PAD - 140, 12, 140, 46, inner, font='font25', color=DIM)],
        0, y, CARD_W, 70, indent, visible=visible)


def header(indent):
    inner = indent + '    '
    return group([
        image(M('brand/milionar-mark.png'), PAD, 30, 52, 52, inner, aspect='keep'),
        label('M I L I O N Á Ř', PAD + 68, 30, 400, 52, inner, font='font25_title', color=SUB,
              visible='!' + is_prop('Mode', 'story')),
        label(localized(35401), PAD + 68, 30, 400, 52, inner, font='font25_title', color=SUB,
              visible=is_prop('Mode', 'story')),
        label(info('Name') + info('Year', '  ·  ', ''), CARD_W - PAD - 560, 30, 560, 52, inner, font='font25',
              color=SUB, align='right', visible=has('Name'))],
        0, 0, CARD_W, 100, indent)


def headline(text, y, indent, color=TXT, visible=None, font='font_MainMenu', x=PAD):
    return label(text, x, y, COL_W + 220, 84, indent, font=font, color=color, scroll=False, visible=visible)


def game_mode_switch(indent):
    """One segmented selector: gold denotes selection; the cream ring denotes focus."""
    inner = indent + '    '
    w, h, inset, gap = 240, 52, 6, 4
    total_w, total_h = 2 * w + gap + 2 * inset, h + 2 * inset
    children = [image(BTN_TEX, 0, 0, total_w, total_h, inner, color=SOLID_FILL, border=R_BTN),
                image(BTN_STROKE_TEX, 0, 0, total_w, total_h, inner, color=BTN_STROKE, border=R_BTN)]
    for index, (ident, string_id, mode, links, enable) in enumerate([
            (9605, 35400, 'millionaire', (None, 9601, None, 9606), None),
            (9606, 35401, 'story', (None, 9601, 9605, None), has('StoryAvailable'))]):
        i = inner + '    '
        selected = is_prop('Mode', mode)
        focus = 'Control.HasFocus({})'.format(ident)
        idle = '!' + selected
        if enable:
            idle += ' + ' + enable
        segment = [
            image(BTN_TEX, -3, -3, w + 6, h + 6, i, color=BTN_FOCUS_FILL, border=R_BTN, visible=focus),
            image(BTN_TEX, 0, 0, w, h, i, color='FF' + CARD_FILL[2:], border=R_BTN),
            image(BTN_TEX, 0, 0, w, h, i, color=GOLD, border=R_BTN, visible=selected),
            image(CIRCLE_TEX, 24, (h - 10) // 2, 10, 10, i, color=INK, visible=selected),
            label(localized(string_id), 36, 0, w - 48, h, i, font='font25_title', color=INK,
                  align='center', visible=selected),
            label(localized(string_id), 0, 0, w, h, i, font='font25_title', color=TXT,
                  align='center', visible=idle)]
        if enable:
            segment.append(label(localized(string_id), 0, 0, w, h, i, font='font25_title', color=DIM,
                                 align='center', visible=empty('StoryAvailable')))
        segment.append(button_target(ident, w, h, i, links, enable=enable))
        children.append(group(segment, inset + index * (w + gap), inset, w, h, inner))
    return group(children, PAD, 102, total_w, total_h, indent)


# ---- the screens
def screen_title(indent):
    i = indent + '    '
    left = [PAD, PAD + 300 + 16, PAD + 600 + 32]
    return group([
        game_mode_switch(i),
        label(info('Name'), PAD, 174, COL_W + 200, 80, i, font='font_MainMenu', color=TXT, scroll=True),
        label(info('Year', '', '  ·  ') + info('Genre'), PAD, 258, COL_W, 44, i, font='font32', color=SUB),
        group([chip('9', 'otázek', left[0], 330, 300, 92, i),
               chip('3', 'nápovědy', left[1], 330, 300, 92, i),
               chip('1', 'virtuální milion', left[2], 330, 300, 92, i),
               textbox(info('Tagline'), PAD, 452, COL_W, 100, i, font='font37', color=TXT)],
              0, 0, CARD_W, CARD_H, i, visible='!' + is_prop('Mode', 'story')),
        group([chip(info('QuestionCount', namespace='WCS.Story'), localized(35444), left[0], 330, 300, 92, i),
               chip('3', localized(35406), left[1], 330, 300, 92, i),
               chip('5', localized(35407), left[2], 330, 300, 92, i),
               textbox(localized(35404), PAD, 452, COL_W, 100, i, font='font37', color=TXT)],
              0, 0, CARD_W, CARD_H, i, visible=is_prop('Mode', 'story')),
        button(9601, localized(35437), PAD, 574, 760, 88, i, (9605, 9602, None, None), icon='osd/fullscreen/buttons/play.png',
               primary=True, visible=has('ButtonsReady')),
        button(9602, localized(35442), PAD, 678, START_HALF_W, 64, i, (9601, 9603, None, 9604),
               icon='icons/infodialogs/info.png', visible=has('ButtonsReady')),
        button(9604, localized(35241), PAD + START_HALF_W + START_GAP, 678, START_HALF_W, 64, i,
               (9601, 9603, 9602, None), icon='icons/settings.png', visible=has('ButtonsReady')),
        button(9603, localized(35438), PAD, 752, 760, 64, i, (9602, None, None, None), icon='icons/infodialogs/cinema.png',
               visible=has('ButtonsReady')),
        label(info('SourceNote', namespace='WCS.Story'), PAD, 834, COL_W, 34, i, font='font25', color=DIM,
              visible=is_prop('Mode', 'story'))],
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('title') + ' + ' + empty('Settings'),
        animations=screen_animations())


def rule_card(number, heading, text, x, indent, body_children):
    i = indent + '    '
    w, h, y = 340, 448, 190
    return group([panel(0, 0, w, h, i),
                  label(number, 28, 18, 120, 60, i, font='font_MainMenu', color=GOLD),
                  image(WHITE_TEX, 28, 86, w - 56, 1, i, color='28FFFFFF')] + body_children + [
                  label(heading, 28, 232, w - 56, 48, i, font='font32_title', color=TXT, aligny='top'),
                  textbox(text, 28, 288, w - 56, 148, i, font='font25', color=SUB)],
                 x, y, w, h, indent, animations=stagger(80 + int(number) * 90))


def letter_chip(text, x, y, indent):
    i = indent + '    '
    return group([image(BTN_STROKE_TEX, 0, 0, 60, 52, i, color=GOLD, border=R_BTN),
                  label(text, 0, 0, 60, 52, i, font='font25_title', color=GOLD, align='center')], x, y, 60, 52, indent)


def rule_pill(text, x, y, w, indent):
    i = indent + '    '
    return group([image(BTN_STROKE_TEX, 0, 0, w, 52, i, color=GOLD, border=R_BTN),
                  label(text, 0, 0, w, 52, i, font='font25_title', color=GOLD, align='center')], x, y, w, 52, indent)


def screen_rules(indent):
    i = indent + '    '
    cards = [
        rule_card('01', 'Devět otázek', 'Tři snadné, tři střední, tři těžké.', PAD, i,
                  [label('1', 28, 112, 40, 70, i + '    ', font='font45_title', color=GOLD),
                   image('icons/back.png', 80, 136, 34, 22, i + '    ', color=GOLD, flipx=True),
                   label('9', 132, 112, 44, 70, i + '    ', font='font45_title', color=GOLD)]),
        rule_card('02', 'Jedna správná', 'Vyberte A, B, C nebo D. Chyba ukončí hru.', PAD + 360, i,
                  [letter_chip('A', 28, 108, i + '    '), letter_chip('B', 100, 108, i + '    '),
                   letter_chip('C', 28, 168, i + '    '), letter_chip('D', 100, 168, i + '    ')]),
        rule_card('03', 'Tři nápovědy', '50:50, Tip a Diváci. Každá jen jednou.', PAD + 720, i,
                  [rule_pill('50:50', 28, 108, 120, i + '    '),
                   rule_pill('Tip', 160, 108, 100, i + '    '),
                   rule_pill('Diváci', 28, 168, 150, i + '    ')])]
    amounts = []
    x = START_ROW_W - 28 - 704
    for index, (text, width) in enumerate([('1 000 Kč', 112), ('5 000 Kč', 112),
                                           ('50 000 Kč', 136), ('1 000 000 Kč', 176)]):
        amounts.append(label(text, x, 0, width, 92, i + '    ', font='font25_title',
                         color=GOLD if index == 3 else TXT, align='right'))
        x += width
        if index < 3:
            amounts.append(image('icons/back.png', x + 16, 39, 24, 14, i + '    ', color=TXT, flipx=True))
            x += 56
    strip = group([
        panel(0, 0, START_ROW_W, 92, i + '    '),
        label('VIRTUÁLNÍ ČÁSTKY', 28, 12, 330, 34, i + '    ', font='font20_title', color=DIM),
        label('Nejde o skutečné peníze.', 28, 46, 330, 34, i + '    ', font='font20', color=SUB),
    ] + amounts, PAD, 656, START_ROW_W, 92, i, animations=stagger(420))
    return group([headline('Jak se hraje', 108, i)] + cards + [
        strip,
        button(9611, 'Začít hru', PAD, START_ROW_Y, START_PRIMARY_W, START_H, i, (None, None, None, 9612), icon='osd/fullscreen/buttons/play.png',
               primary=True),
        button(9612, 'Zpět', PAD + START_PRIMARY_W + START_GAP, START_ROW_Y, START_BACK_W, START_H, i, (None, None, 9611, None), icon='icons/back.png')],
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('rules'), animations=screen_animations())


def moderator_card(x, y, w, h, indent, text_expr, ids=(9620, 9624), links=(9624, 9624, 9621, 9622),
                   caption=('Moderátor', 22, 36, 'font27', GOLD), font='font32', text_top=62, text_bottom=28,
                   animations=(), small=None):
    """The moderator's words: a panel with a caption, the text and a scrollbar (reached with the arrows) when it
    does not fit. ids: (textbox, scrollbar); links: navigation of the scrollbar; caption: (text, y, h, font, colour);
    small: (condition, font) of a second textbox shown instead when the text is too long for the normal font."""
    i = indent + '    '
    inner = i + '    '
    text_id, bar_id = ids
    text_h = h - text_top - text_bottom
    normal = [tag('visible', escape('!' + small[0]), inner)] if small else []
    text = control('textbox', geometry(32, text_top, w - 88, text_h, inner) + [
        tag('font', font, inner), tag('textcolor', TXT, inner), tag('label', escape(text_expr), inner),
        tag('align', 'left', inner), tag('pagecontrol', bar_id, inner),
        inner + '<autoscroll delay="4000" time="1500" repeat="5000">true</autoscroll>'] + normal, i, id=text_id)
    scrollbar = control('scrollbar', geometry(w - 38, text_top, 6, text_h, inner) + [
        tag('orientation', 'vertical', inner), tag('showonepage', 'false', inner),
        inner + '<texturesliderbackground colordiffuse="28FFFFFF">' + WHITE_TEX + '</texturesliderbackground>',
        inner + '<texturesliderbar colordiffuse="B0E8B860">' + WHITE_TEX + '</texturesliderbar>',
        inner + '<texturesliderbarfocus colordiffuse="FFE8B860">' + WHITE_TEX + '</texturesliderbarfocus>',
        tag('textureslidernib', '', inner), tag('textureslidernibfocus', '', inner)
    ] + nav(*links, indent=inner) + normal, i, id=bar_id)
    cap_text, cap_y, cap_h, cap_font, cap_color = caption
    children = [panel(0, 0, w, h, i), label(cap_text, 32, cap_y, w - 64, cap_h, i, font=cap_font, color=cap_color),
                text, scrollbar]
    if small:
        children.append(textbox(text_expr, 32, text_top, w - 64, text_h, i, font=small[1], color=TXT, visible=small[0],
                                autoscroll=True))
    return group(children, x, y, w, h, indent, animations=animations)


def screen_intro(indent):
    i = indent + '    '
    return group([
        headline('Vaše výzva začíná.', 108, i),
        label(info('Name') + '   •   [COLOR {0}]9 otázek[/COLOR]   •   [COLOR {0}]3 nápovědy[/COLOR]'.format(GOLD),
              PAD, 200, COL_W + 100, 44, i, font='font32_title', color=TXT),
        moderator_card(PAD, 276, 1060, 398, i, info('Moderator')),
        group([panel(0, 0, 1060, 64, i + '    '), dots(34, 22, i + '    '),
               label('Moderátor připravuje první otázku…', 150, 0, 880, 64, i + '    ', font='font32', color=TXT)],
              PAD, 686, 1060, 64, i, visible=has('Loading'), animations=stagger(200)),
        button(9621, 'Začít hru', PAD, START_ROW_Y, START_PRIMARY_W, START_H, i, (9624, None, None, 9622), icon='osd/fullscreen/buttons/play.png',
               primary=True, visible=has('ButtonsReady')),
        pill_note('Připravujeme hru…', PAD, START_ROW_Y, START_PRIMARY_W, START_H, i, visible='!' + has('ButtonsReady')),
        button(9622, 'Zpět', PAD + START_PRIMARY_W + START_GAP, START_ROW_Y, START_BACK_W, START_H, i, (9624, None, 9621, None), icon='icons/back.png')],
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('intro'), animations=screen_animations())


def screen_loading(indent):
    i = indent + '    '
    return group([
        headline('Připravujeme otázku…', 108, i),
        label(info('RoundLabel'), PAD, 200, COL_W, 44, i, font='font32_title', color=GOLD),
        group([panel(0, 0, 1060, 104, i + '    '), dots(34, 42, i + '    '),
               label('Moderátor připravuje další otázku…', 150, 0, 880, 104, i + '    ', font='font32', color=TXT)],
              PAD, 280, 1060, 104, i),
        button(9623, 'Zpět', PAD, 430, 300, 80, i, (None, None, None, None), icon='icons/back.png')],
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('loading'), animations=screen_animations())


def lifeline(ident, text, x, w, links, used, icon, indent):
    """A lifeline pill of the question screen; a used one is dimmed and cannot be focused."""
    i = indent + '    '
    btn = button(ident, text, 0, 0, w, 60, i, links, icon=icon, enable=empty(used), font='font25_title')
    dim = [('effect="fade" start="100" end="38" time="260" condition="{}"'.format(has(used)), 'Conditional')]
    return group([btn], x, 0, w, 60, indent, animations=dim)


def answer_tile(ident, letter, x, y, links, indent, namespace='WCS.Game'):
    """An answer: letter and text; cream with a gold ring when focused, gold when chosen, hidden when 50:50 removed."""
    i = indent + '    '
    w, h = 494, ANSWER_H
    focus = 'Control.HasFocus({})'.format(ident)
    removed = is_prop('State' + letter, 'removed', namespace)
    chosen = is_prop('State' + letter, 'pending', namespace)
    body = geometry(0, 0, w, h, i + '    ') + [
        tag('label', '', i + '    '), tag('texturefocus', '-', i + '    '), tag('texturenofocus', '-', i + '    '),
        tag('enable', '!' + removed, i + '    ')] + nav(*links, indent=i + '    ')
    return group([
        image(PANEL_TEX, 0, 0, w, h, i, color='5C0E0E12', border=R_PANEL),
        image(PANEL_STROKE_TEX, 0, 0, w, h, i, color=PANEL_STROKE, border=R_PANEL, visible='!' + focus + ' + !' + chosen),
        image(PANEL_TEX, 0, 0, w, h, i, color='33E8B860', border=R_PANEL, visible=chosen),
        image(PANEL_STROKE_TEX, 0, 0, w, h, i, color=GOLD, border=R_PANEL, visible=chosen),
        image(PANEL_TEX, 0, 0, w, h, i, color=BTN_FOCUS_FILL, border=R_PANEL, visible=focus,
              animations=[('effect="fade" start="0" end="100" time="140"', 'Visible')]),
        image(PANEL_STROKE_TEX, 0, 0, w, h, i, color=GOLD, border=R_PANEL, visible=focus,
              animations=[('effect="fade" start="60" end="100" time="900" tween="sine" easing="inout" pulse="true"', 'Visible')]),
        label(letter, 36, 0, 70, h, i, font='font45_title', color=DIM, align='center', visible='!' + focus),
        label(letter, 36, 0, 70, h, i, font='font45_title', color=GOLD, align='center', visible=focus),
        label(info('Opt' + letter, namespace=namespace), 112, 0, w - 132, h, i, font='font32_title', color=TXT, visible='!' + focus, wrap=True),
        label(info('Opt' + letter, namespace=namespace), 112, 0, w - 132, h, i, font='font32_title', color=INK, visible=focus, wrap=True),
        control('button', body, i, id=ident)],
        x, y, w, h, indent, visible='!' + removed + ' | ' + focus,
        animations=[('effect="zoom" start="100" end="102" center="auto" time="180" tween="cubic" easing="out" condition="{}"'
                     .format(focus), 'Conditional')] + stagger(120 + 'ABCD'.index(letter) * 70))


def poll_row(letter, x, y, indent):
    """One bar of the audience poll: ten segments, lit up to the percentage."""
    i = indent + '    '
    name = 'Poll' + letter
    children = [label(letter, 0, 0, 40, 38, i, font='font25_title', color=GOLD, align='center'),
                image(BTN_TEX, 52, 11, 300, 16, i, color='18FFFFFF', border=7)]
    for step in range(10):
        children.append(image(WHITE_TEX, 52 + step * 30, 11, 27, 16, i, color=GOLD,
                              visible='Integer.IsGreater({},{})'.format(prop(name), step * 10 - 1 if step else 0)))
    children.append(label(info(name, '', ' %'), 360, 0, 90, 38, i, font='font25_title', color=TXT, align='right'))
    return group(children, x, y, 460, 38, indent)


def help_area(indent):
    """The card under the lifelines: the tip, the audience poll, or a hint."""
    i = indent + '    '
    y, w, h = HELP_Y, COL_W, HELP_H
    tip = is_prop('HelpKind', 'tip') + ' + ' + has('TipState')
    poll = is_prop('HelpKind', 'poll')
    counting = has('Countdown')
    body = [
        group([panel(0, 0, w, h, i + '    '),
               label(info('TipLabel'), 32, 8, 500, 34, i + '    ', font='font27', color=GOLD),
               label('Herní nápověda  •  použito', w - 372, 8, 340, 34, i + '    ', font='font20', color=DIM,
                     align='right'),
               textbox(info('TipText'), 32, 42, w - 64, h - 50, i + '    ', font='font27', color=TXT, autoscroll=True),
               dots(32, 66, i + '    ', visible=is_prop('TipState', 'loading'))],
              0, 0, w, h, i, visible=tip + ' + !' + counting, animations=stagger(0)),
        group([panel(0, 0, w, h, i + '    '),
               label('HLASOVÁNÍ DIVÁKŮ', 32, 18, 400, 30, i + '    ', font='font20_title', color=GOLD),
               poll_row('A', 30, 70, i + '    '), poll_row('B', 520, 70, i + '    '),
               poll_row('C', 30, 130, i + '    '), poll_row('D', 520, 130, i + '    ')],
              0, 0, w, h, i, visible=poll + ' + !' + counting, animations=stagger(0)),
        group([panel(0, 0, w, h, i + '    ', tone='gold'),
               label('Vaše odpověď bude vyhodnocena za ' + info('Countdown') + ' s…', 0, 0, w, h, i + '    ',
                     font='font37', color=TXT, align='center')],
              0, 0, w, h, i, visible=counting, animations=stagger(0)),
        label('Nápovědy: každou lze použít jednou.', 0, 0, w, h, i, font='font25', color=DIM, align='center',
              visible='!' + has('HelpKind') + ' + !' + counting)]
    return group(body, PAD, y, w, h, indent)


def ladder_card(indent, caption='HRAJETE O', value=None):
    i = indent + '    '
    x, y, w, h = CARD_W - PAD - 304, 112, 304, 744
    rows = []
    for n in range(9, 0, -1):
        ry = 138 + (9 - n) * 62
        state = 'Ladder.{}.State'.format(n)
        current, done = is_prop(state, 'current'), is_prop(state, 'done')
        rows += [
            image(WHITE_TEX, 22, ry + 60, w - 44, 1, i, color='1AFFFFFF'),
            image(BTN_STROKE_TEX, 10, ry, w - 20, 58, i, color=GOLD, border=R_BTN, visible=current,
                  animations=[('effect="fade" start="55" end="100" time="1000" tween="sine" easing="inout" pulse="true"', 'Visible')]),
            image(BTN_TEX, 10, ry, w - 20, 58, i, color='22E8B860', border=R_BTN, visible=current),
            label(str(n), 24, ry, 44, 58, i, font='font25_title', color=DIM, align='center', visible='!' + current + ' + !' + done),
            label(str(n), 24, ry, 44, 58, i, font='font25_title', color=GOLD, align='center', visible=current),
            label(str(n), 24, ry, 44, 58, i, font='font25_title', color=GREEN, align='center', visible=done),
            label(_money_label(n), 76, ry, w - 100, 58, i, font='font27', color=SUB, visible='!' + current + ' + !' + done),
            label(_money_label(n), 76, ry, w - 100, 58, i, font='font27', color=TXT, visible=current),
            label(_money_label(n), 76, ry, w - 100, 58, i, font='font27', color=GREEN, visible=done)]
    return group([panel(0, 0, w, h, i, tone='solid'),
                  label(caption, 28, 22, w - 56, 32, i, font='font20_title', color=DIM),
                  label(value or info('Money'), 28, 56, w - 56, 56, i, font='font40_title', color=GOLD)] + rows,
                 x, y, w, h, indent, animations=stagger(200))


MONEY = ('1 000 Kč', '2 000 Kč', '5 000 Kč', '10 000 Kč', '20 000 Kč', '50 000 Kč', '100 000 Kč', '500 000 Kč',
         '1 000 000 Kč')


def _money_label(n):
    return MONEY[n - 1]


def screen_question(indent):
    i = indent + '    '
    life_y = 336
    return group([
        label(info('RoundLabel') + '  ·  [COLOR {}]'.format(GOLD) + info('TierLabel') + '[/COLOR]', PAD, 112, COL_W, 36, i,
              font='font25_title', color=TXT),
        textbox(info('QuestionText'), PAD, 154, COL_W, 172, i, font='font40_title', color=TXT),
        group([lifeline(9631, '50:50', 0, 300, (None, 9500, None, 9632), 'Life5050Used', None, i + '    '),
               lifeline(9632, info('TipLabel'), 316, 372, (None, 9501, 9631, 9633), 'LifeTipUsed',
                        'icons/infodialogs/director.png', i + '    '),
               lifeline(9633, 'Diváci', 704, 296, (None, 9501, 9632, None), 'LifeAudienceUsed', None, i + '    ')], PAD, life_y, COL_W, 60, i),
        help_area(i),
        answer_tile(9500, 'A', PAD, ANSWER_Y1, (9631, 9502, None, 9501), i),
        answer_tile(9501, 'B', PAD + 506, ANSWER_Y1, (9632, 9503, 9500, None), i),
        answer_tile(9502, 'C', PAD, ANSWER_Y2, (9500, None, None, 9503), i),
        answer_tile(9503, 'D', PAD + 506, ANSWER_Y2, (9501, None, 9502, None), i),
        ladder_card(i)],
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('question'), animations=screen_animations())


def answer_card(kind, letter_expr, text_expr, caption, x, y, w, h, indent, body_expr=None, head_h=None,
                font='font32_title'):
    """A card with a result mark, a letter and an answer (green: the right one, red: the player's).

    body_expr: a text under the answer (the explanation), separated by a line; head_h: the height of the answer part
    (default: the whole card)."""
    i = indent + '    '
    tone = 'green' if kind == 'right' else 'red'
    colour = GREEN if kind == 'right' else RED
    mark = 'icons/infodialogs/enabled.png' if kind == 'right' else 'icons/infodialogs/disable.png'
    top = head_h or h
    children = [panel(0, 0, w, h, i, tone=tone),
                label(caption, 100, 12, w - 120, 30, i, font='font20_title', color=DIM),
                image(CIRCLE_TEX, 24, (top - 56) // 2 + 6, 56, 56, i, color=colour),
                image(mark, 36, (top - 56) // 2 + 18, 32, 32, i, color=INK, aspect='keep'),
                label(letter_expr, 100, 44, 44, top - 56, i, font='font37_title', color=DIM),
                label(text_expr, 150, 44, w - 170, top - 56, i, font=font, color=TXT, wrap=True)]
    if body_expr:
        children += [image(WHITE_TEX, 24, top, w - 48, 1, i, color='30FFFFFF'),
                     textbox(body_expr, 28, top + 12, w - 56, h - top - 22, i, font='font27', color=TXT,
                             autoscroll=True)]
    return group(children, x, y, w, h, indent, animations=stagger(140))


def result_buttons(ids, labels, icons, y, widths, indent, primary_w=None, up=None, waiting=None):
    """The action buttons of a result screen; waiting: the text of the disabled pill shown until they are ready."""
    i = indent + '    '
    out, x = [], PAD
    for index, (ident, text, icon, w) in enumerate(zip(ids, labels, icons, widths)):
        up_down = (up, None, ids[index - 1] if index else None, ids[index + 1] if index < len(ids) - 1 else None)
        out.append(button(ident, text, x, y, w, 84 if index == 0 else 84, i, up_down, icon=icon, primary=index == 0,
                          visible=has('ButtonsReady')))
        x += w + 20
    if waiting:
        out.append(pill_note(waiting, PAD, y, widths[0], 84, i, visible='!' + has('ButtonsReady')))
    return out


def screen_feedback(indent):
    """A right answer: what was won, the answer with its explanation, the moderator's words and the way on; the
    ladder stays where the question screen has it and lights the next amount."""
    i = indent + '    '
    return group([
        headline('Správně!', 108, i),
        label('Otázka ' + info('Round') + ' / 9   •   Získáno  [COLOR {}]'.format(GOLD) + info('Earned') + '[/COLOR]', PAD,
              192, COL_W, 40, i, font='font32', color=SUB),
        # the answer and why it is right belong together: the explanation (3 lines of ~70 characters; asked for 130)
        # sits in the answer's card; the moderator gets the card of the intro screen, in the explanation's font so
        # that 5 lines of ~70 characters fit (the longest reactions of the models measured are ~4 lines)
        answer_card('right', info('RightLetter'), info('RightText'), 'SPRÁVNÁ ODPOVĚĎ', PAD, 250, 1000, 226, i,
                    body_expr=info('Explanation'), head_h=92),
        moderator_card(PAD, 490, 1000, 258, i,
                       info('Result') + '[CR]' + '[COLOR {}]'.format(SUB) + info('Transition') + '[/COLOR]',
                       ids=(9643, 9644), links=(9644, 9641, None, None), caption=('Moderátor', 14, 36, 'font27', GOLD),
                       font='font27', text_top=52, text_bottom=14, animations=stagger(300),
                       small=(has('ModeratorSmall'), 'font23_narrow')),
        ladder_card(i, caption='DALŠÍ OTÁZKA ZA', value=info('NextMoney')),
        ] + result_buttons((9641, 9642), ('Další otázka', 'Ukončit hru'), ('osd/fullscreen/buttons/next.png', None),
                           START_ROW_Y, (520, 340), i, up=9644, waiting='Připravujeme další otázku…'),
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('feedback'), animations=screen_animations())


def stat_card(x, y, w, h, indent, blocks):
    """The right-hand statistics card: (caption, value expr, colour) blocks."""
    i = indent + '    '
    children, by = [panel(0, 0, w, h, i, tone='solid')], 22
    for caption, value, colour in blocks:
        children += [label(caption, 26, by, w - 52, 30, i, font='font20_title', color=DIM),
                     label(value, 26, by + 34, w - 52, 60, i, font='font45_title', color=colour)]
        by += 128
        if by < h - 100:
            children.append(image(WHITE_TEX, 26, by - 20, w - 52, 1, i, color='28FFFFFF'))
    return group(children, x, y, w, h, indent, animations=stagger(200))


def screen_gameover(indent):
    i = indent + '    '
    return group([
        headline('Tentokrát to nevyšlo.', 108, i),
        label('Konec hry  •  Otázka ' + info('Round') + ' / 9', PAD, 192, COL_W, 40, i, font='font32', color=SUB),
        group([panel(0, 0, 1000, 168, i + '    '),
               label(info('RoundLabel'), 28, 14, 500, 30, i + '    ', font='font20_title', color=DIM),
               textbox(info('QuestionText'), 28, 46, 944, 112, i + '    ', font='font37_title', color=TXT)],
              PAD, 250, 1000, 168, i, animations=stagger(60)),
        answer_card('wrong', info('YourLetter'), info('YourText'), 'VAŠE ODPOVĚĎ', PAD, 434, 494, 118, i),
        answer_card('right', info('RightLetter'), info('RightText'), 'SPRÁVNÁ ODPOVĚĎ', PAD + 506, 434, 494, 118, i),
        group([panel(0, 0, 1000, 150, i + '    '),
               label('VYSVĚTLENÍ', 28, 14, 400, 30, i + '    ', font='font20_title', color=DIM),
               textbox(info('Explanation'), 28, 48, 944, 96, i + '    ', font='font27', color=TXT, autoscroll=True)],
              PAD, 568, 1000, 150, i, animations=stagger(240)),
        stat_card(CARD_W - PAD - 296, 250, 296, 302, i,
                  [('SPRÁVNÝCH ODPOVĚDÍ', info('CorrectLabel'), GOLD), ('DOSAŽENÁ ÚROVEŇ', info('Earned'), GOLD)]),
        ] + result_buttons((9651, 9652, 9653), ('Hrát znovu', 'Vybrat jiný titul', 'Domů'),
                           ('osd/fullscreen/buttons/repeat-all.png', 'icons/infodialogs/cinema.png',
                            'osd/fullscreen/buttons/home.png'), 744, (400, 380, 250), i, waiting='Sčítáme výsledek…'),
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('gameover'), animations=screen_animations())


def trophy(x, y, size, indent):
    """A gold medallion with Kodi's rating star (there is no trophy icon in Kodi)."""
    i = indent + '    '
    return group([image(CIRCLE_TEX, 0, 0, size, size, i, color='33E8B860',
                        animations=[('effect="fade" start="60" end="100" time="1400" tween="sine" easing="inout" pulse="true"', 'Visible')]),
                  image(CIRCLE_STROKE_TEX, 0, 0, size, size, i, color=GOLD),
                  image('icons/infodialogs/rating.png', size // 4, size // 4, size // 2, size // 2, i, color=GOLD, aspect='keep')],
                 x, y, size, size, indent, animations=[('effect="zoom" start="70" end="100" center="auto" time="520" tween="back" easing="out"', 'Visible')])


def screen_win(indent):
    i = indent + '    '
    return group([
        trophy(PAD, 126, 190, i),
        headline('Milion je váš.', 118, i, x=PAD + 230),
        label('Virtuální výhra', PAD + 230, 214, 600, 40, i, font='font32', color=SUB),
        label('1 000 000 Kč', PAD + 230, 254, 800, 84, i, font='font_MainMenu', color=GOLD),
        group([panel(0, 0, 1000, 250, i + '    '),
               image(info('Poster'), 24, 24, 130, 202, i + '    ',
                     diffuse='poster_mask_rounded.png', aspect='scale', fallback='fanart_fallback.jpg'),
               label(info('Name'), 184, 22, 780, 52, i + '    ', font='font37_title', color=TXT, scroll=True),
               label('[COLOR {}]'.format(GOLD) + info('CorrectCount') + ' / 9[/COLOR]  správných odpovědí', 184, 78, 780,
                     44, i + '    ', font='font32', color=SUB),
               image(WHITE_TEX, 184, 134, 770, 1, i + '    ', color='28FFFFFF'),
               label(info('WinLine'), 184, 142, 780, 88, i + '    ', font='font27', color=SUB, wrap=True)],
              PAD, 380, 1000, 250, i, animations=stagger(260)),
        ] + result_buttons((9661, 9662), ('Zobrazit výsledky', 'Nová hra'),
                           ('icons/infodialogs/rating.png', 'osd/fullscreen/buttons/repeat-all.png'), 664, (520, 360), i,
                           waiting='Sčítáme výsledek…'),
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('win'), animations=screen_animations())


def tier_card(caption, value, x, indent):
    i = indent + '    '
    return group([panel(0, 0, 320, 160, i),
                  label(caption, 0, 22, 320, 34, i, font='font20_title', color=SUB, align='center'),
                  label(value, 0, 62, 320, 80, i, font='font_MainMenu', color=GREEN, align='center')],
                 x, 304, 320, 160, indent, animations=stagger(120 + (x // 340) * 90))


def life_item(text, icon, x, shown, indent):
    """A used lifeline in the summary: Kodi's icon (when there is one) and its name."""
    i = indent + '    '
    kids = [label(text, 62 if icon else 0, 0, 260, 56, i, font='font27', color=TXT)]
    if icon:
        kids.insert(0, image(icon, 0, 8, 40, 40, i, aspect='keep', color=GOLD))
    return group(kids, x, 0, 320, 56, indent, visible=shown)


def screen_results(indent):
    i = indent + '    '
    return group([
        headline('Dokonalá hra.', 108, i),
        label('[COLOR {}]'.format(GOLD) + info('Score') + '[/COLOR]', PAD, 196, 360, 90, i, font='font_MainMenu', color=GOLD),
        label('Správné odpovědi', PAD + 330, 196, 500, 90, i, font='font32', color=SUB),
        tier_card('SNADNÉ', info('TierEasy'), PAD, i),
        tier_card('STŘEDNÍ', info('TierMedium'), PAD + 340, i),
        tier_card('TĚŽKÉ', info('TierHard'), PAD + 680, i),
        group([panel(0, 0, 1000, 150, i + '    '),
               label('POUŽITÉ NÁPOVĚDY', 28, 14, 500, 30, i + '    ', font='font20_title', color=DIM),
               group([life_item('50:50', None, 0, has('Life5050Used'), i + '    '),
                      life_item(info('TipLabel'), 'icons/infodialogs/director.png', 330, has('LifeTipUsed'), i + '    '),
                      life_item('Diváci', None, 660, has('LifeAudienceUsed'), i + '    '),
                      label('Žádná nápověda nebyla použita.', 0, 0, 700, 56, i + '    ', font='font27', color=SUB,
                            visible='!' + has('Life5050Used') + ' + !' + has('LifeTipUsed') + ' + !' + has('LifeAudienceUsed'))],
                     28, 62, 960, 56, i + '    ')],
              PAD, 482, 1000, 150, i, animations=stagger(420)),
        group([panel(0, 0, 296, 178, i + '    ', tone='goldsolid'),
               label('VIRTUÁLNÍ VÝHRA', 24, 18, 260, 30, i + '    ', font='font20_title', color=DIM),
               label(info('Earned'), 24, 62, 260, 80, i + '    ', font='font40_title', color=GOLD)],
              CARD_W - PAD - 296, 304, 296, 178, i, animations=stagger(380)),
        ] + result_buttons((9671, 9672, 9673), ('Vybrat další titul', 'Hrát znovu', 'Domů'),
                           ('icons/infodialogs/cinema.png', 'osd/fullscreen/buttons/repeat-all.png',
                            'osd/fullscreen/buttons/home.png'), 674, (440, 330, 250), i),
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('results'), animations=screen_animations())


def screen_error(indent):
    i = indent + '    '
    return group([
        headline('Moderátor má technické potíže.', 108, i),
        group([panel(0, 0, 1000, 220, i + '    ', tone='red'),
               textbox(info('Text'), 32, 24, 936, 180, i + '    ', font='font32', color=TXT)],
              PAD, 230, 1000, 220, i, animations=stagger(80)),
        button(9681, 'Zkusit znovu', PAD, 490, 440, 84, i, (None, None, None, 9682),
               icon='osd/fullscreen/buttons/repeat-all.png', primary=True, visible=has('ButtonsReady')),
        button(9682, 'Zavřít', PAD + 460, 490, 300, 84, i, (None, None, 9681, None), icon='dialogs/close.png',
               visible=has('ButtonsReady'))],
        0, 0, CARD_W, CARD_H, indent, visible=on_screen('error'), animations=screen_animations())


SETTINGS_ROW_H, SETTINGS_PITCH = 52, 56
SETTINGS_VALUE_W = 300


def setting_row(row, y, up, down, indent):
    """A setting: its name, and its value between two arrows (left / right change it, OK takes the next one)."""
    i = indent + '    '
    ident = game_settings.CONTROLS[row.key]
    focus = 'Control.HasFocus({})'.format(ident)
    w, h = COL_W, SETTINGS_ROW_H
    value_x = w - 28 - SETTINGS_VALUE_W
    name = localized(row.label)
    value = info('Set.' + row.key)
    children = button_frame(focus, w, h, i)
    children += [label(name, 28, 0, value_x - 40, h, i, font='font27', color=TXT, visible='!' + focus),
                 label(name, 28, 0, value_x - 40, h, i, font='font27', color=INK, visible=focus)]
    if row.kind != 'bool':
        for flip, x in ((False, value_x + 6), (True, value_x + SETTINGS_VALUE_W - 6 - 26)):
            children += [image('icons/back.png', x, (h - 17) // 2, 26, 17, i, color=DIM, flipx=flip, visible='!' + focus),
                         image('icons/back.png', x, (h - 17) // 2, 26, 17, i, color='AA14141A', flipx=flip, visible=focus)]
    children += [label(value, value_x + 40, 0, SETTINGS_VALUE_W - 80, h, i, font='font27', color=GOLD, align='center',
                       visible='!' + focus),
                 label(value, value_x + 40, 0, SETTINGS_VALUE_W - 80, h, i, font='font27', color=INK, align='center',
                       visible=focus)]
    body = geometry(0, 0, w, h, i + '    ') + [
        tag('label', '', i + '    '), tag('texturefocus', '-', i + '    '), tag('texturenofocus', '-', i + '    ')]
    body += nav(up, down, None, None, indent=i + '    ')
    children.append(control('button', body, i, id=ident))
    zoom = [('effect="zoom" start="100" end="101" center="auto" time="180" tween="cubic" easing="out" condition="{}"'
             .format(focus), 'Conditional')]
    shown = has('Set.' + row.key + '.Show') if row.needs else None
    return group(children, PAD, y, w, h, indent, visible=shown, animations=zoom)


def settings_info_card(indent):
    """What the focused setting does, beside the rows (aligned with their bottom edge)."""
    i = indent + '    '
    w, h = 520, 744
    x, y = CARD_W - PAD - w, 112
    return group([panel(0, 0, w, h, i, tone='solid'),
                  label(info('SetTitle'), 28, 24, w - 56, 34, i, font='font25_title', color=DIM),
                  label(info('SetValue'), 28, 60, w - 56, 62, i, font='font40_title', color=GOLD),
                  image(WHITE_TEX, 28, 138, w - 56, 1, i, color='28FFFFFF'),
                  textbox(info('SetDesc'), 28, 158, w - 56, 176, i, font='font27', color=SUB),
                  textbox(info('SetChoices'), 28, 360, w - 56, 250, i, font='font27', color=SUB),
                  image(WHITE_TEX, 28, h - 124, w - 56, 1, i, color='28FFFFFF'),
                  textbox(localized(35250), 28, h - 108, w - 56, 92, i, font='font25', color=DIM)],
                 x, y, w, h, indent, animations=stagger(200))


def screen_settings(indent, mode='millionaire'):
    """All the game settings but the voice: the rows are the addon settings themselves (wcs/games/game_settings.py)."""
    i = indent + '    '
    rows = game_settings.rows_for(mode)
    body = [label(localized(35240), PAD, 108, COL_W, 52, i, font='font37_title', color=TXT)]
    y = 170
    group_rows = {}
    for row in rows:
        group_rows.setdefault(row.group, []).append(row)
    order = [row for row in rows]
    captions = {'game': localized(35401 if mode == 'story' else 35242), 'spectator': localized(35200)}
    for group_key in group_rows:
        body.append(label(captions[group_key], PAD, y, COL_W, 28, i, font='font20_title', color=DIM))
        y += 32
        for row in group_rows[group_key]:
            index = order.index(row)
            up = game_settings.CONTROLS[order[index - 1].key] if index else None
            down = game_settings.CONTROLS[order[index + 1].key] if index < len(order) - 1 else None
            body.append(setting_row(row, y, up, down, i))
            y += SETTINGS_PITCH
        y += 10
    body.append(settings_info_card(i))
    return group(body, 0, 0, CARD_W, CARD_H, indent,
                 visible=on_screen('title') + ' + ' + has('Settings') + ' + ' + is_prop('Mode', mode),
                 animations=screen_animations())


def exit_overlay(indent):
    """Back during a game: a small card asks before leaving."""
    i = indent + '    '
    w, h = 800, 330
    x, y = (CARD_W - w) // 2, (CARD_H - h) // 2 - 20
    shade = image(WHITE_TEX, 0, 0, CARD_W, CARD_H, i, color='A0000000')
    box = group([image(CARD_TEX, 0, 0, w, h, i + '    ', color='F2202024', border=R_CARD),
                 image(CARD_STROKE_TEX, 0, 0, w, h, i + '    ', color=CARD_STROKE, border=R_CARD),
                 label('Opravdu ukončit hru?', 0, 36, w, 60, i + '    ', font='font_MainMenu', color=TXT, align='center'),
                 label('Dosavadní postup se ztratí.', 0, 110, w, 40, i + '    ', font='font32', color=SUB, align='center'),
                 button(9691, 'Pokračovat ve hře', 48, 190, 360, 84, i + '    ', (None, None, None, 9692), primary=True),
                 button(9692, 'Ukončit hru', 424, 190, 328, 84, i + '    ', (None, None, 9691, None))],
                x, y, w, h, i, animations=[('effect="zoom" start="92" end="100" center="auto" time="260" tween="cubic" easing="out"', 'Visible')])
    return group([shade, box], 0, 0, CARD_W, CARD_H, indent, visible=has('Exit'),
                 animations=[('effect="fade" start="0" end="100" time="180"', 'Visible'),
                             ('effect="fade" start="100" end="0" time="140"', 'Hidden')])


def card(indent):
    i = indent + '    '
    screens = [screen_rules, screen_intro, screen_loading, screen_question, screen_feedback,
               screen_gameover, screen_win, screen_results, screen_error]
    body = [
        image(CARD_TEX, 0, 0, CARD_W, CARD_H, i, color=CARD_FILL, border=R_CARD),
        # the backdrop of the work: right side, rounded on the right, faded in from the left (modern_fanart_mask.png)
        image(info('Fanart'), CARD_W - 840, 0, 840, CARD_H, i, diffuse='modern_fanart_mask.png',
              aspect='scale', color='FF8E8E92',
              animations=[('effect="fade" start="0" end="100" time="900" delay="250" tween="cubic" easing="out"', 'WindowOpen')]),
        image(M('gradient_bottom.png'), CARD_W - 840, 0, 840, CARD_H, i, color='B8000000', diffuse='modern_fanart_mask.png',
              aspect='scale'),
        image(CARD_STROKE_TEX, 0, 0, CARD_W, CARD_H, i, color=CARD_STROKE, border=R_CARD),
        header(i)]
    from scripts.game_dialog import story_screens
    body += [screen_title(i),
             group([screen(i + '    ') for screen in screens], 0, 0, CARD_W, CARD_H, i,
                   visible='!' + is_prop('Mode', 'story')),
             group(story_screens.build(sys.modules[__name__], i + '    '), 0, 0, CARD_W, CARD_H, i,
                   visible=is_prop('Mode', 'story'))]
    body += [screen_settings(i), screen_settings(i, 'story'), hint_bar(i, visible=empty('Settings')),
             hint_bar(i, visible=has('Settings'), texts=(localized(35251), localized(35252), localized(35253))),
             exit_overlay(i)]
    return group(body, CARD_X, CARD_Y, CARD_W, CARD_H, indent,
                 animations=[('effect="fade" start="0" end="100" time="380" tween="cubic" easing="out"', 'WindowOpen'),
                             ('effect="zoom" start="94" end="100" center="auto" time="420" tween="cubic" easing="out"', 'WindowOpen'),
                             ('effect="fade" start="100" end="0" time="220"', 'WindowClose'),
                             ('effect="zoom" start="100" end="96" center="auto" time="220" tween="cubic" easing="in"', 'WindowClose')])


def build():
    indent = '        '
    lines = ['<?xml version="1.0" encoding="UTF-8"?>',
             '<!-- generated by scripts/game_dialog/gen_modern_game.py: do not edit. The modern card of the Millionaire game;'
             ' the screen shown is WCS.Game.Screen (wcs/games/game_view.py), control ids are those of designs.MODERN. -->',
             '<window type="dialog">', '    <defaultcontrol always="true">9601</defaultcontrol>',
             '    <controls>',
             ] + image(WHITE_TEX, 0, 0, 1920, 1080, '        ', color='C8000000',
                       animations=[('effect="fade" start="0" end="100" time="300"', 'WindowOpen'),
                                   ('effect="fade" start="100" end="0" time="220"', 'WindowClose')]) + card(indent) + [
        '    </controls>', '</window>']
    return '\n'.join(lines) + '\n'


if __name__ == '__main__':
    with open(OUT, 'w', encoding='utf-8') as handle:
        handle.write(build())
    print('wrote', os.path.relpath(OUT), len(build().splitlines()), 'lines')
