Skip to content

Commit

Permalink
GroupBoxLayout: ensure notification layout is valid
Browse files Browse the repository at this point in the history
A group box can have a notification which takes up vertical space.
While the height of the notification was already subtracted from
the available size, the layout of the notification widget was never
actually (re-)validated. Because of this, the notification's
HtmlComponent always returned the same cached height, even when the
group box was resized. This resulted in a wrong height for the group
box body.

Example: when a form with a notification with a long text is made
smaller, the notification becomes taller (because the browser
automatically wraps the text), but the height of the group box body
does not change. Consequently, the widgets inside the box "fall out"
of the bottom.

In addition, the notification layout needs to consider the width of
the field status when computing the preferred height. An adjusted
widthHint must be provided for this.

The member '_statusWidth' was renamed to 'fieldStatusWidth' (same as
in other layouts) so we can use the name '_statusWidth' for a new
method to compute the actual status width.

367904
  • Loading branch information
bschwarzent committed Mar 1, 2024
1 parent c3cf9fb commit ed1058e
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 22 deletions.
42 changes: 27 additions & 15 deletions eclipse-scout-core/src/form/fields/groupbox/GroupBoxLayout.js
Expand Up @@ -27,7 +27,7 @@ export default class GroupBoxLayout extends AbstractLayout {
}

_initDefaults() {
this._statusWidth = HtmlEnvironment.get().fieldStatusWidth;
this._fieldStatusWidth = HtmlEnvironment.get().fieldStatusWidth;
}

_onHtmlEnvironmentPropertyChange() {
Expand Down Expand Up @@ -55,11 +55,7 @@ export default class GroupBoxLayout extends AbstractLayout {
ResponsiveManager.get().handleResponsive(this.groupBox, containerSize.width);
}

let $status = this._$status();
if ($status && $status.isVisible()) {
this._layoutStatus();
statusWidth = $status.outerWidth(true);
}
statusWidth = this._statusWidth();

// Menu-bar
if (htmlMenuBar) {
Expand All @@ -83,13 +79,21 @@ export default class GroupBoxLayout extends AbstractLayout {
setWidthForStatus($header);
}

let notificationHeight = 0;
if (this.groupBox.notification) {
setWidthForStatus(this.groupBox.notification.$container, statusWidth);

let notificationPrefSize = this.groupBox.notification.htmlComp.prefSize({
widthHint: containerSize.width - statusWidth,
includeMargin: true
});
this.groupBox.notification.htmlComp.setSize(notificationPrefSize);
notificationHeight = notificationPrefSize.height;
}

gbBodySize = containerSize.subtract(htmlGbBody.margins());
gbBodySize.height -= this._headerHeight();
gbBodySize.height -= this._notificationHeight();
gbBodySize.height -= notificationHeight;
gbBodySize.height -= menuBarHeight;
$.log.isTraceEnabled() && $.log.trace('(GroupBoxLayout#layout) gbBodySize=' + gbBodySize);
htmlGbBody.setSize(gbBodySize);
Expand Down Expand Up @@ -210,7 +214,7 @@ export default class GroupBoxLayout extends AbstractLayout {
statusMargins = graphics.margins($status),
statusPosition = this.groupBox.statusPosition;

$status.cssWidth(this._statusWidth);
$status.cssWidth(this._fieldStatusWidth);
if (statusPosition === FormField.StatusPosition.DEFAULT) {
top += $header.cssMarginTop();
}
Expand Down Expand Up @@ -262,12 +266,19 @@ export default class GroupBoxLayout extends AbstractLayout {
if (htmlMenuBar && this.groupBox.menuBarPosition !== GroupBox.MenuBarPosition.TITLE) {
prefSize.height += htmlMenuBar.prefSize(options).height;
}

if (this.groupBox.notification) {
let notificationPrefSize = this.groupBox.notification.htmlComp.prefSize({
widthHint: scout.nvl(options.widthHint, prefSize.width) - this._statusWidth(),
includeMargin: true
});
prefSize.height += notificationPrefSize.height;
}
} else {
prefSize = new Dimension(0, 0);
}
prefSize = prefSize.add(htmlContainer.insets());
prefSize.height += this._headerHeight();
prefSize.height += this._notificationHeight(options);

// predefined height or width in pixel override other values
if (widthInPixel) {
Expand All @@ -288,13 +299,14 @@ export default class GroupBoxLayout extends AbstractLayout {
return graphics.prefSize(this.groupBox.$header, true).height;
}

_notificationHeight(options) {
options = options || {};
if (!this.groupBox.notification) {
return 0;
_statusWidth() {
let statusWidth = 0;
let $status = this._$status();
if ($status && $status.isVisible()) {
this._layoutStatus();
statusWidth = $status.outerWidth(true);
}
options.includeMargin = true;
return this.groupBox.notification.htmlComp.prefSize(options).height;
return statusWidth;
}

/**
Expand Down
1 change: 1 addition & 0 deletions eclipse-scout-core/src/notification/Notification.js
Expand Up @@ -43,6 +43,7 @@ export default class Notification extends Widget {
this.$content = this.$container.appendDiv('notification-content');
this.$messageText = this.$content.appendDiv('notification-message');
this.htmlComp = HtmlComponent.install(this.$container, this.session);
this.htmlComp.pixelBasedSizing = false;
}

_remove() {
Expand Down
88 changes: 81 additions & 7 deletions eclipse-scout-core/test/form/fields/groupbox/GroupBoxSpec.js
Expand Up @@ -8,7 +8,7 @@
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
*/
import {DialogLayout, FormField, GroupBox, HorizontalGrid, scout, VerticalSmartGrid} from '../../../../src/index';
import {DialogLayout, Dimension, FormField, GroupBox, HorizontalGrid, scout, VerticalSmartGrid} from '../../../../src/index';
import {FormSpecHelper} from '../../../../src/testing/index';

describe('GroupBox', () => {
Expand Down Expand Up @@ -313,7 +313,7 @@ describe('GroupBox', () => {
});

it('uses widthInPixel and heightInPixel as dialog width and height if set on main box', done => {
let $tmpStyle = $('<style type="text/css">.dialog { position: absolute; }</style>')
let $tmpStyle = $('<style>.dialog { position: absolute; }</style>')
.appendTo($('head'));

// stub function because when running in phantom js the window has an unpredictable size, it seems to get smaller when adding new specs...
Expand Down Expand Up @@ -343,6 +343,81 @@ describe('GroupBox', () => {
});
});

describe('notification', () => {

it('validates the notification layout on size change', () => {
let groupBox = helper.createGroupBoxWithFields(session.desktop, 2);
groupBox.render();

groupBox.htmlComp.setSize(new Dimension(500, 300));
expect(groupBox.htmlComp.valid).toBe(true);
expect(groupBox.htmlComp.size()).toEqual(new Dimension(500, 300));
expect(groupBox.htmlBody.valid).toBe(true);
expect(groupBox.htmlBody.size()).toEqual(new Dimension(500, 300));

groupBox.setNotification(scout.create('Notification', {
parent: groupBox,
message: 'Lorem ipsum dolor sit amet, ipsum lorem dolor sit amet, sit lorem dolor ipsum amet, ipsum amet dolor sit lorem.'
}));
groupBox.revalidateLayout(); // trigger layout manually, because the group box is not inside a form

let bodySize1 = groupBox.htmlBody.size();
let notificationSize1 = groupBox.notification.htmlComp.size();
expect(groupBox.htmlComp.valid).toBe(true);
expect(groupBox.htmlComp.size()).toEqual(new Dimension(500, 300));
expect(groupBox.htmlBody.valid).toBe(true);
expect(bodySize1.width).toBe(500);
expect(bodySize1.height).toBeLessThan(300);
expect(groupBox.notification.htmlComp.valid).toBe(true);
expect(notificationSize1.width).toBe(500);
expect(notificationSize1.height).toBeLessThan(300);

groupBox.htmlComp.setSize(new Dimension(200, 300));

let bodySize2 = groupBox.htmlBody.size();
let notificationSize2 = groupBox.notification.htmlComp.size();
expect(groupBox.htmlComp.valid).toBe(true);
expect(groupBox.htmlComp.size()).toEqual(new Dimension(200, 300));
expect(groupBox.htmlBody.valid).toBe(true);
expect(bodySize2.width).toBe(200);
expect(bodySize2.height).toBeLessThan(300);
expect(bodySize2.height).toBeLessThan(bodySize1.height);
expect(groupBox.notification.htmlComp.valid).toBe(true);
expect(notificationSize2.width).toBe(200);
expect(notificationSize2.height).toBeLessThan(300);
expect(notificationSize2.height).toBeGreaterThan(notificationSize1.height);
});

it('adjusts notification height when computing preferred size', () => {
let groupBox = helper.createGroupBoxWithFields(session.desktop, 2);
groupBox.setNotification(scout.create('Notification', {
parent: groupBox,
message: 'Lorem ipsum dolor sit amet, ipsum lorem dolor sit amet, sit lorem dolor ipsum amet, ipsum amet dolor sit lorem.'
}));
groupBox.gridData.widthInPixel = 700;
groupBox.render();
groupBox.pack();

let size1 = groupBox.htmlComp.size();
let bodySize1 = groupBox.htmlBody.size();

groupBox.gridData.widthInPixel = 200;
groupBox.invalidateLayout();
groupBox.pack();

let size2 = groupBox.htmlComp.size();
let bodySize2 = groupBox.htmlBody.size();

expect(size1.width).toBe(700);
expect(size2.width).toBe(200);
expect(bodySize1.width).toBe(700);
expect(bodySize2.width).toBe(200);

expect(size2.height).toBeGreaterThan(size1.height);
expect(bodySize2.height).toBe(bodySize1.height);
});
});

describe('scrollable', () => {
it('null by default', () => {
let groupBox = scout.create('GroupBox', {
Expand Down Expand Up @@ -487,16 +562,15 @@ describe('GroupBox', () => {
expect(groupBox.controls[1]).toBe(sibling);

// At the end
let newField3 = scout.create('StringField', {parent: groupBox});
let newField2 = scout.create('StringField', {parent: groupBox});
sibling = groupBox.fields[2];
groupBox.insertFieldAfter(newField, sibling);
groupBox.insertFieldAfter(newField2, sibling);
expect(groupBox.fields.length).toBe(4);
expect(groupBox.controls.length).toBe(4);
expect(groupBox.fields[3]).toBe(newField);
expect(groupBox.controls[3]).toBe(newField);
expect(groupBox.fields[3]).toBe(newField2);
expect(groupBox.controls[3]).toBe(newField2);
expect(groupBox.fields[2]).toBe(sibling);
expect(groupBox.controls[2]).toBe(sibling);
});
});

});

0 comments on commit ed1058e

Please sign in to comment.