Skip to content

Commit

Permalink
Layout Editor: layer control (#2009)
Browse files Browse the repository at this point in the history
  • Loading branch information
maurofmferrao authored Aug 25, 2023
1 parent 16edb01 commit db71639
Show file tree
Hide file tree
Showing 9 changed files with 495 additions and 5 deletions.
249 changes: 249 additions & 0 deletions ui/src/editor-core/layer-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/*
* Copyright (C) 2023 Xibo Signage Ltd
*
* Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
* Xibo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Xibo 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
*/

const managerTemplate = require('../templates/layer-manager.hbs');

/**
* Layer Manager
* @param {object} parent - Parent object
* @param {object} container - Container to append the manager to
* @param {object} viewerContainer - Viewer container to interact with
*/
const LayerManager = function(parent, container, viewerContainer) {
this.parent = parent;
this.DOMObject = container;
this.viewerContainer = viewerContainer;

this.layerStructure = [];

this.firstRender = true;
this.wasDragged = false;

// Show/Hide ( false by default )
this.visible = false;
};


/**
* Create structure
*/
LayerManager.prototype.createStructure = function() {
const self = this;

// Reset structure
self.layerStructure = [];

const addToLayerStructure = function(layer, object, auxArray = null) {
const arrayToAdd = (auxArray != null) ?
auxArray : self.layerStructure;

if (typeof arrayToAdd[layer] === 'undefined') {
arrayToAdd[layer] = [];
}

arrayToAdd[layer].push(object);
};

// Get canvas
const canvasObject = {};

if (!$.isEmptyObject(self.parent.layout.canvas)) {
const canvas = self.parent.layout.canvas;

// Add properties to canvas object
canvasObject.layer = canvas.zIndex;
canvasObject.type = 'canvas';
canvasObject.name = 'Canvas';
canvasObject.duration = canvas.duration;
canvasObject.subLayers = [];

// Get elements
if ((canvas.widgets)) {
Object.values(canvas.widgets).forEach((widget) => {
const elements = Object.values(widget.elements);
elements.forEach((element) => {
addToLayerStructure(element.layer, {
type: 'element',
name: element.id,
duration: widget.duration, // Element has parent widget duration
id: element.elementId,
hasGroup: (element.groupId != undefined),
groupId: layerManagerTrans.inGroup
.replace('%groupId%', element.groupId),
selected: element.selected,
},
canvasObject.subLayers,
);
});
});
}

// Add canvas to structure
addToLayerStructure(canvas.zIndex, {
type: 'canvas',
name: 'Canvas',
duration: canvas.duration,
layers: canvasObject.subLayers,
});
}

// Get static widgets and playlists
Object.values(self.parent.layout.regions).forEach((region) => {
if (region.subType === 'playlist') {
addToLayerStructure(region.zIndex, {
type: 'playlist',
name: region.name,
duration: region.duration,
id: region.id,
selected: region.selected,
});
} else {
Object.values(region.widgets).forEach((widget) => {
addToLayerStructure(region.zIndex, {
type: 'staticWidget',
name: widget.widgetName,
duration: region.duration,
subType: widget.subType,
id: widget.id,
selected: widget.selected,
});
});
}
});
};

/**
* Set visibility
* @param {boolean=} force Force visible to on/off
*/
LayerManager.prototype.setVisible = function(force) {
// Change manager flag
this.visible = (force != undefined) ? force : !this.visible;

// Set button status
lD.viewer.DOMObject.siblings('#layerManagerBtn')
.toggleClass('active', this.visible);

// Render manager (and reset position)
this.render(true);

// Save editor preferences
lD.savePrefs();
};

/**
* Render Manager
*/
/**
* Render Manager
* @param {boolean=} reset Reset to default state
*/
LayerManager.prototype.render = function(reset) {
const self = this;

// Only render if it's visible
if (this.visible != false) {
// Create layers data structure
this.createStructure();

// Compile layout template with data
const html = managerTemplate({
trans: layerManagerTrans,
layerStructure: this.layerStructure,
});

// Append layout html to the main div
this.DOMObject.html(html);

// Make the layer div draggable
this.DOMObject.draggable({
handle: '.layer-manager-header',
cursor: 'dragging',
drag: function() {
self.wasDragged = true;
},
});

// Select items
this.DOMObject.find('.layer-manager-layer-item.selectable')
.off().on('click', function(ev) {
const elementId = $(ev.currentTarget).data('item-id');
const $viewerObject = self.viewerContainer.find('#' + elementId);

if ($viewerObject.length) {
// Select in editor
lD.selectObject({
target: $viewerObject,
forceSelect: true,
});

// If it's a static widget, we need to give the class to its region
const $auxTarget = ($viewerObject.hasClass('designer-widget')) ?
$viewerObject.parents('.designer-region') :
$viewerObject;

// Select in viewer
lD.viewer.selectElement($auxTarget);

// Mark object with selected from manager class
$auxTarget.addClass('selected-from-layer-manager');
}
});

// Handle close button
this.DOMObject.find('.close-layer-manager')
.off().on('click', function(ev) {
self.setVisible(false);
});

// Show
this.DOMObject.show();
} else {
// Empty container
this.DOMObject.empty();

// Hide container
this.DOMObject.hide();
}

// If it's a reset or first run, show next to the button
if (reset || this.firstRender || !self.wasDragged) {
this.wasDragged = false;

self.DOMObject.css('top', 'auto');
self.DOMObject.css('left', 6);

// Button height plus offset from bottom and top of the button: 6*2
const viewerOffsetBottom =
lD.viewer.DOMObject.siblings('#layerManagerBtn').outerHeight() + (6 * 2);

// Bottom is calculated by using the element height
// and the offset from the bottom of the viewer
self.DOMObject.css(
'bottom',
self.DOMObject.outerHeight() + viewerOffsetBottom,
);
}

this.firstRender = false;
};

module.exports = LayerManager;
3 changes: 3 additions & 0 deletions ui/src/editor-core/properties-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,9 @@ PropertiesPanel.prototype.render = function(
app.viewer.DOMObject.find('.designer-region-canvas')
.css('zIndex', canvasZIndexVal);

// Update layer manager
app.viewer.layerManager.render();

// Don't save the rest of the form
return;
}
Expand Down
9 changes: 9 additions & 0 deletions ui/src/layout-editor/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3571,6 +3571,12 @@ lD.loadPrefs = function() {
// Update moveable UI
self.viewer.updateMoveableUI();
}

if (loadedData.layerManagerOptions) {
// Render layer manager
self.viewer.layerManager
.setVisible(loadedData.layerManagerOptions.visible);
}
} else {
// Login Form needed?
if (res.login) {
Expand Down Expand Up @@ -3608,6 +3614,9 @@ lD.savePrefs = function(clearPrefs = false) {
option: 'editor',
value: JSON.stringify({
snapOptions: this.viewer.moveableOptions,
layerManagerOptions: {
visible: this.viewer.layerManager.visible,
},
}),
},
],
Expand Down
38 changes: 34 additions & 4 deletions ui/src/layout-editor/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
// VIEWER Module

// Load templates
const LayerManager = require('../editor-core/layer-manager.js');
const viewerTemplate = require('../templates/viewer.hbs');
const viewerWidgetTemplate = require('../templates/viewer-widget.hbs');
const viewerLayoutPreview = require('../templates/viewer-layout-preview.hbs');
Expand Down Expand Up @@ -83,6 +84,13 @@ const Viewer = function(parent, container) {

// Fullscreen mode flag
this.fullscreenMode = false;

// Initialize layer manager
this.layerManager = new LayerManager(
lD,
this.parent.editorContainer.find('#layerManager'),
this.DOMObject,
);
};

/**
Expand Down Expand Up @@ -315,6 +323,9 @@ Viewer.prototype.render = function(forceReload = false) {
this.parent.common.reloadTooltips(
this.DOMObject.parent(),
);

// Update layer manager
this.layerManager.render();
};

/**
Expand Down Expand Up @@ -777,13 +788,18 @@ Viewer.prototype.handleInteractions = function() {
});

// Handle fullscreen button
$viewerContainer.parent().find('#fullscreenBtn').off().click(function() {
$viewerContainer.siblings('#fullscreenBtn').off().click(function() {
this.reload = true;
this.toggleFullscreen();
}.bind(this));

// Handle layer manager button
$viewerContainer.siblings('#layerManagerBtn').off().click(function(ev) {
this.layerManager.setVisible();
}.bind(this));

// Handle snap buttons
$viewerContainer.parent().find('#snapToGrid').off().click(function(ev) {
$viewerContainer.siblings('#snapToGrid').off().click(function(ev) {
this.moveableOptions.snapToGrid = !this.moveableOptions.snapToGrid;

// Turn off snap to element if grid is on
Expand Down Expand Up @@ -1140,6 +1156,9 @@ Viewer.prototype.updateElement = _.throttle(function(
lD.viewer.renderElementContent(
element,
);

// Update layer manager
lD.viewer.layerManager.render();
}, drawThrottle);

/**
Expand Down Expand Up @@ -1174,6 +1193,9 @@ Viewer.prototype.updateElementGroup = _.throttle(function(
lD.viewer.renderElementContent(
element,
);

// Update layer manager
lD.viewer.layerManager.render();
});
}, drawThrottle);

Expand Down Expand Up @@ -1226,6 +1248,9 @@ Viewer.prototype.updateRegion = _.throttle(function(
} else {
lD.viewer.updateRegionContent(region, changed);
}

// Update layer manager
lD.viewer.layerManager.render();
}, drawThrottle);


Expand Down Expand Up @@ -2338,8 +2363,10 @@ Viewer.prototype.selectElement = function(
const self = this;

// Deselect all elements
(!multiSelect) &&
this.DOMObject.find('.selected').removeClass('selected');
if (!multiSelect) {
this.DOMObject.find('.selected, .selected-from-layer-manager')
.removeClass('selected selected-from-layer-manager');
}

// Remove all editing from groups
// if we're not selecting an element from that group
Expand Down Expand Up @@ -2381,6 +2408,9 @@ Viewer.prototype.selectElement = function(
},
);
}

// Update layer manager
this.layerManager.render();
};

/**
Expand Down
Loading

0 comments on commit db71639

Please sign in to comment.