diff --git a/openslides/core/config.py b/openslides/core/config.py
index 939a92fd3..d1989da8e 100644
--- a/openslides/core/config.py
+++ b/openslides/core/config.py
@@ -4,13 +4,15 @@ from django.utils.translation import ugettext as _
from .exceptions import ConfigError, ConfigNotFound
from .models import ConfigStore
+# remove resolution when changing to multiprojector
INPUT_TYPE_MAPPING = {
'string': str,
'text': str,
'integer': int,
'boolean': bool,
'choice': str,
- 'colorpicker': str}
+ 'colorpicker': str,
+ 'resolution': dict}
class ConfigHandler:
@@ -86,6 +88,16 @@ class ConfigHandler:
except DjangoValidationError as e:
raise ConfigError(e.messages[0])
+ # remove this block when changing to multiprojector
+ if config_variable.input_type == 'resolution':
+ if value.get('width') is None or value.get('height') is None:
+ raise ConfigError(_('A width and a height have to be given.'))
+ if not isinstance(value['width'], int) or not isinstance(value['height'], int):
+ raise ConfigError(_('Data has to be integers.'))
+ if (value['width'] < 800 or value['width'] > 3840 or
+ value['height'] < 600 or value['height'] > 2160):
+ raise ConfigError(_('The Resolution have to be between 800x600 and 3840x2160.'))
+
# Save the new value to the database.
ConfigStore.objects.update_or_create(key=key, defaults={'value': value})
diff --git a/openslides/core/config_variables.py b/openslides/core/config_variables.py
index 3e5a3e170..60c952d3c 100644
--- a/openslides/core/config_variables.py
+++ b/openslides/core/config_variables.py
@@ -155,3 +155,12 @@ def get_config_variables():
label='Default countdown',
weight=185,
group='Projector')
+
+ # set the resolution for one projector. It can be removed with the multiprojector feature.
+ yield ConfigVariable(
+ name='projector_resolution',
+ default_value={'width': 1024, 'height': 768},
+ input_type='resolution',
+ label='Projector Resolution',
+ weight=200,
+ group='Projector')
diff --git a/openslides/core/migrations/0004_projector_resolution.py b/openslides/core/migrations/0004_projector_resolution.py
new file mode 100644
index 000000000..7d2417784
--- /dev/null
+++ b/openslides/core/migrations/0004_projector_resolution.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.9 on 2016-08-25 11:56
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0003_auto_20160815_1911'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='projector',
+ name='height',
+ field=models.PositiveIntegerField(default=768),
+ ),
+ migrations.AddField(
+ model_name='projector',
+ name='width',
+ field=models.PositiveIntegerField(default=1024),
+ ),
+ ]
diff --git a/openslides/core/models.py b/openslides/core/models.py
index 107cb4506..f93dcbfd6 100644
--- a/openslides/core/models.py
+++ b/openslides/core/models.py
@@ -66,6 +66,11 @@ class Projector(RESTModelMixin, models.Model):
scroll = models.IntegerField(default=0)
+ # currently unused, but important for the multiprojector.
+ width = models.PositiveIntegerField(default=1024)
+
+ height = models.PositiveIntegerField(default=768)
+
class Meta:
"""
Contains general permissions that can not be placed in a specific app.
diff --git a/openslides/core/serializers.py b/openslides/core/serializers.py
index 39dfd971a..5adac0e20 100644
--- a/openslides/core/serializers.py
+++ b/openslides/core/serializers.py
@@ -30,7 +30,7 @@ class ProjectorSerializer(ModelSerializer):
class Meta:
model = Projector
- fields = ('id', 'config', 'elements', 'scale', 'scroll', )
+ fields = ('id', 'config', 'elements', 'scale', 'scroll', 'width', 'height',)
class CustomSlideSerializer(ModelSerializer):
diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css
index 266781896..e49f37135 100644
--- a/openslides/core/static/css/app.css
+++ b/openslides/core/static/css/app.css
@@ -322,6 +322,14 @@ img {
margin-left: 20px;
}
+/* .resolution can be removed with the multiprojector, but maybe
+ * it could be reused for the settings in the projectormanage-view */
+.col1 .input-group .resolution {
+ float: none;
+ display: inline-block;
+ width: 80px;
+ border-radius: 4px !important;
+}
/* Toolbar to save motion in inline editing mode */
.motion-save-toolbar {
@@ -633,23 +641,14 @@ img {
/* iframe for live view */
.col2 #iframe {
- width: 1024px;
- height: 768px;
-moz-transform-origin: 0 0;
-webkit-transform-origin: 0 0;
-o-transform-origin: 0 0;
transform-origin: 0 0 0;
- -moz-transform: scale(0.25);
- -webkit-transform: scale(0.25);
- -o-transform: scale(0.25);
- transform: scale(0.25);
- /* IE8+ - must be on one line, unfortunately */
- -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.25, M12=0, M21=0, M22=0.25, SizingMethod='auto expand')";
}
.col2 #iframewrapper {
width: 256px;
- height: 192px;
position: relative;
overflow: hidden;
border: 1px solid #D5D5D5;
@@ -658,7 +657,6 @@ img {
.col2 #iframeoverlay {
width: 256px;
- height: 192px;
position: absolute;
top: 0px;
left: 0px;
@@ -666,9 +664,7 @@ img {
z-index: 1;
}
-
/** Footer **/
-
#footer {
float: left;
height: 50px;
diff --git a/openslides/core/static/css/projector.css b/openslides/core/static/css/projector.css
index 6bb6d300d..3267a36da 100644
--- a/openslides/core/static/css/projector.css
+++ b/openslides/core/static/css/projector.css
@@ -11,6 +11,44 @@ body{
color: #222;
}
+/*** ProjectorContainer ***/
+.pContainer {
+ background-color: #222;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: table;
+}
+
+.pContainer > div {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+.pContainer #iframe {
+ -moz-transform-origin: 0 0;
+ -webkit-transform-origin: 0 0;
+ -o-transform-origin: 0 0;
+ transform-origin: 0 0 0;
+}
+
+.pContainer #iframewrapper {
+ position: relative;
+ overflow: hidden;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.pContainer #iframeoverlay {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ display: block;
+ z-index: 1;
+}
+
/*** HEADER ***/
#header {
box-shadow: 0 0 7px rgba(0,0,0,0.6);
diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js
index 8747da906..6b46cfaa7 100644
--- a/openslides/core/static/js/core/base.js
+++ b/openslides/core/static/js/core/base.js
@@ -286,7 +286,6 @@ angular.module('OpenSlidesApp.core', [
}
])
-
.factory('jsDataModel', [
'$http',
'Projector',
diff --git a/openslides/core/static/js/core/projector.js b/openslides/core/static/js/core/projector.js
index dc907fc7b..4fc269649 100644
--- a/openslides/core/static/js/core/projector.js
+++ b/openslides/core/static/js/core/projector.js
@@ -57,6 +57,65 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])
}
])
+// Projector Container Controller
+.controller('ProjectorContainerCtrl', [
+ '$scope',
+ 'Config',
+ function($scope, Config) {
+ // watch for changes in Config
+ var last_conf;
+ $scope.$watch(function () {
+ return Config.lastModified();
+ }, function () {
+ var conf = Config.get('projector_resolution').value;
+ // With multiprojector, get the resolution from Prjector.get(pk).{width; height}
+ if(!last_conf || last_conf.width != conf.width || last-conf.height != conf.height) {
+ last_conf = conf;
+ $scope.projectorWidth = conf.width;
+ $scope.projectorHeight = conf.height;
+ $scope.recalculateIframe();
+ }
+ });
+
+ // recalculate the actual Iframesize and scale
+ $scope.recalculateIframe = function () {
+ var scale_width = window.innerWidth / $scope.projectorWidth;
+ var scale_height = window.innerHeight / $scope.projectorHeight;
+
+ if (scale_width > 1 && scale_height > 1) {
+ // Iframe fits in full size in the window
+ $scope.scale = 1;
+ $scope.iframeWidth = $scope.projectorWidth;
+ $scope.iframeHeight = $scope.projectorHeight;
+ } else {
+ // Iframe has to be scaled down
+ if (scale_width <= scale_height) {
+ // width is the reference
+ $scope.iframeWidth = window.innerWidth;
+ $scope.scale = scale_width;
+ $scope.iframeHeight = $scope.projectorHeight * scale_width;
+ } else {
+ // height is the reference
+ $scope.iframeHeight = window.innerHeight;
+ $scope.scale = scale_height;
+ $scope.iframeWidth = $scope.projectorWidth * scale_height;
+ }
+ }
+ };
+
+ // watch for changes in the windowsize
+ $(window).on("resize.doResize", function () {
+ $scope.$apply(function() {
+ $scope.recalculateIframe();
+ });
+ });
+
+ $scope.$on("$destroy",function (){
+ $(window).off("resize.doResize");
+ });
+ }
+])
+
.controller('ProjectorCtrl', [
'$scope',
'Projector',
diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js
index a178bee5f..a264914fd 100644
--- a/openslides/core/static/js/core/site.js
+++ b/openslides/core/static/js/core/site.js
@@ -602,6 +602,15 @@ angular.module('OpenSlidesApp.core.site', [
})
.state('projector', {
url: '/projector',
+ templateUrl: 'static/templates/projector-container.html',
+ data: {extern: true},
+ onEnter: function($window) {
+ $window.location.href = this.url;
+ }
+ })
+ .state('real-projector', {
+ url: '/real-projector',
+ templateUrl: 'static/templates/projector.html',
data: {extern: true},
onEnter: function($window) {
$window.location.href = this.url;
@@ -810,6 +819,7 @@ angular.module('OpenSlidesApp.core.site', [
'Config',
'gettextCatalog',
function($parse, Config, gettextCatalog) {
+ // remove resolution when changing to multiprojector
function getHtmlType(type) {
return {
string: 'text',
@@ -818,6 +828,7 @@ angular.module('OpenSlidesApp.core.site', [
boolean: 'checkbox',
choice: 'choice',
colorpicker: 'colorpicker',
+ resolution: 'resolution',
}[type];
}
@@ -1144,6 +1155,22 @@ angular.module('OpenSlidesApp.core.site', [
});
+ // watch for changes in Config
+ var last_conf;
+ $scope.$watch(function () {
+ return Config.lastModified();
+ }, function () {
+ var conf = Config.get('projector_resolution').value;
+ // With multiprojector, get the resolution from Prjector.get(pk).{width; height}
+ if(!last_conf || last_conf.width != conf.width || last-conf.height != conf.height) {
+ last_conf = conf;
+ $scope.projectorWidth = conf.width;
+ $scope.projectorHeight = conf.height;
+ $scope.scale = 256.0 / $scope.projectorWidth;
+ $scope.iframeHeight = $scope.scale * $scope.projectorHeight;
+ }
+ });
+
// *** countdown functions ***
$scope.calculateCountdownTime = function (countdown) {
countdown.seconds = Math.floor( countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
diff --git a/openslides/core/static/templates/config-form-field.html b/openslides/core/static/templates/config-form-field.html
index ab6f2c8c5..63f237629 100644
--- a/openslides/core/static/templates/config-form-field.html
+++ b/openslides/core/static/templates/config-form-field.html
@@ -11,6 +11,26 @@
id="{{ key }}"
type="{{ type }}">
+
+
+
+
+