]> www.vanbest.org Git - motioneye-debian/commitdiff
added modal dialog functionality
authorCalin Crisan <ccrisan@gmail.com>
Sat, 5 Oct 2013 10:46:31 +0000 (13:46 +0300)
committerCalin Crisan <ccrisan@gmail.com>
Sat, 5 Oct 2013 10:46:31 +0000 (13:46 +0300)
14 files changed:
artwork/top-bar-buttons.svg [new file with mode: 0644]
artwork/video-buttons.svg [deleted file]
doc/colors.txt
doc/todo.txt
motioneye.py
src/config.py
src/handlers.py
static/css/main.css
static/css/ui.css
static/img/top-bar-buttons.png [new file with mode: 0644]
static/img/video-buttons.png [deleted file]
static/js/main.js
static/js/ui.js
templates/main.html

diff --git a/artwork/top-bar-buttons.svg b/artwork/top-bar-buttons.svg
new file mode 100644 (file)
index 0000000..cc54fdc
--- /dev/null
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="32"
+   height="16"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="top-bar-buttons.svg"
+   inkscape:export-filename="/media/data/projects/motioneye/static/img/top-bar-buttons.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="5.1832676"
+     inkscape:cy="-1.5026033"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1027"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="1"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-nodes="true"
+     inkscape:bbox-paths="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     inkscape:object-paths="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-center="true"
+     inkscape:snap-page="true"
+     inkscape:snap-intersection-paths="true"
+     showguides="true"
+     inkscape:guide-bbox="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" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-1036.3622)">
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#3498db;stroke-width:0.84620845000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path3752"
+       sodipodi:cx="7.8036885"
+       sodipodi:cy="8.2353296"
+       sodipodi:rx="5.6186557"
+       sodipodi:ry="5.3845448"
+       d="m 13.422344,8.2353296 c 0,2.9738024 -2.515558,5.3845444 -5.6186555,5.3845444 -3.1030978,0 -5.6186557,-2.410742 -5.6186557,-5.3845444 0,-2.973802 2.5155579,-5.3845448 5.6186557,-5.3845448 3.1030975,0 5.6186555,2.4107428 5.6186555,5.3845448 z"
+       transform="matrix(1.1568604,0,0,1.2071587,-1.0277779,1034.4208)" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+       d="m 5.5,5.5 5,5"
+       id="path3756"
+       inkscape:connector-curvature="0"
+       transform="translate(0,1036.3622)"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3758"
+       d="m 10.5,1041.8622 -5,5"
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+    <path
+       sodipodi:type="arc"
+       style="fill:none;stroke:#3498db;stroke-width:0.84620845000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="path3792"
+       sodipodi:cx="7.8036885"
+       sodipodi:cy="8.2353296"
+       sodipodi:rx="5.6186557"
+       sodipodi:ry="5.3845448"
+       d="m 13.422344,8.2353296 c 0,2.9738024 -2.515558,5.3845444 -5.6186555,5.3845444 -3.1030978,0 -5.6186557,-2.410742 -5.6186557,-5.3845444 0,-2.973802 2.5155579,-5.3845448 5.6186557,-5.3845448 3.1030975,0 5.6186555,2.4107428 5.6186555,5.3845448 z"
+       transform="matrix(-1.1568604,0,0,1.2071587,33.027778,1034.4209)" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3794"
+       d="m 21.5,1046.8622 3,-3"
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+       d="m 24.5,1043.8622 0,-2"
+       id="path3796"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3798"
+       d="m 24.5,1043.8622 2,0"
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+       d="m 27.5,1042.8622 -1,1"
+       id="path3800"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3802"
+       d="m 25.5,1040.8622 -1,1"
+       style="fill:none;stroke:#3498db;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
+    <path
+       transform="matrix(1.1568604,0,0,1.2071587,-1.0277779,1054.4208)"
+       d="m 13.422344,8.2353296 c 0,2.9738024 -2.515558,5.3845444 -5.6186555,5.3845444 -3.1030978,0 -5.6186557,-2.410742 -5.6186557,-5.3845444 0,-2.973802 2.5155579,-5.3845448 5.6186557,-5.3845448 3.1030975,0 5.6186555,2.4107428 5.6186555,5.3845448 z"
+       sodipodi:ry="5.3845448"
+       sodipodi:rx="5.6186557"
+       sodipodi:cy="8.2353296"
+       sodipodi:cx="7.8036885"
+       id="path3816"
+       style="fill:none;stroke:#3498db;stroke-width:0.84620845000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3818"
+       d="m 5.5,1061.8622 5,5"
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 10.5,1061.8622 -5,5"
+       id="path3820"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       transform="matrix(-1.1568604,0,0,1.2071587,33.027778,1054.4209)"
+       d="m 13.422344,8.2353296 c 0,2.9738024 -2.515558,5.3845444 -5.6186555,5.3845444 -3.1030978,0 -5.6186557,-2.410742 -5.6186557,-5.3845444 0,-2.973802 2.5155579,-5.3845448 5.6186557,-5.3845448 3.1030975,0 5.6186555,2.4107428 5.6186555,5.3845448 z"
+       sodipodi:ry="5.3845448"
+       sodipodi:rx="5.6186557"
+       sodipodi:cy="8.2353296"
+       sodipodi:cx="7.8036885"
+       id="path3822"
+       style="fill:none;stroke:#3498db;stroke-width:0.84620845000000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       sodipodi:type="arc" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 22,1066.3622 2,-2"
+       id="path3824"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3826"
+       d="m 24,1064.3622 0,-2"
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 24,1064.3622 2,0"
+       id="path3828"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path3830"
+       d="m 27,1063.3622 -1,1"
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+    <path
+       style="fill:none;stroke:#3498db;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       d="m 25,1061.3622 -1,1"
+       id="path3832"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>
diff --git a/artwork/video-buttons.svg b/artwork/video-buttons.svg
deleted file mode 100644 (file)
index f9a4aad..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="32"
-   height="16"
-   id="svg2"
-   version="1.1"
-   inkscape:version="0.48.4 r9939"
-   sodipodi:docname="video-buttons.svg"
-   inkscape:export-filename="/media/data/projects/motioneye/static/img/validation-error.png"
-   inkscape:export-xdpi="90"
-   inkscape:export-ydpi="90">
-  <defs
-     id="defs4" />
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="1"
-     inkscape:cx="39.954578"
-     inkscape:cy="-30.616453"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     showgrid="false"
-     inkscape:window-width="1920"
-     inkscape:window-height="1027"
-     inkscape:window-x="0"
-     inkscape:window-y="25"
-     inkscape:window-maximized="1"
-     inkscape:snap-bbox="true"
-     inkscape:bbox-nodes="true"
-     inkscape:bbox-paths="true"
-     inkscape:snap-bbox-edge-midpoints="true"
-     inkscape:snap-bbox-midpoints="true"
-     inkscape:object-paths="true"
-     inkscape:object-nodes="true"
-     inkscape:snap-smooth-nodes="true"
-     inkscape:snap-midpoints="true"
-     inkscape:snap-object-midpoints="true"
-     inkscape:snap-center="true"
-     inkscape:snap-page="true"
-     inkscape:snap-intersection-paths="true"
-     showguides="true"
-     inkscape:guide-bbox="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" />
-        <dc:title />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(0,-1036.3622)">
-    <path
-       sodipodi:type="arc"
-       style="fill:none;stroke:#000000;stroke-width:0.84620845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       id="path3752"
-       sodipodi:cx="7.8036885"
-       sodipodi:cy="8.2353296"
-       sodipodi:rx="5.6186557"
-       sodipodi:ry="5.3845448"
-       d="m 13.422344,8.2353296 a 5.6186557,5.3845448 0 1 1 -11.2373112,0 5.6186557,5.3845448 0 1 1 11.2373112,0 z"
-       transform="matrix(1.1568604,0,0,1.2071587,-1.0277779,1034.4208)" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
-       d="m 5.5,5.5 5,5"
-       id="path3756"
-       inkscape:connector-curvature="0"
-       transform="translate(0,1036.3622)"
-       sodipodi:nodetypes="cc" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3758"
-       d="m 10.5,1041.8622 -5,5"
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
-    <path
-       sodipodi:type="arc"
-       style="fill:none;stroke:#000000;stroke-width:0.84620845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       id="path3792"
-       sodipodi:cx="7.8036885"
-       sodipodi:cy="8.2353296"
-       sodipodi:rx="5.6186557"
-       sodipodi:ry="5.3845448"
-       d="m 13.422344,8.2353296 a 5.6186557,5.3845448 0 1 1 -11.2373112,0 5.6186557,5.3845448 0 1 1 11.2373112,0 z"
-       transform="matrix(-1.1568604,0,0,1.2071587,33.027778,1034.4209)" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3794"
-       d="m 21.5,1046.8622 3,-3"
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
-       d="m 24.5,1043.8622 0,-2"
-       id="path3796"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3798"
-       d="m 24.5,1043.8622 2,0"
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
-       d="m 27.5,1042.8622 -1,1"
-       id="path3800"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3802"
-       d="m 25.5,1040.8622 -1,1"
-       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
-    <path
-       transform="matrix(1.1568604,0,0,1.2071587,-1.0277779,1054.4208)"
-       d="m 13.422344,8.2353296 a 5.6186557,5.3845448 0 1 1 -11.2373112,0 5.6186557,5.3845448 0 1 1 11.2373112,0 z"
-       sodipodi:ry="5.3845448"
-       sodipodi:rx="5.6186557"
-       sodipodi:cy="8.2353296"
-       sodipodi:cx="7.8036885"
-       id="path3816"
-       style="fill:none;stroke:#000000;stroke-width:0.84620845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       sodipodi:type="arc" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3818"
-       d="m 5.5,1061.8622 5,5"
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
-       d="m 10.5,1061.8622 -5,5"
-       id="path3820"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       transform="matrix(-1.1568604,0,0,1.2071587,33.027778,1054.4209)"
-       d="m 13.422344,8.2353296 a 5.6186557,5.3845448 0 1 1 -11.2373112,0 5.6186557,5.3845448 0 1 1 11.2373112,0 z"
-       sodipodi:ry="5.3845448"
-       sodipodi:rx="5.6186557"
-       sodipodi:cy="8.2353296"
-       sodipodi:cx="7.8036885"
-       id="path3822"
-       style="fill:none;stroke:#000000;stroke-width:0.84620845;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       sodipodi:type="arc" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       d="m 22,1066.3622 2,-2"
-       id="path3824"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3826"
-       d="m 24,1064.3622 0,-2"
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       d="m 24,1064.3622 2,0"
-       id="path3828"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-    <path
-       sodipodi:nodetypes="cc"
-       inkscape:connector-curvature="0"
-       id="path3830"
-       d="m 27,1063.3622 -1,1"
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
-    <path
-       style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
-       d="m 25,1061.3622 -1,1"
-       id="path3832"
-       inkscape:connector-curvature="0"
-       sodipodi:nodetypes="cc" />
-  </g>
-</svg>
index da654b0b0b4df3e95865c4501e8169bae2d9eada..cc6fa2be82d56cd8651073f983cb46398e4657ff 100644 (file)
@@ -7,5 +7,5 @@ normal-text: #dddddd (86%)
 focused-text: #ffffff (100%)
 
 action-text: #3498db
-action-border-unfocused: #2A6C96
+action-border-unfocused: #317CAD
 action-border-focused: #3498db
index e4302cddadaa35011a0aef67b346a9d559d5a506..52385e1966af7a40c245899706af905613002473 100644 (file)
@@ -1,3 +1,7 @@
+-> make camera frames positions configurable
+-> hide horrible 404 image on cameras
+-> prevent Request closed errors by stopping mjpg clients before stopping motion
+-> network server storage should only be enabled on special devices (rpi)
 -> camera not available background and icon design
 -> remove current snapshot GET logs
 -> add a motion running status indicator (and maybe a start/stop button)
index b6a793874d0b1ba3a04e21b79ae38f943907fec7..8e45f1000bb62ab86d14b700d8902be86e620b1e 100644 (file)
@@ -48,7 +48,7 @@ def _start_server():
 
 
 def _start_motion():
-    if not motionctl.running() and len(config.get_enabled_cameras()) > 0:
+    if not motionctl.running() and config.has_enabled_cameras():
         motionctl.start()
         logging.info('motion started')
 
index 4f2fbf670be56eabfaf53e68b38bf43776f3b205..52d10285919cc283a9926438ed5a7ce692d5e295 100644 (file)
@@ -136,10 +136,13 @@ def get_camera_ids():
     return camera_ids
 
 
-def get_enabled_cameras():
+def has_enabled_cameras():
+    if not get_main().get('@enabled'):
+        return False
+    
     camera_ids = get_camera_ids()
     cameras = [get_camera(camera_id) for camera_id in camera_ids]
-    return [c for c in cameras if c['@enabled']]
+    return bool([c for c in cameras if c['@enabled']])
 
 
 def get_camera(camera_id, as_lines=False):
@@ -515,6 +518,7 @@ def _set_default_motion_camera(data):
     data.setdefault('quality', 75)
     data.setdefault('@preserve_images', 0)
     
+    data.setdefault('motion_movies', False)
     data.setdefault('ffmpeg_variable_bitrate', 14)
     data.setdefault('movie_filename', '')
     data.setdefault('ffmpeg_cap_new', False)
index baedcd785cf2975c4812bf400d5c945f51ff8a4d..3127648d6d65921a43b1db6ec0137f942956fed3 100644 (file)
@@ -146,7 +146,7 @@ class ConfigHandler(BaseHandler):
         
         finally:
             if restart:
-                if len(config.get_enabled_cameras()) > 0:
+                if config.has_enabled_cameras():
                     motionctl.start()
 
     def set_preview(self, camera_id):
index 4d65e15c6d2ea135ece2ca97eae773004c115bef..2bfd409e8b04c65a6b43d61a3a87f08ab0cc6c47 100644 (file)
@@ -43,6 +43,7 @@ div.page,
 div.header-container {
     position: relative;
     min-width: 320px;
+    min-height: 60px;
     width: 100%;
 }
 
@@ -252,14 +253,6 @@ div.check-box.section {
     float: left;
 }
 
-div.check-box.section div.check-box-button {
-    background-color: #515151;
-}
-
-div.check-box.on.section div.check-box-button {
-    background-color: #3498db;
-}
-
 input[type=text].working-schedule.number {
     width: 50px;
 }
@@ -305,19 +298,15 @@ div.camera-button {
     display: inline-block;
     width: 16px;
     height: 16px;
-    background-image: url(../img/video-buttons.png);
+    background-image: url(../img/top-bar-buttons.png);
     margin-left: 3px;
     cursor: pointer;
-    opacity: 0.7;
-    transition: all 0.1s linear;
-}
-
-div.camera-button:HOVER {
     opacity: 1;
+    transition: all 0.1s linear;
 }
 
 div.camera-button:ACTIVE {
-    opacity: 0.5;
+    opacity: 0.6;
 }
 
 div.camera-button.close {
index 97afe28827b75911605e75030e66901deb3a3dc3..3fcc012945f61e5ed0916be6fd99ac398e4db1b0 100644 (file)
@@ -18,7 +18,7 @@ input[type=checkbox].styled {
 }
 
 
-    /* button */
+    /* buttons */
 
 div.button {
     -webkit-user-select: none;
@@ -27,6 +27,43 @@ div.button {
     cursor: pointer;    
 }
 
+div.button.dialog {
+    display: inline-block;
+    background-color: #414141;
+    min-width: 60px;
+    height: 1.2em;
+    line-height: 1.2em;
+    text-align: center;
+    padding: 0.2em 0.4em;
+    border: 1px solid #317CAD;
+    border-radius: 2px;
+    color: white;
+    transition: all 0.1s linear;
+}
+
+div.button.dialog:FOCUS,
+div.button.dialog:HOVER {
+    border: 1px solid #3498db;
+    background-color: #515151;
+}
+
+div.button.dialog:ACTIVE {
+    background-color: #414141;
+}
+
+div.button.dialog.default {
+    background-color: #317CAD;
+}
+
+div.button.dialog.default:FOCUS,
+div.button.dialog.default:HOVER {
+    background-color: #3498db;
+}
+
+div.button.dialog.default:ACTIVE {
+    background-color: #317CAD;
+}
+
 
     /* check box */
 
@@ -35,7 +72,7 @@ div.check-box {
     position: relative;
     width: 2.5em;
     height: 1em;
-    border: 1px solid #2A6C96;
+    border: 1px solid #317CAD;
     border-radius: 2px;
     color: #aaaaaa;
     vertical-align: middle;
@@ -72,17 +109,22 @@ span.check-box-text {
 
 div.check-box.on div.check-box-button {
     left: 50%;
-    background-color: #3498db;
+    background-color: #317CAD;
     color: white;
 }
 
+div.check-box.on:FOCUS div.check-box-button,
+div.check-box.on:HOVER div.check-box-button {
+    background-color: #3498db;
+}
+
 
     /* input box */
 
 input[type=password].styled,
 input[type=text].styled {
     width: 90%;
-    border: 1px solid #2A6C96;
+    border: 1px solid #317CAD;
     border-radius: 2px;
     background-color: transparent;
     padding: 1px;
@@ -128,7 +170,7 @@ select.styled {
     -webkit-appearance: none;
     appearance: none;
     width: 90%;
-    border: 1px solid #2A6C96;
+    border: 1px solid #317CAD;
     border-radius: 2px;
     background-color: transparent;
     padding: 1px 1.25em 1px 1px;
@@ -198,7 +240,7 @@ div.slider-bar {
 }
 
 div.slider-bar-inside {
-    border: 1px solid #2A6C96;
+    border: 1px solid #317CAD;
     height: 3px;
     position: relative;
     top: 3px;
@@ -226,6 +268,75 @@ div.slider-cursor {
 }
 
 
+    /* modal dialogs */
+    
+div.modal-glass {
+    display: none;
+    position: fixed;
+    z-index: 10000;
+    top: 0px;
+    right: 0px;
+    bottom: 0px;
+    left: 0px;
+    background-color: black;
+    opacity: 0;
+}
+
+div.modal-container {
+    position: fixed;
+    display: none;
+    z-index: 10001;
+    background-color: #313131;
+    border-radius: 3px;
+    opacity: 0;
+    padding: 5px;
+    box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
+}
+
+div.modal-title-bar {
+    height: 1.5em;
+    line-height: 1.5em;
+    text-align: center;
+    position: relative;
+}
+
+span.modal-title {
+    color: white;
+}
+
+div.modal-close-button {
+    position: absolute;
+    top: 0.3em;
+    right: 0.3em;
+    width: 16px;
+    height: 16px;
+    background-image: url(../img/top-bar-buttons.png);
+    opacity: 1;
+    transition: all 0.1s linear;
+    cursor: pointer;
+}
+
+div.modal-close-button:ACTIVE {
+    opacity: 0.6;
+}
+
+table.modal-buttons-container {
+    width: 100%;
+    text-align: center;
+    -webkit-user-select: none;
+    -moz-user-select: none;
+    user-select: none;
+}
+
+table.modal-buttons-container td:not(:FIRST-CHILD) {
+    padding-left: 5px;
+}
+
+table.modal-buttons-container div.button.dialog {
+    display: block;
+}
+
+
     /* misc */
 
 span.help-mark {
diff --git a/static/img/top-bar-buttons.png b/static/img/top-bar-buttons.png
new file mode 100644 (file)
index 0000000..871543b
Binary files /dev/null and b/static/img/top-bar-buttons.png differ
diff --git a/static/img/video-buttons.png b/static/img/video-buttons.png
deleted file mode 100644 (file)
index d27d5e4..0000000
Binary files a/static/img/video-buttons.png and /dev/null differ
index 526b9f8ba2c74ef47ec45fa4c94b9309dbe6bb85..7874cd7e90c46ae0692d264560d72de26b3bba10 100644 (file)
@@ -113,7 +113,7 @@ Array.prototype.map = function (func, thisArg) {
 };
 
 
-    /* UI */
+    /* UI initialization */
 
 function initUI() {
     /* checkboxes */
@@ -234,6 +234,10 @@ function initUI() {
         
         doApply();
     });
+    
+    /* whenever the window is resized,
+     * if a modal dialog is visible, it should be repositioned */
+    $(window).resize(updateModalDialogPosition);
 }
 
 
@@ -711,24 +715,24 @@ function fetchCurrentConfig() {
     /* fetch the main configuration */
     ajax('GET', '/config/main/get/', null, function (data) {
         dict2MainUi(data);
-    });
-    
-    /* fetch the camera list */
-    ajax('GET', '/config/list/', null, function (data) {
-        var i, cameras = data.cameras;
-        var videoDeviceSelect = $('#videoDeviceSelect');
-        videoDeviceSelect.html('');
-        for (i = 0; i < cameras.length; i++) {
-            var camera = cameras[i];
-            videoDeviceSelect.append('<option value="' + camera['id'] + '">' + camera['name'] + '</option>');
-        }
-        
-        if (cameras.length) {
-            videoDeviceSelect[0].selectedIndex = 0;
-            fetchCurrentCameraConfig();
-        }
-        
-        recreateCameraFrames(cameras);
+
+        /* fetch the camera list */
+        ajax('GET', '/config/list/', null, function (data) {
+            var i, cameras = data.cameras;
+            var videoDeviceSelect = $('#videoDeviceSelect');
+            videoDeviceSelect.html('');
+            for (i = 0; i < cameras.length; i++) {
+                var camera = cameras[i];
+                videoDeviceSelect.append('<option value="' + camera['id'] + '">' + camera['name'] + '</option>');
+            }
+            
+            if (cameras.length) {
+                videoDeviceSelect[0].selectedIndex = 0;
+                fetchCurrentCameraConfig();
+            }
+            
+            recreateCameraFrames(cameras);
+        });
     });
 }
 
@@ -866,6 +870,11 @@ function remCameraFrameUi(cameraId) {
 }
 
 function recreateCameraFrames(cameras) {
+    /* if motioneye is globally disabled, we remove all the camera frames */;
+    if (!$('#motionEyeSwitch')[0].checked) {
+        cameras = [];
+    }
+    
     var pageContainer = $('div.page-container');
     
     function updateCameras(cameras) {
index 463fbe52921d756010efa5ac0c4fade7563ec186..0b2eaaba02e46825b1140f44ff0c14d626967097 100644 (file)
@@ -1,4 +1,7 @@
 
+
+    /* UI widgets */
+
 function makeCheckBox($input) {
     var mainDiv = $('<div class="check-box"></div>');
     var buttonDiv = $('<div class="check-box-button"></div>');
@@ -223,6 +226,9 @@ function makeSlider($input, minVal, maxVal, snapMode, ticks, ticksNumber, decima
     return slider;
 }
 
+
+    /* validators */
+
 function makeTextValidator($input, required) {
     if (required == null) {
         required = true;
@@ -392,3 +398,203 @@ function makeTimeValidator($input) {
     $input.addClass('time-validator');
     $input[0].validate = validate;
 }
+
+
+    /* modal dialog */
+
+function showModalDialog(content, onClose) {
+    var glass = $('div.modal-glass');
+    var container = $('div.modal-container');
+    
+    glass.css('display', 'block');
+    glass.animate({'opacity': '0.7'}, 200);
+    
+    container[0]._onClose = onClose; /* remember the onClose handler */
+    container.html(content);
+    
+    container.css('display', 'block');
+    updateModalDialogPosition();
+    container.animate({'opacity': '1'}, 200);
+}
+
+function hideModalDialog() {
+    var glass = $('div.modal-glass');
+    var container = $('div.modal-container');
+    
+    glass.animate({'opacity': '0'}, 200, function () {
+        glass.css('display', 'none');
+    });
+    
+    container.animate({'opacity': '0'}, 200, function () {
+        container.css('display', 'none');
+        container.html('');
+    });
+    
+    /* run the onClose handler, if supplied */
+    if (container[0]._onClose) {
+        container[0]._onClose();
+    }
+}
+
+function updateModalDialogPosition() {
+    var container = $('div.modal-container');
+    if (!container.is(':visible')) {
+        return;
+    }
+    
+    var windowWidth = $(window).width();
+    var windowHeight = $(window).height();
+    var modalWidth = container.width();
+    var modalHeight = container.width();
+    
+    container.css('left', (windowWidth - modalWidth) / 2);
+    container.css('top', (windowHeight - modalHeight) / 2);
+}
+
+function makeModalDialogButtons(buttonsInfo) {
+    /* buttonsInfo is an array of:
+     * * caption: String
+     * * isDefault: Boolean
+     * * click: Function
+     */
+    
+    var buttonsContainer = $('<table class="modal-buttons-container"><tr></tr></table>');
+    var tr = buttonsContainer.find('tr');
+    
+    buttonsInfo.forEach(function (info) {
+        var buttonDiv = $('<div class="button dialog"></div>');
+        
+        buttonDiv.click(hideModalDialog); /* every button closes the dialog */
+        buttonDiv.attr('tabIndex', '0'); /* make button focusable */
+        buttonDiv.html(info.caption);
+        
+        if (info.isDefault) {
+            buttonDiv.addClass('default');
+        }
+        
+        if (info.click) {
+            buttonDiv.click(info.click);
+        }
+        
+        var td = $('<td></td>');
+        td.append(buttonDiv);
+        tr.append(td);
+    });
+    
+    return buttonsContainer;
+}
+
+function makeModalDialogTitleBar(options) {
+    /* available options:
+     * * title: String
+     * * closeButton: Boolean
+     */
+    
+    var titleBar = $('<div class="modal-title-bar"></div>');
+    
+    var titleSpan = $('<span class="modal-title"></span>');
+    titleSpan.html(options.title || '');
+    
+    titleBar.append(titleSpan);
+    
+    if (options.closeButton) {
+        var closeButton = $('<div class="modal-close-button" title="close"></div>');
+        closeButton.click(hideModalDialog);
+        titleBar.append(closeButton);
+    }
+    
+    return titleBar;
+}
+
+function runModalDialog(options) {
+    /* available options:
+     * * title: String
+     * * closeButton: Boolean
+     * * content: any
+     * * buttons: 'yesno'|'okcancel'|Array
+     * * onYes: Function
+     * * onNo: Function
+     * * onOk: Function
+     * * onCancel: Function
+     * * onClose: Function
+     */
+    
+    var content = $('<div></div>');
+    var titleBar = null;
+    var buttonsDiv = null;
+    var defaultClick = null;
+    
+    /* add title bar */
+    if (options.title) {
+        titleBar = makeModalDialogTitleBar({title: options.title, closeButton: options.closeButton});
+        content.append(titleBar);
+    }
+    
+    /* add supplied content */
+    if (options.content) {
+        content.append(options.content);
+    }
+    
+    /* add buttons */
+    if (options.buttons === 'yesno') {
+        options.buttons = [
+            {caption: 'No', click: options.onNo},
+            {caption: 'Yes', isDefault: true, click: options.onYes}
+        ];
+    }
+    else if (options.buttons === 'okcancel') {
+        options.buttons = [
+            {caption: 'Cancel', click: options.onCancel},
+            {caption: 'OK', isDefault: true, click: options.onOk}
+        ];
+    }
+    
+    if (options.buttons) {
+        buttonsDiv = makeModalDialogButtons(options.buttons);
+        content.append(buttonsDiv);
+        
+        options.buttons.forEach(function (info) {
+            if (info.isDefault) {
+                defaultClick = info.click;
+            }
+        });
+    }
+    
+    if ((buttonsDiv || options.content) && titleBar) {
+        titleBar.css('margin-bottom', '5px');
+    }
+    
+    var handleKeyUp = function (e) {
+        switch (e.which) {
+            case 13:
+                if (defaultClick) {
+                    defaultClick();
+                }
+                /* intentionally no break */
+           
+            case 27:
+                hideModalDialog();
+        }
+    };
+    
+    var onClose = function () {
+        if (options.onClose) {
+            options.onClose();
+        }
+        
+        /* unbind html handlers */
+        
+        $('html').unbind('keyup', handleKeyUp);
+    };
+    
+    /* bind key handlers */
+    $('html').bind('keyup', handleKeyUp);
+    
+    /* and finally, show the dialog */
+    showModalDialog(content, onClose);
+    
+    /* focus the default button if nothing else is focused */
+    if (content.find('*:focus').length === 0) {
+        content.find('div.button.default').focus();
+    }
+}
index 04bf770888118d1b502f1ccad05727d56ffc44b5..5d07a3d7ac795363b565ec6e0d8d7521b2426ba6 100644 (file)
                                 <option value="180">180&deg;</option>
                                 <option value="270">270&deg;</option>
                             </select>
-                            <td><span class="help-mark" title="use this to rotate the captured image, if your camera is not positioned correctly">?</span></td>
                         </td>
+                        <td><span class="help-mark" title="use this to rotate the captured image, if your camera is not positioned correctly">?</span></td>
                     </tr>
                     <tr class="settings-item advanced-setting">
                         <td class="settings-item-label"><span class="settings-item-label">Frame Rate</span></td>
             copyright &copy; Calin Crisan 2013
         </div> 
     </div>
+    <div class="modal-glass"></div>
+    <div class="modal-container"></div>
 {% endblock %}