#! /usr/bin/env python
# todiscgui

"""A GUI for the todisc command-line program.

Usage:

    $ todiscgui

This GUI is written using the 'metagui' module from libtovid, a high-level
GUI design language that involves very little code.

See the wiki page about metagui for more details:

    http://tovid.wikia.com/wiki/Metagui

"""

# Get supporting classes from libtovid.metagui
from libtovid.metagui import *

### --------------------------------------------------------------------
### -files and -titles
### --------------------------------------------------------------------

"""todisc's -files and -titles options have a one-to-one correspondence.
Rather than make the user manually enter a title for each file, this
approach uses two lists, with one "dependent" on another via a filter.

Specifically, when the GUI user adds to -files, the corresponding
-titles should be automatically filled in with the filename, minus
pathname and extension.

In other words:
"""

import os
def to_title(filename):
    basename = os.path.basename(filename)
    firstdot = basename.find('.')
    return basename[0:firstdot]

files = FileList('Video files', '-files', None,
    'Video files to include on the disc',
    required=True)

titles = TextList('Video titles', '-titles', None,
    'Titles for each video',
    pull=files, # -titles is updated when -files is updated
    filter=to_title, # strip pathname and extension from filenames
    required=True)

# The rest of the GUI is pretty straightforward, so don't be frightened
# by the above :-)

### --------------------------------------------------------------------
### Main todisc options
### --------------------------------------------------------------------

main = Panel("Main",
    Text('Menu title', '-menu-title', 'My video collection',
        'Title text displayed on the main menu'),
    
    HPanel('', files, titles),

    HPanel('',
        FlagGroup('Format', 'exclusive',
            Flag("DVD", '-dvd', True),
            Flag("SVCD", '-svcd', False)),
        FlagGroup('TV System', 'exclusive',
            Flag("NTSC", '-ntsc', True),
            Flag("PAL", '-pal', False)),
        FlagGroup('Menu options', 'normal',
            Flag('Static menus', '-static', False,
                'Create still-image menus; takes less time.  '
                'For duration of background audio for static '
                'menus, use "menu length" on the "Menu" tab'),
            Flag('Create Submenus', '-submenus', False,
                'Create a submenu for each video title; takes more time.'))
        ),

        VPanel('Menu style',
            FlagGroup('', 'exclusive',
                Flag('Default', '', True,
                'Thumbnail menu links, centred, and as large as space '
                'restraints allow'),
                Flag('Showcase', '-showcase', False,
                "Arrange menu links along the outside edges, to leave room for"
                " an optional 'showcase' image or video.",
                enables=Filename('', '', '',
                'Image or video file to be showcased in a large central frame',
                'load', 'Select an image or video file.'),
                ),
            ),
            HPanel('Showcase options',
                Flag("Textmenu", '-textmenu', False,
                'Showcase style text only menu.  Optionally use a "showcase" '
                'image/video, or static/animated background.  Use the '
                '"columns" option to set the maximum number of titles per '
                ' column.  See also quick-menu and switched menu.',
                enables=Number('     columns', '', 13,
                '', 1, 50)
                ),
                    Flag("Quick menu", '-quick-menu', False,
                        'Ten times faster than normal showcase animation.  '
                        'A showcase video is required unless doing switched '
                        'menus.  No video thumbs are made.  Not compatible '
                        'with wave or rotate options'),
                    Flag("Switched menus", '-switched-menus', False,
                        'This makes a showcase style menu with text menu '
                        'links.  The showcased VIDEO or IMAGE will be of each '
                        'video "title", and will change as you press the '
                        'up/down keys on your remote.  Do not select a '
                        'showcase file for this option.  Use with '
                        '"Quick menu" option for a huge speed up !'),
            ),
        ),
    VPanel('Menu backgrounds',
        Filename('Image or video', '-background', '',
            'Image or video displayed in the background of the main menu',
            'load', 'Select an image or video file'),
        Filename('Audio', '-bgaudio', '',
            'Audio file to play while the main menu plays.  '
            'Static menus use default audio length of 20 seconds.  ' 
            'Change with "Menu length" on "Menu" tab.  '
            'Use almost any filetype containing audio.',
            'load', 'Select an audio file')
    ),
    Filename('Output name', '-out', '',
        'Name to use for the output directory where the disc will be created.',
        'save', 'Choose an output name',
        required=True)
)

general = Panel("General",
    Flag('Keep useful intermediate files on exit', '-keep-files', False),
    Flag('No prompts for questions', '-no-ask', False),
    Flag('Do not pause at warnings', '-no-warn', False),
    Flag('Use makemenu', '-use-makemenu', False,
        'Create menus using the makemenu script instead of todisc'),
    List('Custom todisc options', '', '',
        'Space-separated list of custom options to pass to todisc.'),
    Text('Custom tovid options', '-tovidopts', '',
        "Space-separated list of options to pass to tovid for encoding.")
)

menu = Panel("Menu",
    Number('Menu length', '-menu-length', 20,
        'Duration of menu in seconds.  The length of the menu will also set '
        'the length of background audio for a static menu',
        0, 120, toggles=True),
    Number('Menu audio fade', '-menu-audio-fade', 1,
        'Number  of  sec to fade given menu audio in and out '
        '(default: 1.0 seconds). Use a fade of "0" for no fade.',
        0, 10),
    Flag('Fade in menu', '-menu-fade', False,
        'Fade the menu in and out.  The background '
        ' will fade in first, then the title '
        '(and mist if called for), then the menu thumbs and/or titles.  '
        'The fadeout is in reverse order.'),
    Color('Quick menu background color', '-pad-color', 'white',
        'Color of background for -quick-menu menus.  ' 
        'Default if not enabled: ntsc color-safe black (#161514).  '
        'Note: the color turns out MUCH lighter than the one you choose, '
        'so pick a VERY dark version of the color you want.',
        toggles=True),
    Filename('Intro video', '-intro', '',
        'Video to play before showing the main menu.  At present this must '
        'be a DVD compatible video at the correct resolution etc.  Only 4:3 '
        'aspect is supported.',
        'load', 'Select a video file'),
    Choice('Montage alignment', '-align', 'north',
        'Controls positioning of the thumbnails and their titles.  '
        'With some arrangements this will have limited effects however.',
        'north|south|east|west|center'),
        Panel('Seek times',
            List('Thumbnails', '-seek', '',
                'Play thumbnail videos from the given seek time (seconds).  '
                'A single value or space separated list, 1 value per video.  '
                'Also used for seeking in switched menus.'),
            Number('Background video', '-bgvideo-seek', 2,
                'Play background video from the given seek time (seconds)',
                0, 3600),
            Number('Background audio', '-bgaudio-seek', 2,
                'Play background audio from the given seek time (seconds)',
                0, 3600),
            Number('Showcased video', '-showcase-seek', 2,
                'Play showcase video from the given seek time (seconds).  '
                'Note: switched menus uses the value(s) from "Seek time" '
                'option above, not this one',
                0, 3600)
        ),
    Choice('Showcase frame style', '-showcase-framestyle', 'none',
        'This is a showcase style only option.  The "none" option will use '
        'the default frame method, using imagemagick. The "glass" option '
        'will use mplayer to make frames, giving an animated effect.  The ' 
        'glass style can be much faster - especially if used without '
        '-rotate and -wave options',
        'none|glass'),
    Text('Showcase image position (XxY)', '-showcase-geo', '',
        'This is a showcase style only option.  Enter the position of the '
        'top left corner of the showcase image: e.g. "200x80".  This '
        'value is applied to the video *before* is is scaled.'),
)

thumbnails = Panel("Thumbnails",
    Choice('Thumb shape', '-thumb-shape', 'normal',
        'Apply a shaped transparency mask to thumbnail videos. '
        'Note: to disable the "mist" background '
        'behind each thumb, use see "Thumb mist" section below.',
        'normal|oval|plectrum|egg'),
    Number('Thumbnail opacity', '-opacity', 100,
        'Opacity  of thumbnail videos as a percentage '
        '(no percent sign).  Less than 100(%) '
        'is semi-transparent.  Not recommended with dark backgrounds.',
        1, 100, 'spin'),
    Number('Blur', '-blur', 4,
        'The amount of feather blur to apply to the thumb-shape.  '
        'Default is 4.0 which will more or less keep the shape, '
        'creating transparency at the edges.  Choose float or '
        'integer values between 0.1 and 5.0',
        1, 5, 'spin'),
    Flag('Create 3D thumbs', '-3dthumbs', False,
        'This will give an illusion of 3D to the thumbnails: '
        'dynamic lighting on rounded thumbs, and a  raised '
        ' effect on rectangular thumbs'),
    List('Rotate Thumbs (list)', '-rotate-thumbs', '',
        'Rotate  thumbs  the  given amount in degrees - can be positive '
        'or negative.  There must be one value for each file given with '
        'files.  If the values are not the same distance from zero, the '
        'thumbs will be of  different sizes as images are necessarily '
        'resized *after* rotating.'),
    Flag('Wave effect for showcase thumb', '-wave', False,
        'Wave effect for showcase image|video.  Alters thumbs along a sine '
        'wave.  This will pass a wave arg of -20x556, producing a gentle '
        'wave with a small amount of distortion.  To use other values you '
        'will need to use the "tovidopts" box on the first panel.  '
        'See man todisc for details.'),
    Number('Rotate Showcase thumb', '-rotate', 0,
        'Rotate the showcase image|video clockwise by this number of degrees.',
        -30, 30, 'spin'),
    VPanel('Thumb mist',
        Color('Thumb mist color', '-thumb-mist-color', 'white',
            'Color of mist behind thumbnails (not a showcase option). ' 
            'Default if not enabled: white', toggles=True),
        Flag("No thumb mist", '-thumb-mist-color', False,
            'Do not use mist behind thumbs (not a showcase option).  Warning: '
            'might cause contrast problems (use a large bold font)')
    ),
    FlagGroup('Special thumb arrangements', 'exclusive',
        Flag('1 row of 3 thumbs', '-tile3x1', False,
            'Use a montage tile of 3x1 instead of the usual 2x2 '
            '(3 videos only).  Not a showcase option.'),
        Flag('1 row of 4 thumbs', '-tile4x1', False,
            'Use a montage tile of 4x1 instead of the usual 2x2 '
            '(4 videos only).  Not a showcase option.')
    ),
)

submenus = Panel("Submenus",
    Flag('Animated submenus (takes more time)', '-ani-submenus', False,
        'Create an animated submenu for each video.  '
        'Submenu links lead to chapter points.'),
    VPanel('Titles',
        List('', '-submenu-titles', '',
            'Space-separated list of quoted submenu titles.'),
        Color('Font color', '-submenu-title-color', '#CDC0B0',
            'The font color to use for submenu title(s)', toggles=True),
        Color('Stroke color', '-submenu-stroke-color', 'none',
            'The color for the submenu font outline (stroke).', toggles=True),
    ),
    HPanel('Audio',
        FileList('File(s)', '-submenu-audio', None,
            'Audio file(s) that will play as background for each submenu.  '
            'Use a single file for all submenus, or 1 file per submenu',),
        VPanel('',
            Number('Length', '-submenu-audio-length', 30,
                'Background audio length for static submenus.  Default: use '
                'the full length of the supplied audio file.  Animated '
                'submenu length is NOT adjustable: 10 sec NTSC, 12 sec PAL.',
                0, 120),
            Number('Fade', '-submenu-audio-fade', 1,
                'Number of sec to fade given submenu audio in and out.  '
                ' (default: 1.0 seconds)',
                0, 10)
        ),
    )
)

text = Panel("Text/Font",
    Tabs(
        VPanel('Menu title', 
            Font('Font', '-menu-font', 'Helvetica',
                'The font to use for the menu title'),
            Number('Font size', '-menu-fontsize', 30,
                'The font size to use for the menu title',
                0, 80, toggles=True),
            Color('Color', '-title-color', '#CDC0B0',
                'The font color to use for the menu title', toggles=True),
            Color('Stroke color', '-stroke-color', 'gray',
                'Outline color for the main menu font.', toggles=True,
                initialcolor="gray"),
            HPanel('Title position',
                Choice('', '-menu-title-geo', 'south',
                    'The position of the menu title',
                    'north|south|west|east|center'),
                Text('Offset', '-menu-title-offset', '+0+50',
                    'Menu title position as an offset (in pixels) from '
                    'the N/S/E/W "Title position".  Use +X+Y syntax.  This '
                    'value is applied to the video *before* is is scaled.', toggles=True),
            ),
            Panel("Mist",
                Flag('Text mist', '-text-mist', False,
                    'Use "mist" behind the menu title (helps with contrast).'),
                Color('Text mist color', '-text-mist-color', 'white',
                    'Color of the mist behind the menu title.', toggles=True),
                Number('Text mist opacity', '-text-mist-opacity', 60,
                    'The opacity of the mist behind the menu title.',
                    1, 100, 'spin')
                ),
            ),
        VPanel('Video title(s)',
            Font('Font', '-thumb-font', 'Helvetica',
                'The font to use for the video titles'),
            Number('Font size', '-thumb-fontsize', 12,
                'The font size to use for the video titles.  '
                'Default size varies depending on options chosen.',
                0, 80, toggles=True),
            Color('Color', '-thumb-text-color', '#C6C6C6',
                'The font color to use for the video titles', toggles=True),
            Choice('Video(s) title alignment', '-showcase-titles-align', 'none',
                'This is a showcase style only option.  Default is to center '
                'the text above the thumbnails.  This option will align the '
                'titles either to the left (west), right (east), or center.  '
                'Leave at "none" to let todisc sort it out for you.',
                'west|east|center|none'),
            Number('Space between Textmenu titles (pixels)', '-title-gap', 10,
                'Leave this much vertical gap between titles.  '
                'Default is 10 for line buttons, 15 for text-rect buttons.  '
                'This value is applied before the menu is scaled.',
                0, 400, 'spin', toggles=True),
            Number('Start Textmenu titles at: (pixels)', '-text-start', 50,
                'Titles will start at this pixel in the vertical axis.  '
                'This value is applied before the menu is scaled.',
                0, 460, 'spin')
        ),
    )
)

authoring = Panel("Authoring",
    VPanel('Play control',
        List('Chapters', '-chapters', '',
            'Single value/string or list.  '
            'Can be an integer for "# of chapters", or a comma '
            'separated string of chapter points in HH:MM:SS format.  '
            'The first HH:MM:SS format chapter MUST be 00:00:00 '
            'If using grouped videos and HH:MM:SS format '
            'link grouped chapter points with a "+" separator.'),
        List('Group videos', '', '',
            'For each video group, you will need to use an integer for the '
            'number of the 1st video in the group, as well as the path to the '
            'videos that will be grouped with it (quoted).  Each group will need to be '
            'preceeded with the "-group" switch.  Example: -group 2 "2b.mpg" '
            '"2c.mpg" -group 4 "4b.mpg" "4c.mpg". See man todisc for details.'),
        Flag('Chain videos together', '-chain-videos', False,
            'This option will "chain" videos so they play sequentially '
            'until the last, which will return to the menu.  You can also '
            'specify individual videos to behave like this, but you will need '
            'to use the "Custom todisc options" box under "General" tab.  '
            'See man todisc for details.'),
        Flag('"Play all" button', '-playall', False,
            'Create a "Play All" button that jumps to the 1st title and plays '
            'all the videos in sucession before returning to the main menu.'),
        Number('Pause', '-loop', 10,
            'Pause in seconds at end of menu.  Or leave this value at "10" '
            'and use the "Indefinate pause item below.',
            0, 30, toggles=True),
        Flag('Indefinite pause', '-loop', False,
            'Pause indefinitely at the end of the menu.')
    ),
    VPanel('Aspect',
        Choice('Widescreen', '-widescreen', 'none',
            'This will output a <video widescreen=nopanscan /> tag '
            '(for example) for the dvdauthor xml file.  It affects all '
            'videos in the titleset.  Use in conjunction with "Aspect ratio" '
            'if your dvd player is cropping your videos.  '
            'Leave this at "none" to not output a widescreen tag',
            'nopanscan|noletterbox|none'),
        Choice('Aspect ratio', '-aspect', 'none',
            'This will output a <video aspect WIDTH:HEIGHT /> tag for the '
            'dvdauthor xml file.  It will affect all videos in the titleset.  '
            'Leave this at "none" to let dvdauthor figure it out for you',
            '4:3|16:9|none'),
    ),
    VPanel('Language(s)',
        List('Audio', '-audio-lang', '',
            'Single value or list'),
        List('Subtitles', '-subtitles', '',
            'Single value or list'),
    ),
    VPanel('Buttons',
        Choice('Style', '-button-style', 'none',
            'Style or shape of the buttons seen when playing the DVD '
            'menu.  "rect": rectangle around the thumbs, "text": uses '
            'the title text, "text-rect": rectangle around the title text, '
            '"line": line underneath title.  The "line" style is showcase only'
            ', and the "text" buttons can not be used with "showcase" menus.'
            'Leave at "none" to let todisc pick the most appropriate style. ',
            'rect|line|text|text-rect|none'),
        Color('Highlight color', '-highlight-color', '#266CAE',
            'Color for the menu buttons the dvd remote uses to navigate.', toggles=True),
        Color('Selection color', '-select-color', '"#DE7F7C"',
            'Color for the menu buttons the dvd remote uses to select.', toggles=True),
        Number('Outlinewidth for spumux', '-outlinewidth', 14,
            'For spumux outlinewidth variable.  This option helps if spumux '
            'fails because of a large gap between button words or characters.',
            0, 20, toggles=True),
    )
)
burning = Panel("Burning",
    Flag('Burn project on completion', '-burn', False),
    Number('Burning speed', '-speed', 8,
        'Speed for burning',
        0, 30, toggles=True),
    Filename('Device to use for burning', '-device', '/dev/dvdrw',
        'Select or type your burning device (default: /dev/dvdrw)',
        'load', 'Select or type your burning device')
)

### --------------------------------------------------------------------
### Application and GUI
### --------------------------------------------------------------------

todisc = Application('todisc',
    [main, general, menu, submenus, thumbnails, text, authoring, burning])
gui = GUI("todiscgui", [todisc], 600, 800)
gui.run()

