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

Add alignment and distribution buttons to the context pad #1682

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 33 additions & 4 deletions assets/bpmn-js.css
Expand Up @@ -8,7 +8,7 @@
--color-grey-225-10-80: hsl(225, 10%, 80%);
--color-grey-225-10-85: hsl(225, 10%, 85%);
--color-grey-225-10-90: hsl(225, 10%, 90%);
--color-grey-225-10-95: hsl(225, 10%, 95%);
--color-grey-225-10-95: hsl(225, 10%, 95%);
--color-grey-225-10-97: hsl(225, 10%, 97%);

--color-blue-205-100-45: hsl(205, 100%, 45%);
Expand All @@ -24,8 +24,8 @@
--color-red-360-100-97: hsl(360, 100%, 97%);

--color-white: hsl(0, 0%, 100%);
--color-black: hsl(0, 0%, 0%);
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
--color-black: hsl(0, 0%, 0%);
--color-black-opacity-05: hsla(0, 0%, 0%, 5%);
--color-black-opacity-10: hsla(0, 0%, 0%, 10%);

--breadcrumbs-font-family: var(--bjs-font-family);
Expand Down Expand Up @@ -113,4 +113,33 @@

.selected .bjs-drilldown-empty {
display: inherit;
}
}

[data-popup="align-elements"] .djs-popup-body {
display: flex;
}

[data-popup="align-elements"] .djs-popup-body [data-group] + [data-group] {
border-left: 1px solid var(--popup-border-color);
}

[data-popup="align-elements"] [data-group="align"] {
display: grid;
grid-template-columns: repeat(3, 1fr);
}

[data-popup="align-elements"] .djs-popup-body .entry {
height: 20px;
width: 20px;

padding: 6px 8px;
}

[data-popup="align-elements"] .djs-popup-body .entry img {
height: 100%;
width: 100%;
}

[data-popup="align-elements"] .bjs-align-elements-menu-entry {
display: inline-block;
}
2 changes: 1 addition & 1 deletion lib/Modeler.js
Expand Up @@ -10,7 +10,7 @@ import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas';
import TouchModule from 'diagram-js/lib/navigation/touch';
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll';

import AlignElementsModule from 'diagram-js/lib/features/align-elements';
import AlignElementsModule from './features/align-elements';
import AutoPlaceModule from './features/auto-place';
import AutoResizeModule from './features/auto-resize';
import AutoScrollModule from 'diagram-js/lib/features/auto-scroll';
Expand Down
87 changes: 87 additions & 0 deletions lib/features/align-elements/AlignElementsContextPadProvider.js
@@ -0,0 +1,87 @@
import {
assign
} from 'min-dash';

import ICONS from './AlignElementsIcons';

var LOW_PRIORITY = 900;

/**
* A provider for align elements context pad button
*/
export default function AlignElementsContextPadProvider(contextPad, popupMenu, translate, canvas) {

contextPad.registerProvider(LOW_PRIORITY, this);

this._contextPad = contextPad;
this._popupMenu = popupMenu;
this._translate = translate;
this._canvas = canvas;
}

AlignElementsContextPadProvider.$inject = [
'contextPad',
'popupMenu',
'translate',
'canvas'
];

AlignElementsContextPadProvider.prototype.getMultiElementContextPadEntries = function(elements) {
var actions = {};

if (this._isAllowed(elements)) {
assign(actions, this._getEntries(elements));
}

return actions;
};

AlignElementsContextPadProvider.prototype._isAllowed = function(elements) {
return !this._popupMenu.isEmpty(elements, 'align-elements');
};

AlignElementsContextPadProvider.prototype._getEntries = function(elements) {
var self = this;

return {
'align-elements': {
group: 'align-elements',
title: self._translate('Align elements'),
imageUrl: ICONS['align'],
action: {
click: function(event, elements) {
var position = self._getMenuPosition(elements);

assign(position, {
cursor: {
x: event.x,
y: event.y
}
});

self._popupMenu.open(elements, 'align-elements', position);
}
}
}
};
};

AlignElementsContextPadProvider.prototype._getMenuPosition = function(elements) {
var Y_OFFSET = 5;

var diagramContainer = this._canvas.getContainer(),
pad = this._contextPad.getPad(elements).html;

var diagramRect = diagramContainer.getBoundingClientRect(),
padRect = pad.getBoundingClientRect();

var top = padRect.top - diagramRect.top;
var left = padRect.left - diagramRect.left;

var pos = {
x: left,
y: top + padRect.height + Y_OFFSET
};

return pos;
};
15 changes: 15 additions & 0 deletions lib/features/align-elements/AlignElementsIcons.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions lib/features/align-elements/AlignElementsMenuProvider.js
@@ -0,0 +1,72 @@
import ICONS from './AlignElementsIcons';

import {
assign,
forEach,
} from 'min-dash';

var ALIGNMENT_OPTIONS = [
'left',
'center',
'right',
'top',
'middle',
'bottom'
];

/**
* A provider for align elements popup menu.
*/
export default function AlignElementsMenuProvider(popupMenu, alignElements, translate, rules) {

this._alignElements = alignElements;
this._translate = translate;
this._popupMenu = popupMenu;
this._rules = rules;

popupMenu.registerProvider('align-elements', this);
}

AlignElementsMenuProvider.$inject = [
'popupMenu',
'alignElements',
'translate',
'rules'
];

AlignElementsMenuProvider.prototype.getPopupMenuEntries = function(elements) {
var entries = {};

if (this._isAllowed(elements)) {
assign(entries, this._getEntries(elements));
}

return entries;
};

AlignElementsMenuProvider.prototype._isAllowed = function(elements) {
return this._rules.allowed('elements.align', { elements: elements });
};

AlignElementsMenuProvider.prototype._getEntries = function(elements) {
var alignElements = this._alignElements,
translate = this._translate,
popupMenu = this._popupMenu;

var entries = {};

forEach(ALIGNMENT_OPTIONS, function(alignment) {
entries[ 'align-elements-' + alignment ] = {
group: 'align',
title: translate('Align elements ' + alignment),
className: 'bjs-align-elements-menu-entry',
imageUrl: ICONS[alignment],
action: function(event, entry) {
alignElements.trigger(elements, alignment);
popupMenu.close();
}
};
});

return entries;
};
39 changes: 39 additions & 0 deletions lib/features/align-elements/BpmnAlignElements.js
@@ -0,0 +1,39 @@
import inherits from 'inherits-browser';

import RuleProvider from 'diagram-js/lib/features/rules/RuleProvider';
import { getParents } from 'diagram-js/lib/util/Elements';

import {
filter
} from 'min-dash';

/**
* Rule provider for alignment of BPMN elements.
*/
export default function BpmnAlignElements(eventBus) {
RuleProvider.call(this, eventBus);
}

BpmnAlignElements.$inject = [ 'eventBus' ];

inherits(BpmnAlignElements, RuleProvider);

BpmnAlignElements.prototype.init = function() {
this.addRule('elements.align', function(context) {
var elements = context.elements;

// filter out elements which cannot be aligned
var filteredElements = filter(elements, function(element) {
return !(element.waypoints || element.host || element.labelTarget);
});

// filter out elements which are children of any of the selected elements
filteredElements = getParents(filteredElements);

if (filteredElements.length < 2) {
return false;
}

return filteredElements;
});
};
23 changes: 23 additions & 0 deletions lib/features/align-elements/index.js
@@ -0,0 +1,23 @@
import AlignElementsModule from 'diagram-js/lib/features/align-elements';
import ContextPadModule from 'diagram-js/lib/features/context-pad';
import PopupMenuModule from 'diagram-js/lib/features/popup-menu';

import AlignElementsContextPadProvider from './AlignElementsContextPadProvider';
import AlignElementsMenuProvider from './AlignElementsMenuProvider';
import BpmnAlignElements from './BpmnAlignElements';

export default {
__depends__: [
AlignElementsModule,
ContextPadModule,
PopupMenuModule
],
__init__: [
'alignElementsContextPadProvider',
'alignElementsMenuProvider',
'bpmnAlignElements'
],
alignElementsContextPadProvider: [ 'type', AlignElementsContextPadProvider ],
alignElementsMenuProvider: [ 'type', AlignElementsMenuProvider ],
bpmnAlignElements: [ 'type', BpmnAlignElements]
};
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-bottom-tool.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-left-tool.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-right-tool.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-tool.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions lib/features/align-elements/resources/align-top-tool.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.