Add a simple DCP editor.
authorCarl Hetherington <cth@carlh.net>
Fri, 22 Apr 2022 23:59:10 +0000 (01:59 +0200)
committerCarl Hetherington <cth@carlh.net>
Fri, 29 Apr 2022 21:37:48 +0000 (23:37 +0200)
32 files changed:
cscript
graphics/linux/128/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/16/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/22/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/256/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/32/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/48/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/512/dcpomatic2_editor.png [new file with mode: 0644]
graphics/linux/64/dcpomatic2_editor.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.icns [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_128x128.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_128x128@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_16x16.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_16x16@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_256x256.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_256x256@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_32x32.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_32x32@2x.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_512x512.png [new file with mode: 0644]
graphics/osx/dcpomatic2_editor.iconset/icon_512x512@2x.png [new file with mode: 0644]
graphics/src/dcpomatic2_editor.svg [new file with mode: 0644]
graphics/update
graphics/windows/dcpomatic2_editor.ico [new file with mode: 0644]
platform/osx/dcpomatic2_editor.Info.plist.in [new file with mode: 0644]
platform/osx/make_dmg.sh
platform/osx/wscript
platform/windows/dcpomatic_editor.rc [new file with mode: 0644]
platform/windows/wscript
run/dcpomatic_editor [new file with mode: 0755]
src/lib/writer.cc
src/tools/dcpomatic_editor.cc [new file with mode: 0644]
src/tools/wscript

diff --git a/cscript b/cscript
index 3ac340796d066ce6ebe2e55d3d6a4c0d532371c7..dbcd3b7a2c252b5f6d4b00ecffd77ada57f29d41 100644 (file)
--- a/cscript
+++ b/cscript
@@ -424,8 +424,8 @@ def dependencies(target, options):
         # Use distro-provided FFmpeg on Arch
         deps = []
 
-    deps.append(('libdcp', 'v1.8.16'))
-    deps.append(('libsub', 'v1.6.17'))
+    deps.append(('libdcp', 'c4c176e9d3bd72fe1746f22d7afb442ca72a72f2'))
+    deps.append(('libsub', '079cf6179c1a41284858feaf61c6e57384d72777'))
     deps.append(('leqm-nrt', '93ae9e6'))
     deps.append(('rtaudio', 'f619b76'))
     # We get our OpenSSL libraries from the environment, but we
diff --git a/graphics/linux/128/dcpomatic2_editor.png b/graphics/linux/128/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..d05282c
Binary files /dev/null and b/graphics/linux/128/dcpomatic2_editor.png differ
diff --git a/graphics/linux/16/dcpomatic2_editor.png b/graphics/linux/16/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..2ec12f8
Binary files /dev/null and b/graphics/linux/16/dcpomatic2_editor.png differ
diff --git a/graphics/linux/22/dcpomatic2_editor.png b/graphics/linux/22/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..3c492a7
Binary files /dev/null and b/graphics/linux/22/dcpomatic2_editor.png differ
diff --git a/graphics/linux/256/dcpomatic2_editor.png b/graphics/linux/256/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..d78fcb7
Binary files /dev/null and b/graphics/linux/256/dcpomatic2_editor.png differ
diff --git a/graphics/linux/32/dcpomatic2_editor.png b/graphics/linux/32/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..821af7d
Binary files /dev/null and b/graphics/linux/32/dcpomatic2_editor.png differ
diff --git a/graphics/linux/48/dcpomatic2_editor.png b/graphics/linux/48/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..6d6f03d
Binary files /dev/null and b/graphics/linux/48/dcpomatic2_editor.png differ
diff --git a/graphics/linux/512/dcpomatic2_editor.png b/graphics/linux/512/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..53bf933
Binary files /dev/null and b/graphics/linux/512/dcpomatic2_editor.png differ
diff --git a/graphics/linux/64/dcpomatic2_editor.png b/graphics/linux/64/dcpomatic2_editor.png
new file mode 100644 (file)
index 0000000..a1cfa19
Binary files /dev/null and b/graphics/linux/64/dcpomatic2_editor.png differ
diff --git a/graphics/osx/dcpomatic2_editor.icns b/graphics/osx/dcpomatic2_editor.icns
new file mode 100644 (file)
index 0000000..30729b8
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.icns differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_128x128.png b/graphics/osx/dcpomatic2_editor.iconset/icon_128x128.png
new file mode 100644 (file)
index 0000000..d05282c
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_128x128.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_128x128@2x.png b/graphics/osx/dcpomatic2_editor.iconset/icon_128x128@2x.png
new file mode 100644 (file)
index 0000000..d05282c
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_128x128@2x.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_16x16.png b/graphics/osx/dcpomatic2_editor.iconset/icon_16x16.png
new file mode 100644 (file)
index 0000000..2ec12f8
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_16x16.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_16x16@2x.png b/graphics/osx/dcpomatic2_editor.iconset/icon_16x16@2x.png
new file mode 100644 (file)
index 0000000..2ec12f8
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_16x16@2x.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_256x256.png b/graphics/osx/dcpomatic2_editor.iconset/icon_256x256.png
new file mode 100644 (file)
index 0000000..d78fcb7
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_256x256.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_256x256@2x.png b/graphics/osx/dcpomatic2_editor.iconset/icon_256x256@2x.png
new file mode 100644 (file)
index 0000000..d78fcb7
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_256x256@2x.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_32x32.png b/graphics/osx/dcpomatic2_editor.iconset/icon_32x32.png
new file mode 100644 (file)
index 0000000..821af7d
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_32x32.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_32x32@2x.png b/graphics/osx/dcpomatic2_editor.iconset/icon_32x32@2x.png
new file mode 100644 (file)
index 0000000..821af7d
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_32x32@2x.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_512x512.png b/graphics/osx/dcpomatic2_editor.iconset/icon_512x512.png
new file mode 100644 (file)
index 0000000..53bf933
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_512x512.png differ
diff --git a/graphics/osx/dcpomatic2_editor.iconset/icon_512x512@2x.png b/graphics/osx/dcpomatic2_editor.iconset/icon_512x512@2x.png
new file mode 100644 (file)
index 0000000..53bf933
Binary files /dev/null and b/graphics/osx/dcpomatic2_editor.iconset/icon_512x512@2x.png differ
diff --git a/graphics/src/dcpomatic2_editor.svg b/graphics/src/dcpomatic2_editor.svg
new file mode 100644 (file)
index 0000000..e5bb7b1
--- /dev/null
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   viewBox="0 0 1000 1000"
+   sodipodi:docname="dcpomatic2_editor.svg"
+   inkscape:version="1.1.1 (3bf5ae0, 2021-09-20)"
+   version="1.1"
+   id="svg2"
+   height="1066.6666"
+   width="1066.6666"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="Arrow1Mstart"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Mstart">
+      <path
+         transform="scale(0.4) translate(10,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path893" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="marker1193"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="scale(0.8) rotate(180) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path1191" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1189"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="scale(0.8) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path1187" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker1167"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="scale(0.8) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path1165" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible;"
+       id="Arrow1Lend"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="scale(0.8) rotate(180) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path890" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="Arrow1Lstart"
+       refX="0.0"
+       refY="0.0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         transform="scale(0.8) translate(12.5,0)"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         id="path887" />
+    </marker>
+    <linearGradient
+       id="linearGradient3594"
+       y2="742.5"
+       gradientUnits="userSpaceOnUse"
+       x2="-886.76001"
+       gradientTransform="matrix(-0.84033,-0.84033,-0.84033,0.84033,136.32259,-691.39649)"
+       y1="742.5"
+       x1="-772.01001">
+      <stop
+         id="stop4687"
+         stop-color="#fff"
+         offset="0" />
+      <stop
+         id="stop4689"
+         stop-color="#fff"
+         stop-opacity="0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3601"
+       y2="613.94"
+       gradientUnits="userSpaceOnUse"
+       x2="385.04001"
+       gradientTransform="matrix(0.70711,-0.70711,0.70711,0.70711,-203.97741,756.21351)"
+       y1="63.870998"
+       x1="386.39001">
+      <stop
+         id="stop3797"
+         stop-color="#ffe800"
+         offset="0" />
+      <stop
+         id="stop3799"
+         stop-color="#dfb300"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3609"
+       y2="161.84"
+       gradientUnits="userSpaceOnUse"
+       x2="212.92999"
+       y1="358.29999"
+       x1="409.38"
+       gradientTransform="translate(-77.797413,384.00351)">
+      <stop
+         id="stop4034"
+         stop-color="#dfb300"
+         offset="0" />
+      <stop
+         id="stop3374"
+         stop-color="#dfb300"
+         offset=".5" />
+      <stop
+         id="stop3376"
+         stop-color="#dfb300"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3632"
+       y2="448.35001"
+       gradientUnits="userSpaceOnUse"
+       x2="382.89999"
+       gradientTransform="matrix(0.70711,-0.70711,0.70711,0.70711,-203.97741,756.21351)"
+       y1="448.35001"
+       x1="403.63">
+      <stop
+         id="stop3636"
+         stop-color="#ffe800"
+         stop-opacity=".39216"
+         offset="0" />
+      <stop
+         id="stop3638"
+         stop-color="#dfb300"
+         stop-opacity=".39216"
+         offset="1" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     inkscape:snap-midpoints="true"
+     inkscape:document-rotation="0"
+     inkscape:window-maximized="1"
+     inkscape:window-y="0"
+     inkscape:window-x="0"
+     inkscape:window-height="1043"
+     inkscape:window-width="1920"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:document-units="px"
+     inkscape:cy="182.21133"
+     inkscape:cx="38.466836"
+     inkscape:zoom="0.24696598"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     inkscape:pagecheckerboard="0"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-bbox="true"
+     inkscape:snap-bbox-midpoints="true" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     transform="translate(0,-52.362188)"
+     id="layer1"
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1">
+    <image
+       xlink:href="dcpomatic.png"
+       id="image4358"
+       preserveAspectRatio="none"
+       height="960.00006"
+       width="960.00006"
+       x="10.670144"
+       y="80.386467" />
+    <g
+       id="g8530"
+       transform="rotate(45,1084.1843,1784.932)">
+      <rect
+         style="font-variation-settings:normal;opacity:0.792898;vector-effect:none;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:14.2059;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
+         id="rect1581"
+         width="307.76059"
+         height="110.81631"
+         x="-350.94226"
+         y="1283.3156" />
+      <path
+         id="path1605"
+         style="font-variation-settings:normal;opacity:0.792898;vector-effect:none;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:15.5608;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
+         d="m -12.416849,1368.7621 c 83.822764,-19.6805 86.251983,62.0217 60.827987,62.3855 l -60.841013,0.8707 c -51.520013,0.7373 -93.294775,-41.7695 -93.294755,-93.2948 3e-5,-51.5252 41.770681,-93.6427 93.294755,-93.2947 l 65.466374,0.4422 c 21.731192,0.1468 14.788626,78.6616 -67.922673,59.3129 -41.565783,-9.7235 -40.507802,75.1684 2.469325,63.5782 z"
+         sodipodi:nodetypes="csssssscc" />
+      <path
+         id="path1605-6"
+         style="font-variation-settings:normal;opacity:0.792898;vector-effect:none;fill:#5e5e5e;fill-opacity:1;stroke:#000000;stroke-width:15.5608;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000"
+         d="m -390.33914,1368.7586 c -83.82277,-19.6805 -86.25198,62.0217 -60.82799,62.3855 l 60.84101,0.8707 c 51.52002,0.7373 93.29478,-41.7695 93.29476,-93.2948 -3e-5,-51.5252 -41.77068,-93.6427 -93.29476,-93.2947 l -65.46637,0.4422 c -21.73119,0.1468 -14.78863,78.6616 67.92267,59.3129 41.56579,-9.7235 40.50781,75.1684 -2.46932,63.5782 z"
+         sodipodi:nodetypes="csssssscc" />
+    </g>
+  </g>
+</svg>
index 35aec325a78bb0f279f5b988804a65ca713038b5..f518b5b5bf39ba224c0cf16aa876056cd077cacc 100755 (executable)
@@ -25,7 +25,7 @@ function required_font()
     fi
 }
 
-svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner"
+svg_apps="dcpomatic2_kdm dcpomatic2_server dcpomatic2_batch dcpomatic2_player dcpomatic2_playlist dcpomatic2_disk dcpomatic2_combiner dcpomatic2_editor"
 
 
 if [ `uname -s` == "Darwin" ]; then
diff --git a/graphics/windows/dcpomatic2_editor.ico b/graphics/windows/dcpomatic2_editor.ico
new file mode 100644 (file)
index 0000000..f079983
Binary files /dev/null and b/graphics/windows/dcpomatic2_editor.ico differ
diff --git a/platform/osx/dcpomatic2_editor.Info.plist.in b/platform/osx/dcpomatic2_editor.Info.plist.in
new file mode 100644 (file)
index 0000000..229202e
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>dcpomatic2_editor</string>
+       <key>CFBundleGetInfoString</key>
+       <string>DCP-o-matic 2 Editor</string>
+       <key>CFBundleIconFile</key>
+       <string>dcpomatic2_editor.icns</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.dcpomatic.editor</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>DCP-o-matic 2 Editor</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersions</key>
+       <string>@VERSION@</string>
+       <key>CFBundleSignature</key>
+       <string>DOMC</string>
+       <key>CFBundleVersion</key>
+       <string>@VERSION@</string>
+       <key>CFBundleAllowMixedLocalizations</key>
+       <true/>
+       <key>LSUIElement</key>
+       <string>0</string>
+       <key>NSMainNibFile</key>
+       <string>MainMenu</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
index 6f36839f77a10683000e3fcdbba754f63e532eb7..c9ed43b9433a4fef584fa700d07eb4babb885423 100644 (file)
@@ -202,6 +202,7 @@ function copy_resources {
     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_playlist.icns "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_disk.icns "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_combiner.icns "$dest"
+    cp $prefix/src/dcpomatic/graphics/osx/dcpomatic2_editor.icns "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults.png "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/preferences/defaults@2x.png "$dest"
     cp $prefix/src/dcpomatic/graphics/osx/preferences/kdm_email.png "$dest"
@@ -537,6 +538,16 @@ rl=("$approot/MacOS/dcpomatic2_combiner" "$approot/Frameworks/"*.dylib)
 relink_relative "${rl[@]}"
 make_dmg "$appdir" "" "DCP-o-matic Combiner" "dcpomatic2_verify openssl dcpomatic2_combiner"
 
+# DCP-o-matic Editor
+setup "DCP-o-matic 2 Editor.app"
+copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_editor "$approot/MacOS"
+copy $ROOT src/openssl/apps/openssl "$approot/MacOS"
+copy_verify
+cp $prefix/src/dcpomatic/build/platform/osx/dcpomatic2_editor.Info.plist "$approot/Info.plist"
+rl=("$approot/MacOS/dcpomatic2_editor" "$approot/Frameworks/"*.dylib)
+relink_relative "${rl[@]}"
+make_dmg "$appdir" "" "DCP-o-matic Editor" "dcpomatic2_verify openssl dcpomatic2_editor"
+
 # DCP-o-matic Disk Writer .app
 setup "DCP-o-matic 2 Disk Writer.app"
 copy $ROOT src/dcpomatic/build/src/tools/dcpomatic2_disk "$approot/MacOS"
index c0b3d9d10a69545470ab3e0410f118713875804a..fd6733a66f987e5e6438b7d8ed29409df1f8062f 100644 (file)
@@ -7,3 +7,4 @@ def build(bld):
     obj = bld(features='subst', source='dcpomatic2_playlist.Info.plist.in', target='dcpomatic2_playlist.Info.plist', version=bld.env.VERSION)
     obj = bld(features='subst', source='dcpomatic2_disk.Info.plist.in', target='dcpomatic2_disk.Info.plist', version=bld.env.VERSION)
     obj = bld(features='subst', source='dcpomatic2_combiner.Info.plist.in', target='dcpomatic2_combiner.Info.plist', version=bld.env.VERSION)
+    obj = bld(features='subst', source='dcpomatic2_editor.Info.plist.in', target='dcpomatic2_editor.Info.plist', version=bld.env.VERSION)
diff --git a/platform/windows/dcpomatic_editor.rc b/platform/windows/dcpomatic_editor.rc
new file mode 100644 (file)
index 0000000..865590f
--- /dev/null
@@ -0,0 +1,2 @@
+id ICON "../../graphics/windows/dcpomatic2_editor.ico"
+#include "wx-3.1/wx/msw/wx.rc"
index 46974ed0f553c4dba607597a88f22b069255088d..a01d3dd5aeb9ed6243c4f1977e3f58ae56f1a866 100644 (file)
@@ -12,6 +12,7 @@ def write_installer(bits, dcpomatic_version, debug, disk):
         ('create', 'Creator'),
         ('playlist', 'Playlist Editor'),
         ('combiner', 'Combiner'),
+        ('editor', 'Editor'),
     ]
 
     if disk:
diff --git a/run/dcpomatic_editor b/run/dcpomatic_editor
new file mode 100755 (executable)
index 0000000..28ef4a9
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:$LD_LIBRARY_PATH
+export DYLD_LIBRARY_PATH=$build/src/lib:$build/src/wx:$build/src/asdcplib/src:/Users/ci/osx-environment/x86_64/10.10/lib
+export DCPOMATIC_GRAPHICS=graphics
+if [ "$1" == "--debug" ]; then
+    shift
+    gdb --args build/src/tools/dcpomatic2_editor $*
+elif [ "$1" == "--valgrind" ]; then
+    shift
+    valgrind --tool="memcheck" --suppressions=suppressions --track-fds=yes build/src/tools/dcpomatic2_editor $*
+elif [ "$1" == "--callgrind" ]; then
+    shift
+    valgrind --tool="callgrind" build/src/tools/dcpomatic2_editor $*
+elif [ "$1" == "--massif" ]; then
+    shift
+    valgrind --tool="massif" build/src/tools/dcpomatic2_editor $*
+elif [ "$1" == "--i18n" ]; then
+    shift
+    LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 LC_ALL=fr_FR.UTF8 build/src/tools/dcpomatic2_editor "$*"
+elif [ "$1" == "--perf" ]; then
+    shift
+    perf record build/src/tools/dcpomatic2_editor $*
+else
+    build/src/tools/dcpomatic2_editor $*
+fi
index f14ef49ef320b8a7ca9cfd57cd0211d9ae526e5f..954c135d3a90d4e43fcfa0e4e3b34ea4b81320e0 100644 (file)
@@ -692,14 +692,11 @@ Writer::finish (boost::filesystem::path output_dcp)
                throw InvalidSignerError (reason);
        }
 
-       dcp.write_xml (
-               issuer,
-               creator,
-               dcp::LocalTime().as_string(),
-               film()->dcp_name(),
-               signer,
-               Config::instance()->dcp_metadata_filename_format()
-               );
+       dcp.set_issuer(issuer);
+       dcp.set_creator(creator);
+       dcp.set_annotation_text(film()->dcp_name());
+
+       dcp.write_xml (signer, Config::instance()->dcp_metadata_filename_format());
 
        LOG_GENERAL (
                N_("Wrote %1 FULL, %2 FAKE, %3 REPEAT, %4 pushed to disk"), _full_written, _fake_written, _repeat_written, _pushed_to_disk
diff --git a/src/tools/dcpomatic_editor.cc b/src/tools/dcpomatic_editor.cc
new file mode 100644 (file)
index 0000000..075cf17
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+    Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    DCP-o-matic is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "wx/about_dialog.h"
+#include "wx/editable_list.h"
+#include "wx/wx_signal_manager.h"
+#include "wx/wx_util.h"
+#include "lib/cross.h"
+#include "lib/dcpomatic_log.h"
+#include "lib/null_log.h"
+#include "lib/util.h"
+#include <dcp/cpl.h>
+#include <dcp/dcp.h>
+#include <dcp/reel.h>
+#include <dcp/reel_picture_asset.h>
+#include <dcp/reel_sound_asset.h>
+#include <dcp/reel_subtitle_asset.h>
+#include <dcp/warnings.h>
+LIBDCP_DISABLE_WARNINGS
+#include <wx/cmdline.h>
+#include <wx/notebook.h>
+#include <wx/spinctrl.h>
+#include <wx/splash.h>
+#include <wx/stdpaths.h>
+#include <wx/wx.h>
+LIBDCP_ENABLE_WARNINGS
+#ifdef __WXGTK__
+#include <X11/Xlib.h>
+#endif
+#include <iostream>
+
+
+using std::exception;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using boost::optional;
+#if BOOST_VERSION >= 106100
+using namespace boost::placeholders;
+#endif
+
+
+enum {
+       ID_file_open = 1,
+       ID_file_save,
+};
+
+
+class AssetPanel : public wxPanel
+{
+public:
+       AssetPanel(wxWindow* parent, shared_ptr<dcp::ReelAsset> asset)
+               : wxPanel(parent, wxID_ANY)
+               , _asset(asset)
+       {
+               auto sizer = new wxGridBagSizer(DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+
+               int r = 0;
+
+               add_label_to_sizer(sizer, this, _("Annotation text"), true, wxGBPosition(r, 0));
+               _annotation_text = new wxTextCtrl(this, wxID_ANY, std_to_wx(asset->annotation_text().get_value_or("")), wxDefaultPosition, wxSize(600, -1));
+               sizer->Add(_annotation_text, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Entry point"), true, wxGBPosition(r, 0));
+               _entry_point = new wxSpinCtrl(this, wxID_ANY);
+               sizer->Add(_entry_point, wxGBPosition(r, 1), wxDefaultSpan);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Duration"), true, wxGBPosition(r, 0));
+               _duration = new wxSpinCtrl(this, wxID_ANY);
+               sizer->Add(_duration, wxGBPosition(r, 1), wxDefaultSpan);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Intrinsic duration"), true, wxGBPosition(r, 0));
+               auto intrinsic_duration = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
+               sizer->Add(intrinsic_duration, wxGBPosition(r, 1), wxDefaultSpan);
+               ++r;
+
+               auto space = new wxBoxSizer(wxVERTICAL);
+               space->Add(sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+               SetSizerAndFit(space);
+
+               _entry_point->SetRange(0, 259200);
+               _entry_point->SetValue(asset->entry_point().get_value_or(0));
+
+               _duration->SetRange(0, 259200);
+               _duration->SetValue(asset->duration().get_value_or(0));
+
+               intrinsic_duration->SetValue(wxString::Format("%ld", asset->intrinsic_duration()));
+
+               _annotation_text->Bind(wxEVT_TEXT, boost::bind(&AssetPanel::annotation_text_changed, this));
+               _entry_point->Bind(wxEVT_SPINCTRL, boost::bind(&AssetPanel::entry_point_changed, this));
+               _duration->Bind(wxEVT_SPINCTRL, boost::bind(&AssetPanel::duration_changed, this));
+       }
+
+private:
+       void annotation_text_changed()
+       {
+               _asset->set_annotation_text(wx_to_std(_annotation_text->GetValue()));
+       }
+
+       void entry_point_changed()
+       {
+               _asset->set_entry_point(_entry_point->GetValue());
+               auto const fixed_duration = std::min(_asset->intrinsic_duration() - _asset->entry_point().get_value_or(0LL), _asset->duration().get_value_or(_asset->intrinsic_duration()));
+               _duration->SetValue(fixed_duration);
+               _asset->set_duration(fixed_duration);
+       }
+
+       void duration_changed()
+       {
+               _asset->set_duration(_duration->GetValue());
+               auto const fixed_entry_point = std::min(_asset->intrinsic_duration() - _asset->duration().get_value_or(_asset->intrinsic_duration()), _asset->entry_point().get_value_or(0LL));
+               _entry_point->SetValue(fixed_entry_point);
+               _asset->set_entry_point(fixed_entry_point);
+       }
+
+       wxTextCtrl* _annotation_text = nullptr;
+       wxSpinCtrl* _entry_point = nullptr;
+       wxSpinCtrl* _duration = nullptr;
+       shared_ptr<dcp::ReelAsset> _asset;
+};
+
+
+class ReelEditor : public wxDialog
+{
+public:
+       ReelEditor(wxWindow* parent)
+               : wxDialog(parent, wxID_ANY, _("Edit reel"))
+       {
+               auto sizer = new wxBoxSizer(wxVERTICAL);
+               _notebook = new wxNotebook(this, wxID_ANY);
+               sizer->Add(_notebook, wxEXPAND | wxALL, 1, DCPOMATIC_DIALOG_BORDER);
+               SetSizerAndFit(sizer);
+       }
+
+       optional<shared_ptr<dcp::Reel>> get() {
+               return _reel;
+       }
+
+       void set(shared_ptr<dcp::Reel> reel)
+       {
+               _reel = reel;
+
+               _notebook->DeleteAllPages();
+               if (_reel->main_picture()) {
+                       _notebook->AddPage(new AssetPanel(_notebook, _reel->main_picture()), _("Picture"));
+               }
+               if (_reel->main_sound()) {
+                       _notebook->AddPage(new AssetPanel(_notebook, _reel->main_sound()), _("Sound"));
+               }
+               if (_reel->main_subtitle()) {
+                       _notebook->AddPage(new AssetPanel(_notebook, _reel->main_subtitle()), _("Subtitle"));
+               }
+       }
+
+private:
+       wxNotebook* _notebook = nullptr;
+       shared_ptr<dcp::Reel> _reel;
+};
+
+
+class CPLPanel : public wxPanel
+{
+public:
+       CPLPanel(wxWindow* parent, shared_ptr<dcp::CPL> cpl)
+               : wxPanel(parent, wxID_ANY)
+               , _cpl(cpl)
+       {
+               auto sizer = new wxGridBagSizer(DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+
+               int r = 0;
+
+               add_label_to_sizer(sizer, this, _("Annotation text"), true, wxGBPosition(r, 0));
+               _annotation_text = new wxTextCtrl(this, wxID_ANY, std_to_wx(cpl->annotation_text().get_value_or("")), wxDefaultPosition, wxSize(600, -1));
+               sizer->Add(_annotation_text, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Issuer"), true, wxGBPosition(r, 0));
+               _issuer = new wxTextCtrl(this, wxID_ANY, std_to_wx(cpl->issuer()), wxDefaultPosition, wxSize(600, -1));
+               sizer->Add(_issuer, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Creator"), true, wxGBPosition(r, 0));
+               _creator = new wxTextCtrl(this, wxID_ANY, std_to_wx(cpl->creator()), wxDefaultPosition, wxSize(600, -1));
+               sizer->Add(_creator, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Content title text"), true, wxGBPosition(r, 0));
+               _content_title_text = new wxTextCtrl(this, wxID_ANY, std_to_wx(cpl->content_title_text()), wxDefaultPosition, wxSize(600, -1));
+               sizer->Add(_content_title_text, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+               ++r;
+
+               add_label_to_sizer(sizer, this, _("Reels"), true, wxGBPosition(r, 0));
+               _reels = new EditableList<shared_ptr<dcp::Reel>, ReelEditor>(
+                       this,
+                       { EditableListColumn("Name", 600, true) },
+                       [this]() { return _cpl->reels(); },
+                       [this](vector<shared_ptr<dcp::Reel>> reels) {
+                               _cpl->set(reels);
+                       },
+                       [](shared_ptr<dcp::Reel> reel, int) {
+                               return reel->id();
+                       },
+                       false,
+                       EditableListButton::EDIT
+               );
+               sizer->Add(_reels, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND);
+
+               auto space = new wxBoxSizer(wxVERTICAL);
+               space->Add(sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+               SetSizerAndFit(space);
+
+               _annotation_text->Bind(wxEVT_TEXT, boost::bind(&CPLPanel::annotation_text_changed, this));
+               _issuer->Bind(wxEVT_TEXT, boost::bind(&CPLPanel::issuer_changed, this));
+               _creator->Bind(wxEVT_TEXT, boost::bind(&CPLPanel::creator_changed, this));
+               _content_title_text->Bind(wxEVT_TEXT, boost::bind(&CPLPanel::content_title_text_changed, this));
+       }
+
+private:
+       void annotation_text_changed()
+       {
+               _cpl->set_annotation_text(wx_to_std(_annotation_text->GetValue()));
+       }
+
+       void issuer_changed()
+       {
+               _cpl->set_issuer(wx_to_std(_issuer->GetValue()));
+       }
+
+       void creator_changed()
+       {
+               _cpl->set_creator(wx_to_std(_creator->GetValue()));
+       }
+
+       void content_title_text_changed()
+       {
+               _cpl->set_content_title_text(wx_to_std(_content_title_text->GetValue()));
+       }
+
+       std::shared_ptr<dcp::CPL> _cpl;
+       wxTextCtrl* _annotation_text = nullptr;
+       wxTextCtrl* _issuer = nullptr;
+       wxTextCtrl* _creator = nullptr;
+       wxTextCtrl* _content_title_text = nullptr;
+       EditableList<shared_ptr<dcp::Reel>, ReelEditor>* _reels;
+};
+
+
+class DummyPanel : public wxPanel
+{
+public:
+       DummyPanel(wxWindow* parent)
+               : wxPanel(parent, wxID_ANY)
+       {
+               auto sizer = new wxBoxSizer(wxVERTICAL);
+               add_label_to_sizer(sizer, this, _("Open a DCP using File -> Open"), false);
+               auto space = new wxBoxSizer(wxVERTICAL);
+               space->Add(sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
+               SetSizerAndFit(space);
+       }
+};
+
+
+class DOMFrame : public wxFrame
+{
+public:
+       DOMFrame ()
+               : wxFrame(nullptr, -1, _("DCP-o-matic Editor"))
+               , _main_sizer(new wxBoxSizer(wxVERTICAL))
+       {
+               dcpomatic_log = make_shared<NullLog>();
+
+#if defined(DCPOMATIC_WINDOWS)
+               maybe_open_console();
+               std::cout << "DCP-o-matic Editor is starting." << "\n";
+#endif
+
+               auto bar = new wxMenuBar;
+               setup_menu(bar);
+               SetMenuBar(bar);
+
+#ifdef DCPOMATIC_WINDOWS
+               SetIcon(wxIcon(std_to_wx("id")));
+#endif
+
+               Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_open, this), ID_file_open);
+               Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_save, this), ID_file_save);
+               Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_exit, this), wxID_EXIT);
+               Bind(wxEVT_MENU, boost::bind(&DOMFrame::help_about, this), wxID_ABOUT);
+
+               /* Use a panel as the only child of the Frame so that we avoid
+                  the dark-grey background on Windows.
+               */
+               _overall_panel = new wxPanel (this, wxID_ANY);
+
+               auto sizer = new wxBoxSizer(wxVERTICAL);
+
+               _notebook = new wxNotebook(_overall_panel, wxID_ANY);
+               _notebook->AddPage(new DummyPanel(_notebook), _("CPL"));
+
+               sizer->Add(_notebook, 1, wxEXPAND);
+               _overall_panel->SetSizerAndFit(sizer);
+       }
+
+       void load_dcp (boost::filesystem::path path)
+       {
+               _notebook->DeleteAllPages();
+
+               _dcp = dcp::DCP(path);
+               _dcp->read();
+               for (auto cpl: _dcp->cpls()) {
+                       _notebook->AddPage(new CPLPanel(_notebook, cpl), wx_to_std(cpl->annotation_text().get_value_or(cpl->id())));
+               }
+       }
+
+private:
+
+       void setup_menu (wxMenuBar* m)
+       {
+               _file_menu = new wxMenu;
+               _file_menu->Append (ID_file_open, _("&Open...\tCtrl-O"));
+               _file_menu->AppendSeparator ();
+               _file_menu->Append (ID_file_save, _("&Save\tCtrl-S"));
+               _file_menu->AppendSeparator ();
+#ifdef __WXOSX__
+               _file_menu->Append (wxID_EXIT, _("&Exit"));
+#else
+               _file_menu->Append (wxID_EXIT, _("&Quit"));
+#endif
+
+               auto help = new wxMenu;
+#ifdef __WXOSX__
+               help->Append (wxID_ABOUT, _("About DCP-o-matic"));
+#else
+               help->Append (wxID_ABOUT, _("About"));
+#endif
+
+               m->Append (_file_menu, _("&File"));
+               m->Append (help, _("&Help"));
+       }
+
+       void file_open ()
+       {
+               auto d = wxStandardPaths::Get().GetDocumentsDir();
+               auto c = new wxDirDialog (this, _("Select DCP to open"), d, wxDEFAULT_DIALOG_STYLE | wxDD_DIR_MUST_EXIST);
+
+               int r;
+               while (true) {
+                       r = c->ShowModal ();
+                       if (r == wxID_OK && c->GetPath() == wxStandardPaths::Get().GetDocumentsDir()) {
+                               error_dialog (this, _("You did not select a folder.  Make sure that you select a folder before clicking Open."));
+                       } else {
+                               break;
+                       }
+               }
+
+               if (r == wxID_OK) {
+                       boost::filesystem::path const dcp (wx_to_std (c->GetPath ()));
+                       load_dcp (dcp);
+               }
+
+               c->Destroy ();
+       }
+
+       void file_save ()
+       {
+               _dcp->write_xml();
+       }
+
+       void file_exit ()
+       {
+               Close ();
+       }
+
+       void help_about ()
+       {
+               auto d = new AboutDialog (this);
+               d->ShowModal ();
+               d->Destroy ();
+       }
+
+       wxPanel* _overall_panel = nullptr;
+       wxMenu* _file_menu = nullptr;
+       wxSizer* _main_sizer = nullptr;
+       wxNotebook* _notebook = nullptr;
+       optional<dcp::DCP> _dcp;
+};
+
+
+static const wxCmdLineEntryDesc command_line_description[] = {
+       { wxCMD_LINE_PARAM, 0, 0, "DCP to edit", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
+       { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 }
+};
+
+
+/** @class App
+ *  @brief The magic App class for wxWidgets.
+ */
+class App : public wxApp
+{
+public:
+       App ()
+               : wxApp ()
+       {
+#ifdef DCPOMATIC_LINUX
+               XInitThreads ();
+#endif
+       }
+
+private:
+
+       bool OnInit () override
+       {
+               wxSplashScreen* splash = nullptr;
+               try {
+                       wxInitAllImageHandlers ();
+
+                       splash = maybe_show_splash ();
+
+                       SetAppName (_("DCP-o-matic Editor"));
+
+                       if (!wxApp::OnInit()) {
+                               return false;
+                       }
+
+#ifdef DCPOMATIC_LINUX
+                       unsetenv ("UBUNTU_MENUPROXY");
+#endif
+
+#ifdef DCPOMATIC_OSX
+                       make_foreground_application ();
+#endif
+
+                       dcpomatic_setup_path_encoding ();
+
+                       /* Enable i18n; this will create a Config object
+                          to look for a force-configured language.  This Config
+                          object will be wrong, however, because dcpomatic_setup
+                          hasn't yet been called and there aren't any filters etc.
+                          set up yet.
+                       */
+                       dcpomatic_setup_i18n ();
+
+                       /* Set things up, including filters etc.
+                          which will now be internationalised correctly.
+                       */
+                       dcpomatic_setup ();
+
+                       signal_manager = new wxSignalManager (this);
+
+                       _frame = new DOMFrame ();
+                       SetTopWindow (_frame);
+                       _frame->Maximize ();
+                       if (splash) {
+                               splash->Destroy ();
+                               splash = nullptr;
+                       }
+                       _frame->Show ();
+
+                       if (_dcp_to_load) {
+                               _frame->load_dcp(*_dcp_to_load);
+                       }
+
+                       Bind (wxEVT_IDLE, boost::bind (&App::idle, this));
+               }
+               catch (exception& e)
+               {
+                       if (splash) {
+                               splash->Destroy ();
+                       }
+                       error_dialog (0, _("DCP-o-matic Editor could not start."), std_to_wx(e.what()));
+               }
+
+               return true;
+       }
+
+       void OnInitCmdLine (wxCmdLineParser& parser) override
+       {
+               parser.SetDesc (command_line_description);
+               parser.SetSwitchChars (wxT ("-"));
+       }
+
+       bool OnCmdLineParsed (wxCmdLineParser& parser) override
+       {
+               if (parser.GetParamCount() > 0) {
+                       _dcp_to_load = wx_to_std(parser.GetParam(0));
+               }
+
+               return true;
+       }
+
+       void report_exception ()
+       {
+               try {
+                       throw;
+               } catch (FileError& e) {
+                       error_dialog (
+                               0,
+                               wxString::Format (
+                                       _("An exception occurred: %s (%s)\n\n") + REPORT_PROBLEM,
+                                       std_to_wx (e.what()),
+                                       std_to_wx (e.file().string().c_str ())
+                                       )
+                               );
+               } catch (exception& e) {
+                       error_dialog (
+                               0,
+                               wxString::Format (
+                                       _("An exception occurred: %s.\n\n") + REPORT_PROBLEM,
+                                       std_to_wx (e.what ())
+                                       )
+                               );
+               } catch (...) {
+                       error_dialog (0, _("An unknown exception occurred.") + "  " + REPORT_PROBLEM);
+               }
+       }
+
+       /* An unhandled exception has occurred inside the main event loop */
+       bool OnExceptionInMainLoop () override
+       {
+               report_exception ();
+               /* This will terminate the program */
+               return false;
+       }
+
+       void OnUnhandledException () override
+       {
+               report_exception ();
+       }
+
+       void idle ()
+       {
+               signal_manager->ui_idle ();
+       }
+
+       DOMFrame* _frame = nullptr;
+       optional<boost::filesystem::path> _dcp_to_load;
+};
+
+
+IMPLEMENT_APP (App)
index bb3798aa70cdfba5bb03736eaa12c4c799df310f..be5297beb06e8cee0f1ac1f6acf73fc49ca905dd 100644 (file)
@@ -62,7 +62,7 @@ def build(bld):
 
     gui_tools = []
     if not bld.env.DISABLE_GUI:
-        gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist', 'dcpomatic_combiner']
+        gui_tools = ['dcpomatic', 'dcpomatic_batch', 'dcpomatic_server', 'dcpomatic_kdm', 'dcpomatic_player', 'dcpomatic_playlist', 'dcpomatic_combiner', 'dcpomatic_editor']
         if bld.env.ENABLE_DISK:
             gui_tools.append('dcpomatic_disk')