8
from libtovid.gui.configs import TovidConfig
9
from libtovid.gui.constants import *
10
from libtovid.gui.controls import BoldToggleButton, FlexTreeCtrl, HeadingText
11
from libtovid.gui.dialogs import FontChooserDialog
12
from libtovid.gui.icons import MenuIcon, SlideIcon, VideoIcon, DiscIcon, GroupIcon
13
from libtovid.gui.options import DiscOptions, MenuOptions, VideoOptions, GroupOptions
14
from libtovid.gui import util
15
from libtovid.gui.util import _, VER_GetFirstChild, VideoStatSeeker
16
from libtovid.author import Group
19
"AuthorFilesTaskPanel",
35
class AuthorFilesTaskPanel(wx.Panel):
36
"""A three-step interface for authoring video files to disc.
37
Uses DiscLayoutPanel, EncodingPanel, and BurnDiscPanel."""
39
def __init__(self, parent, id):
40
wx.Panel.__init__(self, parent, id)
42
# Global configuration
43
self.curConfig = TovidConfig()
46
self.panDiscLayout = DiscLayoutPanel(self, wx.ID_ANY)
47
self.panEncoding = EncodingPanel(self, wx.ID_ANY)
48
self.panBurnDisc = BurnDiscPanel(self, wx.ID_ANY)
49
self.panEncoding.Hide()
50
self.panBurnDisc.Hide()
51
# Keep an eye on the current panel
52
self.curPanel = self.panDiscLayout
54
# 3-step buttons (toggle buttons)
55
# Layout / Encode / Burn
57
# ======================
59
self.btnLayout = BoldToggleButton(self, wx.ID_ANY, _("1. Layout"))
60
self.btnEncode = BoldToggleButton(self, wx.ID_ANY, _("2. Encode"))
61
self.btnBurn = BoldToggleButton(self, wx.ID_ANY, _("3. Burn"))
62
# ======================
64
self.btnLayout.SetToolTipString("Modify the arrangement of videos "
65
"and menus on the disc")
66
self.btnEncode.SetToolTipString("Set up and encode the videos "
67
"and menus in the current disc layout")
68
self.btnBurn.SetToolTipString("Burn the completed disc")
70
# Toggle button events
71
wx.EVT_TOGGLEBUTTON(self, self.btnLayout.GetId(), self.OnLayout)
72
wx.EVT_TOGGLEBUTTON(self, self.btnEncode.GetId(), self.OnEncode)
73
wx.EVT_TOGGLEBUTTON(self, self.btnBurn.GetId(), self.OnBurn)
74
self.btnLayout.SetValue(True)
75
self.btnEncode.Enable(False)
76
self.btnBurn.Enable(False)
79
self.sizSteps = wx.BoxSizer(wx.HORIZONTAL)
80
self.sizSteps.Add(self.btnLayout, 1, wx.EXPAND | wx.ALL, 2)
81
self.sizSteps.Add(self.btnEncode, 1, wx.EXPAND | wx.ALL, 2)
82
self.sizSteps.Add(self.btnBurn, 1, wx.EXPAND | wx.ALL, 2)
84
# Task sizer. Holds panel(s) related to current task
85
# (layout, encoding, burning). Shows only one panel
87
self.sizTask = wx.BoxSizer(wx.VERTICAL)
88
self.sizTask.Add(self.panDiscLayout, 1, wx.EXPAND)
90
# Main sizer. Holds task (layout, encoding) panel and 3-step buttons
91
self.sizMain = wx.BoxSizer(wx.VERTICAL)
92
self.sizMain.Add(self.sizSteps, 0, wx.EXPAND | wx.ALL, 6)
93
self.sizMain.Add(wx.StaticLine(self, wx.ID_ANY, style = wx.LI_HORIZONTAL),
95
self.sizMain.Add(self.sizTask, 1, wx.EXPAND)
96
self.SetSizer(self.sizMain)
98
def EncodeOK(self, ok):
99
"""Indicate whether it's okay to begin encoding."""
101
self.btnEncode.Enable(True)
103
self.btnEncode.Enable(False)
105
def BurnOK(self, ok):
106
"""Indicate whether it's okay to begin burning."""
108
self.btnBurn.Enable(True)
110
self.btnBurn.Enable(False)
113
def OnLayout(self, evt):
114
"""Display controls for doing disc layout."""
116
self.btnLayout.SetValue(True)
117
self.btnEncode.SetValue(False)
118
self.btnBurn.SetValue(False)
119
# If Layout is showing, do nothing else
120
if self.curPanel == self.panDiscLayout:
122
# Clear Encoding panel command list
123
self.panEncoding.panCmdList.Clear()
125
self.curPanel = self.panDiscLayout
126
self.sizTask.Remove(0)
127
self.panEncoding.Hide()
128
self.panBurnDisc.Hide()
129
self.sizTask.Add(self.panDiscLayout, 1, wx.EXPAND)
130
self.panDiscLayout.Show()
131
self.sizTask.Layout()
132
self.curPanel = self.panDiscLayout
134
self.btnLayout.SetValue(True)
135
self.btnEncode.SetValue(False)
136
self.btnBurn.SetValue(False)
137
# Set appropriate guide text
138
self.curConfig.panGuide.SetTask(ID_TASK_GETTING_STARTED)
140
def OnEncode(self, evt):
142
# Clear Encoding panel command list
143
self.panEncoding.panCmdList.Clear()
145
# Abort encoding if detected an error
146
if self.btnLayout.GetValue() == True:
147
CanContinue = self.panDiscLayout.PerformSanityCheckOnFiles(self)
148
if CanContinue == False:
150
self.btnLayout.SetValue(True)
151
self.btnEncode.SetValue(False)
152
self.btnBurn.SetValue(False)
155
"""Display controls for encoding."""
157
self.btnLayout.SetValue(False)
158
self.btnEncode.SetValue(True)
159
self.btnBurn.SetValue(False)
160
# If Encode is showing, do nothing else
161
if self.curPanel == self.panEncoding:
164
self.curPanel = self.panEncoding
165
self.sizTask.Remove(0)
166
self.panDiscLayout.Hide()
167
self.panBurnDisc.Hide()
168
self.sizTask.Add(self.panEncoding, 1, wx.EXPAND)
169
self.panEncoding.Show()
170
self.sizTask.Layout()
171
self.curPanel = self.panEncoding
172
# Give command list to encoding panel
173
cmdList = self.panDiscLayout.GetAllCommands()
174
self.panEncoding.SetCommands(cmdList)
175
# Set appropriate guide text
176
self.curConfig.panGuide.SetTask(ID_TASK_PREP_ENCODING)
178
def OnBurn(self, evt):
179
"""Display controls for burning the disc."""
181
self.btnLayout.SetValue(False)
182
self.btnEncode.SetValue(False)
183
self.btnBurn.SetValue(True)
184
# If Burn is showing, do nothing
185
if self.curPanel == self.panBurnDisc:
188
self.curPanel = self.panBurnDisc
189
self.sizTask.Remove(0)
190
self.panDiscLayout.Hide()
191
self.panEncoding.Hide()
192
self.sizTask.Add(self.panBurnDisc, 1, wx.EXPAND)
193
self.panBurnDisc.Show()
194
self.sizTask.Layout()
195
self.curPanel = self.panBurnDisc
196
# Generate the default commandlist
197
self.panBurnDisc.SetCommands()
198
# Set appropriate guide text
199
self.curConfig.panGuide.SetTask(ID_TASK_BURN_DISC)
202
class BurnDiscPanel(wx.Panel):
203
"""A panel of controls for burning a disc"""
205
def __init__(self, parent, id):
206
wx.Panel.__init__(self, parent, id)
208
# Keep track of parent
210
self.device = "/dev/dvdrw"
214
self.txtHeading = HeadingText(self, wx.ID_ANY, "Author and burn")
216
self.chkDoAuthor = wx.CheckBox(self, wx.ID_ANY, "Author disc structure")
217
self.chkDoBurn = wx.CheckBox(self, wx.ID_ANY, "Burn disc")
218
self.chkDoAuthor.SetToolTipString("Create the disc filesystem " \
219
"hierarchy using dvdauthor")
220
self.chkDoBurn.SetToolTipString("Burn a disc in the selected " \
222
self.chkDoAuthor.SetValue(self.doAuthor)
223
self.chkDoBurn.SetValue(self.doBurn)
224
wx.EVT_CHECKBOX(self, self.chkDoAuthor.GetId(), self.OnDoAuthor)
225
wx.EVT_CHECKBOX(self, self.chkDoBurn.GetId(), self.OnDoBurn)
227
self.lblDiscDevice = wx.StaticText(self, wx.ID_ANY, "Burn to device:")
228
self.txtDiscDevice = wx.TextCtrl(self, wx.ID_ANY, self.device)
229
wx.EVT_TEXT(self, self.txtDiscDevice.GetId(), self.OnSetDevice)
231
# Sizer to hold burning controls
232
self.sizBurn = wx.FlexGridSizer(4, 2, 8, 8)
233
self.sizBurn.Add((2, 2))
234
self.sizBurn.Add(self.chkDoAuthor, 0, wx.EXPAND)
235
self.sizBurn.Add((2, 2))
236
self.sizBurn.Add(self.chkDoBurn, 0, wx.EXPAND)
237
self.sizBurn.Add(self.lblDiscDevice, 0, wx.EXPAND)
238
self.sizBurn.Add(self.txtDiscDevice, 1, wx.EXPAND)
241
self.panCmdList = CommandOutputPanel(self, wx.ID_ANY)
242
self.panCmdList.Enable(False)
245
self.btnStart = wx.Button(self, wx.ID_ANY, "Start")
246
wx.EVT_BUTTON(self, self.btnStart.GetId(), self.OnStart)
248
# Sizer to hold controls
249
self.sizMain = wx.BoxSizer(wx.VERTICAL)
250
self.sizMain.Add(self.txtHeading, 0, wx.EXPAND | wx.ALL, 8)
251
self.sizMain.Add(self.sizBurn, 0, wx.EXPAND | wx.ALL, 8)
252
self.sizMain.Add(self.panCmdList, 1, wx.EXPAND | wx.ALL, 8)
253
self.sizMain.Add(self.btnStart, 0, wx.EXPAND | wx.ALL, 8)
254
self.SetSizer(self.sizMain)
256
def OnDoAuthor(self, evt):
257
self.doAuthor = evt.Checked()
260
def OnDoBurn(self, evt):
261
self.doBurn = evt.Checked()
264
def OnSetDevice(self, evt):
265
"""Use the selected device."""
266
self.device = self.txtDiscDevice.GetValue()
269
def OnStart(self, evt):
270
"""Begin authoring and burning the disc."""
272
msgWarning = wx.MessageDialog(self,
273
"Disc burning is still experimental in this release,\n" \
274
"and might not work. Please report any bugs you encounter!",
275
"Experimental feature", wx.ICON_INFORMATION | wx.OK)
276
msgWarning.ShowModal()
278
#Disable button to prevent e.g. double clicks
279
self.btnStart.Enable(False)
280
#Clear any previous errors from previous attempts at burning
281
self.panCmdList.errorOccurred = False
282
self.panCmdList.Start()
284
def ProcessingDone(self, errorOccurred):
285
"""Signify that disc burning is done."""
286
# Let user know if error(s) occurred
288
msgError = wx.MessageDialog(self,
289
"Error(s) occurred during burning. If you want to\n" \
290
"help improve this software, please file a bug report\n" \
291
"containing a copy of the output log. \n" \
292
"Sorry for the inconvenience!",
293
"Error occurred during burning", wx.ICON_ERROR | wx.OK)
295
# Show success message and enable burning
298
strSuccess = "Done burning the disc."
300
strSuccess = "Done authoring the disc."
301
msgSuccess = wx.MessageDialog(self, strSuccess, "Success!",
302
wx.ICON_INFORMATION | wx.OK)
303
msgSuccess.ShowModal()
306
#Set the command, so can do another burn immediately
307
self.SetCommandsWithoutClearingList()
309
self.btnStart.Enable(True)
311
def SetCommands(self):
312
"""Set command-list to be executed based on Author and Burn boxes."""
313
self.panCmdList.Clear()
314
self.SetCommandsWithoutClearingList()
316
def SetCommandsWithoutClearingList(self):
319
# Get global config (for XML filename and format)
320
curConfig = TovidConfig()
322
# Construct authoring/imaging/burning options
323
if curConfig.curDiscFormat == 'vcd' or \
324
curConfig.curDiscFormat == 'svcd':
325
strAuthorCmd = "makevcd -quiet -overwrite "
327
strAuthorCmd = "makedvd -quiet -author "
329
strAuthorCmd += "-burn -device %s " % (self.device)
330
strAuthorCmd += "%s.xml" % (curConfig.strOutputXMLFile)
332
self.panCmdList.Enable(True)
333
self.panCmdList.Execute(strAuthorCmd)
335
# ===================================================================
336
class CommandOutputPanel(wx.Panel):
337
"""A panel for executing and logging command-lines.
339
To use CommandOutputPanel, the parent should implement a function
340
ProcessingDone(bool errStatus), which is called by CommandOutputPanel to
341
notify the parent that the panel is done running commands. Presumably, the
342
commands that are executing must finish before proceeding with another
343
operation, so this function is used to let the parent know that the commands
344
are done executing."""
345
# Current (running) process
347
# Has an error occurred in any of the commands?
348
errorOccurred = False
349
# Command queue (starts out empty)
353
def __init__(self, parent, id):
354
wx.Panel.__init__(self, parent, id)
356
# Process list and labels
357
self.lblCurCmd = wx.StaticText(self, wx.ID_ANY, _("Running command:"))
358
self.txtCurCmd = wx.TextCtrl(self, wx.ID_ANY, "")
359
self.txtCurCmd.Enable(False)
360
self.lblQueue = wx.StaticText(self, wx.ID_ANY, _("Commands left to run:") + '0')
362
# Output window (fixed-width font)
363
self.txtOut = wx.TextCtrl(self, wx.ID_ANY,
364
style = wx.TE_MULTILINE | wx.TE_READONLY)
365
self.txtOut.SetFont(wx.Font(10, wx.FONTFAMILY_TELETYPE,
366
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
367
self.txtOut.AppendText(_("The following commands will be run:") + \
368
"\n=========================================\n")
370
# Log window font size widget
371
self.lblFontSize = wx.StaticText(self, wx.ID_ANY, _("Log window font size:"))
372
strFontSizes = ["8", "10", "12", "14"]
373
self.cboFontSize = wx.ComboBox(self, wx.ID_ANY, "10", choices = strFontSizes,
374
style = wx.CB_READONLY)
375
wx.EVT_TEXT(self, self.cboFontSize.GetId(), self.OnFontSize)
378
self.btnSaveLog = wx.Button(self, wx.ID_ANY, _("Save log"))
379
self.btnSaveLog.SetToolTipString(_("Save the output log to a file"))
380
wx.EVT_BUTTON(self, self.btnSaveLog.GetId(), self.OnSaveLog)
382
# Save as script button
383
self.btnSaveAsScript = wx.Button(self, wx.ID_ANY, _("Save as script"))
384
self.btnSaveAsScript.SetToolTipString(_("Save the commands as a script file"))
385
wx.EVT_BUTTON(self, self.btnSaveAsScript.GetId(), self.OnSaveAsScript)
387
# Keep track of who parent is
390
# Timer to produce continuous output and keep
391
# running the next command
392
self.idleTimer = wx.Timer(self, ID_CMD_TIMER)
395
#wx.EVT_IDLE(self, self.OnIdle)
396
wx.EVT_TIMER(self, ID_CMD_TIMER, self.OnIdleTime)
397
wx.EVT_END_PROCESS(self, wx.ID_ANY, self.OnProcessEnded)
399
# Current command sizer
400
self.sizCurCmd = wx.BoxSizer(wx.HORIZONTAL)
401
self.sizCurCmd.Add(self.lblCurCmd, 0, wx.EXPAND | wx.RIGHT, 6)
402
self.sizCurCmd.Add(self.txtCurCmd, 1, wx.EXPAND)
403
# Control sizer (may have more controls later)
404
self.sizControl = wx.BoxSizer(wx.HORIZONTAL)
405
self.sizControl.Add(self.lblQueue, 1, wx.EXPAND | wx.ALIGN_LEFT)
406
self.sizControl.Add(self.lblFontSize, 0, wx.EXPAND | wx.ALIGN_RIGHT)
407
self.sizControl.Add(self.cboFontSize, 0, wx.EXPAND | wx.ALIGN_RIGHT)
408
self.sizControl.Add(self.btnSaveLog, 0, wx.EXPAND)
409
self.sizControl.Add(self.btnSaveAsScript, 0, wx.EXPAND)
411
self.sizMain = wx.BoxSizer(wx.VERTICAL)
412
self.sizMain.Add(self.sizCurCmd, 0, wx.EXPAND | wx.BOTTOM, 6)
413
self.sizMain.Add(self.txtOut, 3, wx.EXPAND | wx.BOTTOM, 6)
414
self.sizMain.Add(self.sizControl, 0, wx.EXPAND | wx.BOTTOM, 6)
415
self.SetSizer(self.sizMain)
418
"""Detach any running process."""
419
# Detach any running process
421
self.process.Detach()
423
def OnFontSize(self, evt):
424
"""Change log window font size."""
425
newFontSize = int(self.cboFontSize.GetValue())
426
self.txtOut.SetFont(wx.Font(newFontSize, wx.FONTFAMILY_TELETYPE,
427
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
428
#self.txtOut.Refresh()
430
def OnSaveLog(self, evt):
431
"""Save output log to a file."""
432
# Prompt for a filename
433
outFileDlg = wx.FileDialog(self, _("Choose a filename to save to"),
434
"", "", "*.*", wx.SAVE | wx.OVERWRITE_PROMPT)
435
if outFileDlg.ShowModal() == wx.ID_OK:
436
outFile = outFileDlg.GetPath()
437
success = self.txtOut.SaveFile(outFile)
439
dlgAck = wx.MessageDialog(self,
440
_("The log was successfully saved to ") + outFile,
441
_("Log saved"), wx.OK | wx.ICON_INFORMATION)
443
dlgAck = wx.MessageDialog(self,
444
_("The log could not be saved to ") + outFile + \
445
_("Maybe you don't have write permission to the given file?"),
446
_("Log not saved"), wx.OK | wx.ICON_INFORMATION)
451
def OnSaveAsScript(self, evt):
452
"""Save commands as a script."""
453
# Prompt for a filename
454
msgExecFlagDlg = wx.MessageDialog(self, \
455
"Commands can only be run from partitions that have\n" \
456
"been mounted with the executable flag set. \n" \
457
"Consequently, in order to run this script, ensure that\n" \
458
"it is saved to an appropriate partition.",
459
"Warning about partitions",
460
wx.OK | wx.ICON_ERROR)
461
msgExecFlagDlg.ShowModal()
462
msgExecFlagDlg.Destroy()
463
outFileDlg = wx.FileDialog(self, _("Choose a filename to save to"),
464
"", "", "*.*", wx.SAVE | wx.OVERWRITE_PROMPT)
465
if outFileDlg.ShowModal() == wx.ID_OK:
466
outFile = outFileDlg.GetPath()
467
commandList = "#!/usr/bin/env bash\n"
470
for eachCommand in self.strCmdQueue:
471
commandList = commandList + eachCommand + "\n"
473
output = open(outFile,'w')
474
output.writelines(commandList)
479
os.chmod(outFile,0755)
481
dlgAck = wx.MessageDialog(self,
482
_("The commands were successfully saved to: \n") + outFile,
483
_("Script saved"), wx.OK | wx.ICON_INFORMATION)
485
dlgAck = wx.MessageDialog(self,
486
_("The commands could not be saved to:\n") + outFile + "\n" + \
487
_("Maybe you don't have write permission to the given file?"),
488
_("Script not saved"), wx.OK | wx.ICON_INFORMATION)
493
def OnIdleTime(self, evt):
494
"""Execute commands in the queue and print output to the log."""
495
# If processing hasn't been started/enabled, do nothing
496
if not self.idleTimer.IsRunning():
498
# If no process is currently executing, start the next
500
if self.process is None:
501
self.StartNextProcess()
502
# If a process is currently running, get its output and
503
# print it to the command window
504
if self.process is not None and self.pid != 0:
505
stream = self.process.GetInputStream()
507
self.txtOut.AppendText(unicode(stream.read(), errors='ignore'))
509
def StartNextProcess(self):
510
"""Start the next process in the queue."""
511
# If there is a command in the queue
512
if len(self.strCmdQueue) > 0:
513
self.strCurCmd = self.strCmdQueue.pop(0)
514
# Show the command that is being executed,
515
# and the number remaining in queue
516
self.txtCurCmd.SetValue(self.strCurCmd)
517
self.txtOut.AppendText("Running command: %s\n" % self.strCurCmd)
518
# Start the process running
519
self.process = wx.Process(self)
520
self.process.Redirect()
521
self.pid = wx.Execute(self.strCurCmd, wx.EXEC_ASYNC, self.process)
522
self.lblQueue.SetLabel("Commands left to run: %d" % \
523
len(self.strCmdQueue))
525
def OnProcessEnded(self, evt):
526
"""Print any remaining output, and destroy the process."""
527
# Get process exit status
528
curExitStatus = evt.GetExitCode()
529
# Print message to console if there was an error
530
if curExitStatus != 0:
532
print "The following command returned an exit status of %d:" % \
535
print "Please report this bug on the tovid forum or IRC channel:"
536
print " Forum: http://www.createphpbb.com/phpbb/tovid.html"
537
print " IRC: irc://irc.freenode.net/tovid"
538
print "Include all the output shown above, as well as any output"
539
print "shown in the log window of the tovid GUI."
540
self.errorOccurred = True
541
# Print any remaining output
542
stream = self.process.GetInputStream()
544
self.txtOut.AppendText(unicode(stream.read(), errors='ignore'))
545
self.process.Destroy()
547
# If there are more commands in the queue, start the next one
548
if len(self.strCmdQueue) > 0:
549
self.StartNextProcess()
550
# Otherwise, stop running and update status messages
552
self.idleTimer.Stop()
553
self.txtCurCmd.SetValue("")
554
self.lblQueue.SetLabel("Commands left to run: 0")
555
# Let parent know that processing is done
556
self.parent.ProcessingDone(self.errorOccurred)
557
self.errorOccurred = False
559
"""Clear out the command queue."""
560
self.strCmdQueue = []
561
self.txtCurCmd.SetValue("")
563
self.txtOut.AppendText("The following commands will be run:\n"
564
"=========================================\n")
565
self.lblQueue.SetLabel("Commands left to run: 0")
568
def Execute(self, command):
569
"""Put the given command-line string into the queue for execution."""
570
self.strCmdQueue.append(command)
571
self.txtOut.AppendText("%s\n------------------------\n" % command)
572
# Update the queue size indicator
573
self.lblQueue.SetLabel("Commands left to run: %d" % len(self.strCmdQueue))
574
self.sizCurCmd.Layout()
577
"""Start processing all commands in queue."""
578
# NOTE FOR FUTURE VERSION: Include capability to resume
579
# a cancelled queue, or start over from the beginning
580
# (requires keeping a copy of the original queue)
581
# If already running, do nothing
582
if self.idleTimer.IsRunning():
584
# Start running commands, if any remain to be executed
585
if len(self.strCmdQueue) > 0:
586
# Start the idle timer (1s interval)
587
self.idleTimer.Start(1000)
589
self.parent.ProcessingDone(self.errorOccurred)
592
"""Stop processing and return current process to queue."""
593
# Stop the idle timer and kill current process
594
self.idleTimer.Stop()
595
if self.process is not None:
597
self.process.Destroy()
599
# Return current command to queue
600
self.strCmdQueue.insert(0, self.strCurCmd)
603
self.txtCurCmd.SetValue("")
604
self.lblQueue.SetLabel("Commands left to run: %d" % len(self.strCmdQueue))
607
class DiscLayoutPanel(wx.Panel):
608
"""Panel for adding menus and videos to a disc, with configurations"""
610
def __init__(self, parent, id):
611
wx.Panel.__init__(self, parent, id)
613
self.numMenus = 0 # Layout begins with no menus
614
self.numGroups = 0 # Layout begins with no groups
615
self.discFormat = 'dvd'
616
self.discTVSystem = 'ntsc'
618
self.curConfig = TovidConfig()
619
self.lastUsedPath = ""
621
# Set up controls and sizers
622
# Buttons and their tooltips
623
self.btnAddVideos = wx.Button(self, wx.ID_ANY, "Add video(s)")
624
#self.btnAddSlides = wx.Button(self, wx.ID_ANY, "Add slide(s)")
625
self.btnAddGroup = wx.Button(self, wx.ID_ANY, "Add a group")
626
self.btnAddMenu = wx.Button(self, wx.ID_ANY, "Add menu")
627
self.btnMoveUp = wx.Button(self, wx.ID_ANY, "Move up")
628
self.btnMoveDown = wx.Button(self, wx.ID_ANY, "Move down")
629
self.btnRemove = wx.Button(self, wx.ID_ANY, "Remove")
630
self.btnAddVideos.SetToolTipString("Add video files under this menu")
631
#self.btnAddSlides.SetToolTipString("Add still-image files under this menu")
632
self.btnAddGroup.SetToolTipString("Add group of videos under this menu")
633
self.btnAddMenu.SetToolTipString("Add a navigation menu to the disc; "
634
"you must add at least one navigation menu before adding any videos.")
635
self.btnMoveUp.SetToolTipString("Move the current item up")
636
self.btnMoveDown.SetToolTipString("Move the current item down")
637
self.btnRemove.SetToolTipString("Remove the current item from the disc")
638
wx.EVT_BUTTON(self, self.btnAddVideos.GetId(), self.OnAddVideos)
639
# wx.EVT_BUTTON(self, self.btnAddSlides.GetId(), self.OnAddSlides)
640
wx.EVT_BUTTON(self, self.btnAddGroup.GetId(), self.OnAddGroup)
641
wx.EVT_BUTTON(self, self.btnAddMenu.GetId(), self.OnAddMenu)
642
wx.EVT_BUTTON(self, self.btnMoveUp.GetId(), self.OnCuritemUp)
643
wx.EVT_BUTTON(self, self.btnMoveDown.GetId(), self.OnCuritemDown)
644
wx.EVT_BUTTON(self, self.btnRemove.GetId(), self.OnRemoveCuritem)
645
# All buttons except AddMenu disabled to start with
646
self.btnAddVideos.Enable(False)
647
#self.btnAddSlides.Enable(False)
648
self.btnAddGroup.Enable(False)
649
self.btnMoveUp.Enable(False)
650
self.btnMoveDown.Enable(False)
651
self.btnRemove.Enable(False)
653
# The disc layout tree
654
self.discTree = FlexTreeCtrl(self, wx.ID_ANY, style = wx.TR_SINGLE \
655
| wx.TR_HAS_BUTTONS | wx.TR_EDIT_LABELS | wx.SUNKEN_BORDER)
656
# Icons to use in the tree
658
self.listIcons = wx.ImageList(iconSize[0], iconSize[1])
659
self.idxIconMenu = self.listIcons.Add(MenuIcon())
660
self.idxIconSlide = self.listIcons.Add(SlideIcon())
661
self.idxIconGroup = self.listIcons.Add(GroupIcon())
662
self.idxIconVideo = self.listIcons.Add(VideoIcon())
663
self.idxIconDisc = self.listIcons.Add(DiscIcon())
664
self.discTree.SetImageList(self.listIcons)
666
# Root of disc. Non-deletable.
667
self.rootItem = self.discTree.AddRoot("Untitled disc", self.idxIconDisc)
668
self.discTree.SetPyData(self.rootItem, DiscOptions())
669
self.discTree.SetToolTipString("Navigation layout of the disc. "
670
"Use the buttons below to add elements. Click on the title of "
671
"an element to edit it.")
672
wx.EVT_TREE_SEL_CHANGED(self.discTree, self.discTree.GetId(), \
673
self.OnTreeSelChanged)
674
wx.EVT_TREE_END_LABEL_EDIT(self.discTree, self.discTree.GetId(), \
676
self.discTree.Expand(self.rootItem)
677
# topItem starts out being root
678
self.topItem = self.rootItem
680
# Horizontal box sizer to hold tree manipulation buttons
681
self.sizBtn = wx.GridSizer(2, 3, 0, 0)
682
self.sizBtn.AddMany([ (self.btnAddMenu, 1, wx.EXPAND),
683
(self.btnRemove, 1, wx.EXPAND),
684
(self.btnMoveUp, 1, wx.EXPAND),
685
(self.btnAddVideos, 1, wx.EXPAND),
686
(self.btnAddGroup, 1, wx.EXPAND),
687
(self.btnMoveDown, 1, wx.EXPAND) ])
689
# Outer vertical box sizer to hold tree and button-box
690
self.sizTree = wx.BoxSizer(wx.VERTICAL)
691
self.sizTree.Add(self.discTree, 1, wx.EXPAND | wx.ALL, 0)
692
self.sizTree.Add(self.sizBtn, 0, wx.EXPAND)
694
# Panel to contain disc options (format, tvsys, etc.)
695
self.panDisc = DiscPanel(self, wx.ID_ANY)
696
self.panDisc.SetOptions(self.discTree.GetPyData(self.rootItem))
697
# Panels to contain video/menu/group encoding options
698
self.panVideoOptions = VideoPanel(self, wx.ID_ANY)
699
self.panMenuOptions = MenuPanel(self, wx.ID_ANY)
700
self.panGroupOptions = GroupPanel(self, wx.ID_ANY)
701
# Hide currently-unused options panels
702
self.panVideoOptions.Hide()
703
self.panMenuOptions.Hide()
704
self.panGroupOptions.Hide()
705
# Sizers to hold options panel (and more later?)
706
self.sizOptions = wx.BoxSizer(wx.VERTICAL)
707
self.sizOptions.Add(self.panDisc, 1, wx.EXPAND | wx.ALL, 8)
709
# Horizontal splitter to hold tree and options panel
710
self.sizTreeOpts = wx.BoxSizer(wx.HORIZONTAL)
711
self.sizTreeOpts.Add(self.sizTree, 2, wx.EXPAND | wx.ALL, 8)
712
self.sizTreeOpts.Add(self.sizOptions, 3, wx.EXPAND | wx.ALL, 0)
714
# Main splitter to hold panels
715
self.sizMain = wx.BoxSizer(wx.VERTICAL)
716
self.sizMain.Add(self.sizTreeOpts, 1, wx.EXPAND | wx.ALL, 0)
717
self.SetSizer(self.sizMain)
719
# Select DVD/NTSC by default
720
self.SetDiscFormat('dvd')
721
self.SetDiscTVSystem('ntsc')
723
def OnTreeSelChanged(self, evt):
724
"""Update controls when a tree selection changes."""
725
curItem = self.discTree.GetSelection()
726
curOpts = self.discTree.GetPyData(curItem)
727
curType = curOpts.type
728
curParent = self.discTree.GetItemParent(curItem)
730
# If root is selected, dis/enable unusable buttons
731
if curItem == self.rootItem:
732
self.btnMoveUp.Enable(False)
733
self.btnMoveDown.Enable(False)
734
self.btnRemove.Enable(False)
735
self.btnAddVideos.Enable(False)
736
if self.numMenus == 0:
737
self.btnAddMenu.Enable(True)
739
self.btnAddMenu.Enable(False)
740
#self.btnAddSlides.Enable(False)
741
self.btnAddGroup.Enable(False)
742
# Otherwise, enable usable buttons
744
# Can always remove non-root items
745
self.btnRemove.Enable(True)
746
# Can only move up/down for items with siblings
747
if self.discTree.GetChildrenCount(curParent, False) > 1:
748
self.btnMoveUp.Enable(True)
749
self.btnMoveDown.Enable(True)
751
self.btnMoveUp.Enable(False)
752
self.btnMoveDown.Enable(False)
753
# If a non top-level menu is selected, enable the
754
# AddVideos/AddSlides/AddGroup buttons
755
if curType == ID_MENU and curItem != self.topItem:
756
self.btnAddVideos.Enable(True)
757
#self.btnAddSlides.Enable(True)
758
self.btnAddGroup.Enable(True)
759
if self.numMenus == 1:
760
self.btnAddMenu.Enable(True)
762
self.btnAddMenu.Enable(False)
763
elif curType == ID_GROUP and curItem != self.topItem:
764
self.btnAddVideos.Enable(True)
765
self.btnAddGroup.Enable(False)
766
self.btnAddMenu.Enable(False)
767
#self.btnAddSlides.Enable(True)
768
# Otherwise, disable them
770
self.btnAddVideos.Enable(False)
771
#self.btnAddSlides.Enable(False)
772
self.btnAddGroup.Enable(False)
773
self.btnAddMenu.Enable(True)
775
# If disc was selected, show disc options
776
if curType == ID_DISC:
777
self.sizOptions.Remove(0)
778
self.sizOptions.Add(self.panDisc, 1, wx.EXPAND | wx.ALL, 8)
779
self.panMenuOptions.Hide()
780
self.panVideoOptions.Hide()
781
self.panGroupOptions.Hide()
783
self.sizOptions.Layout()
785
# Set appropriate guide text
786
self.curConfig.panGuide.SetTask(ID_TASK_DISC_SELECTED)
788
# For a video, show video encoding options
789
elif curType == ID_VIDEO:
790
# Remove existing panel and show panVideoOptions
791
self.sizOptions.Remove(0)
792
self.panVideoOptions.SetOptions(curOpts)
793
self.sizOptions.Add(self.panVideoOptions, 1, wx.EXPAND | wx.ALL, 8)
795
self.panMenuOptions.Hide()
796
self.panGroupOptions.Hide()
797
self.panVideoOptions.Show()
798
self.sizOptions.Layout()
800
# Set appropriate guide text
801
self.curConfig.panGuide.SetTask(ID_TASK_VIDEO_SELECTED)
803
# For a menu, show menu encoding options
804
elif curType == ID_MENU:
805
# Do I need to do this?
806
self.RefreshItem(curItem)
808
# Remove existing panel and show panMenuOptions
809
self.sizOptions.Remove(0)
810
self.panMenuOptions.SetOptions(curOpts)
811
self.sizOptions.Add(self.panMenuOptions, 1, wx.EXPAND | wx.ALL, 8)
813
self.panVideoOptions.Hide()
814
self.panMenuOptions.Show()
815
self.sizOptions.Layout()
817
# Set appropriate guide text
818
self.curConfig.panGuide.SetTask(ID_TASK_MENU_SELECTED)
820
# For a group, show group options
821
elif curType == ID_GROUP:
822
# Remove existing panel and show panGroupOptions
823
self.sizOptions.Remove(0)
824
self.panGroupOptions.SetOptions(curOpts)
825
self.sizOptions.Add(self.panGroupOptions, 1, wx.EXPAND | wx.ALL, 8)
827
self.panMenuOptions.Hide()
828
self.panVideoOptions.Hide()
829
self.panGroupOptions.Show()
830
self.sizOptions.Layout()
832
# Set appropriate guide text
833
self.curConfig.panGuide.SetTask(ID_TASK_GROUP_SELECTED)
835
def OnTreeItemEdit(self, evt):
836
"""Update controls when a tree item's title is edited."""
837
if not evt.IsEditCancelled():
838
curItem = evt.GetItem()
839
curOpts = self.discTree.GetPyData(curItem)
840
curOpts.title = evt.GetLabel()
841
# Assign outPrefix based on title
842
curOpts.outPrefix = curOpts.title.replace(' ', '_')
844
# Update the appropriate panel
845
if curOpts.type == ID_DISC:
846
self.panDisc.SetOptions(curOpts)
847
elif curOpts.type == ID_MENU:
848
self.panMenuOptions.SetOptions(curOpts)
849
elif curOpts.type == ID_VIDEO:
850
self.panVideoOptions.SetOptions(curOpts)
852
# Update the titles shown list in the menu panel
854
# Get the parent menu
855
curParent = self.discTree.GetItemParent(curItem)
856
# and the options for the parent menu
857
parentOpts = self.discTree.GetPyData(curParent)
858
if parentOpts.type == ID_MENU:
859
# Get the text of the item as it was before it the change
860
curText = self.discTree.GetItemText(curItem)
861
# find the title index to change
862
for titleIndex in range(len(parentOpts.titles)):
863
# compare title with old text
864
if parentOpts.titles[titleIndex] == curText:
865
# item found, change it
866
parentOpts.titles[titleIndex] = evt.GetLabel()
867
# get out of the loop
869
elif curOpts.type == ID_GROUP:
870
self.panGroupOptions.SetOptions(curOpts)
872
# Update the titles shown list in the menu panel
874
# Get the parent menu
875
curParent = self.discTree.GetItemParent(curItem)
876
# and the options for the parent menu
877
parentOpts = self.discTree.GetPyData(curParent)
878
# Get the text of the item as it was before it the change
879
curText = self.discTree.GetItemText(curItem)
880
# find the title index to change
881
for titleIndex in range(len(parentOpts.titles)):
882
# compare title with old text
883
if parentOpts.titles[titleIndex] == curText:
884
# item found, change it
885
parentOpts.titles[titleIndex] = evt.GetLabel()
886
# get out of the loop
889
def OnAddMenu(self, evt):
890
"""Append a menu to the disc."""
892
# If this is the second menu on the disc, and a top menu does
893
# not already exist, create a top menu and insert the current
895
if self.numMenus == 2 and self.topItem == self.rootItem:
896
oldMenu, cookie = VER_GetFirstChild(self.discTree, self.topItem)
897
self.topItem = self.discTree.AppendItem(self.rootItem,
898
"Main menu", self.idxIconMenu)
899
# Create a new top menu at the root of the tree
900
self.discTree.SetPyData(self.topItem,
901
MenuOptions(self.discFormat, self.discTVSystem, \
903
copiedMenu = self.discTree.AppendItemMove(self.topItem, oldMenu)
904
# Refresh the copied menu
905
self.RefreshItem(copiedMenu)
906
self.discTree.Expand(copiedMenu)
907
# One more menu (top menu); commented to preserve menu numbering
910
# New menu is appended under topItem
911
curItem = self.discTree.AppendItem(self.topItem,
912
"Untitled menu %d" % self.numMenus, self.idxIconMenu)
913
self.discTree.SetPyData(curItem, MenuOptions(self.discFormat,
914
self.discTVSystem, "Untitled menu %d" % self.numMenus))
915
# Refresh the current item (for empty menus, just adds the "Back" button)
916
self.RefreshItem(curItem)
917
# Expand, show, and select the new menu
918
self.discTree.EnsureVisible(curItem)
919
self.discTree.Expand(curItem)
920
self.discTree.SelectItem(curItem)
922
# If tree has more than one item, enable encoding button
923
if self.discTree.GetCount() > 1:
924
self.parent.EncodeOK(True)
926
# Refresh the top item to include any added menus
927
self.RefreshItem(self.topItem)
929
# Set appropriate guide text
930
self.curConfig.panGuide.SetTask(ID_TASK_MENU_ADDED)
932
def OnAddVideos(self, evt):
933
"""Add videos to the disc, under the currently-selected menu."""
934
curParent = self.discTree.GetSelection()
936
# If there are no menus yet, create one before adding
937
# the videos under it
938
if self.numMenus < 1:
939
self.OnAddMenu(wx.CommandEvent())
941
# If there are menus, but none is selected, ask user to
942
# select a menu before adding videos
943
elif self.numMenus > 0 and \
944
self.discTree.GetPyData(curParent).type != ID_MENU and \
945
self.discTree.GetPyData(curParent).type != ID_GROUP:
946
# Show a message dialog
947
msgDlg = wx.MessageDialog(self, "Please select a menu or group before adding videos",
948
"No menu or group selected",
949
wx.OK | wx.ICON_EXCLAMATION)
954
# Open a file dialog for user to choose videos to add
955
addFileDlg= wx.FileDialog(self, "Select video files", self.lastUsedPath,
956
"", "*.*", wx.OPEN | wx.MULTIPLE)
957
if addFileDlg.ShowModal() == wx.ID_OK:
958
# Get all the filenames that were selected
959
strPathnames = addFileDlg.GetPaths()
960
# Remember the last used directory
961
self.lastUsedPath = os.path.dirname(strPathnames[0])
962
# Store the directory name for later use
967
# Append items as children of the current selection
968
for curFile in range(len(strPathnames)):
969
# Make sure path exists
970
if not os.path.exists(strPathnames[ curFile ]):
973
# Use file basename, underscores replaced with spaces,
974
# for the default title
975
curTitle = os.path.basename(strPathnames[ curFile ]).replace('_', ' ')
976
curItem = self.discTree.AppendItem(curParent, curTitle, self.idxIconVideo)
977
curOpts = VideoOptions(self.discFormat, self.discTVSystem,
978
strPathnames[ curFile ])
979
self.discTree.SetPyData(curItem, curOpts)
980
curStats = VideoStatSeeker(curOpts)
983
# If tree has more than one item, enable encoding button
984
if self.discTree.GetCount() > 1:
985
self.parent.EncodeOK(True)
987
self.discTree.EnsureVisible(curItem)
989
# Refresh the parent to include all added videos
990
self.RefreshItem(curParent)
991
# Refresh the panel view of the parent menu
992
self.discTree.SelectItem(curParent)
993
curOpts = self.discTree.GetPyData(curParent)
995
if self.discTree.GetPyData(curParent).type == ID_MENU:
996
self.panMenuOptions.SetOptions(curOpts)
997
elif self.discTree.GetPyData(curParent).type == ID_GROUP:
998
self.panGroupOptions.SetOptions(curOpts)
999
# Set appropriate guide text
1000
self.curConfig.panGuide.SetTask(ID_TASK_VIDEO_ADDED)
1002
def OnAddSlides(self, evt):
1003
"""Add slides to the disc structure. Not enabled yet."""
1004
# Display a message and return
1005
msgDlg = wx.MessageDialog(self, "Slideshows are not supported "
1006
"in this version. Sorry!", "Slides not functional yet",
1007
wx.OK | wx.ICON_EXCLAMATION)
1012
# The real functionality, for when slides are supported
1013
curParent = self.discTree.GetSelection()
1014
# If a menu is not selected, print an error and return
1015
if self.discTree.GetPyData(curParent).type != ID_MENU:
1016
msgDlg = wx.MessageDialog(self, "Please select a menu before "
1019
wx.OK | wx.ICON_EXCLAMATION)
1024
# Open a file dialog for user to choose slides to add
1025
addFileDlg= wx.FileDialog(self, "Select image files", "", "", "*.*",
1026
wx.OPEN | wx.MULTIPLE)
1027
if addFileDlg.ShowModal() == wx.ID_OK:
1028
# Get all the filenames that were selected
1029
strPathnames = addFileDlg.GetPaths()
1030
# Store the directory name for later use
1031
addFileDlg.Destroy()
1035
# Append a new slide element containing the given list of files
1036
curItem = self.discTree.AppendItem(curParent, "Untitled slides",
1038
curOpts = SlideOptions(self.discFormat, self.discTVSystem, strPathnames)
1039
self.discTree.SetPyData(curItem, curOpts)
1041
self.discTree.EnsureVisible(curItem)
1043
# Refresh the parent to include all added videos
1044
self.RefreshItem(curParent)
1046
# If tree has more than one item, enable encoding button
1047
if self.discTree.GetCount() > 1:
1048
self.parent.EncodeOK(True)
1050
def OnAddGroup(self, evt):
1051
"""Add group to the disc, under the currently-selected menu."""
1053
curParent = self.discTree.GetSelection()
1055
# If there are no menus yet, create one before adding
1056
# the videos under it
1057
if self.numMenus < 1:
1058
self.OnAddMenu(wx.CommandEvent())
1060
# If there are menus, but none is selected, ask user to
1061
# select a menu before adding group
1062
elif self.numMenus > 0 and \
1063
self.discTree.GetPyData(curParent).type != ID_MENU:
1064
# Show a message dialog
1065
msgDlg = wx.MessageDialog(self, "Please select a menu before adding a group",
1067
wx.OK | wx.ICON_EXCLAMATION)
1072
# New menu is appended under curParent
1073
curItem = self.discTree.AppendItem(curParent,
1074
"Untitled group %d" % self.numGroups, self.idxIconGroup)
1075
self.discTree.SetPyData(curItem, GroupOptions("Untitled group %d" % self.numGroups))
1077
# Refresh the current item (for empty menus, just adds the "Back" button)
1078
self.RefreshItem(curItem)
1080
# Refresh the parent to include all added group
1081
self.RefreshItem(curParent)
1083
# Expand, show, and select the new menu
1084
self.discTree.EnsureVisible(curItem)
1085
self.discTree.Expand(curItem)
1086
self.discTree.SelectItem(curItem)
1088
# Set appropriate guide text
1089
self.curConfig.panGuide.SetTask(ID_TASK_GROUP_ADDED)
1092
def OnCuritemUp(self, evt):
1093
"""Move the currently-selected item up in the tree."""
1094
self.discTree.MoveItemUp()
1095
# Refresh the parent
1096
curParent = self.discTree.GetItemParent(self.discTree.GetSelection())
1097
self.RefreshItem(curParent)
1099
def OnCuritemDown(self, evt):
1100
"""Move the currently-selected item down in the tree."""
1101
self.discTree.MoveItemDown()
1102
# Refresh the parent
1103
curParent = self.discTree.GetItemParent(self.discTree.GetSelection())
1104
self.RefreshItem(curParent)
1106
def OnRemoveCuritem(self, evt):
1107
"""Remove the currently-selected item and its descendants from the
1109
curItem = self.discTree.GetSelection()
1110
curParent = self.discTree.GetItemParent(curItem)
1112
# If root is selected, do nothing
1113
if curItem == self.rootItem:
1116
# If the top item is selected, verify before deletion
1117
elif curItem.IsOk() and curItem == self.topItem:
1118
dlgConfirm = wx.MessageDialog(self,
1119
"This will remove all menus, groups and videos\n"
1120
"from the disc layout. Proceed?",
1121
"Confirm removal", wx.YES_NO | wx.ICON_QUESTION)
1122
if dlgConfirm.ShowModal() == wx.ID_YES:
1123
self.discTree.Delete(curItem)
1124
# Top item goes back to being root
1125
self.topItem = self.rootItem
1126
dlgConfirm.Destroy()
1127
# Back to having 0 menus
1129
self.btnAddMenu.Enable(True)
1131
# Make sure the item isn't root or topItem before being deleted
1132
elif curItem.IsOk():
1133
# If deleting a menu, confirm deletion and
1134
# decrement the menu counter
1135
if self.discTree.GetPyData(curItem).type == ID_MENU:
1136
dlgConfirm = wx.MessageDialog(self,
1137
"This will remove the currently selected\n"
1138
"menu, along with all videos, groups and stills\n"
1139
"under it. Proceed?",
1140
"Confirm removal", wx.YES_NO | wx.ICON_QUESTION)
1141
if dlgConfirm.ShowModal() == wx.ID_NO:
1144
# If deleting a group, confirm deletion and
1145
# decrement the group counter
1146
elif self.discTree.GetPyData(curItem).type == ID_GROUP:
1147
dlgConfirm = wx.MessageDialog(self,
1148
"This will remove the currently selected\n"
1149
"group, along with all videos \n"
1150
"under it. Proceed?",
1151
"Confirm removal", wx.YES_NO | wx.ICON_QUESTION)
1152
if dlgConfirm.ShowModal() == wx.ID_NO:
1155
# Delete the current item
1156
self.discTree.Delete(curItem)
1158
# Refresh the parent
1159
self.RefreshItem(curParent)
1161
# If only one item remains, disable encode button
1162
if self.discTree.GetCount() < 2:
1163
self.parent.EncodeOK(False)
1166
def SetOptions(self, options):
1167
"""Set the encoding options associated with the current item."""
1168
self.discTree.SetPyData(self.discTree.GetSelection(), options)
1170
def GetOptions(self):
1171
"""Get the encoding options associated with the current item."""
1172
return self.discTree.GetPyData(self.discTree.GetSelection())
1174
def SetDiscFormat(self, format):
1175
"""Set the disc format (DVD, VCD, SVCD)."""
1176
self.discFormat = format
1177
# Make video panel controls appropriate for this disc format
1178
self.panVideoOptions.SetDiscFormat(format)
1179
# Make menu panel controls appropriate for this disc format
1180
self.panMenuOptions.SetDiscFormat(format)
1181
# Make all encoding options in the disc compliant
1182
format = self.discTree.GetPyData(self.rootItem).format
1183
refs = self.discTree.GetReferenceList(self.rootItem)
1184
for curItem in refs:
1185
if curItem.type != ID_DISC:
1186
curItem.SetDiscFormat(format)
1188
def SetDiscTVSystem(self, tvsys):
1189
"""Set the disc TV system (NTSC, PAL)."""
1190
self.discTVSystem = tvsys
1191
# Make video panel controls appropriate for this disc TVsystem
1192
self.panVideoOptions.SetDiscTVSystem(tvsys)
1193
# Make all encoding options in the disc compliant
1194
tvsys = self.discTree.GetPyData(self.rootItem).tvsys
1195
refs = self.discTree.GetReferenceList(self.rootItem)
1196
for curItem in refs:
1197
# Menus and slides need to know TV system
1198
if curItem.type != ID_DISC:
1199
curItem.SetDiscTVSystem(tvsys)
1201
def RefreshItem(self, curItem):
1202
"""Refresh the given tree item and make sure it is up-to-date.
1203
Should be called for an item after its children have changed."""
1204
curOpts = self.discTree.GetPyData(curItem)
1205
# If it's a menu, fill it with the titles listed below it
1206
if curOpts.type == ID_MENU:
1208
curChild, cookie = VER_GetFirstChild(self.discTree, curItem)
1209
while curChild.IsOk():
1210
curOpts.titles.append(self.discTree.GetItemText(curChild))
1211
curChild, cookie = self.discTree.GetNextChild(curItem, cookie)
1212
# If this is not a top menu, add a "Back" title (link)
1213
if not curOpts.isTopMenu and self.numMenus > 1:
1214
curOpts.titles.append("Back")
1215
elif curOpts.type == ID_GROUP:
1216
curOpts.groupMemberCount = 0
1217
curChild, cookie = VER_GetFirstChild(self.discTree, curItem)
1218
while curChild.IsOk():
1219
curOpts.groupMemberCount = curOpts.groupMemberCount + 1
1220
curChild, cookie = self.discTree.GetNextChild(curItem, cookie)
1222
def UseForAllItems(self, opts):
1223
"""Use the given options for all videos/menus/slides."""
1224
# Get references for all items
1225
refs = self.discTree.GetReferenceList(self.rootItem)
1226
# Count how many items are changed
1228
# Apply options to all items in the tree of the same type
1229
# Don't copy to self
1230
for curItem in refs:
1232
if curItem.type == opts.type:
1233
curItem.CopyFrom(opts)
1237
def CheckForNoDuplicateOutputFiles(self, panel):
1238
"""Check for when two files have same output name"""
1239
# Get references for all items
1240
refs = self.discTree.GetReferenceList(self.rootItem)
1241
for curItem in refs:
1242
#Check that no other references have same output name as this one
1243
if curItem.type == ID_DISC:
1244
#No possibility of duplication
1246
elif curItem.type == ID_MENU:
1247
outputFileName = "%s" % (curItem.outPrefix)
1248
elif curItem.type == ID_VIDEO:
1249
outputFileName = "%s" % (curItem.outPrefix)
1250
elif curItem.type == ID_SLIDE:
1252
elif curItem.type == ID_GROUP:
1253
outputFileName = "%s" % (curItem.outPrefix)
1255
for otherItem in refs:
1256
if otherItem.type == ID_DISC:
1257
#No possibility of duplication
1259
elif otherItem.type == ID_MENU:
1260
otherOutputFileName = "%s" % (otherItem.outPrefix)
1261
elif otherItem.type == ID_VIDEO:
1262
otherOutputFileName = "%s" % (otherItem.outPrefix)
1263
elif otherItem.type == ID_SLIDE:
1265
elif otherItem.type == ID_GROUP:
1266
otherOutputFileName = "%s" % (otherItem.outPrefix)
1267
if otherOutputFileName == outputFileName:
1268
sameNameCount = sameNameCount + 1
1269
if sameNameCount > 1:
1270
msgImageFileMissingDlg = wx.MessageDialog(panel, \
1271
"Two menus, groups or videos have been given the same label.\n" \
1272
"Currently, this is not allowed.\n" \
1273
"This label is: %s\n\n" \
1274
"Please choose unique names." % (outputFileName),
1276
wx.OK | wx.ICON_ERROR)
1277
msgImageFileMissingDlg.ShowModal()
1278
msgImageFileMissingDlg.Destroy()
1282
def CheckMenuCountLimitsNotExceeded(self, panel):
1283
"""Ensure the menu limit is not exceeded"""
1284
MAX_BUTTONS_ON_DVD_MENU = 36
1285
MAX_BUTTONS_ON_SVCD_MENU = 9
1287
# Get all items in tree
1288
items = self.discTree.GetItemList(self.rootItem)
1289
for curItem in items:
1290
curOpts = self.discTree.GetPyData(curItem)
1291
if curOpts.type == ID_MENU:
1292
#Need to check there are not too many items in menu
1293
menuCount = self.discTree.GetChildrenCount(curItem, False)
1294
tooManyButtonsOnMenu = False
1295
if self.discFormat == 'dvd' and menuCount > MAX_BUTTONS_ON_DVD_MENU:
1296
tooManyButtonsOnMenu = True
1297
elif self.discFormat in [ 'vcd', 'svcd' ] and menuCount > MAX_BUTTONS_ON_SVCD_MENU:
1298
tooManyButtonsOnMenu = True
1300
if tooManyButtonsOnMenu == True:
1301
msgTooManyButtonsDlg = wx.MessageDialog(panel, \
1302
"The number of buttons that can be on a menu is limited.\n" \
1303
"For DVDs, this limit is %s.\n" \
1304
"For (S)VCDs, this limit is %s\n\n" \
1305
"Currently, a menu has %s.\n" \
1306
"Please correct this." \
1307
% (MAX_BUTTONS_ON_DVD_MENU, MAX_BUTTONS_ON_SVCD_MENU, menuCount),
1308
"Too many buttons on menu",
1309
wx.OK | wx.ICON_ERROR)
1310
msgTooManyButtonsDlg.ShowModal()
1311
msgTooManyButtonsDlg.Destroy()
1315
def CheckForNoGroupsWhenNotDVD(self, panel):
1316
"""Check for invalid characters in filenames etc"""
1317
if self.discFormat in [ 'vcd', 'svcd' ] and self.numGroups > 0:
1318
msgGroupsWhenSVCDDlg = wx.MessageDialog(panel, \
1319
"Tovid does not currently support groups for (S)VCDs\n" \
1320
"Please remove all groups or change to a DVD disc.",
1321
"Groups not supported for (S)VCDs",
1322
wx.OK | wx.ICON_ERROR)
1323
msgGroupsWhenSVCDDlg.ShowModal()
1324
msgGroupsWhenSVCDDlg.Destroy()
1328
def PerformSanityCheckOnFiles(self, panel):
1329
"""Check for invalid characters in filenames etc"""
1330
# Get references for all items
1331
refs = self.discTree.GetReferenceList(self.rootItem)
1332
if self.CheckForNoGroupsWhenNotDVD(panel) == False:
1334
for curItem in refs:
1335
if curItem.RelevantFilesAreOK(panel) == False:
1337
if self.CheckMenuCountLimitsNotExceeded(panel) == False:
1339
if self.CheckForNoDuplicateOutputFiles(panel) == False:
1344
def GetAllCommands(self):
1345
"""Return an array of strings containing all encoding commands to be
1347
# Get references for all items
1348
refs = self.discTree.GetReferenceList(self.rootItem)
1349
# Send the reference list to the root DiscOptions item
1350
# (so it can generate the authoring command)
1351
discOpts = self.discTree.GetPyData(self.rootItem)
1352
discOpts.SetLayout(refs)
1353
# Pop root command off, since it needs to be
1354
# put at the end of the command list
1355
strDiscCmd = refs.pop(0).GetCommand()
1356
# Append command associated with each item
1358
for curItem in refs:
1359
#NB, groups do not actually require commands of their own
1360
curCommand = curItem.GetCommand()
1361
if curCommand != "":
1362
commands.append(curCommand)
1363
# Append root command
1364
commands.append(strDiscCmd)
1367
def GetIcon(self, element):
1368
if isinstance(element, Disc):
1369
return self.idxIconDisc
1370
elif isinstance(element, Menu):
1371
return self.idxIconMenu
1372
elif isinstance(element, Group):
1373
return self.idxIconGroup
1375
return self.idxIconVideo
1378
class DiscPanel(wx.Panel):
1379
"""Panel for choosing disc format (DVD/VCD/SVCD, PAL/NTSC)"""
1381
def __init__(self, parent, id):
1382
wx.Panel.__init__(self, parent, id)
1384
# Global configuration
1385
self.curConfig = TovidConfig()
1387
# Disc options associated with this panel
1388
self.curOptions = DiscOptions()
1389
self.parent = parent
1391
# Disc format selector
1392
self.lblDiscFormat = wx.StaticText(self, wx.ID_ANY, \
1393
"Choose what kind of video disc you want to make:")
1394
strFormats = ["VCD: Low-quality, up to about one hour of video",
1395
"SVCD: Medium quality, 30 to 70 minutes of video",
1396
"DVD: Range of quality, from 1 to 8 hours of video"]
1399
self.rbFormat = wx.RadioBox(self, wx.ID_ANY, "Disc format", \
1400
wx.DefaultPosition, wx.DefaultSize, strFormats, 1, \
1402
self.rbFormat.SetToolTipString("Select what disc format you want to use."
1403
" For VCD and SVCD, you can use a normal CD-recordable drive. For"
1404
" DVD, you need a DVD-recordable drive.")
1405
self.rbFormat.SetSelection(ID_FMT_DVD)
1406
wx.EVT_RADIOBOX(self, self.rbFormat.GetId(), self.OnFormat)
1408
# Disc TV system selector
1409
strTVSystems = ["NTSC: Used in the Americas and East Asia",
1410
"NTSC Film: Same as NTSC, with a film frame rate",
1411
"PAL: Used in most of Europe, Asia, and Africa"]
1412
self.rbTVSystem = wx.RadioBox(self, wx.ID_ANY, "TV format", \
1413
wx.DefaultPosition, wx.DefaultSize, strTVSystems, 1, \
1415
self.rbTVSystem.SetToolTipString("Select NTSC or PAL, depending " \
1416
"on what kind of TV you want to play the disc on.")
1417
self.rbTVSystem.SetSelection(ID_TVSYS_NTSC)
1418
wx.EVT_RADIOBOX(self, self.rbTVSystem.GetId(), self.OnTVSystem)
1420
# Disc options heading
1421
self.txtHeading = HeadingText(self, wx.ID_ANY, "Disc")
1424
self.lblOutputDirectory = wx.StaticText(self, wx.ID_ANY, \
1425
"Output directory:")
1426
self.txtOutputDirectory = wx.TextCtrl(self, wx.ID_ANY,
1427
self.curConfig.strOutputDirectory)
1428
self.txtOutputDirectory.SetToolTipString("Type the full path of a "
1429
"directory where you want to save finished videos and disc images, "
1430
"or use the browse button. Should have 2-6GB of free space.")
1431
self.btnBrowseOutputDirectory = wx.Button(self, wx.ID_ANY, "Browse")
1432
wx.EVT_BUTTON(self, self.btnBrowseOutputDirectory.GetId(),
1433
self.OnBrowseOutputDirectory)
1434
wx.EVT_TEXT(self, self.txtOutputDirectory.GetId(),
1435
self.OnEditOutputDirectory)
1437
# Sizer to hold working directory controls
1438
self.sizDirs = wx.BoxSizer(wx.HORIZONTAL)
1439
self.sizDirs.AddMany([\
1440
(self.lblOutputDirectory, 0, wx.ALIGN_RIGHT | wx.ALL, 8),
1441
(self.txtOutputDirectory, 1, wx.EXPAND | wx.ALL, 8),
1442
(self.btnBrowseOutputDirectory, 0, wx.ALL, 8)
1445
# Sizer to hold controls
1446
self.sizMain = wx.BoxSizer(wx.VERTICAL)
1447
self.sizMain.Add(self.txtHeading, 0, wx.EXPAND | wx.ALL, 8)
1448
self.sizMain.Add(self.lblDiscFormat, 0, wx.EXPAND | wx.ALL, 8)
1449
self.sizMain.Add(self.rbFormat, 0, wx.EXPAND | wx.ALL, 8)
1450
self.sizMain.Add(self.rbTVSystem, 0, wx.EXPAND | wx.ALL, 8)
1451
self.sizMain.Add(self.sizDirs, 0, wx.EXPAND | wx.ALL, 8)
1452
self.SetSizer(self.sizMain)
1454
def OnFormat(self, evt):
1455
"""Set disc format according to radiobox."""
1456
self.curOptions.format = util.ID_to_text('format', evt.GetInt())
1457
# Tell parent to adjust disc format
1458
self.parent.SetDiscFormat(self.curOptions.format)
1460
def OnTVSystem(self, evt):
1461
"""Set disc TV system according to radiobox."""
1462
self.curOptions.tvsys = util.ID_to_text('tvsys', evt.GetInt())
1463
# Tell parent to adjust disc TVSystem
1464
self.parent.SetDiscTVSystem(self.curOptions.tvsys)
1466
def OnBrowseOutputDirectory(self, evt):
1467
"""Browse for output directory."""
1468
workDirDlg = wx.DirDialog(self, "Select a directory for output",
1469
style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
1470
workDirDlg.SetPath(self.txtOutputDirectory.GetValue())
1472
if workDirDlg.ShowModal() == wx.ID_OK:
1473
self.curConfig.strOutputDirectory = workDirDlg.GetPath()
1474
self.txtOutputDirectory.SetValue(self.curConfig.strOutputDirectory)
1475
workDirDlg.Destroy()
1477
def OnEditOutputDirectory(self, evt):
1478
"""Update Config with newly-entered output directory."""
1479
self.curConfig.strOutputDirectory = self.txtOutputDirectory.GetValue()
1481
def SetOptions(self, discOpts):
1482
"""Set control values based on the provided DiscOptions"""
1483
self.curOptions = discOpts
1484
self.rbFormat.SetSelection(util.text_to_ID(self.curOptions.format))
1485
self.rbTVSystem.SetSelection(util.text_to_ID(self.curOptions.tvsys))
1486
self.txtHeading.SetLabel("Disc options: %s" % self.curOptions.title)
1489
class EncodingPanel(wx.Panel):
1490
"""Encoding setup panel. Allow selection of output directory, display
1491
estimated encoding and final size requirements, controls and log window for
1492
running all encoding commands.
1494
def __init__(self, parent, id):
1495
wx.Panel.__init__(self, parent, id)
1496
self.parent = parent
1497
self.curConfig = TovidConfig()
1499
self.panCmdList = CommandOutputPanel(self, wx.ID_ANY)
1500
# Start/interrupt button
1501
self.btnStartStop = wx.Button(self, wx.ID_ANY, "Start encoding")
1502
self.btnStartStop.SetToolTipString("Begin encoding and preparing " \
1503
"all videos and menus on the disc")
1505
wx.EVT_BUTTON(self, self.btnStartStop.GetId(), self.OnStartStop)
1506
# Sizer to hold controls
1507
self.sizMain = wx.BoxSizer(wx.VERTICAL)
1508
#self.sizMain.Add(self.sizEstimates, 0, wx.EXPAND | wx.ALL, 8)
1509
self.sizMain.Add(self.panCmdList, 1, wx.EXPAND | wx.ALL, 8)
1510
self.sizMain.Add(self.btnStartStop, 0, wx.EXPAND | wx.ALL, 8)
1511
self.SetSizer(self.sizMain)
1513
def OnBrowseOutDir(self, evt):
1514
"""Browse for output directory."""
1515
outDirDlg = wx.DirDialog(self, "Select a directory for output",
1516
style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
1517
if outDirDlg.ShowModal() == wx.ID_OK:
1518
self.curConfig.strOutputDirectory = outDirDlg.GetPath()
1519
self.txtOutDir.SetValue(self.curConfig.strOutputDirectory)
1522
def OnStartStop(self, evt):
1523
"""Start/suspend/resume encoding."""
1524
# If currently running, stop/suspend processing
1525
if self.panCmdList.idleTimer.IsRunning():
1527
# Disable 'suspend encoding' since it's not working
1528
# Disable button temporarily, to allow processes to die
1529
# self.btnStartStop.Enable(False)
1530
# self.panCmdList.Stop()
1531
# self.btnStartStop.SetLabel("Resume encoding")
1532
# self.btnStartStop.SetToolTipString("Resume the encoding process " \
1533
# "where it left off")
1534
# Show message that processing stopped
1535
# msgStopped = wx.MessageDialog(self,
1536
# "Encoding is now suspended. You can continue\n" \
1537
# "by selecting \"Resume encoding\".",
1538
# "Encoding suspended", wx.OK | wx.ICON_INFORMATION)
1539
# msgStopped.ShowModal()
1540
# Give processes time to die before re-enabling button
1541
# os.system("sleep 2s")
1542
# self.btnStartStop.Enable(True)
1544
# Not running; start/resume processing
1546
self.curConfig.panGuide.SetTask(ID_TASK_ENCODING_STARTED)
1547
self.panCmdList.Start()
1548
self.btnStartStop.Enable(False)
1549
self.btnStartStop.SetLabel("Currently encoding...")
1550
# self.btnStartStop.SetToolTipString("Interrupt the current " \
1551
# "encoding process and return the current command to the queue")
1553
def SetCommands(self, commands):
1554
"""Set command-list to be executed from DiscLayoutPanel."""
1555
for cmd in commands:
1556
self.panCmdList.Execute(cmd)
1558
def SetOutputDirectory(self, outDir):
1559
"""Set the output directory to use."""
1560
self.txtOutDir.SetValue(outDir)
1562
def ProcessingDone(self, errorOccurred):
1563
"""Signify that processing (video encoding) is done."""
1564
self.parent.btnBurn.Enable(False)
1565
# Let user know if error(s) occurred
1567
msgError = wx.MessageDialog(self,
1568
"Error(s) occurred during encoding. If you want to\n" \
1569
"help improve this software, please file a bug report\n" \
1570
"containing a copy of the output log. Unfortunately,\n" \
1571
"this also means you won't be able to continue to\n" \
1572
"burning your disc. Sorry for the inconvenience!",
1573
"Error occurred during encoding", wx.ICON_ERROR | wx.OK)
1574
msgError.ShowModal()
1575
# Show success message and enable burning
1577
strSuccess = "Done encoding. You may now proceed " \
1578
"with burning the disc."
1579
msgSuccess = wx.MessageDialog(self, strSuccess, "Success!",
1580
wx.ICON_INFORMATION | wx.OK)
1581
msgSuccess.ShowModal()
1584
self.parent.BurnOK(True)
1587
self.btnStartStop.SetLabel("Start encoding")
1588
self.btnStartStop.Enable(True)
1590
class GroupPanel(wx.Panel):
1591
"""A panel showing controls appropriate to encoding a group of videoes."""
1592
def __init__(self, parent, id):
1593
wx.Panel.__init__(self, parent, id)
1596
self.curOptions = GroupOptions()
1597
self.parent = parent
1599
# Group options heading
1600
self.txtHeading = HeadingText(self, wx.ID_ANY, "Group options")
1602
# Add controls to main vertical sizer
1603
self.sizMain = wx.BoxSizer(wx.VERTICAL)
1604
self.sizMain.Add(self.txtHeading, 0, wx.EXPAND | wx.ALL, 8)
1605
self.SetSizer(self.sizMain)
1607
def SetOptions(self, groupOpts):
1608
"""Set control values based on the provided GroupOptions."""
1609
self.curOptions = groupOpts
1611
self.txtHeading.SetLabel("Group options: %s" % self.curOptions.title)
1613
def GetOptions(self):
1614
"""Return the currently-set encoding options."""
1615
return self.curOptions
1617
class GuidePanel(wx.Panel):
1618
"""A panel showing live context-sensitive help."""
1620
def __init__(self, parent, id):
1621
wx.Panel.__init__(self, parent, id)
1623
self.txtHeading = HeadingText(self, wx.ID_ANY, "What to do next")
1625
self.txtGuide = wx.TextCtrl(self, wx.ID_ANY, "",
1626
style = wx.TE_MULTILINE | wx.TE_READONLY)
1629
self.SetTask(ID_TASK_GETTING_STARTED)
1631
self.sizMain = wx.BoxSizer(wx.VERTICAL)
1632
self.sizMain.Add(self.txtHeading, 0, wx.EXPAND | wx.ALL, 8)
1633
self.sizMain.Add(self.txtGuide, 1, wx.EXPAND | wx.ALL, 8)
1634
self.SetSizer(self.sizMain)
1636
def InitTaskText(self):
1637
"""Initialize task-based guide text for all tasks."""
1638
self.strGettingStarted = _("Welcome to the tovid GUI. This program is " \
1639
"designed to help you create a video disc (VCD, SVCD, or DVD) " \
1640
"from videos that you provide. All you need is a CD or DVD " \
1641
"recorder, and one or more videos in almost any format.\n\n" \
1642
"If you don't want to see this help window, select the \"View\" " \
1643
"menu, and then \"Show guide\". Do the same if you want to turn " \
1644
"this help window back on at any time.\n\n" \
1645
"First choose the type of disc you want to create. " \
1646
"VCD and SVCD can be burned to normal CD-R discs with a CD-R(W) drive. " \
1647
"For DVD, you will need a DVD-recordable drive. VCD is a low-resolution " \
1648
"format that can hold about 1 hour of video; SVCD is a medium-resolution " \
1649
"format that also holds about 1 hour of video. DVD is a very versatile " \
1650
"format that can hold anywhere from 1 to 9 hours of video, depending " \
1651
"on the resolution and quality you choose.\n\n" \
1652
"You should also select NTSC or PAL, depending on what kind of TV " \
1653
"you have. NTSC is most popular in the United States and East Asia, " \
1654
"while PAL is commonly used in most of Europe, Asia, and Africa. " \
1655
"(If you aren't sure which one to use, check the manual for your TV " \
1656
"or DVD player.) For NTSC, you can choose between regular NTSC and " \
1657
"NTSC film; use NTSC film to encode using a film frame rate (appropriate " \
1658
"for source videos using a film framerate, or for converting from PAL).\n\n" \
1659
"You can also select a directory to use for output. Output files will " \
1660
"go here, as well as any temporary files created during encoding. " \
1661
"Make sure the directory has plenty of space (2-6 GB).\n\n" \
1662
"Click \"Add menu\" when you are ready to begin adding content to " \
1664
self.strDiscSelected = _("The disc item in the disc layout tree is " \
1665
"now selected. You can change the title of the current disc " \
1666
"by clicking once on the disc title in the tree.\n\n" \
1667
"When you select the disc item in the tree, a set of disc options " \
1668
"are displayed. Here, you can choose what kind of disc to create " \
1669
"(VCD, SVCD, or DVD) and television system to use (NTSC or PAL). " \
1670
"You can also choose a working directory. This is where " \
1671
"encoded videos and temporary files created during encoding will be " \
1672
"stored. Make sure you choose a directory with plenty of space " \
1674
self.strMenuAdded = _("A menu has been added to the disc. Menus are " \
1675
"represented by a menu icon in the disc layout tree. The first menu " \
1676
"shown in the tree is the first thing you will see when you " \
1677
"put the disc in your DVD player. A menu may have other menus " \
1678
"or videos listed below it. You can add videos now by selecting a menu " \
1679
"and choosing \"Add video(s)\".\n\n")
1680
self.strMenuSelected = _("A menu is now selected. You can change the " \
1681
"title of the menu by clicking once on its title in the disc layout " \
1683
"When you select a menu, a set of options are displayed. You can " \
1684
"select a background image or audio clip to use for the menu. " \
1685
"Background images can be in any standard image format such as " \
1686
"JPEG, PNG, BMP, or GIF, and audio clips can be in any standard " \
1687
"audio format such as WAV or MP3. It's best to choose a short " \
1688
"audio clip (30 to 60 seconds in length).\n\n" \
1689
"Each menu has a list of titles, for each item below the menu in the " \
1690
"disc layout tree. These titles will be displayed on the finished menu " \
1691
"in a certain font and color; you can specify what font and color(s) to " \
1692
"use in the menu options panel.\n\n" \
1693
"If you want to use the same background, font, and color settings for " \
1694
"all the menus on your disc, first create all the menus, and configure " \
1695
"one of them the way you like. Then select \"Use these settings for "\
1696
"all menus\". The current settings will be applied to all other " \
1697
"existing menus on the disc.")
1698
self.strVideoAdded = _("One or more videos have been added to the disc. " \
1699
"Notice that your videos have been added to the list of titles in " \
1700
"the currently-selected menu.\n\n" \
1701
"Videos are represented by a film-strip icon in the disc layout tree. " \
1702
"Click on a video in the tree to view options for that video.")
1703
self.strVideoSelected = _("A video is now selected. You can change the " \
1704
"title of the video by clicking once on its title in the disc layout " \
1706
"Videos can be in almost any video format, and tovid will convert them " \
1707
"for you. When you select a video, a set of options are displayed. " \
1708
"Here, you can choose what resolution and aspect ratio to use for the " \
1710
"You can preview the video in GMplayer using the \"Preview video\" " \
1711
"button. This is useful if you aren't sure what aspect ratio or " \
1712
"resolution is most appropriate for the video.\n\n" \
1713
"If you want to use the same resolution, bitrate and other options for all " \
1714
"the videos on your disc, first add all the videos you want, and " \
1715
"configure one of them the way you like. Then select \"Use these settings " \
1716
"for all videos\". The current settings will be applied to all other " \
1717
"existing videos on the disc.\n\n" \
1718
"Use the \"Remove\" button to remove a video from the disc. You can " \
1719
"also use the \"Move up\" and \"Move down\" buttons to rearrange the " \
1720
"video within the tree.\n\n" \
1721
"When you are satisfied with the titles, menu options, and video options " \
1722
"for your disc, select \"2. Encode\" to proceed with encoding " \
1723
"and authoring your disc.")
1724
self.strGroupAdded = _("One or more groups have been added to the disc. " \
1725
"Notice that your groups have been added to the list of titles in " \
1726
"the currently-selected menu.\n\n" \
1727
"Groups are represented by a multiple film icon in the disc layout tree. " \
1728
"Click on a group in the tree to view options for that group.")
1729
self.strGroupSelected = _("A group is now selected. You can change the " \
1730
"title of the group by clicking once on its title in the disc layout " \
1732
"When you are satisfied with the titles, menu, group and video options " \
1733
"for your disc, select \"2. Encode\" to proceed with encoding " \
1734
"and authoring your disc.")
1735
self.strPrepEncoding = _("You are now ready to begin the process of encoding " \
1736
"all the menus and videos you have selected for your disc.\n\n" \
1737
"Here, a log window displays a list of all the commands that will be " \
1738
"executed. Select \"Start encoding\" to begin.\n\n" \
1739
"If you change your mind and want to go back to the disc layout panel, " \
1740
"select \"1. Layout\".")
1741
self.strEncodingStarted = _("The encoding process has begun. Each of the " \
1742
"necessary commands will be executed sequentially. Output from the " \
1743
"currently-running command is displayed in the log window, so you " \
1744
"can monitor its progress. The currently-running command is shown " \
1745
"above the log window, and the number of commands remaining is shown " \
1746
"below the log window.\n\n" \
1747
"Be advised that video encoding can be a very time-consuming process! " \
1748
"A disc with one hour of video content may take from 1-3 hours to encode, " \
1749
"depending on your CPU speed. You may need to leave this running for " \
1750
"several hours in order for your disc to finish authoring.")
1752
def SetTask(self, curTask = ID_TASK_GETTING_STARTED):
1753
"""Show the appropriate guide text for the given task."""
1754
if curTask == ID_TASK_GETTING_STARTED:
1755
self.txtHeading.SetLabel(_("Getting started"))
1756
self.txtGuide.SetValue(self.strGettingStarted)
1757
elif curTask == ID_TASK_MENU_ADDED:
1758
self.txtHeading.SetLabel(_("Menu added"))
1759
self.txtGuide.SetValue(self.strMenuAdded)
1760
elif curTask == ID_TASK_VIDEO_ADDED:
1761
self.txtHeading.SetLabel(_("Video added"))
1762
self.txtGuide.SetValue(self.strVideoAdded)
1763
elif curTask == ID_TASK_DISC_SELECTED:
1764
self.txtHeading.SetLabel(_("Disc selected"))
1765
self.txtGuide.SetValue(self.strDiscSelected)
1766
elif curTask == ID_TASK_MENU_SELECTED:
1767
self.txtHeading.SetLabel(_("Menu selected"))
1768
self.txtGuide.SetValue(self.strMenuSelected)
1769
elif curTask == ID_TASK_VIDEO_SELECTED:
1770
self.txtHeading.SetLabel(_("Video selected"))
1771
self.txtGuide.SetValue(self.strVideoSelected)
1772
elif curTask == ID_TASK_PREP_ENCODING:
1773
self.txtHeading.SetLabel(_("Encoding preparation"))
1774
self.txtGuide.SetValue(self.strPrepEncoding)
1775
elif curTask == ID_TASK_ENCODING_STARTED:
1776
self.txtHeading.SetLabel(_("Encoding started"))
1777
self.txtGuide.SetValue(self.strEncodingStarted)
1778
elif curTask == ID_TASK_GROUP_ADDED:
1779
self.txtHeading.SetLabel(_("Group added"))
1780
self.txtGuide.SetValue(self.strGroupAdded)
1781
elif curTask == ID_TASK_GROUP_SELECTED:
1782
self.txtHeading.SetLabel(_("Video selected"))
1783
self.txtGuide.SetValue(self.strGroupSelected)
1786
class HidablePanel(wx.Panel):
1787
"""A panel that can be hidden from view.
1789
The panel may be horizontal or vertical, and contains show/hide controls
1790
along with one additional window or sizer, added via the Add() method.
1792
To use HidablePanel, first declare a HidablePanel object. Then, create the
1793
wx.Window object that will go into the HidablePanel, passing the
1794
HidablePanel as its parent. Add the HidablePanel to the desired location
1795
(inside another sizer). Finally, call SetParent with the containing sizer as
1796
the argument, to let the HidablePanel know what sizer contains it.
1799
def __init__(self, parent, id, orientation = wx.VERTICAL):
1800
"""Initialize hidable panel. orientation is wx.VERTICAL or
1801
wx.HORIZONTAL. A vertical panel has the hide controls at the top and
1802
extends downwards; a horizontal one has controls on the left and extends
1805
wx.Panel.__init__(self, parent, id)
1806
# Reference to contained content (window or sizer)
1808
self.sizParent = None
1810
self.btnShowHide = wx.ToggleButton(self, wx.ID_ANY, _("More >>"))
1811
self.btnShowHide.SetValue(True)
1812
wx.EVT_TOGGLEBUTTON(self, self.btnShowHide.GetId(), self.ShowHide)
1814
self.sizMain = wx.BoxSizer(orientation)
1815
self.sizMain.Add(self.btnShowHide, 0)
1816
self.SetSizer(self.sizMain)
1818
def SetContent(self, newContent):
1819
"""Set the window/sizer that the panel will contain."""
1820
self.content = newContent
1821
self.sizMain.Add(self.content, 1, wx.EXPAND)
1822
self.sizMain.SetItemMinSize(self.content, 200, 200)
1823
self.sizMain.Layout()
1825
def SetParent(self, parent):
1826
"""Set the parent sizer (the sizer that holds the HidablePanel)."""
1827
self.sizParent = parent
1829
def ShowHide(self, evt):
1830
"""Show/hide the main part of the sizer based on state of
1832
# If button is down, show content
1833
if self.btnShowHide.GetValue() == True:
1834
self.sizMain.Add(self.content)
1836
self.sizMain.Layout()
1837
# Otherwise, hide content
1839
self.sizMain.Remove(self.content)
1841
self.sizMain.Layout()
1842
# Layout parent, if it has been set
1843
if self.sizParent != None:
1844
self.sizParent.Layout()
1847
class MenuPanel(wx.Panel):
1848
"""A panel showing controls appropriate to generating a menu"""
1849
def __init__(self, parent, id):
1850
wx.Panel.__init__(self, parent, id)
1851
self.curOptions = MenuOptions()
1852
self.curColorData = wx.ColourData()
1853
self.parent = parent
1854
self.sboxBG = wx.StaticBox(self, wx.ID_ANY, "Menu background options")
1855
self.sizBG = wx.StaticBoxSizer(self.sboxBG, wx.VERTICAL)
1857
# Background image/audio selection controls =======================\
1859
self.lblMenuTitle = wx.StaticText(self, wx.ID_ANY, "Menu Header:")
1860
self.txtMenuTitle = wx.TextCtrl(self, wx.ID_ANY)
1861
self.txtMenuTitle.SetToolTipString(\
1862
"Enter a header for your menu. Leave blank if you" \
1864
wx.EVT_TEXT(self, self.txtMenuTitle.GetId(), self.OnMenuTitle)
1865
## Menu title font size
1866
self.lblMenuTitleFontSize = wx.StaticText(self, wx.ID_ANY, "Size:")
1867
self.txtMenuTitleFontSize = wx.TextCtrl(self, wx.ID_ANY)
1868
self.txtMenuTitleFontSize.SetToolTipString(\
1869
"Specify the header's font size")
1870
wx.EVT_TEXT(self, self.txtMenuTitleFontSize.GetId(), \
1871
self.OnMenuTitleFontSize)
1872
self.sizMenuTitleFontSize = wx.BoxSizer(wx.HORIZONTAL)
1873
self.sizMenuTitleFontSize.Add(self.lblMenuTitleFontSize, 0,
1874
wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4)
1875
self.sizMenuTitleFontSize.Add(self.txtMenuTitleFontSize, 1,
1876
wx.EXPAND | wx.ALL, 4)
1878
self.lblBGImage = wx.StaticText(self, wx.ID_ANY, "Image:")
1879
self.txtBGImage = wx.TextCtrl(self, wx.ID_ANY)
1880
self.txtBGImage.SetToolTipString(\
1881
"Type the full name of the image file you want to use in the" \
1882
" background of the menu, or use the browse button.")
1883
self.btnBrowseBGImage = wx.Button(self, wx.ID_ANY, "Choose image...")
1884
self.btnBrowseBGImage.SetToolTipString("Browse for an image file to " \
1885
"use for the background of the menu")
1886
wx.EVT_TEXT(self, self.txtBGImage.GetId(), self.OnBGImage)
1887
wx.EVT_BUTTON(self, self.btnBrowseBGImage.GetId(), self.OnBrowseBGImage)
1889
self.lblBGAudio = wx.StaticText(self, wx.ID_ANY, "Audio:")
1890
self.txtBGAudio = wx.TextCtrl(self, wx.ID_ANY)
1891
self.txtBGAudio.SetToolTipString(\
1892
"Type the full name of the audio file " \
1893
"you want to play while the menu is shown, " \
1894
"or use the browse button.")
1895
self.btnBrowseBGAudio = wx.Button(self, wx.ID_ANY, "Choose audio...")
1896
self.btnBrowseBGAudio.SetToolTipString(\
1897
"Browse for an audio file to " \
1898
"play while the menu is shown")
1899
wx.EVT_TEXT(self, self.txtBGAudio.GetId(), self.OnBGAudio)
1900
wx.EVT_BUTTON(self, self.btnBrowseBGAudio.GetId(), self.OnBrowseBGAudio)
1902
self.lblMenuLength = wx.StaticText(self, wx.ID_ANY, "Length (sec):")
1903
self.txtMenuLength = wx.TextCtrl(self, wx.ID_ANY)
1904
self.txtMenuLength.SetToolTipString(\
1905
"Set the length of the menu in seconds. " \
1906
"Leave blank to use the full-length of your audio file.")
1907
wx.EVT_TEXT(self, self.txtMenuLength.GetId(), self.OnMenuLength)
1908
## Group background controls together
1909
self.sizBGInner = wx.FlexGridSizer(4, 3, 4, 8)
1910
self.sizBGInner.AddMany([
1911
(self.lblMenuTitle, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1912
(self.txtMenuTitle, 0, wx.EXPAND),
1913
(self.sizMenuTitleFontSize),
1914
(self.lblBGImage, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1915
(self.txtBGImage, 1, wx.EXPAND),
1916
(self.btnBrowseBGImage, 0, wx.EXPAND),
1917
(self.lblBGAudio, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1918
(self.txtBGAudio, 1, wx.EXPAND),
1919
(self.btnBrowseBGAudio, 0, wx.EXPAND),
1920
(self.lblMenuLength, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1921
(self.txtMenuLength, 1),
1923
self.sizBGInner.AddGrowableCol(1)
1924
## Add inner sizer to outer staticbox sizer
1925
self.sizBG.Add(self.sizBGInner, 0, wx.EXPAND | wx.ALL, 8)
1927
# Menu font and size controls =====================================\
1928
self.lblFontFace = wx.StaticText(self, wx.ID_ANY, "Font:")
1929
self.btnFontChooserDialog = wx.Button(self, wx.ID_ANY, "Default")
1930
self.btnFontChooserDialog.SetToolTipString(\
1931
"Select a font to use for the menu text")
1932
wx.EVT_BUTTON(self, self.btnFontChooserDialog.GetId(), \
1933
self.OnFontSelection)
1934
self.lblFontSize = wx.StaticText(self, wx.ID_ANY, "Size:")
1935
self.txtFontSize = wx.TextCtrl(self, wx.ID_ANY)
1936
self.txtFontSize.SetToolTipString(\
1937
"Specify the font size")
1938
wx.EVT_TEXT(self, self.txtFontSize.GetId(), \
1940
## Place font items together
1941
self.sizFontFace = wx.BoxSizer(wx.HORIZONTAL)
1942
self.sizFontFace.AddMany([\
1943
(self.lblFontFace, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4),
1944
(self.btnFontChooserDialog, 3, wx.ALL, 4),
1945
(self.lblFontSize, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4),
1946
(self.txtFontSize, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 4) ])
1948
self.lblAlignment = wx.StaticText(self, wx.ID_ANY, "Alignment:")
1949
strAlignments = ['Top left', 'Top center', 'Top right', \
1950
'Left', 'Middle', 'Right', \
1951
'Bottom left', 'Bottom center', 'Bottom right']
1952
self.chAlignment = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, \
1953
wx.DefaultSize, strAlignments, name="Alignment")
1954
self.chAlignment.SetToolTipString(\
1955
"Select how the menu text should be aligned")
1956
wx.EVT_CHOICE(self, self.chAlignment.GetId(), self.OnAlignment)
1957
## Place alignment items together
1958
self.sizAlignment = wx.BoxSizer(wx.HORIZONTAL)
1959
self.sizAlignment.AddMany([ \
1960
(self.lblAlignment, 0, wx.ALL| wx.ALIGN_CENTER_VERTICAL, 4),
1961
(self.chAlignment, 0, wx.ALL, 4) ])
1962
# Menu text fill controls
1963
self.lblTextFill = wx.StaticText(self, wx.ID_ANY, "Fill text with:")
1964
strFillTypes = ['Color', 'Fractal', 'Gradient', 'Pattern']
1965
self.chFillType = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, \
1966
wx.DefaultSize, strFillTypes, name="Fill type")
1967
self.chFillType.SetToolTipString("Click to choose text fill style")
1968
wx.EVT_CHOICE(self, self.chFillType.GetId(), self.OnFillType)
1970
self.chkFillColor = wx.CheckBox(self, wx.ID_ANY, style=wx.ALIGN_RIGHT,
1972
wx.EVT_CHECKBOX(self, self.chkFillColor.GetId(), self.OnColorNone)
1973
self.btnFillColor = wx.Button(self, wx.ID_ANY, "Choose...")
1974
self.btnFillColor.SetToolTipString("Choose a color")
1975
self.btnFillColor.SetBackgroundColour(self.curOptions.color1)
1976
self.sizFillColor1 = wx.BoxSizer(wx.HORIZONTAL)
1977
self.sizFillColor1.Add(self.btnFillColor, 1)
1978
self.sizFillColor1.Add(self.chkFillColor, 0, wx.ALIGN_CENTER_VERTICAL)
1979
wx.EVT_BUTTON(self, self.btnFillColor.GetId(), self.OnFillColor)
1981
self.chkFillColor2 = wx.CheckBox(self, wx.ID_ANY, style=wx.ALIGN_RIGHT,
1983
wx.EVT_CHECKBOX(self, self.chkFillColor2.GetId(), self.OnColorNone)
1984
self.btnFillColor2 = wx.Button(self, wx.ID_ANY, "Choose...")
1985
self.btnFillColor2.SetToolTipString("Choose a color")
1986
self.btnFillColor2.SetBackgroundColour(self.curOptions.color2)
1987
self.sizFillColor2 = wx.BoxSizer(wx.HORIZONTAL)
1988
self.sizFillColor2.Add(self.btnFillColor2, 1)
1989
self.sizFillColor2.Add(self.chkFillColor2, 0,
1990
wx.ALIGN_CENTER_VERTICAL)
1991
wx.EVT_BUTTON(self, self.btnFillColor2.GetId(), self.OnFillColor2)
1993
self.dictPatternTypes = { 'bricks': 'bricks',
1994
'circles': 'circles',
1995
'small squares': 'crosshatch',
1996
'big squares': 'hs_cross',
1997
'crosshatching': 'hs_diagcross',
1998
'hexagons': 'hexagons',
1999
'fish scales': 'smallfishscales',
2000
'sawtooth lines': 'horizontalsaw',
2001
'45 deg lines': 'hs_bdiagonal',
2002
'-45 deg lines': 'hs_fdiagonal',
2003
'vertical lines': 'hs_vertical',
2004
'horizontal lines': 'hs_horizontal' }
2005
liPatternTypes = self.dictPatternTypes.keys()
2006
liPatternTypes.sort()
2007
self.cbPattern = wx.ComboBox(self, wx.ID_ANY, style=wx.CB_DROPDOWN,
2008
value="bricks", choices=liPatternTypes, name="Pattern types")
2009
self.cbPattern.SetToolTipString("Choose a pattern to fill the text " \
2010
"with, or enter an ImageMagick pattern name")
2011
wx.EVT_TEXT(self, self.cbPattern.GetId(), self.OnPattern)
2012
## Place text fill items together
2013
self.sizTextFill = wx.BoxSizer(wx.HORIZONTAL)
2014
self.sizTextFill.AddMany([
2015
(self.lblTextFill, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2016
(self.chFillType, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2017
(self.cbPattern, 1, wx.EXPAND | wx.ALL, 4),
2018
(self.sizFillColor1, 1, wx.ALL, 4),
2019
(self.sizFillColor2, 1, wx.ALL, 4) ])
2020
## Hide unselected fill controls
2021
self.sizTextFill.Hide(self.sizFillColor2)
2022
self.sizTextFill.Hide(self.cbPattern)
2024
# Menu text outline controls
2025
self.lblStrokeColor = wx.StaticText(self, wx.ID_ANY, "Text outline:")
2026
self.chkStrokeColor = wx.CheckBox(self, wx.ID_ANY, style=wx.ALIGN_RIGHT,
2028
wx.EVT_CHECKBOX(self, self.chkStrokeColor.GetId(), self.OnColorNone)
2029
self.btnStrokeColor = wx.Button(self, wx.ID_ANY, "Choose...")
2030
self.btnStrokeColor.SetToolTipString("Choose the outline color")
2031
self.btnStrokeColor.SetBackgroundColour(self.curOptions.colorStroke)
2032
wx.EVT_BUTTON(self, self.btnStrokeColor.GetId(), self.OnStrokeColor)
2033
self.lblStrokeWidth = wx.StaticText(self, wx.ID_ANY, "Width (px):")
2034
self.txtStrokeWidth = wx.TextCtrl(self, wx.ID_ANY)
2035
self.txtStrokeWidth.SetToolTipString("Width of ouline in pixels")
2036
wx.EVT_TEXT(self, self.txtStrokeWidth.GetId(), self.OnStrokeWidth)
2037
## Group the 'None?' checkbox and StrokeColor button
2038
self.sizStrokeColor = wx.BoxSizer(wx.VERTICAL)
2039
self.sizStrokeColor.Add(self.btnStrokeColor, 1, wx.EXPAND)
2040
self.sizStrokeColor.Add(self.chkStrokeColor, 0,
2041
wx.ALIGN_CENTER_HORIZONTAL)
2042
## Group the text outline controls together
2043
self.sizTextOutline = wx.BoxSizer(wx.HORIZONTAL)
2044
self.sizTextOutline.AddMany([
2045
(self.lblStrokeColor, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2046
(self.sizStrokeColor, 1, wx.ALL, 4),
2047
(self.lblStrokeWidth, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2048
(self.txtStrokeWidth, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4) ])
2050
# Put all menu text controls in a static box
2051
self.sboxTextFormat = wx.StaticBox(self, wx.ID_ANY, "Menu text format")
2052
self.sizTextFormat = wx.StaticBoxSizer(self.sboxTextFormat, wx.VERTICAL)
2053
self.sizTextFormat.AddMany([\
2054
(self.sizFontFace, 0, wx.EXPAND),
2055
(self.sizAlignment, 0, wx.EXPAND),
2056
(self.sizTextFill, 0, wx.EXPAND),
2057
(self.sizTextOutline, 0, wx.EXPAND) ])
2059
# DVD buttons ======================================================\
2061
strButtons = ['>', '~', 'play', 'movie']
2062
self.lblButton = wx.StaticText(self, wx.ID_ANY, "Button shape:")
2063
self.lblButtonPreview = wx.StaticText(self, wx.ID_ANY, "Preview:")
2064
self.lblButtonExample = wx.StaticText(self, wx.ID_ANY)
2065
self.lblButtonExample.SetLabel(self.curOptions.button)
2066
self.lblButtonExample.SetFont(self.curOptions.buttonFont)
2067
self.cbButton = wx.ComboBox(self, wx.ID_ANY, value='>', \
2068
style=wx.CB_DROPDOWN, choices=strButtons)
2069
self.cbButton.SetToolTipString(\
2070
"Choose the shape of the DVD buttons."\
2071
"You may also type your own button (can only be 1 character).")
2072
wx.EVT_TEXT(self, self.cbButton.GetId(), self.OnButton)
2073
## group shape controls together
2074
self.sizDVDShapes = wx.BoxSizer(wx.HORIZONTAL)
2075
self.sizDVDShapes.AddMany([
2076
(self.lblButton, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | \
2078
(self.cbButton, 1, wx.EXPAND | wx.ALL, 4),
2079
(self.lblButtonPreview, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2080
(self.lblButtonExample, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4) ])
2082
self.lblButtonFont = wx.StaticText(self, wx.ID_ANY, "Font:")
2083
self.chkLockButtonFont = wx.CheckBox(self, wx.ID_ANY,
2084
style=wx.ALIGN_RIGHT, label="Lock?")
2085
wx.EVT_CHECKBOX(self, self.chkLockButtonFont.GetId(),
2086
self.OnLockButtonFont)
2087
self.btnButtonFontChooserDialog = wx.Button(self, wx.ID_ANY, "Default")
2088
self.btnButtonFontChooserDialog.SetToolTipString(\
2089
"Select a font to use for the buttons")
2090
wx.EVT_BUTTON(self, self.btnButtonFontChooserDialog.GetId(), \
2091
self.OnButtonFontSelection)
2092
## group font controls together
2093
self.sizButtonFont = wx.BoxSizer(wx.HORIZONTAL)
2094
self.sizButtonFont.AddMany([
2095
(self.lblButtonFont, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2096
(self.btnButtonFontChooserDialog, 1, wx.EXPAND | wx.ALL, 4),
2097
(self.chkLockButtonFont, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4) ])
2099
self.lblHiColor = wx.StaticText(self, wx.ID_ANY, _("Highlight:"))
2100
self.lblSelColor = wx.StaticText(self, wx.ID_ANY, _("Selection:"))
2101
self.chkHiColor = wx.CheckBox(self, wx.ID_ANY, style=wx.ALIGN_RIGHT,
2103
self.chkSelColor = wx.CheckBox(self, wx.ID_ANY, style=wx.ALIGN_RIGHT,
2105
wx.EVT_CHECKBOX(self, self.chkHiColor.GetId(), self.OnColorNone)
2106
wx.EVT_CHECKBOX(self, self.chkSelColor.GetId(), self.OnColorNone)
2107
self.btnHiColor = wx.Button(self, wx.ID_ANY, _("Choose..."))
2108
self.btnSelColor = wx.Button(self, wx.ID_ANY, _("Choose..."))
2109
self.btnHiColor.SetToolTipString(_("Choose the color used "
2110
"to highlight menu items as they are navigated"))
2111
self.btnSelColor.SetToolTipString(_("Choose the color used "
2112
"when a menu item is chosen or activated for playback"))
2113
self.btnHiColor.SetBackgroundColour(self.curOptions.colorHi)
2114
self.btnSelColor.SetBackgroundColour(self.curOptions.colorSel)
2115
wx.EVT_BUTTON(self, self.btnHiColor.GetId(), self.OnHiColor)
2116
wx.EVT_BUTTON(self, self.btnSelColor.GetId(), self.OnSelColor)
2117
## group checkboxes and color
2118
self.sizDVDHighlightColor = wx.BoxSizer(wx.VERTICAL)
2119
self.sizDVDHighlightColor.AddMany([
2120
(self.btnHiColor, 0, wx.EXPAND),
2121
(self.chkHiColor, 0, wx.ALIGN_CENTER_HORIZONTAL) ])
2122
self.sizDVDSelectColor = wx.BoxSizer(wx.VERTICAL)
2123
self.sizDVDSelectColor.AddMany([
2124
(self.btnSelColor, 0, wx.EXPAND),
2125
(self.chkSelColor, 0, wx.ALIGN_CENTER_HORIZONTAL) ])
2126
## group highlight and selection color conttrols together
2127
self.sizDVDButtonColors = wx.BoxSizer(wx.HORIZONTAL)
2128
self.sizDVDButtonColors.AddMany([
2129
(self.lblHiColor, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | \
2131
(self.sizDVDHighlightColor, 0, wx.EXPAND | wx.ALL, 4),
2132
(self.lblSelColor, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | \
2134
(self.sizDVDSelectColor, 1, wx.EXPAND | wx.ALL, 4) ])
2136
self.lblButtonOutline = wx.StaticText(self, wx.ID_ANY, "Outline:")
2137
self.chkButtonOutline = wx.CheckBox(self, wx.ID_ANY,
2138
style=wx.ALIGN_RIGHT, label="None?")
2139
self.chkButtonOutline.SetToolTipString(\
2140
"Should the buttons be outlined?")
2141
wx.EVT_CHECKBOX(self, self.chkButtonOutline.GetId(),
2143
self.btnButtonOutlineColor = wx.Button(self, wx.ID_ANY, "Choose...")
2144
self.btnButtonOutlineColor.SetToolTipString(\
2145
"Choose a color for the button outline.")
2146
wx.EVT_BUTTON(self, self.btnButtonOutlineColor.GetId(),
2147
self.OnButtonOutlineColor)
2148
## group outline together
2149
self.sizDVDOutline = wx.BoxSizer(wx.HORIZONTAL)
2150
self.sizDVDOutline.AddMany([
2151
(self.lblButtonOutline, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4),
2152
(self.btnButtonOutlineColor, 1, wx.EXPAND | wx.ALL, 4),
2153
(self.chkButtonOutline, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 4) ])
2154
# Put DVD button controls in a static box
2155
self.sboxDVDButtonStyle = wx.StaticBox(self, wx.ID_ANY,
2157
self.sizDVDButtonStyle = wx.StaticBoxSizer(self.sboxDVDButtonStyle,
2159
self.sizDVDButtonStyle.AddMany([
2160
(self.sizDVDShapes, 0),
2161
(self.sizButtonFont, 0, wx.EXPAND),
2162
(self.sizDVDButtonColors, 0, wx.EXPAND),
2163
(self.sizDVDOutline, 0) ])
2165
# Vertical sizer putting sizTextFormat above sizDVDButtonStyle ====\
2166
self.sizTextAndButtons = wx.BoxSizer(wx.VERTICAL)
2167
self.sizTextAndButtons.Add(self.sizTextFormat, 0, wx.EXPAND, 0)
2168
self.sizTextAndButtons.Add(self.sizDVDButtonStyle, 1, wx.EXPAND, 0)
2170
# List of titles in this menu ======================================\
2171
self.lblTitleList = wx.StaticText(self, wx.ID_ANY,
2172
_("Titles shown in this menu"))
2173
self.lbTitles = wx.ListBox(self, wx.ID_ANY)
2174
self.lbTitles.SetToolTipString(_("This lists all the sub-menus "
2175
"and videos that are under this menu. To change the text that "
2176
"appears here, edit the titles in the disc layout tree."))
2177
self.lbTitles.Enable(False)
2178
# Sizer to hold title list
2179
self.sizTitles = wx.BoxSizer(wx.VERTICAL)
2180
self.sizTitles.AddMany([ (self.lblTitleList, 0),
2181
(self.lbTitles, 1, wx.EXPAND) ])
2183
# Horizontal sizer holding sizTextAndButtons and sizTitles =========\
2184
self.sizTextTitles = wx.BoxSizer(wx.HORIZONTAL)
2185
self.sizTextTitles.Add(self.sizTextAndButtons, 2, 0)
2186
self.sizTextTitles.Add(self.sizTitles, 1, wx.EXPAND | wx.LEFT, 10)
2188
# Menu options heading
2189
self.txtHeading = HeadingText(self, wx.ID_ANY, "Menu options")
2191
# Button to copy menu options to all menus on disc =================\
2192
self.btnUseForAll = wx.Button(self, wx.ID_ANY,
2193
"Use these settings for all menus")
2194
self.btnUseForAll.SetToolTipString("Apply the current menu settings,"
2195
" including background image, audio, text alignment, text color" \
2196
" and font, to all menus on the disc.")
2197
wx.EVT_BUTTON(self, self.btnUseForAll.GetId(), self.OnUseForAll)
2199
# Main sizer to hold all controls ==================================\
2200
self.sizMain = wx.BoxSizer(wx.VERTICAL)
2201
self.sizMain.Add(self.txtHeading, 0, wx.EXPAND | wx.ALL, 8)
2202
self.sizMain.Add(self.sizBG, 0, wx.EXPAND | wx.ALL, 8)
2203
self.sizMain.Add(self.sizTextTitles, 1, wx.EXPAND | wx.ALL, 8)
2204
self.sizMain.Add(self.btnUseForAll, 0, wx.EXPAND | wx.ALL, 8)
2205
self.SetSizer(self.sizMain)
2207
def OnMenuTitle(self, evt):
2208
"""Set the menu's main title in curOptions whenever text is altered."""
2209
self.curOptions.menutitle = self.txtMenuTitle.GetValue()
2211
def OnMenuTitleFontSize(self, evt):
2212
"""Set the menu title font size whenever text is altered"""
2213
self.curOptions.titlefontsize = self.txtMenuTitleFontSize.GetValue()
2215
def OnBGImage(self, evt):
2216
"""Set the background image in curOptions whenever text is altered."""
2217
self.curOptions.background = self.txtBGImage.GetValue()
2219
def OnBGAudio(self, evt):
2220
"""Set the background audio in curOptions whenever text is altered."""
2221
self.curOptions.audio = self.txtBGAudio.GetValue()
2223
def OnMenuLength(self, evt):
2224
"""Set the menu length in curOptions whenever text is altered."""
2225
self.curOptions.menulength = self.txtMenuLength.GetValue()
2227
def OnBrowseBGImage(self, evt):
2228
"""Show a file dialog and set the background image."""
2229
inFileDlg = wx.FileDialog(self, "Select an image file", "", "", \
2231
if inFileDlg.ShowModal() == wx.ID_OK:
2232
self.txtBGImage.SetValue(inFileDlg.GetPath())
2235
def OnBrowseBGAudio(self, evt):
2236
"""Show a file dialog and set the background audio."""
2237
inFileDlg = wx.FileDialog(self, "Select an audio file", "", "", \
2239
if inFileDlg.ShowModal() == wx.ID_OK:
2240
self.txtBGAudio.SetValue(inFileDlg.GetPath())
2243
def OnAlignment(self, evt):
2244
"""Set the text alignment according to the choice box selection."""
2245
self.curOptions.alignment = util.ID_to_text(\
2246
'alignment', evt.GetSelection())
2248
def OnFillType(self, evt):
2249
"""Set the fill type and show/hide the appropriate controls."""
2250
self.fillType = util.ID_to_text('fillType', evt.GetSelection())
2251
self.curOptions.fillType = self.fillType
2252
# Only show the first color box for 'Color'
2253
if self.fillType == "Color":
2254
self.sizTextFill.Show(self.sizFillColor1)
2255
self.sizTextFill.Hide(self.sizFillColor2)
2256
self.sizTextFill.Hide(self.cbPattern)
2257
self.btnFillColor.SetLabel("Choose...")
2258
self.sizFillColor1.Show(self.chkFillColor)
2259
# Show both color boxes for 'Fractal' or 'Gradient'
2260
elif self.fillType == "Fractal" or self.fillType == "Gradient":
2261
self.chkFillColor.SetValue(False) # enable color 1
2262
self.btnFillColor.Enable()
2263
self.sizTextFill.Show(self.sizFillColor1)
2264
self.sizTextFill.Show(self.sizFillColor2)
2265
self.sizTextFill.Hide(self.cbPattern)
2266
self.btnFillColor.SetLabel("From...")
2267
self.btnFillColor2.SetLabel("To...")
2268
self.sizFillColor1.Hide(self.chkFillColor)
2269
self.sizFillColor2.Hide(self.chkFillColor2)
2270
self.chkStrokeColor.Enable(True)
2271
self.curOptions.fillColor1 = "rgb(%d,%d,%d)" % \
2272
( self.curOptions.color1.Red(),
2273
self.curOptions.color1.Green(),
2274
self.curOptions.color1.Blue() )
2275
# Only show the pattern drop box for 'pattern'
2276
elif self.fillType == "Pattern":
2277
self.sizTextFill.Hide(self.sizFillColor1)
2278
self.sizTextFill.Hide(self.sizFillColor2)
2279
self.sizTextFill.Show(self.cbPattern)
2280
self.chkStrokeColor.Enable(True)
2282
print "DEBUG: invalid FillType: %d" % evt.GetSelection()
2283
print "DEBUG: selection was: %s" % selection
2285
self.sizTextFill.Layout()
2286
self.sizTextFormat.Layout()
2287
self.sizTextAndButtons.Layout()
2288
self.sizTextTitles.Layout()
2290
def OnColorNone(self, evt):
2291
"""When checked, don't use a color box's color, but 'none' instead."""
2292
if evt.GetId() == self.chkFillColor.GetId():
2294
self.btnFillColor.Enable(False)
2295
self.curOptions.fillColor1 = "none"
2296
# Can't have both no fill and no stroke, so set stroke
2297
self.chkStrokeColor.Enable(False)
2298
self.chkStrokeColor.SetValue(False)
2299
self.curOptions.textStrokeColor = "rgb(%d,%d,%d)" % \
2300
( self.curOptions.colorStroke.Red(),
2301
self.curOptions.colorStroke.Green(),
2302
self.curOptions.colorStroke.Blue() )
2304
self.btnFillColor.Enable(True)
2305
self.curOptions.fillColor1 = "rgb(%d,%d,%d)" % \
2306
( self.curOptions.color1.Red(),
2307
self.curOptions.color1.Green(),
2308
self.curOptions.color1.Blue() )
2309
# Re-enable disabled stroke color controls
2310
self.chkStrokeColor.Enable(True)
2312
elif evt.GetId() == self.chkFillColor2.GetId():
2314
self.btnFillColor2.Enable(False)
2315
self.curOptions.fillColor2 = "none"
2317
self.btnFillColor2.Enable(True)
2318
self.curOptions.fillColor2 = "rgb(%d,%d,%d)" % \
2319
( self.curOptions.color2.Red(),
2320
self.curOptions.color2.Green(),
2321
self.curOptions.color2.Blue() )
2323
elif evt.GetId() == self.chkStrokeColor.GetId():
2325
self.btnStrokeColor.Enable(False)
2326
self.curOptions.textStrokeColor = "none"
2327
# Can't have both no color and no fill, so set fill
2328
self.chkFillColor.Enable(False)
2329
self.chkFillColor.SetValue(False)
2330
self.curOptions.fillColor1 = "rgb(%d,%d,%d)" % \
2331
( self.curOptions.color1.Red(),
2332
self.curOptions.color1.Green(),
2333
self.curOptions.color1.Blue() )
2335
self.btnStrokeColor.Enable(True)
2336
self.curOptions.textStrokeColor = "rgb(%d,%d,%d)" % \
2337
( self.curOptions.colorStroke.Red(),
2338
self.curOptions.colorStroke.Green(),
2339
self.curOptions.colorStroke.Blue() )
2340
# Re-enable fill controls
2341
self.chkFillColor.Enable(True)
2343
elif evt.GetId() == self.chkButtonOutline.GetId():
2345
self.btnButtonOutlineColor.Enable(False)
2346
self.curOptions.buttonOutlineColor = "none"
2347
# Can't have both no fill and no outline, so set fill
2348
self.chkHiColor.Enable(False)
2349
self.chkSelColor.Enable(False)
2350
self.curOptions.highlightColor = "rgb(%d,%d,%d)" % \
2351
( self.curOptions.colorHi.Red(),
2352
self.curOptions.colorHi.Green(),
2353
self.curOptions.colorHi.Blue() )
2354
self.curOptions.selectColor = "rgb(%d,%d,%d)" % \
2355
( self.curOptions.colorSel.Red(),
2356
self.curOptions.colorSel.Green(),
2357
self.curOptions.colorSel.Blue() )
2359
self.btnButtonOutlineColor.Enable(True)
2360
self.curOptions.buttonOutlineColor = "rgb(%d,%d,%d)" % \
2361
( self.curOptions.colorButtonOutline.Red(),
2362
self.curOptions.colorButtonOutline.Green(),
2363
self.curOptions.colorButtonOutline.Blue() )
2364
# Re-enable button fill controls
2365
self.chkHiColor.Enable(True)
2366
self.chkSelColor.Enable(True)
2368
elif evt.GetId() == self.chkHiColor.GetId():
2370
self.btnHiColor.Enable(False)
2371
self.curOptions.highlightColor = "none"
2372
# Can't have both no fill and no stroke, so set outline
2373
self.chkButtonOutline.Enable(False)
2374
self.curOptions.buttonOutlineColor = "rgb(%d,%d,%d)" % \
2375
( self.curOptions.colorButtonOutline.Red(),
2376
self.curOptions.colorButtonOutline.Green(),
2377
self.curOptions.colorButtonOutline.Blue() )
2379
self.btnHiColor.Enable(True)
2380
self.curOptions.highlightColor = "rgb(%d,%d,%d)" % \
2381
( self.curOptions.colorHi.Red(),
2382
self.curOptions.colorHi.Green(),
2383
self.curOptions.colorHi.Blue() )
2384
# Re-enable button outline controls
2385
if self.chkSelColor.IsChecked():
2388
self.chkButtonOutline.Enable(True)
2390
elif evt.GetId() == self.chkSelColor.GetId():
2392
self.btnSelColor.Enable(False)
2393
self.curOptions.selectColor = "none"
2394
# Can't have both no fill and no stroke, so set outline
2395
self.chkButtonOutline.Enable(False)
2396
self.curOptions.buttonOutlineColor = "rgb(%d,%d,%d)" % \
2397
( self.curOptions.colorButtonOutline.Red(),
2398
self.curOptions.colorButtonOutline.Green(),
2399
self.curOptions.colorButtonOutline.Blue() )
2401
self.btnSelColor.Enable(True)
2402
self.curOptions.selectColor = "rgb(%d,%d,%d)" % \
2403
( self.curOptions.colorSel.Red(),
2404
self.curOptions.colorSel.Green(),
2405
self.curOptions.colorSel.Blue() )
2406
# Re-enable button outline controls
2407
if self.chkHiColor.IsChecked():
2410
self.chkButtonOutline.Enable(True)
2413
print "DEBUG: ", evt.IsChecked(), self.GetId()
2414
print "DEBUG: ", self.chkFillColor.GetId(), self.chkFillColor2.GetId()
2416
def OnPattern(self, evt):
2417
"""Set the patten that will fill the menu text."""
2418
pattern = self.cbPattern.GetValue()
2419
if pattern in self.dictPatternTypes.keys():
2420
self.curOptions.pattern = self.dictPatternTypes[pattern]
2422
self.curOptions.pattern = pattern
2424
def OnFontSelection(self, evt):
2425
"""Show a font selection dialog and set the font."""
2426
dlgFontChooserDialog = FontChooserDialog(self, wx.ID_ANY,
2427
self.curOptions.font.GetFaceName())
2428
if dlgFontChooserDialog.ShowModal() == wx.ID_OK:
2429
strFontName = dlgFontChooserDialog.GetSelectedFont().GetFaceName()
2430
self.curOptions.font = wx.Font(10, wx.FONTFAMILY_DEFAULT,
2431
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, strFontName)
2432
# Button shows selected font name in selected font
2433
self.btnFontChooserDialog.SetFont(self.curOptions.font)
2434
self.btnFontChooserDialog.SetLabel(strFontName)
2435
self.UpdateButtonFontChooserButton()
2437
def OnFontSize(self, evt):
2438
"""Set the font size whenever text is altered"""
2439
self.curOptions.fontsize = self.txtFontSize.GetValue()
2440
self.UpdateButtonExample()
2442
def OnFillColor(self, evt):
2443
"""Display a color dialog to select the text color."""
2444
self.curColorData.SetColour(self.curOptions.color1)
2445
dlgColor = wx.ColourDialog(self, self.curColorData)
2446
if dlgColor.ShowModal() == wx.ID_OK:
2447
self.curColorData = dlgColor.GetColourData()
2448
self.curOptions.color1 = self.curColorData.GetColour()
2449
self.btnFillColor.SetBackgroundColour(self.curOptions.color1)
2450
self.curOptions.fillColor1 = "rgb(%d,%d,%d)" % \
2451
( self.curOptions.color1.Red(),
2452
self.curOptions.color1.Green(),
2453
self.curOptions.color1.Blue() )
2455
def OnFillColor2(self, evt):
2456
"""Display a color dialog to select the second fill color."""
2457
self.curColorData.SetColour(self.curOptions.color2)
2458
dlgColor = wx.ColourDialog(self, self.curColorData)
2459
if dlgColor.ShowModal() == wx.ID_OK:
2460
self.curColorData = dlgColor.GetColourData()
2461
self.curOptions.color2 = self.curColorData.GetColour()
2462
self.btnFillColor2.SetBackgroundColour(self.curOptions.color2)
2463
self.curOptions.fillColor2 = "rgb(%d,%d,%d)" % \
2464
( self.curOptions.color2.Red(),
2465
self.curOptions.color2.Green(),
2466
self.curOptions.color2.Blue() )
2468
def OnStrokeColor(self, evt):
2469
"""Display a color dialog to select the text stroke color."""
2470
self.curColorData.SetColour(self.curOptions.colorStroke)
2471
dlgColor = wx.ColourDialog(self, self.curColorData)
2472
if dlgColor.ShowModal() == wx.ID_OK:
2473
self.curColorData = dlgColor.GetColourData()
2474
self.curOptions.colorStroke = self.curColorData.GetColour()
2475
self.btnStrokeColor.SetBackgroundColour(
2476
self.curOptions.colorStroke)
2477
self.curOptions.textStrokeColor = "rgb(%d,%d,%d)" % \
2478
( self.curOptions.colorStroke.Red(),
2479
self.curOptions.colorStroke.Green(),
2480
self.curOptions.colorStroke.Blue() )
2482
def OnStrokeWidth(self, evt):
2483
"""Update the outline width whenever text is updated."""
2484
self.curOptions.textStrokeWidth = self.txtStrokeWidth.GetValue()
2486
def OnButtonFontSelection(self, evt):
2487
"""Show a font selection dialog and set the font."""
2488
dlgButtonFontChooserDialog = FontChooserDialog(self, wx.ID_ANY,
2489
self.curOptions.font.GetFaceName())
2490
if dlgButtonFontChooserDialog.ShowModal() == wx.ID_OK:
2492
dlgButtonFontChooserDialog.GetSelectedFont().GetFaceName()
2493
self.curOptions.buttonFont = wx.Font(10, wx.FONTFAMILY_DEFAULT,
2494
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, strFontName)
2495
# Button shows selected font name in selected font
2496
self.btnButtonFontChooserDialog.SetFont(self.curOptions.buttonFont)
2497
self.btnButtonFontChooserDialog.SetLabel(\
2498
self.curOptions.buttonFont.GetFaceName())
2499
self.UpdateButtonExample()
2501
def OnLockButtonFont(self, evt):
2502
"""Lock/unlock the -button-font chooser"""
2504
self.btnButtonFontChooserDialog.Enable(False)
2506
self.btnButtonFontChooserDialog.Enable(True)
2508
def UpdateButtonExample(self):
2509
"""Redraw the button example acc to existing options' constraints"""
2510
# 'play' or 'movie' buttons change font and button
2511
newButton = self.curOptions.button
2512
if newButton != "play" and newButton != "movie":
2513
newFontName = self.curOptions.buttonFont.GetFaceName()
2515
newFontName = "Webdings"
2516
if newButton == "play":
2519
newButton = u'\u220f'
2522
newFont = wx.Font(pointSize=int(self.curOptions.fontsize),
2523
family=wx.FONTFAMILY_DEFAULT,
2524
style=wx.FONTSTYLE_NORMAL,
2525
weight=wx.FONTWEIGHT_BOLD,
2530
self.lblButtonExample.SetLabel(newButton)
2531
self.lblButtonExample.SetFont(newFont)
2532
self.sizButtonFont.Layout()
2533
self.sizDVDButtonStyle.Layout()
2534
self.sizTextAndButtons.Layout()
2535
self.sizTextTitles.Layout()
2537
def UpdateButtonFontChooserButton(self):
2538
"""Change font/label of -button-font chooser acc to curOptions"""
2539
# For normal buttons, follow the text font (unless locked)
2540
if self.curOptions.button != "play" and self.curOptions.button != "movie":
2541
if self.chkLockButtonFont.IsChecked():
2544
self.curOptions.buttonFont = self.curOptions.font
2545
newFont = self.curOptions.buttonFont
2546
newFontName = self.curOptions.buttonFont.GetFaceName()
2547
# Otherwise, set the font name in a readable font
2549
newFont = wx.Font(12, wx.FONTFAMILY_DEFAULT,
2550
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL,
2552
newFontName = "Webdings"
2553
self.btnButtonFontChooserDialog.SetLabel(newFontName)
2554
self.btnButtonFontChooserDialog.SetFont(newFont)
2555
self.UpdateButtonExample()
2557
def OnHiColor(self, evt):
2558
"""Display a color dialog to select the text highlight color."""
2559
self.curColorData.SetColour(self.curOptions.colorHi)
2560
dlgColor = wx.ColourDialog(self, self.curColorData)
2561
if dlgColor.ShowModal() == wx.ID_OK:
2562
self.curColorData = dlgColor.GetColourData()
2563
self.curOptions.colorHi = self.curColorData.GetColour()
2564
self.btnHiColor.SetBackgroundColour(self.curOptions.colorHi)
2565
self.curOptions.highlightColor = "rgb(%d,%d,%d)" % \
2566
( self.curOptions.colorHi.Red(),
2567
self.curOptions.colorHi.Green(),
2568
self.curOptions.colorHi.Blue() )
2570
def OnSelColor(self, evt):
2571
"""Display a color dialog to select the text selection color."""
2572
self.curColorData.SetColour(self.curOptions.colorSel)
2573
dlgColor = wx.ColourDialog(self, self.curColorData)
2574
if dlgColor.ShowModal() == wx.ID_OK:
2575
self.curColorData = dlgColor.GetColourData()
2576
self.curOptions.colorSel = self.curColorData.GetColour()
2577
self.btnSelColor.SetBackgroundColour(self.curOptions.colorSel)
2578
self.curOptions.selectColor = "rgb(%d,%d,%d)" % \
2579
( self.curOptions.colorSel.Red(),
2580
self.curOptions.colorSel.Green(),
2581
self.curOptions.colorSel.Blue() )
2583
def OnButton(self, evt):
2584
"""Set the button character whenever text is altered."""
2585
self.curOptions.button = self.cbButton.GetValue()
2586
# En/Disable font selection for buttons
2587
if self.curOptions.button == ">" or self.curOptions.button == "~":
2588
self.btnButtonFontChooserDialog.Enable(True)
2589
self.chkLockButtonFont.SetValue(False)
2590
self.chkLockButtonFont.Enable(True)
2591
elif self.curOptions.button == "play" or self.curOptions.button == "movie":
2592
self.btnButtonFontChooserDialog.Enable(False)
2593
self.chkLockButtonFont.SetValue(True)
2594
self.chkLockButtonFont.Enable(False)
2595
self.UpdateButtonExample()
2596
self.UpdateButtonFontChooserButton()
2598
def OnButtonOutlineColor(self, evt):
2599
"""Display a color dialog to select the button outline color."""
2600
self.curColorData.SetColour(self.curOptions.colorButtonOutline)
2601
dlgColor = wx.ColourDialog(self, self.curColorData)
2602
if dlgColor.ShowModal() == wx.ID_OK:
2603
self.curColorData = dlgColor.GetColourData()
2604
self.curOptions.colorButtonOutline = self.curColorData.GetColour()
2605
self.btnButtonOutlineColor.SetBackgroundColour(
2606
self.curOptions.colorButtonOutline)
2607
self.curOptions.buttonOutlineColor = "rgb(%d,%d,%d)" % \
2608
( self.curOptions.colorButtonOutline.Red(),
2609
self.curOptions.colorButtonOutline.Green(),
2610
self.curOptions.colorButtonOutline.Blue() )
2612
def OnUseForAll(self, evt):
2613
"""Use the current menu settings for all menus on disc."""
2614
countItems = self.parent.UseForAllItems(self.curOptions)
2615
# Display acknowledgement
2616
dlgAck = wx.MessageDialog(self,
2617
"The current menu settings were copied to\n"
2618
"%d other menus on the disc." % countItems,
2619
"Settings copied", wx.OK | wx.ICON_INFORMATION)
2622
def SetOptions(self, menuOpts):
2623
"""Set control values based on the provided MenuOptions."""
2624
self.curOptions = menuOpts
2626
self.txtHeading.SetLabel("Menu options: %s" % self.curOptions.title)
2628
self.txtMenuTitleFontSize.SetValue(self.curOptions.titlefontsize)
2629
self.txtMenuTitle.SetValue(self.curOptions.menutitle)
2630
self.txtBGImage.SetValue(self.curOptions.background)
2631
self.txtBGAudio.SetValue(self.curOptions.audio or '')
2632
self.txtMenuLength.SetValue(self.curOptions.menulength)
2634
self.btnFontChooserDialog.SetFont(self.curOptions.font)
2635
if self.curOptions.font.GetFaceName() == "":
2636
self.btnFontChooserDialog.SetLabel("Default")
2638
self.btnFontChooserDialog.SetLabel(
2639
self.curOptions.font.GetFaceName() )
2640
self.txtFontSize.SetValue(self.curOptions.fontsize)
2641
self.chAlignment.SetSelection(
2642
util.text_to_ID(self.curOptions.alignment))
2643
self.chFillType.SetSelection(util.text_to_ID(self.curOptions.fillType))
2644
self.btnFillColor.SetBackgroundColour(self.curOptions.color1)
2645
self.btnFillColor2.SetBackgroundColour(self.curOptions.color2)
2646
self.btnStrokeColor.SetBackgroundColour(self.curOptions.colorStroke)
2647
self.txtStrokeWidth.SetValue(self.curOptions.textStrokeWidth)
2649
self.btnButtonFontChooserDialog.SetFont(self.curOptions.buttonFont)
2650
if self.curOptions.buttonFont.GetFaceName() == "":
2651
self.btnButtonFontChooserDialog.SetLabel("Default")
2653
self.btnButtonFontChooserDialog.SetLabel(
2654
self.curOptions.buttonFont.GetFaceName() )
2655
self.btnHiColor.SetBackgroundColour(self.curOptions.colorHi)
2656
self.btnSelColor.SetBackgroundColour(self.curOptions.colorSel)
2657
self.cbButton.SetValue(self.curOptions.button)
2658
self.btnButtonOutlineColor.SetBackgroundColour(
2659
self.curOptions.colorButtonOutline)
2661
self.lbTitles.Set(self.curOptions.titles)
2663
def GetOptions(self):
2664
"""Get currently-set encoding options."""
2665
return self.curOptions
2667
def SetDiscFormat(self, format):
2668
"""Enable/disable controls appropriate to the given disc format."""
2670
self.sizDVDButtonStyle.ShowItems(True)
2671
elif format in [ 'vcd', 'svcd' ]:
2672
self.sizDVDButtonStyle.ShowItems(False)
2675
class VideoPanel(wx.Panel):
2676
"""A panel showing controls appropriate to encoding a video."""
2677
def __init__(self, parent, id):
2678
wx.Panel.__init__(self, parent, id)
2681
self.curOptions = VideoOptions()
2682
self.parent = parent
2684
# File information display
2685
self.lblInFile = wx.StaticText(self, wx.ID_ANY, "Filename:")
2686
self.txtInFile = wx.StaticText(self, wx.ID_ANY, "None")
2688
# Statix box and sizer to hold file info
2689
self.sboxFileInfo = wx.StaticBox(self, wx.ID_ANY, "Video information")
2690
self.sizFileInfo = wx.StaticBoxSizer(self.sboxFileInfo, wx.HORIZONTAL)
2691
self.sizFileInfo.Add(self.lblInFile, 0, wx.EXPAND | wx.ALL, 6)
2692
self.sizFileInfo.Add(self.txtInFile, 1, wx.EXPAND | wx.ALL, 6)
2695
# Format-selection radio buttons
2696
outFormatList = ['352x240 VCD',
2700
'352x240 VCD on DVD' ]
2702
# Aspect ratio radio buttons
2703
aspectList = ['4:3 Fullscreen TV',
2704
'16:9 Widescreen TV',
2705
'2.35:1 Theatrical widescreen']
2707
# Radio boxes and tooltips
2708
self.rbResolution = wx.RadioBox(self, wx.ID_ANY, "Output resolution",
2709
wx.DefaultPosition, wx.DefaultSize,
2710
outFormatList, 1, wx.RA_SPECIFY_COLS)
2711
wx.EVT_RADIOBOX(self, self.rbResolution.GetId(), self.OnFormat)
2712
self.rbResolution.SetToolTipString("Select which resolution you want to "
2713
"encode your video in. The available resolutions are shown depending on "
2714
"whether you are making a VCD, SVCD, or DVD disc.")
2715
self.rbAspect = wx.RadioBox(self, wx.ID_ANY, "Aspect ratio of input",
2716
wx.DefaultPosition, wx.DefaultSize,
2717
aspectList, 1, wx.RA_SPECIFY_COLS)
2718
wx.EVT_RADIOBOX(self, self.rbAspect.GetId(), self.OnAspect)
2719
self.rbAspect.SetToolTipString("Select which aspect ratio the original video "
2720
"is in. If it is roughly TV-shaped, use '4:3'. If it is more than "
2721
"twice as wide as it is tall, use '2.35:1'. If it's somewhere in "
2722
"between, use '16:9'.")
2724
# Sizer for radioboxes
2725
self.sizResAspect = wx.BoxSizer(wx.HORIZONTAL)
2726
self.sizResAspect.Add(self.rbResolution, 1, wx.EXPAND | wx.ALL)
2727
self.sizResAspect.Add(self.rbAspect, 1, wx.EXPAND | wx.ALL)
2729
# Direct-entry CLI option box
2730
self.lblCLIOptions = wx.StaticText(self, wx.ID_ANY, "Custom options:")
2731
self.txtCLIOptions = wx.TextCtrl(self, wx.ID_ANY, "")
2732
self.txtCLIOptions.SetToolTipString("Type custom tovid command-line "
2733
"options that you'd like to use, separated by spaces. Warning:"
2734
"Please make sure you know what you are doing!")
2735
wx.EVT_TEXT(self, self.txtCLIOptions.GetId(), self.OnCLIOptions)
2736
self.sizCLIOptions = wx.BoxSizer(wx.HORIZONTAL)
2737
self.sizCLIOptions.Add(self.lblCLIOptions, 0, wx.EXPAND | wx.ALL, 8)
2738
self.sizCLIOptions.Add(self.txtCLIOptions, 1, wx.EXPAND | wx.ALL, 8)
2740
#Combo boxes for extra options
2741
self.lblQuality = wx.StaticText(self, wx.ID_ANY, "Quality: ")
2742
self.cbQuality = wx.ComboBox(self, wx.ID_ANY, choices = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], style=wx.CB_DROPDOWN|wx.CB_READONLY)
2743
self.cbQuality.SetToolTipString("Choose compression level: \n" \
2744
"1 = Low quality but small files\n" \
2745
"10 = High quality but large files")
2746
wx.EVT_TEXT(self, self.cbQuality.GetId(), self.OnQualityChange)
2748
self.cbQuality.SetValue("8")
2749
self.lblQualityPlaceHolder = wx.StaticText(self, wx.ID_ANY, " ")
2751
self.lblEncoding = wx.StaticText(self, wx.ID_ANY, "Encoding: ")
2752
self.cbEncodingMethod = wx.ComboBox(self, wx.ID_ANY, choices = ["mpeg2enc", "ffmpeg"], style=wx.CB_DROPDOWN|wx.CB_READONLY)
2753
self.cbEncodingMethod.SetValue("mpeg2enc")
2754
self.cbEncodingMethod.SetToolTipString("Choose encoding method: \n" \
2755
"mpeg2enc - Generally a bit better image but slower to encode\n" \
2756
"ffmpeg - Generally a bit worse image but faster to encode\n" \
2757
"NB, at lower quality settings, ffmpeg may be better.")
2758
wx.EVT_TEXT(self, self.cbEncodingMethod.GetId(), self.OnEncodingChange)
2759
self.lblTypePlaceHolder = wx.StaticText(self, wx.ID_ANY, " ")
2761
# Sizers for combo boxes
2762
self.sizQuality = wx.BoxSizer(wx.HORIZONTAL)
2763
self.sizQuality.Add(self.lblQuality, 0, wx.EXPAND | wx.ALL)
2764
self.sizQuality.Add(self.cbQuality, 0, wx.EXPAND | wx.ALL)
2765
self.sizQuality.Add(self.lblQualityPlaceHolder, 1, wx.EXPAND | wx.ALL)
2767
self.sizType = wx.BoxSizer(wx.HORIZONTAL)
2768
self.sizType.Add(self.lblEncoding, 0, wx.EXPAND | wx.ALL)
2769
self.sizType.Add(self.cbEncodingMethod, 0, wx.EXPAND | wx.ALL)
2770
self.sizType.Add(self.lblTypePlaceHolder, 1, wx.EXPAND | wx.ALL)
2772
self.sizQualityType = wx.BoxSizer(wx.HORIZONTAL)
2773
self.sizQualityType.Add(self.sizQuality, 1, wx.EXPAND | wx.ALL)
2774
self.sizQualityType.Add(self.sizType, 1, wx.EXPAND | wx.ALL)
2776
# Sizer to hold all encoding options
2777
self.sizEncOpts = wx.BoxSizer(wx.VERTICAL)
2778
self.sizEncOpts.Add(self.sizResAspect, 1, wx.EXPAND | wx.ALL)
2779
self.sizEncOpts.Add(self.sizQualityType, 0, wx.EXPAND | wx.ALL)
2780
self.sizEncOpts.Add(self.sizCLIOptions, 0, wx.EXPAND | wx.ALL)
2782
# Button to preview the video
2783
self.btnPreview = wx.Button(self, wx.ID_ANY, "Preview video")
2784
self.btnPreview.SetToolTipString("Play the video using mplayer")
2785
wx.EVT_BUTTON(self, self.btnPreview.GetId(), self.OnPreview)
2787
# Button to copy video options to all videos on disc
2788
self.btnUseForAll = wx.Button(self, wx.ID_ANY,
2789
"Use these settings for all videos")
2790
self.btnUseForAll.SetToolTipString("Apply the current video"
2791
" settings, including resolution, aspect ratio, and"
2792
" custom command-line options, to all videos on the disc.")
2793
wx.EVT_BUTTON(self, self.btnUseForAll.GetId(), self.OnUseForAll)
2795
# Video options heading
2796
self.txtHeading = HeadingText(self, wx.ID_ANY, "Video options")
2799
# Add controls to main vertical sizer
2800
self.sizMain = wx.BoxSizer(wx.VERTICAL)
2801
self.sizMain.Add(self.txtHeading, 0, wx.EXPAND | wx.ALL, 8)
2802
self.sizMain.Add(self.sizFileInfo, 0, wx.EXPAND | wx.ALL, 8)
2803
self.sizMain.Add(self.sizEncOpts, 1, wx.EXPAND | wx.ALL, 8)
2804
self.sizMain.Add(self.btnPreview, 0, wx.EXPAND | wx.ALL, 8)
2805
self.sizMain.Add(self.btnUseForAll, 0, wx.EXPAND | wx.ALL, 8)
2806
self.SetSizer(self.sizMain)
2808
def OnFormat(self, evt):
2809
"""Set appropriate format based on radio button selection."""
2810
# Convert integer value to text representation
2811
# (e.g., ID_FMT_DVD to 'dvd')
2812
self.curOptions.format = util.ID_to_text('format', evt.GetInt())
2814
def OnAspect(self, evt):
2815
"""Set aspect ratio based on radio button selection."""
2816
self.curOptions.aspect = util.ID_to_text('aspect', evt.GetInt())
2818
def OnQualityChange(self, evt):
2819
"""Update quality options when the user changes the combobox."""
2820
self.curOptions.quality = self.cbQuality.GetValue()
2822
def OnEncodingChange(self, evt):
2823
"""Update encoding method when the user changes the combobox."""
2824
self.curOptions.encodingMethod = self.cbEncodingMethod.GetValue()
2826
def OnCLIOptions(self, evt):
2827
"""Update custom CLI options when the user edits the textbox."""
2828
self.curOptions.addoptions = self.txtCLIOptions.GetValue()
2830
def OnUseForAll(self, evt):
2831
"""Use the current video settings for all videos on disc."""
2832
countItems = self.parent.UseForAllItems(self.curOptions)
2833
# Display acknowledgement
2834
dlgAck = wx.MessageDialog(self,
2835
"The current video settings were copied to\n"
2836
"%d other videos on the disc." % countItems,
2837
"Settings copied", wx.OK | wx.ICON_INFORMATION)
2840
def OnPreview(self, evt):
2841
"""Preview the video in mplayer."""
2842
strCommand = "gmplayer \"%s\"" % self.curOptions.inFile
2843
wx.Execute(strCommand, wx.EXEC_SYNC)
2846
def SetOptions(self, videoOpts):
2847
"""Set control values based on the provided VideoOptions."""
2848
self.curOptions = videoOpts
2850
self.txtHeading.SetLabel("Video options: %s" % self.curOptions.title)
2851
self.txtInFile.SetLabel(self.curOptions.inFile)
2852
self.rbResolution.SetSelection(util.text_to_ID(self.curOptions.format))
2853
self.rbAspect.SetSelection(util.text_to_ID(self.curOptions.aspect))
2854
self.cbQuality.SetValue(self.curOptions.quality)
2855
self.cbEncodingMethod.SetValue(self.curOptions.encodingMethod)
2856
self.txtCLIOptions.SetValue(self.curOptions.addoptions)
2858
def GetOptions(self):
2859
"""Return the currently-set encoding options."""
2860
return self.curOptions
2862
def SetDiscFormat(self, format):
2863
"""Enable/disable controls to suit DVD, VCD, or SVCD-compliance."""
2864
# For DVD, disable non-DVD output formats
2866
for rbItem in [ID_FMT_DVD, ID_FMT_HALFDVD, ID_FMT_DVDVCD]:
2867
self.rbResolution.EnableItem(rbItem, True)
2868
for rbItem in [ID_FMT_SVCD, ID_FMT_VCD]:
2869
self.rbResolution.EnableItem(rbItem, False)
2870
# For VCD, enable only VCD output and disable bitrate controls
2871
elif format == 'vcd':
2872
for rbItem in range(0, 5):
2873
self.rbResolution.EnableItem(rbItem, False)
2874
self.rbResolution.EnableItem(ID_FMT_VCD, True)
2875
# For SVCD, enable only SVCD output
2876
elif format == 'svcd':
2877
for rbItem in range(0, 5):
2878
self.rbResolution.EnableItem(rbItem, False)
2879
self.rbResolution.EnableItem(ID_FMT_SVCD, True)
2882
print "VideoPanel.SetDiscFormat: Unknown format %s" % format
2884
def SetDiscTVSystem(self, format):
2885
"""Set NTSC or PAL, and show appropriate controls."""
2886
# Display NTSC resolutions in format radiobox
2887
if format in [ 'ntsc', 'ntscfilm' ]:
2888
self.rbResolution.SetItemLabel(ID_FMT_VCD, '352x240 VCD')
2889
self.rbResolution.SetItemLabel(ID_FMT_SVCD, '480x480 SVCD')
2890
self.rbResolution.SetItemLabel(ID_FMT_DVD, '720x480 DVD')
2891
self.rbResolution.SetItemLabel(ID_FMT_HALFDVD, '352x480 Half-DVD')
2892
self.rbResolution.SetItemLabel(ID_FMT_DVDVCD, '352x240 VCD on DVD')
2893
# Display PAL resolutions in format radiobox
2894
elif format == 'pal':
2895
self.rbResolution.SetItemLabel(ID_FMT_VCD, '352x288 VCD')
2896
self.rbResolution.SetItemLabel(ID_FMT_SVCD, '480x576 SVCD')
2897
self.rbResolution.SetItemLabel(ID_FMT_DVD, '720x576 DVD')
2898
self.rbResolution.SetItemLabel(ID_FMT_HALFDVD, '352x576 Half-DVD')
2899
self.rbResolution.SetItemLabel(ID_FMT_DVDVCD, '352x288 VCD on DVD')
2902
print "VideoPanel.SetDiscTVSystem: Unknown format %s" % format
2904
# ************************************************************************
2908
# Note: Each panel stores a subset of todisc command-line options in a
2909
# todisc_opts dictionary; GUI events should set dictionary items appropriately.
2911
# todisc options that do not have GUI controls yet:
2921
# ************************************************************************
2923
class PlaylistTabPanel(wx.Panel):
2924
def __init__(self, parent, id):
2925
wx.Panel.__init__(self, parent, id)
2926
# todisc options controlled by this panel, and default values
2927
# (as a dictionary of option/value pairs)
2928
self.todisc_opts = {\
2937
'submenu-titles': [],
2938
'submenu-audio': None,
2941
self.szVideoInfoBox_staticbox = \
2942
wx.StaticBox(self, wx.ID_ANY, _("Video Information"))
2943
self.szTitleInfoBox_staticbox = \
2944
wx.StaticBox(self, wx.ID_ANY, _("Title"))
2945
self.szAudioInfoBox_staticbox = \
2946
wx.StaticBox(self, wx.ID_ANY, _("Audio"))
2948
wx.RadioBox(self, wx.ID_ANY, _("Disc Format"),
2949
choices=[_("DVD"), _("SVCD")],
2951
style=wx.RA_SPECIFY_ROWS)
2952
self.videoFormat = \
2953
wx.RadioBox(self, wx.ID_ANY, _("Video Format"),
2954
choices=[_("NTSC"), _("PAL")],
2956
style=wx.RA_SPECIFY_ROWS)
2959
self.submenus = wx.CheckBox(self, wx.ID_ANY, _("Create submenus?"))
2960
wx.EVT_CHECKBOX(self, self.submenus.GetId(), self.submenus_OnClick)
2962
self.lblChapters = \
2963
wx.StaticText(self, wx.ID_ANY, _("Chapters per video:"))
2965
wx.SpinCtrl(self, wx.ID_ANY, "6", min=0, max=100,
2967
self.files = wx.ListBox(self, wx.ID_ANY, choices=[])
2971
wx.StaticText(self, wx.ID_ANY, _("Video Thumb Title:"))
2972
self.title = wx.TextCtrl(self, wx.ID_ANY, "")
2973
#wx.EVT_TEXT(self, self.title.GetId(), self.title_OnEdit)
2976
self.lblSubmenuTitle = \
2977
wx.StaticText(self, wx.ID_ANY, _("Video Submenu Title:"))
2978
self.submenu_title = wx.TextCtrl(self, wx.ID_ANY, "")
2979
#wx.EVT_TEXT(self, self.submenu_title.GetId(), self.submenu_title_OnEdit)
2982
self.lblSubmenuAudio = \
2983
wx.StaticText(self, wx.ID_ANY, _("Audio for Submenu:"))
2984
self.submenu_audio = wx.TextCtrl(self, wx.ID_ANY, "")
2985
#wx.EVT_TEXT(self, self.submenu_audio.GetId(), self.submenu_audio_OnEdit)
2986
self.subaudio_all = \
2987
wx.CheckBox(self, wx.ID_ANY, _("Use for all submenu audio?"))
2988
#wx.EVT_BUTTON(self, self.subaudio_all.GetId(), self.subaudio_all_OnClick)
2989
self.btnAudio = wx.Button(self, wx.ID_ANY, _("Browse"))
2990
wx.EVT_BUTTON(self, self.btnAudio.GetId(), self.btnAudio_OnClick)
2992
# "Add Video" button
2993
self.btnAddVideo = wx.Button(self, wx.ID_ANY, _("Add Video"))
2994
wx.EVT_BUTTON(self, self.btnAddVideo.GetId(), self.btnAddVideo_OnClick)
2995
# "Remove Video" button
2996
self.btnRemoveVideo = wx.Button(self, wx.ID_ANY, _("Remove Video"))
2997
wx.EVT_BUTTON(self, self.btnRemoveVideo.GetId(), \
2998
self.btnRemoveVideo_OnClick)
3000
self.static_line_4 = wx.StaticLine(self, wx.ID_ANY)
3001
self.lblOut = wx.StaticText(self, wx.ID_ANY, _("Output"))
3003
# Output file textbox and browse button
3004
self.out = wx.TextCtrl(self, wx.ID_ANY, "")
3005
self.btnOut = wx.Button(self, wx.ID_ANY, _("Browse"))
3006
wx.EVT_BUTTON(self, self.btnOut.GetId(), self.btnOut_OnClick)
3008
self.discFormat.SetSelection(0)
3009
self.videoFormat.SetSelection(0)
3010
self.files.SetMinSize((414, 225))
3011
self.btnAddVideo.SetDefault()
3012
self.btnRemoveVideo.Disable()
3013
self.DisableSubmenus()
3015
szFormats = wx.FlexGridSizer(1, 2, 0, 5)
3016
szFormats.Add(self.discFormat, 0,
3017
wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 0)
3018
szFormats.Add(self.videoFormat, 0,
3019
wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 0)
3020
szFormats.AddGrowableCol(0)
3021
szFormats.AddGrowableCol(1)
3023
szChapters = wx.GridSizer(1, 2, 0, 0)
3024
szChapters.Add(self.lblChapters, 0,
3025
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3026
szChapters.Add(self.chapters, 0, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
3028
szTitleInfo = wx.FlexGridSizer(2, 2, 5, 5)
3029
szTitleInfo.Add(self.lblTitle, 0,
3030
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3031
szTitleInfo.Add(self.title, 0, wx.EXPAND, 0)
3032
szTitleInfo.Add(self.lblSubmenuTitle, 0,
3033
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3034
szTitleInfo.Add(self.submenu_title, 0, wx.EXPAND, 0)
3035
szTitleInfo.AddGrowableCol(1)
3038
wx.StaticBoxSizer(self.szTitleInfoBox_staticbox, wx.VERTICAL)
3039
szTitleInfoBox.Add(szTitleInfo, 1, wx.EXPAND, 0)
3041
szAudioInfo = wx.FlexGridSizer(1, 2, 5, 5)
3042
szAudioInfo.Add(self.lblSubmenuAudio, 0,
3043
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3044
szAudioInfo.Add(self.submenu_audio, 0, wx.EXPAND, 0)
3045
szAudioInfo.AddGrowableCol(1)
3047
szAudioOptions = wx.GridSizer(1, 2, 0, 5)
3048
szAudioOptions.Add(self.subaudio_all, 0,
3049
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3050
szAudioOptions.Add(self.btnAudio, 0,
3051
wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
3053
wx.StaticBoxSizer(self.szAudioInfoBox_staticbox, wx.VERTICAL)
3054
szAudioInfoBox.Add(szAudioInfo, 1, wx.EXPAND, 0)
3055
szAudioInfoBox.Add(szAudioOptions, 1, wx.EXPAND, 0)
3057
szVideoInfo = wx.FlexGridSizer(3, 1, 5, 5)
3058
szVideoInfo.Add(self.files, 0, wx.EXPAND, 0)
3059
szVideoInfo.Add(szTitleInfoBox, 1, wx.EXPAND, 0)
3060
szVideoInfo.Add(szAudioInfoBox, 1, wx.EXPAND, 0)
3061
szVideoInfo.AddGrowableRow(0)
3062
szVideoInfo.AddGrowableCol(0)
3065
wx.StaticBoxSizer(self.szVideoInfoBox_staticbox, wx.VERTICAL)
3066
szVideoInfoBox.Add(szVideoInfo, 0, wx.EXPAND, 0)
3068
szVidButtons = wx.BoxSizer(wx.HORIZONTAL)
3069
szVidButtons.Add(self.btnAddVideo, 1, wx.ADJUST_MINSIZE, 0)
3070
szVidButtons.Add(self.btnRemoveVideo, 1, wx.ADJUST_MINSIZE, 0)
3072
szOutput = wx.FlexGridSizer(1, 3, 0, 7)
3073
szOutput.Add(self.lblOut, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3074
szOutput.Add(self.out, 0, wx.EXPAND, 0)
3075
szOutput.Add(self.btnOut, 0, wx.ADJUST_MINSIZE, 0)
3076
szOutput.AddGrowableCol(1)
3078
szPlaylist = wx.FlexGridSizer(7, 1, 7, 0)
3079
szPlaylist.Add(szFormats, 0, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 0)
3080
szPlaylist.Add(self.submenus, 0,
3081
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3082
szPlaylist.Add(szChapters, 1, wx.EXPAND, 0)
3083
szPlaylist.Add(szVideoInfoBox, 1, wx.EXPAND, 0)
3084
szPlaylist.Add(szVidButtons, 1, wx.EXPAND, 0)
3085
szPlaylist.Add(self.static_line_4, 0, wx.EXPAND, 0)
3086
szPlaylist.Add(szOutput, 1, wx.EXPAND, 0)
3087
szPlaylist.Fit(self)
3088
szPlaylist.SetSizeHints(self)
3089
szPlaylist.AddGrowableRow(3)
3090
szPlaylist.AddGrowableCol(0)
3092
self.SetAutoLayout(True)
3093
self.SetSizer(szPlaylist)
3096
def EnableSubmenus(self):
3097
self.submenu_title.Enable()
3098
self.submenu_audio.Enable()
3099
self.subaudio_all.Enable()
3100
self.btnAudio.Enable()
3102
def DisableSubmenus(self):
3103
self.submenu_title.Disable()
3104
self.submenu_audio.Disable()
3105
self.subaudio_all.Disable()
3106
self.btnAudio.Disable()
3108
def submenus_OnClick(self, evt):
3109
if (evt.IsChecked()):
3110
self.EnableSubmenus()
3111
self.GetParent().GetParent().nbMenus.EnableSubmenus()
3112
self.todisc_opts['submenus'] = True
3114
self.DisableSubmenus()
3115
self.GetParent().GetParent().nbMenus.DisableSubmenus()
3116
self.todisc_opts['submenus'] = False
3118
def btnAddVideo_OnClick(self, evt):
3119
dlgFile = wx.FileDialog(None)
3120
if (dlgFile.ShowModal() == wx.ID_OK):
3121
self.files.Append(dlgFile.GetPath())
3122
if (not self.btnRemoveVideo.IsEnabled()):
3123
self.btnRemoveVideo.Enable()
3125
def btnRemoveVideo_OnClick(self, evt):
3126
self.files.Delete(self.files.GetSelection())
3127
if (self.files.GetCount() == 0):
3128
self.btnRemoveVideo.Disable()
3130
def btnAudio_OnClick(self, evt):
3131
dlgFile = wx.FileDialog(None)
3132
if (dlgFile.ShowModal() == wx.ID_OK):
3133
self.submenu_audio.SetValue(dlgFile.GetPath())
3135
def btnOut_OnClick(self, evt):
3136
dlgFile = wx.DirDialog(None)
3137
if (dlgFile.ShowModal() == wx.ID_OK):
3138
self.out.SetValue(dlgFile.GetPath())
3139
self.tovid_opts['out'] = dlgFile.GetPath()
3141
class MenuTabPanel(wx.Panel):
3142
def __init__(self, parent, id):
3143
wx.Panel.__init__(self, parent, id)
3144
# todisc options controlled by this panel, and default values
3145
# (as a dictionary of option/value pairs)
3146
self.todisc_opts = {\
3147
'menu-title': "My Video Collection",
3148
'menu-font': wx.FontData(),
3149
'title-colour': None,
3150
'stroke-color': None,
3153
'text-mist-color': None,
3154
'text-mist-opacity': None,
3158
'menu-audio-fade': None,
3159
'submenu-audio-fade': None,
3161
'menu-length': None,
3162
'ani-submenus': None,
3163
'submenu-title-color': None,
3164
'submenu-stroke-color': None
3167
self.szMistOpacity_staticbox = \
3168
wx.StaticBox(self, wx.ID_ANY, _("Text Mist Opacity"))
3169
self.szMainMenuBox_staticbox = \
3170
wx.StaticBox(self, wx.ID_ANY, _("Main Menu"))
3171
self.szBackgroundBox_staticbox = \
3172
wx.StaticBox(self, wx.ID_ANY, _("Background"))
3173
self.szAudioFadeBox_staticbox = \
3174
wx.StaticBox(self, wx.ID_ANY, _("Audio Fade"))
3175
self.szMenuAnim_staticbox = \
3176
wx.StaticBox(self, wx.ID_ANY, _("Menu Animations"))
3177
self.szSubmenuBox_staticbox = \
3178
wx.StaticBox(self, wx.ID_ANY, _("Submenus"))
3181
self.lblMenuTitle = wx.StaticText(self, wx.ID_ANY, _("Title:"))
3182
self.menu_title = wx.TextCtrl(self, wx.ID_ANY, "")
3183
#wx.EVT_TEXT(self, self.menu_title.GetId(), self.menu_title_OnEdit)
3185
self.lblMenuFont = wx.StaticText(self, wx.ID_ANY, _("Title Font:"))
3186
self.btnMenuFont = wx.Button(self, wx.ID_ANY, _("Default"))
3187
self.lblTitleColor = wx.StaticText(self, wx.ID_ANY, _("Title Color:"))
3188
self.btnTitleColor = wx.Button(self, wx.ID_ANY, _("Choose"))
3189
self.lblStrokeColor = wx.StaticText(self, wx.ID_ANY, _("Stroke Color:"))
3190
self.btnStrokeColor = wx.Button(self, wx.ID_ANY, _("Choose"))
3191
self.static_line_3 = wx.StaticLine(self, wx.ID_ANY)
3192
self.menu_fade = wx.CheckBox(self, wx.ID_ANY, _("Use menu fade?"))
3193
self.static_line_2 = wx.StaticLine(self, wx.ID_ANY)
3194
self.text_mist = wx.CheckBox(self, wx.ID_ANY, _("Use text mist?"))
3195
self.lblTextMistColor = \
3196
wx.StaticText(self, wx.ID_ANY, _("Text Mist Color:"))
3197
self.btnTextMistColor = wx.Button(self, wx.ID_ANY, _("Choose"))
3199
wx.Slider(self, wx.ID_ANY, 100, 0, 100,
3200
style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
3203
self.lblBgAudio = wx.StaticText(self, wx.ID_ANY, _("Background Audio"))
3204
self.bgaudio = wx.TextCtrl(self, wx.ID_ANY, "")
3205
wx.EVT_TEXT(self, self.bgaudio.GetId(), self.bgaudio_OnEdit)
3206
self.btnBgAudio = wx.Button(self, wx.ID_ANY, _("Browse"))
3209
self.lblBgImage = wx.StaticText(self, wx.ID_ANY, _("Background Image"))
3210
self.bgimage = wx.TextCtrl(self, wx.ID_ANY, "")
3211
wx.EVT_TEXT(self, self.bgimage.GetId(), self.bgimage_OnEdit)
3212
self.btnBgImage = wx.Button(self, wx.ID_ANY, _("Browse"))
3215
self.lblBgVideo = wx.StaticText(self, wx.ID_ANY, _("Background Video"))
3216
self.bgvideo = wx.TextCtrl(self, wx.ID_ANY, "")
3217
wx.EVT_TEXT(self, self.bgvideo.GetId(), self.bgvideo_OnEdit)
3218
self.btnBgVideo = wx.Button(self, wx.ID_ANY, _("Browse"))
3220
self.lblMenuAudioFade = wx.StaticText(self, wx.ID_ANY, _("Menu:"))
3221
self.menu_audio_fade = wx.SpinCtrl(self, wx.ID_ANY, "", min=0, max=100)
3222
self.lblSubmenuAudioFade = \
3223
wx.StaticText(self, wx.ID_ANY, _("Submenu:"))
3224
self.submenu_audio_fade = \
3225
wx.SpinCtrl(self, wx.ID_ANY, "", min=0, max=100)
3226
self.static = wx.CheckBox(self, wx.ID_ANY, _("Animate menus?"))
3227
self.lblMenuLength = \
3228
wx.StaticText(self, wx.ID_ANY, _("Menu animation length:"))
3229
self.menu_length = wx.SpinCtrl(self, wx.ID_ANY, "", min=0, max=100)
3230
self.lblLoop = wx.StaticText(self, wx.ID_ANY, _("Menu pause length:"))
3231
self.loop = wx.SpinCtrl(self, wx.ID_ANY, "", min=0, max=100)
3232
self.static_line_1 = wx.StaticLine(self, wx.ID_ANY)
3233
self.ani_submenus = wx.CheckBox(self, wx.ID_ANY, _("Animate submenus?"))
3234
self.lblSubmenuTitleColor = \
3235
wx.StaticText(self, wx.ID_ANY, _("Title Color:"))
3236
self.btnSubmenuTitleColor = wx.Button(self, wx.ID_ANY, _("Choose"))
3237
self.lblSubmenuStrokeColor = \
3238
wx.StaticText(self, wx.ID_ANY, _("Stroke Color:"))
3239
self.btnSubmenuStrokeColor = wx.Button(self, wx.ID_ANY, _("Choose"))
3241
self.lblMenuTitle.SetFont(\
3242
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3243
self.lblMenuFont.SetFont(\
3244
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3245
self.lblTitleColor.SetFont(\
3246
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3247
self.lblStrokeColor.SetFont(\
3248
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3249
self.lblBgAudio.SetFont(\
3250
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3251
self.lblBgImage.SetFont(\
3252
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3253
self.static.SetValue(1)
3254
self.lblSubmenuTitleColor.SetFont(\
3255
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3256
self.lblSubmenuStrokeColor.SetFont(\
3257
wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, "DejaVu Sans"))
3258
self.btnTextMistColor.Disable()
3259
self.DisableSubmenus()
3261
szMenuTitle = wx.FlexGridSizer(1, 2, 0, 5)
3262
szMenuTitle.Add(self.lblMenuTitle, 0,
3263
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3264
szMenuTitle.Add(self.menu_title, 0, wx.EXPAND, 0)
3265
szMenuTitle.AddGrowableCol(1)
3267
szTitleFont = wx.FlexGridSizer(2, 4, 0, 5)
3268
szTitleFont.Add(self.lblMenuFont, 0,
3269
wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3270
szTitleFont.Add(self.btnMenuFont, 0, wx.ADJUST_MINSIZE, 0)
3271
# szTitleFont.Add(self.lblMenuFontSize, 0, wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3272
# szTitleFont.Add(self.menu_fontsize, 0, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
3273
szTitleFont.Add(self.lblTitleColor, 0,
3274
wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3275
szTitleFont.Add(self.btnTitleColor, 0, wx.ADJUST_MINSIZE, 0)
3276
szTitleFont.Add(self.lblStrokeColor, 0,
3277
wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3278
szTitleFont.Add(self.btnStrokeColor, 0,
3279
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3280
szTitleFont.AddGrowableCol(1)
3282
szTextMist = wx.FlexGridSizer(1, 3, 0, 5)
3283
szTextMist.Add(self.text_mist, 0,
3284
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3285
szTextMist.Add(self.lblTextMistColor, 0,
3286
wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
3287
szTextMist.Add(self.btnTextMistColor, 0, wx.ADJUST_MINSIZE, 0)
3288
szTextMist.AddGrowableCol(1)
3291
wx.StaticBoxSizer(self.szMistOpacity_staticbox, wx.VERTICAL)
3292
szMistOpacity.Add(self.opacity, 0, wx.EXPAND, 0)
3295
wx.StaticBoxSizer(self.szMainMenuBox_staticbox, wx.VERTICAL)
3296
szMainMenuBox.Add(szMenuTitle, 0, wx.EXPAND, 0)
3297
szMainMenuBox.Add(szTitleFont, 1,
3298
wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 0)
3299
szMainMenuBox.Add(self.static_line_3, 0, wx.EXPAND, 0)
3300
szMainMenuBox.Add(self.menu_fade, 0,
3301
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3302
szMainMenuBox.Add(self.static_line_2, 0, wx.EXPAND, 0)
3303
szMainMenuBox.Add(szTextMist, 0, wx.EXPAND, 0)
3304
szMainMenuBox.Add(szMistOpacity, 0, wx.EXPAND, 0)
3306
szBackground = wx.FlexGridSizer(3, 3, 5, 5)
3307
szBackground.Add(self.lblBgAudio, 0,
3308
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3309
szBackground.Add(self.bgaudio, 0, wx.EXPAND, 0)
3310
szBackground.Add(self.btnBgAudio, 0, wx.ADJUST_MINSIZE, 0)
3311
szBackground.Add(self.lblBgImage, 0,
3312
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3313
szBackground.Add(self.bgimage, 0, wx.EXPAND, 0)
3314
szBackground.Add(self.btnBgImage, 0, wx.ADJUST_MINSIZE, 0)
3315
szBackground.Add(self.lblBgVideo, 0,
3316
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3317
szBackground.Add(self.bgvideo, 0, wx.EXPAND, 0)
3318
szBackground.Add(self.btnBgVideo, 0, wx.ADJUST_MINSIZE, 0)
3319
szBackground.AddGrowableCol(1)
3322
wx.StaticBoxSizer(self.szBackgroundBox_staticbox, wx.VERTICAL)
3323
szBackgroundBox.Add(szBackground, 1, wx.EXPAND, 0)
3325
szAudioFade = wx.FlexGridSizer(1, 4, 0, 5)
3326
szAudioFade.Add(self.lblMenuAudioFade, 0,
3327
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3328
szAudioFade.Add(self.menu_audio_fade, 0, wx.ADJUST_MINSIZE, 0)
3329
szAudioFade.Add(self.lblSubmenuAudioFade, 0,
3330
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3331
szAudioFade.Add(self.submenu_audio_fade, 0, wx.ADJUST_MINSIZE, 0)
3332
szAudioFade.AddGrowableCol(1)
3335
wx.StaticBoxSizer(self.szAudioFadeBox_staticbox, wx.HORIZONTAL)
3336
szAudioFadeBox.Add(szAudioFade, 1, wx.EXPAND, 0)
3338
szMenuLength = wx.FlexGridSizer(1, 2, 0, 0)
3339
szMenuLength.Add(self.lblMenuLength, 0,
3340
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3341
szMenuLength.Add(self.menu_length, 0,
3342
wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
3343
szMenuLength.AddGrowableCol(0)
3344
szMenuLength.AddGrowableCol(1)
3346
szLoop = wx.GridSizer(1, 2, 0, 0)
3347
szLoop.Add(self.lblLoop, 0,
3348
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3349
szLoop.Add(self.loop, 0, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
3351
szSubmenus = wx.FlexGridSizer(10, 1, 5, 0)
3352
szSubmenus.Add(self.static, 0, wx.ADJUST_MINSIZE, 0)
3353
szSubmenus.Add(szMenuLength, 1, wx.EXPAND, 0)
3354
szSubmenus.Add(szLoop, 1, wx.EXPAND, 0)
3355
szSubmenus.Add(self.static_line_1, 0, wx.EXPAND, 0)
3356
szSubmenus.Add(self.ani_submenus, 0,
3357
wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3358
szSubmenus.AddGrowableCol(0)
3360
szMenuAnim = wx.StaticBoxSizer(self.szMenuAnim_staticbox, wx.VERTICAL)
3361
szMenuAnim.Add(szSubmenus, 1, wx.EXPAND, 0)
3363
szSubmenuColor = wx.FlexGridSizer(1, 4, 0, 7)
3364
szSubmenuColor.Add(self.lblSubmenuTitleColor, 0,
3365
wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3366
szSubmenuColor.Add(self.btnSubmenuTitleColor, 0, wx.ADJUST_MINSIZE, 0)
3367
szSubmenuColor.Add(self.lblSubmenuStrokeColor, 0,
3368
wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3369
szSubmenuColor.Add(self.btnSubmenuStrokeColor, 0, wx.ADJUST_MINSIZE, 0)
3370
szSubmenuColor.AddGrowableCol(1)
3373
wx.StaticBoxSizer(self.szSubmenuBox_staticbox, wx.HORIZONTAL)
3374
szSubmenuBox.Add(szSubmenuColor, 1, wx.EXPAND, 0)
3376
szMenus = wx.FlexGridSizer(5, 1, 7, 0)
3377
szMenus.Add(szMainMenuBox, 1, wx.EXPAND, 0)
3378
szMenus.Add(szBackgroundBox, 1, wx.EXPAND, 0)
3379
szMenus.Add(szAudioFadeBox, 1, wx.EXPAND, 0)
3380
szMenus.Add(szMenuAnim, 1, wx.EXPAND, 0)
3381
szMenus.Add(szSubmenuBox, 1, wx.EXPAND, 0)
3383
szMenus.SetSizeHints(self)
3384
szMenus.AddGrowableCol(0)
3386
self.SetAutoLayout(True)
3387
self.SetSizer(szMenus)
3389
wx.EVT_BUTTON(self, self.btnMenuFont.GetId(), self.btnMenuFont_OnClick)
3390
wx.EVT_BUTTON(self, self.btnTitleColor.GetId(),
3391
self.btnTitleColor_OnClick)
3392
wx.EVT_BUTTON(self, self.btnStrokeColor.GetId(),
3393
self.btnStrokeColor_OnClick)
3394
wx.EVT_CHECKBOX(self, self.text_mist.GetId(), self.text_mist_OnClick)
3395
wx.EVT_CHECKBOX(self, self.static.GetId(), self.static_OnClick)
3397
def EnableSubmenus(self):
3398
self.submenu_audio_fade.Enable()
3399
self.ani_submenus.Enable()
3400
self.btnSubmenuTitleColor.Enable()
3401
self.btnSubmenuStrokeColor.Enable()
3403
def DisableSubmenus(self):
3404
self.submenu_audio_fade.Disable()
3405
self.ani_submenus.Disable()
3406
self.btnSubmenuTitleColor.Disable()
3407
self.btnSubmenuStrokeColor.Disable()
3409
def btnMenuFont_OnClick(self, evt):
3410
dlgFont = wx.FontDialog(None, wx.FontData())
3411
if (dlgFont.ShowModal() == wx.ID_OK):
3412
font = dlgFont.GetFontData().GetChosenFont()
3413
self.todisc_opts['menu-font'] = font.GetFaceName()
3414
self.todisc_opts['menu-fontsize'] = font.GetPointSize()
3415
self.btnMenuFont.SetLabel(font.GetFaceName())
3417
def btnTitleColor_OnClick(self, evt):
3418
dlgColour = wx.ColourDialog(None, self.todisc_opts['title-colour'])
3419
if (dlgColour.ShowModal() == wx.ID_OK):
3420
self.todisc_opts['title-colour'] = dlgColour.GetColourData()
3422
def btnStrokeColor_OnClick(self, evt):
3423
dlgColour = wx.ColourDialog(None)
3424
if (dlgColour.ShowModal() == wx.ID_OK):
3425
colour = dlgColour.GetColourData().GetColour()
3426
self.todisc_opts['stroke-colour'] = colour
3428
def text_mist_OnClick(self, evt):
3429
if (evt.IsChecked()):
3430
self.btnTextMistColor.Enable()
3432
self.btnTextMistColor.Disable()
3434
def static_OnClick(self, evt):
3435
if (evt.IsChecked()):
3436
self.menu_length.Enable()
3439
self.menu_length.Disable()
3441
def bgaudio_OnEdit(self, evt):
3442
self.todisc_opts['bgaudio'] = self.bgaudio.GetValue()
3444
def bgimage_OnEdit(self, evt):
3445
self.todisc_opts['bgimage'] = self.bgimage.GetValue()
3447
def bgvideo_OnEdit(self, evt):
3448
self.todisc_opts['bgvideo'] = self.bgvideo.GetValue()
3450
class ThumbnailTabPanel(wx.Panel):
3451
def __init__(self, parent, id):
3452
self.todisc_opts = {\
3453
'thumb-shape': None,
3455
'thumb-text-color': None,
3456
'thumb-mist-color': None,
3462
wx.Panel.__init__(self, parent, id)
3463
self.feather_thumbs = wx.CheckBox(self, wx.ID_ANY, _("Feather thumbnails?"))
3464
self.szBlur_staticbox = wx.StaticBox(self, wx.ID_ANY, _("Blur"))
3465
self.szOpacity_staticbox = wx.StaticBox(self, wx.ID_ANY, _("Opacity"))
3466
self.thumb_shape = wx.RadioBox(self, wx.ID_ANY, _("Feather Shape"), choices=[_("Normal"), _("Oval"), _("Cloud"), _("Egg")], majorDimension=1, style=wx.RA_SPECIFY_ROWS)
3467
self.lblThumbTitleFont = wx.StaticText(self, wx.ID_ANY, _("Thumb Font:"))
3468
self.thumb_font = wx.Button(self, wx.ID_ANY, _("Default"))
3469
self.lblThumbTitleColor = wx.StaticText(self, wx.ID_ANY, _("Thumb Font Color:"))
3470
self.thumb_text_color = wx.Button(self, wx.ID_ANY, _("Choose"))
3471
self.lblThumbTitleMistColor = wx.StaticText(self, wx.ID_ANY, _("Thumb Mist Color:"))
3472
self.thumb_mist_color = wx.Button(self, wx.ID_ANY, _("Choose"))
3473
self.blur = wx.Slider(self, wx.ID_ANY, 5, 0, 10, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
3474
self.opacity = wx.Slider(self, wx.ID_ANY, 100, 0, 100, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS)
3475
self.lblSeek = wx.StaticText(self, wx.ID_ANY, _("Seconds to seek before generating thumbs:"))
3476
self.seek = wx.SpinCtrl(self, wx.ID_ANY, "", min=0, max=100, style=wx.TE_RIGHT)
3478
self.thumb_shape.SetSelection(0)
3479
self.thumb_shape.Disable()
3481
szThumbFont = wx.FlexGridSizer(2, 4, 5, 5)
3482
szThumbFont.Add(self.lblThumbTitleFont, 0, wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3483
szThumbFont.Add(self.thumb_font, 0, wx.ADJUST_MINSIZE, 0)
3484
szThumbFont.Add(self.lblThumbTitleColor, 0, wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3485
szThumbFont.Add(self.thumb_text_color, 0, wx.ADJUST_MINSIZE, 0)
3486
szThumbFont.Add(self.lblThumbTitleMistColor, 0, wx.ALIGN_CENTER_VERTICAL|wx.SHAPED, 0)
3487
szThumbFont.Add(self.thumb_mist_color, 0, wx.ADJUST_MINSIZE, 0)
3488
szThumbFont.AddGrowableCol(1)
3490
szThumbShape = wx.FlexGridSizer(2, 1, 5, 0)
3491
szThumbShape.Add(self.thumb_shape, 0, wx.EXPAND, 0)
3492
szThumbShape.Add(szThumbFont, 0, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 0)
3493
szThumbShape.AddGrowableCol(0)
3495
szBlur = wx.StaticBoxSizer(self.szBlur_staticbox, wx.VERTICAL)
3496
szBlur.Add(self.blur, 0, wx.EXPAND, 0)
3498
szOpacity = wx.StaticBoxSizer(self.szOpacity_staticbox, wx.VERTICAL)
3499
szOpacity.Add(self.opacity, 0, wx.EXPAND, 0)
3501
szSeek = wx.FlexGridSizer(1, 2, 0, 5)
3502
szSeek.Add(self.lblSeek, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3503
szSeek.Add(self.seek, 0, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0)
3504
szSeek.AddGrowableCol(0)
3506
szThumbnails = wx.FlexGridSizer(5, 1, 7, 0)
3507
szThumbnails.Add(self.feather_thumbs, 0, wx.ADJUST_MINSIZE, 0)
3508
szThumbnails.Add(szThumbShape, 1, wx.EXPAND, 0)
3509
szThumbnails.Add(szBlur, 0, wx.EXPAND, 0)
3510
szThumbnails.Add(szOpacity, 0, wx.EXPAND, 0)
3511
szThumbnails.Add(szSeek, 1, wx.EXPAND, 0)
3512
szThumbnails.Fit(self)
3513
szThumbnails.SetSizeHints(self)
3514
szThumbnails.AddGrowableCol(0)
3516
self.SetAutoLayout(True)
3517
self.SetSizer(szThumbnails)
3519
wx.EVT_CHECKBOX(self, self.feather_thumbs.GetId(), self.feather_thumbs_OnClick)
3521
def feather_thumbs_OnClick(self, evt):
3522
if (evt.IsChecked()):
3523
self.thumb_shape.Enable()
3525
self.thumb_shape.Disable()
3527
class DebugTabPanel(wx.Panel):
3528
def __init__(self, parent, id):
3529
wx.Panel.__init__(self, parent, id)
3530
self.szDebugBox_staticbox = wx.StaticBox(self, wx.ID_ANY, _("Debug Flags"))
3531
self.debug = wx.CheckBox(self, wx.ID_ANY, _("Turn on debug logging?"))
3532
self.keepfiles = wx.CheckBox(self, wx.ID_ANY, _("Keep files when finished?"))
3534
szDebugBox = wx.StaticBoxSizer(self.szDebugBox_staticbox, wx.VERTICAL)
3535
szDebugBox.Add(self.debug, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3536
szDebugBox.Add(self.keepfiles, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0)
3538
szDebug = wx.FlexGridSizer(1, 1, 7, 0)
3539
szDebug.Add(szDebugBox, 0, wx.EXPAND, 0)
3541
szDebug.SetSizeHints(self)
3542
szDebug.AddGrowableRow(1)
3543
szDebug.AddGrowableCol(0)
3545
self.SetAutoLayout(True)
3546
self.SetSizer(szDebug)