Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elements in groups: Align to corners/centre #2810

Merged
merged 1 commit into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ui/bundle_templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ window.templates = {
header: require('./src/templates/forms/inputs/header.hbs'),
richText: require('./src/templates/forms/inputs/richText.hbs'),
divider: require('./src/templates/forms/inputs/divider.hbs'),
buttonSwitch: require('./src/templates/forms/inputs/buttonSwitch.hbs'),
custom: require('./src/templates/forms/inputs/custom.hbs'),
datasetSelector:
require('./src/templates/forms/inputs/datasetSelector.hbs'),
Expand Down
23 changes: 23 additions & 0 deletions ui/src/core/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,29 @@ window.forms = {
});
});

// Button group switch
findElements(
'.button-switch-input-group',
target,
).each(function(_k, el) {
const $buttonGroup = $(el).find('.btn-group');
const $hiddenInput = $(el).find('input[type="hidden"]');

$buttonGroup.find('button').on('click', function(ev) {
const $button = $(ev.currentTarget);

// Deselect all other buttons
$buttonGroup.find('button')
.removeClass('selected');
// Add selected to target button
$button.addClass('selected');

// Update hidden input with chosen button value
$hiddenInput.val($button.data('value'))
.trigger('change');
});
});

// Dataset order clause
findElements(
'.dataset-order-clause',
Expand Down
66 changes: 65 additions & 1 deletion ui/src/editor-core/element-group.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,11 @@ ElementGroup.prototype.transform = function(transform) {
scaleY: 0,
};

const originalDimensions = {
width: this.width,
height: this.height,
};

// Apply changes to the group ( updating values )
if (transform.width) {
transformation.scaleX = transform.width / this.width;
Expand Down Expand Up @@ -275,7 +280,66 @@ ElementGroup.prototype.transform = function(transform) {
left: elGroup.left + elRelativePositionScaled.left,
});
} else {
// TODO: Don't scale, but stick to corners
// Keep top and left on the same place by default
let newTop = el.top - elGroup.top;
let newLeft = el.left - elGroup.left;

// If bottom bound
if (
el.groupScaleTypeV === 'bottom'
) {
// Distance to bottom
const distToBottom = originalDimensions.height - el.height;

// Calculate top based on bottom position
newTop = newTop - (distToBottom - (elGroup.height - el.height));
} else if (
el.groupScaleTypeV === 'middle'
) {
// Group middle
const groupMiddle = originalDimensions.height / 2;

const newGroupMiddle = elGroup.height /2;

// Element middle
const elMiddle = el.height / 2;

// Distance to middle
const distMiddleToMiddle = groupMiddle - elMiddle;

// Calculate top based on bottom position
newTop = newTop + (newGroupMiddle - distMiddleToMiddle - elMiddle);
}

// If right bound
if (
el.groupScaleTypeH === 'right'
) {
// Calculate left based on right position
newLeft = newLeft - (originalDimensions.width - elGroup.width);
} else if (
el.groupScaleTypeV === 'middle'
) {
// Group center
const groupCenter = originalDimensions.width / 2;

const newGroupCenter = elGroup.width /2;

// Element center
const elCenter = el.width / 2;

// Distance to center
const distCenterToCenter = groupCenter - elCenter;

// Calculate top based on bottom position
newLeft = newLeft + (newGroupCenter - distCenterToCenter - elCenter);
}

// Transform without scaling
el.transform({
top: elGroup.top + newTop,
left: elGroup.left + newLeft,
});
}
});
};
Expand Down
6 changes: 4 additions & 2 deletions ui/src/editor-core/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ const Element = function(data, widgetId, regionId, parentWidget) {
// Group scale
this.groupScale = (data.groupScale != undefined) ?
data.groupScale : 1;
this.groupScaleType = (data.groupScaleType != undefined) ?
data.groupScaleType : 'top_left';
this.groupScaleTypeV = (data.groupScaleTypeV != undefined) ?
data.groupScaleTypeV : 'top';
this.groupScaleTypeH = (data.groupScaleTypeH != undefined) ?
data.groupScaleTypeH : 'left';

// Animation effect
this.effect = data.effect || 'noTransition';
Expand Down
66 changes: 49 additions & 17 deletions ui/src/editor-core/properties-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -916,48 +916,75 @@ PropertiesPanel.prototype.render = function(
// Create common fields
const commonFields = [];

// TODO: for now we disable scaling type
// Show scaling type if element is in a group
if (
false &&
targetAux.groupId != '' &&
targetAux.groupId != undefined
) {
commonFields.unshift(
{
id: 'groupScale',
customClass: 'group-scale-properties',
title: propertiesPanelTrans.groupScale,
helpText: propertiesPanelTrans.groupScaleHelpText,
value: targetAux.groupScale,
type: 'checkbox',
visibility: [],
},
{
id: 'groupScaleType',
title: propertiesPanelTrans.groupScaleType,
helpText: propertiesPanelTrans.groupScaleTypeHelpText,
value: targetAux.groupScaleType,
id: 'groupScaleTypeH',
customClass: 'group-scale-properties',
title: propertiesPanelTrans.groupScaleTypeH,
helpText: propertiesPanelTrans.groupScaleTypeHHelpText,
value: targetAux.groupScaleTypeH,
options: [
{
title: propertiesPanelTrans.groupScaleTypeOptions.topLeft,
name: 'top_left',
title: propertiesPanelTrans.groupScaleTypeOptions.left,
name: 'left',
},
{
title: propertiesPanelTrans.groupScaleTypeOptions.topRight,
name: 'top_right',
title: propertiesPanelTrans.groupScaleTypeOptions.center,
name: 'center',
},
{
title: propertiesPanelTrans
.groupScaleTypeOptions.bottomLeft,
name: 'bottom_left',
title: propertiesPanelTrans.groupScaleTypeOptions.right,
name: 'right',
},
],
type: 'buttonSwitch',
visibility: [
{
conditions: [
{
field: 'groupScale',
type: 'eq',
value: '0',
},
],
},
],
},
{
id: 'groupScaleTypeV',
customClass: 'group-scale-properties',
title: propertiesPanelTrans.groupScaleTypeV,
helpText: propertiesPanelTrans.groupScaleTypeVHelpText,
value: targetAux.groupScaleTypeV,
options: [
{
title: propertiesPanelTrans
.groupScaleTypeOptions.bottomRight,
name: 'bottom_right',
title: propertiesPanelTrans.groupScaleTypeOptions.top,
name: 'top',
},
{
title: propertiesPanelTrans.groupScaleTypeOptions.middle,
name: 'middle',
},
{
title: propertiesPanelTrans.groupScaleTypeOptions.bottom,
name: 'bottom',
},
],
type: 'dropdown',
type: 'buttonSwitch',
visibility: [
{
conditions: [
Expand Down Expand Up @@ -1700,6 +1727,11 @@ PropertiesPanel.prototype.render = function(
// Update moveable
lD.viewer.updateMoveable();
});

// Check if we have group scale properties for elements
// and move them to the top of the position tab
self.DOMObject.find('#appearanceTab .group-scale-properties')
.prependTo(self.DOMObject.find('#positionTab'));
};

// If it's an element, get properties, first to update it
Expand Down
8 changes: 6 additions & 2 deletions ui/src/editor-core/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,9 +513,13 @@ const Widget = function(id, data, regionId = null, layoutObject = null) {
// Save group scale type if exists
if (element.groupScale) {
elementObject.groupScale = 1;
} else if (element.groupScaleType) {
} else if (
element.groupScaleTypeH &&
element.groupScaleTypeV
) {
elementObject.groupScale = 0;
elementObject.groupScaleType = element.groupScaleType;
elementObject.groupScaleTypeH = element.groupScaleTypeH;
elementObject.groupScaleTypeV = element.groupScaleTypeV;
}
} else {
// Save effect if exists
Expand Down
7 changes: 6 additions & 1 deletion ui/src/layout-editor/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2813,6 +2813,11 @@ Viewer.prototype.initMoveable = function() {
// Save transformation
transformSplit = saveTransformation(e.target);

// Check if item was not resized
if (transformSplit.length === 1) {
return;
}

// Check if the region moved when resizing
const moved = (
parseFloat(transformSplit[1]) != 0 ||
Expand Down Expand Up @@ -2850,7 +2855,7 @@ Viewer.prototype.initMoveable = function() {
lD.selectedObject.type == 'element-group'
) && self.saveElementGroupProperties(
e.target,
false,
true,
true,
);
});
Expand Down
18 changes: 18 additions & 0 deletions ui/src/style/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -865,4 +865,22 @@ select[readonly].select2-hidden-accessible + .select2-container .select2-selecti
}
}
}
}

// Button switch
.button-switch-input-group {
button {
color: $xibo-color-primary;
border-color: $xibo-color-primary;

&:not(.selected):hover {
color: $xibo-color-primary;
background-color: lighten($xibo-color-primary, 35%);
}

&.selected {
background-color: $xibo-color-primary;
color: $xibo-color-neutral-0;
}
}
}
36 changes: 36 additions & 0 deletions ui/src/templates/forms/inputs/buttonSwitch.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<div class="form-group xibo-form-input button-switch-input-group
{{customClass}}
{{variant}}"
{{#if visibility}}data-visibility="{{visibility}}"{{/if}}
{{#if dependsOn}}data-depends-on="{{dependsOn}}"{{/if}}
{{#if isRequired}}data-is-required="{{isRequired}}"{{/if}}
>
<label for="{{#unless forceId}}input_{{/unless}}{{id}}" class="control-label"><strong>{{title}}</strong></label>
<div class="input-info-container">
{{#if helpText}}
{{> add-ons/helpText helpText=helpText}}
{{/if}}
</div>
<input id="{{#unless forceId}}input_{{/unless}}{{id}}" name="{{#if name}}{{name}}{{else}}{{id}}{{/if}}" value="{{value}}" type="hidden"/>
<div class="btn-group btn-block" role="group"
{{#each customData}}
data-{{this.name}}="{{this.value}}"
{{/each}}
{{#if readonly}}readonly{{/if}}
>
{{!-- Set default property values --}}
{{#unless optionsValue}}
{{set "optionsValue" "name"}}
{{/unless}}
{{#unless optionsTitle}}
{{set "optionsTitle" "title"}}
{{/unless}}

{{!-- Render options --}}
{{#each options}}
<button type="button" class="btn btn-sm {{#eq (lookup this ../optionsValue) ../value}}selected{{/eq}}"
data-value="{{lookup this ../optionsValue}}"
>{{lookup this ../optionsTitle}}</button>
{{/each}}
</div>
</div>
16 changes: 10 additions & 6 deletions views/editorTranslations.twig
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,17 @@
pinSlotHelpText: "{{ "The first item that appears in a slot will be pinned and will not cycle with the rest of the items."|trans }}",
groupScale: "{{ "Scale with group"|trans }}",
groupScaleHelpText: "{{ "Scale element when scaling containing group."|trans }}",
groupScaleType: "{{ "Align"|trans }}",
groupScaleTypeHelpText: "{{ "Alignment when scaling the containing group."|trans }}",
groupScaleTypeH: "{{ "Horizontal Align"|trans }}",
groupScaleTypeHHelpText: "{{ "Horizontal alignment when scaling the containing group."|trans }}",
groupScaleTypeV: "{{ "Vertical Align"|trans }}",
groupScaleTypeVHelpText: "{{ "Vertical alignment when scaling the containing group."|trans }}",
groupScaleTypeOptions: {
topLeft: "{{ "Top/Left" |trans }}",
topRight: "{{ "Top/Right" |trans }}",
bottomLeft: "{{ "Bottom/Left" |trans }}",
bottomRight: "{{ "Bottom/Right" |trans }}",
left: "{{ "Left" |trans }}",
center: "{{ "Center" |trans }}",
right: "{{ "Right" |trans }}",
top: "{{ "Top" |trans }}",
middle: "{{ "Middle" |trans }}",
bottom: "{{ "Bottom" |trans }}",
},
somethingWentWrong: "{{ "Something went wrong!"|trans }}",
somethingWentWrongEditPermissions: "{{ "Selected item is not shared with you with edit permission!"|trans }}",
Expand Down