diff --git a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyComponentType.java b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyComponentType.java index 8dc28abe..5f256d03 100644 --- a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyComponentType.java +++ b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyComponentType.java @@ -80,7 +80,7 @@ default PAreaSizeI layout( Objects.requireNonNull(constraints, "constraints"); /* - * First, consult the theme to see if there are size constraints specified + * Consult the theme to see if there are size constraints specified * for this component. Derive a new set of constraints that try to * satisfy the theme whilst also satisfying the passed in constraints. */ diff --git a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyConstraints.java b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyConstraints.java index 19bc5199..2f4c5054 100644 --- a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyConstraints.java +++ b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyConstraints.java @@ -37,6 +37,9 @@ public record SyConstraints( int sizeMaximumX, int sizeMaximumY) { + private static final SyConstraints ZERO = + new SyConstraints(0, 0, 0, 0); + /** * A set of size constraints. * @@ -62,6 +65,15 @@ public SyConstraints( Math.clamp(sizeMaximumY, this.sizeMinimumY, MAX_VALUE); } + /** + * @return Constraints that force a zero size + */ + + public static SyConstraints zero() + { + return ZERO; + } + /** * @param The coordinate space type * diff --git a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarPresencePolicy.java b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarHideIfDisabled.java similarity index 74% rename from com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarPresencePolicy.java rename to com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarHideIfDisabled.java index f59332a8..5d385855 100644 --- a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarPresencePolicy.java +++ b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarHideIfDisabled.java @@ -18,22 +18,22 @@ package com.io7m.jsycamore.api.components; /** - * The presence policy for scrollbars. + * A specification of whether to collapse scrollbars to zero size when + * disabled. */ -public enum SyScrollBarPresencePolicy +public enum SyScrollBarHideIfDisabled { /** - * The scrollbar should always be present and enabled. + * When disabled, the scrollbar collapses to zero size and is effectively + * hidden. */ - ALWAYS_ENABLED, + HIDE_IF_DISABLED, /** - * The scrollbar is disabled if the entire range is shown. - * - * @see SyScrollBarType#setScrollAmountShown(double) + * When disabled, the scrollbar remains visible. */ - DISABLED_IF_ENTIRE_RANGE_SHOWN + SHOW_EVEN_IF_DISABLED } diff --git a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarReadableType.java b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarReadableType.java index 3dcd5a3c..189f5a21 100644 --- a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarReadableType.java +++ b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarReadableType.java @@ -37,6 +37,12 @@ public interface SyScrollBarReadableType SyComponentReadableType track(); + /** + * @return The scroll amount shown in the range {@code [0, 1]} + */ + + double scrollAmountShown(); + /** * @return The scroll position in the range {@code [0, 1]} */ @@ -59,10 +65,4 @@ public interface SyScrollBarReadableType */ double scrollIncrementSize(); - - /** - * @return The scrollbar presence policy - */ - - AttributeReadableType presencePolicy(); } diff --git a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarType.java b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarType.java index 46cf8315..98fd94be 100644 --- a/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarType.java +++ b/com.io7m.jsycamore.api/src/main/java/com/io7m/jsycamore/api/components/SyScrollBarType.java @@ -16,7 +16,7 @@ package com.io7m.jsycamore.api.components; -import com.io7m.jattribute.core.AttributeType; +import com.io7m.jsycamore.api.layout.SyLayoutContextType; import java.util.function.Consumer; @@ -27,8 +27,17 @@ public interface SyScrollBarType extends SyScrollBarReadableType, SyComponentType { - @Override - AttributeType presencePolicy(); + /** + * Allow for hiding the scrollbar if it is disabled. If hiding-if-disabled + * is enabled, then the scrollbar's size will collapse to zero when + * {@link #layout(SyLayoutContextType, SyConstraints)} is called and the + * scrollbar is disabled. + * + * @param hideIfDisabled The hide-if-disabled setting + */ + + void setHideIfDisabled( + SyScrollBarHideIfDisabled hideIfDisabled); /** * Set the scroll position in the range {@code [0, 1]}. diff --git a/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarH.java b/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarH.java index 580d940d..11754428 100644 --- a/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarH.java +++ b/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarH.java @@ -17,30 +17,29 @@ package com.io7m.jsycamore.components.standard.internal.scrollbars; -import com.io7m.jattribute.core.AttributeType; import com.io7m.jregions.core.parameterized.areas.PAreasI; import com.io7m.jregions.core.parameterized.sizes.PAreaSizeI; import com.io7m.jsycamore.api.components.SyButtonReadableType; import com.io7m.jsycamore.api.components.SyComponentReadableType; import com.io7m.jsycamore.api.components.SyConstraints; import com.io7m.jsycamore.api.components.SyScrollBarDrag; +import com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled; import com.io7m.jsycamore.api.components.SyScrollBarHorizontalType; -import com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy; import com.io7m.jsycamore.api.events.SyEventConsumed; import com.io7m.jsycamore.api.events.SyEventType; import com.io7m.jsycamore.api.layout.SyLayoutContextType; import com.io7m.jsycamore.api.spaces.SySpaceParentRelativeType; import com.io7m.jsycamore.api.themes.SyThemeClassNameType; import com.io7m.jsycamore.components.standard.SyComponentAbstract; -import com.io7m.jsycamore.components.standard.SyComponentAttributes; import com.io7m.jtensors.core.parameterized.vectors.PVector2I; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import static com.io7m.jsycamore.api.active.SyActive.ACTIVE; import static com.io7m.jsycamore.api.active.SyActive.INACTIVE; -import static com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy.DISABLED_IF_ENTIRE_RANGE_SHOWN; +import static com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled.HIDE_IF_DISABLED; import static com.io7m.jsycamore.api.events.SyEventConsumed.EVENT_NOT_CONSUMED; /** @@ -57,7 +56,8 @@ public final class SyScrollBarH private final SyScrollBarHButtonLeft buttonLeft; private final SyScrollBarHButtonRight buttonRight; private final SyScrollBarHTrack track; - private final AttributeType presencePolicy; + private SyScrollBarHideIfDisabled hideIfDisabled = + SyScrollBarHideIfDisabled.SHOW_EVEN_IF_DISABLED; /** * A horizontal scrollbar. @@ -70,9 +70,6 @@ public SyScrollBarH( { super(inThemeClassesExtra); - this.presencePolicy = - SyComponentAttributes.get().create(DISABLED_IF_ENTIRE_RANGE_SHOWN); - this.buttonLeft = new SyScrollBarHButtonLeft(); this.buttonRight = @@ -90,6 +87,19 @@ public PAreaSizeI layout( final SyLayoutContextType layoutContext, final SyConstraints constraints) { + /* + * Scrollbars are able to hide themselves by collapsing to zero size. + */ + + if (this.hideIfDisabled == HIDE_IF_DISABLED) { + if (!this.isActive()) { + final var zero = + PAreaSizeI.of(0, 0); + this.setSize(zero); + return zero; + } + } + var limitedConstraints = layoutContext.deriveThemeConstraints(constraints, this); @@ -262,6 +272,14 @@ public double scrollIncrementSize() return this.track.scrollIncrementSize(); } + @Override + public void setHideIfDisabled( + final SyScrollBarHideIfDisabled newHideIfDisabled) + { + this.hideIfDisabled = + Objects.requireNonNull(newHideIfDisabled, "newHideIfDisabled"); + } + @Override public void setScrollPosition( final double position) @@ -281,23 +299,7 @@ public void setScrollAmountShown( final double amount) { this.track.setScrollAmountShown(amount); - - final var all = - this.track.scrollAmountShown() >= 1.0; - - final var active = - switch (this.presencePolicy.get()) { - case ALWAYS_ENABLED -> { - yield ACTIVE; - } - case DISABLED_IF_ENTIRE_RANGE_SHOWN -> { - yield all ? INACTIVE : ACTIVE; - } - }; - - this.buttonLeft.setActive(active); - this.buttonRight.setActive(active); - this.track.setActive(active); + this.setActive(this.track.scrollAmountShown() >= 1.0 ? INACTIVE : ACTIVE); } @Override @@ -325,20 +327,20 @@ public SyComponentReadableType track() } @Override - public double scrollPosition() + public double scrollAmountShown() { - return this.track.scrollPosition(); + return this.track.scrollAmountShown(); } @Override - public double scrollPositionSnapping() + public double scrollPosition() { - return this.track.scrollPositionSnapping(); + return this.track.scrollPosition(); } @Override - public AttributeType presencePolicy() + public double scrollPositionSnapping() { - return this.presencePolicy; + return this.track.scrollPositionSnapping(); } } diff --git a/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarV.java b/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarV.java index db350562..5ceb8276 100644 --- a/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarV.java +++ b/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollbars/SyScrollBarV.java @@ -17,14 +17,13 @@ package com.io7m.jsycamore.components.standard.internal.scrollbars; -import com.io7m.jattribute.core.AttributeType; import com.io7m.jregions.core.parameterized.areas.PAreasI; import com.io7m.jregions.core.parameterized.sizes.PAreaSizeI; import com.io7m.jsycamore.api.components.SyButtonReadableType; import com.io7m.jsycamore.api.components.SyComponentReadableType; import com.io7m.jsycamore.api.components.SyConstraints; import com.io7m.jsycamore.api.components.SyScrollBarDrag; -import com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy; +import com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled; import com.io7m.jsycamore.api.components.SyScrollBarVerticalType; import com.io7m.jsycamore.api.events.SyEventConsumed; import com.io7m.jsycamore.api.events.SyEventType; @@ -32,15 +31,15 @@ import com.io7m.jsycamore.api.spaces.SySpaceParentRelativeType; import com.io7m.jsycamore.api.themes.SyThemeClassNameType; import com.io7m.jsycamore.components.standard.SyComponentAbstract; -import com.io7m.jsycamore.components.standard.SyComponentAttributes; import com.io7m.jtensors.core.parameterized.vectors.PVector2I; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import static com.io7m.jsycamore.api.active.SyActive.ACTIVE; import static com.io7m.jsycamore.api.active.SyActive.INACTIVE; -import static com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy.DISABLED_IF_ENTIRE_RANGE_SHOWN; +import static com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled.HIDE_IF_DISABLED; import static com.io7m.jsycamore.api.events.SyEventConsumed.EVENT_NOT_CONSUMED; /** @@ -57,7 +56,8 @@ public final class SyScrollBarV private final SyScrollBarVButtonUp buttonUp; private final SyScrollBarVButtonDown buttonDown; private final SyScrollBarVTrack track; - private final AttributeType presencePolicy; + private SyScrollBarHideIfDisabled hideIfDisabled = + SyScrollBarHideIfDisabled.SHOW_EVEN_IF_DISABLED; /** * A vertical scrollbar. @@ -70,9 +70,6 @@ public SyScrollBarV( { super(inThemeClassesExtra); - this.presencePolicy = - SyComponentAttributes.get().create(DISABLED_IF_ENTIRE_RANGE_SHOWN); - this.buttonUp = new SyScrollBarVButtonUp(); this.buttonDown = @@ -90,6 +87,19 @@ public PAreaSizeI layout( final SyLayoutContextType layoutContext, final SyConstraints constraints) { + /* + * Scrollbars are able to hide themselves by collapsing to zero size. + */ + + if (this.hideIfDisabled == HIDE_IF_DISABLED) { + if (!this.isActive()) { + final var zero = + PAreaSizeI.of(0, 0); + this.setSize(zero); + return zero; + } + } + var limitedConstraints = layoutContext.deriveThemeConstraints(constraints, this); @@ -249,23 +259,7 @@ public void setScrollAmountShown( final double amount) { this.track.setScrollAmountShown(amount); - - final var all = - this.track.scrollAmountShown() >= 1.0; - - final var active = - switch (this.presencePolicy.get()) { - case ALWAYS_ENABLED -> { - yield ACTIVE; - } - case DISABLED_IF_ENTIRE_RANGE_SHOWN -> { - yield all ? INACTIVE : ACTIVE; - } - }; - - this.buttonUp.setActive(active); - this.buttonDown.setActive(active); - this.track.setActive(active); + this.setActive(this.track.scrollAmountShown() >= 1.0 ? INACTIVE : ACTIVE); } @Override @@ -292,6 +286,12 @@ public SyComponentReadableType track() return this.track; } + @Override + public double scrollAmountShown() + { + return this.track.scrollAmountShown(); + } + @Override public double scrollPosition() { @@ -310,12 +310,6 @@ public double scrollIncrementSize() return this.track.scrollIncrementSize(); } - @Override - public AttributeType presencePolicy() - { - return this.presencePolicy; - } - @Override public void setOnClickUpListener( final Runnable runnable) @@ -341,4 +335,12 @@ public void removeOnClickDownListener() { this.buttonDown.removeOnClickListener(); } + + @Override + public void setHideIfDisabled( + final SyScrollBarHideIfDisabled newHideIfDisabled) + { + this.hideIfDisabled = + Objects.requireNonNull(newHideIfDisabled, "newHideIfDisabled"); + } } diff --git a/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollpanes/SyScrollPane.java b/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollpanes/SyScrollPane.java index 9b8ae849..355bd302 100644 --- a/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollpanes/SyScrollPane.java +++ b/com.io7m.jsycamore.components.standard/src/main/java/com/io7m/jsycamore/components/standard/internal/scrollpanes/SyScrollPane.java @@ -81,9 +81,9 @@ public SyScrollPane( this.contentAreaSize = attributes.create(PAreaSizeI.of(1024, 1024)); - this.childAdd(this.contentAreaViewport); this.childAdd(this.scrollH); this.childAdd(this.scrollV); + this.childAdd(this.contentAreaViewport); this.scrollH.setOnClickLeftListener( this.onScrollClickLeftListener()); @@ -95,19 +95,22 @@ public SyScrollPane( this.onScrollClickDownListener()); } - private void updateScrollBars( - final PAreaSizeI newContentAreaSize, - final PAreaSizeI newContentViewportSize) + private void updateScrollBars() { + final var contentAreaSizeNow = + this.contentAreaSize.get(); + final var contentViewportSizeNow = + this.contentAreaViewport.size().get(); + final var viewportX = - (double) newContentViewportSize.sizeX(); + (double) contentViewportSizeNow.sizeX(); final var viewportY = - (double) newContentViewportSize.sizeY(); + (double) contentViewportSizeNow.sizeY(); final var contentX = - (double) newContentAreaSize.sizeX(); + (double) contentAreaSizeNow.sizeX(); final var contentY = - (double) newContentAreaSize.sizeY(); + (double) contentAreaSizeNow.sizeY(); /* * Clamp the results to [0, 1]. This has the effect of stamping out any @@ -128,6 +131,8 @@ public PAreaSizeI layout( final SyLayoutContextType layoutContext, final SyConstraints constraints) { + this.updateScrollBars(); + /* * Resize this main component to the maximum size allowed by the * constraints. @@ -156,8 +161,9 @@ public PAreaSizeI layout( this.scrollV.layout(layoutContext, limitedConstraints); /* - * Now, the scrollbars needed to be shortened slightly, and placed at - * the edges of the component. + * The width of the horizontal scrollbar must be reduced by the width of + * the vertical scrollbar. This may be nothing if that scrollbar isn't + * visible. */ final var scrollHConstraints = @@ -165,6 +171,12 @@ public PAreaSizeI layout( this.scrollV.size().get().sizeX() ); + /* + * The height of the scrollbar must be reduced by the height of the + * horizontal scrollbar. This may be nothing if that scrollbar isn't + * visible. + */ + final var scrollVConstraints = limitedConstraints.deriveSubtractMaximumHeight( this.scrollH.size().get().sizeY() @@ -178,7 +190,8 @@ public PAreaSizeI layout( * content area viewport is derived from the size of the scrollpane as a * whole, minus the sizes of the scrollbars. The size of the content area * within the viewport is of a fixed size and may be far, far larger than - * the content viewport. + * the content viewport. If either of the scrollbars aren't enabled, then + * the viewport is sized such that it overlaps them. * * Therefore, to set their sizes independently: * @@ -224,8 +237,6 @@ public PAreaSizeI layout( PVector2I.of(contentViewportSizeNow.sizeX(), 0) ); - this.updateScrollBars(contentAreaSizeNow, contentViewportSizeNow); - /* * The content area is offset by a proportion of the scrollable region * within the viewport. diff --git a/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarHorizontalTest.java b/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarHorizontalTest.java index be627abb..2efc038e 100644 --- a/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarHorizontalTest.java +++ b/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarHorizontalTest.java @@ -19,8 +19,8 @@ import com.io7m.jsycamore.api.active.SyActive; import com.io7m.jsycamore.api.components.SyScrollBarDrag; +import com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled; import com.io7m.jsycamore.api.components.SyScrollBarHorizontalType; -import com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy; import com.io7m.jsycamore.api.spaces.SySpaceViewportType; import com.io7m.jsycamore.components.standard.SyScrollBarsHorizontal; import com.io7m.jtensors.core.parameterized.vectors.PVector2I; @@ -30,11 +30,11 @@ import java.util.LinkedList; +import static com.io7m.jsycamore.api.active.SyActive.INACTIVE; import static com.io7m.jsycamore.api.components.SyScrollBarDrag.Kind.DRAG_CONTINUED; import static com.io7m.jsycamore.api.components.SyScrollBarDrag.Kind.DRAG_ENDED; import static com.io7m.jsycamore.api.components.SyScrollBarDrag.Kind.DRAG_STARTED; -import static com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy.ALWAYS_ENABLED; -import static com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy.DISABLED_IF_ENTIRE_RANGE_SHOWN; +import static com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled.HIDE_IF_DISABLED; import static com.io7m.jsycamore.api.mouse.SyMouseButton.MOUSE_BUTTON_LEFT; import static com.io7m.jsycamore.api.mouse.SyMouseButton.MOUSE_BUTTON_RIGHT; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -310,14 +310,13 @@ public void testThumbDragNotButton() } /** - * The ALWAYS_ENABLED presence policy works. + * The bar is disabled if the full amount is shown. */ @Test - public void testPresencePolicyAlwaysActive() + public void testDisabledIfFullyShown() { final var c = this.newComponent(); - c.presencePolicy().set(ALWAYS_ENABLED); final var t = c.thumb(); final var l = c.buttonLeft(); @@ -333,9 +332,9 @@ public void testPresencePolicyAlwaysActive() assertTrue(r.isActive()); c.setScrollAmountShown(1.0); - assertTrue(t.isActive()); - assertTrue(l.isActive()); - assertTrue(r.isActive()); + assertFalse(t.isActive()); + assertFalse(l.isActive()); + assertFalse(r.isActive()); c.setScrollAmountShown(0.0); assertTrue(t.isActive()); @@ -344,36 +343,21 @@ public void testPresencePolicyAlwaysActive() } /** - * The DISABLED_IF_ENTIRE_RANGE_SHOWN presence policy works. + * The bar is disabled if the full amount is shown. */ @Test - public void testPresencePolicyDisabledIfFullyShown() + public void testCollapsedIfDisabled() { final var c = this.newComponent(); - c.presencePolicy().set(DISABLED_IF_ENTIRE_RANGE_SHOWN); - final var t = c.thumb(); - final var l = c.buttonLeft(); - final var r = c.buttonRight(); + c.setHideIfDisabled(HIDE_IF_DISABLED); + c.setActive(INACTIVE); this.windowContentArea().childAdd(c); this.window().layout(this.layoutContext); - this.screen().mouseMoved(Z); - - c.setScrollAmountShown(0.0); - assertTrue(t.isActive()); - assertTrue(l.isActive()); - assertTrue(r.isActive()); - - c.setScrollAmountShown(1.0); - assertFalse(t.isActive()); - assertFalse(l.isActive()); - assertFalse(r.isActive()); - c.setScrollAmountShown(0.0); - assertTrue(t.isActive()); - assertTrue(l.isActive()); - assertTrue(r.isActive()); + assertEquals(0, c.size().get().sizeX()); + assertEquals(0, c.size().get().sizeY()); } } diff --git a/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarVerticalTest.java b/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarVerticalTest.java index 0a296567..e2f16a3b 100644 --- a/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarVerticalTest.java +++ b/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyScrollBarVerticalTest.java @@ -28,11 +28,11 @@ import java.util.LinkedList; +import static com.io7m.jsycamore.api.active.SyActive.INACTIVE; import static com.io7m.jsycamore.api.components.SyScrollBarDrag.Kind.DRAG_CONTINUED; import static com.io7m.jsycamore.api.components.SyScrollBarDrag.Kind.DRAG_ENDED; import static com.io7m.jsycamore.api.components.SyScrollBarDrag.Kind.DRAG_STARTED; -import static com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy.ALWAYS_ENABLED; -import static com.io7m.jsycamore.api.components.SyScrollBarPresencePolicy.DISABLED_IF_ENTIRE_RANGE_SHOWN; +import static com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled.HIDE_IF_DISABLED; import static com.io7m.jsycamore.api.mouse.SyMouseButton.MOUSE_BUTTON_LEFT; import static com.io7m.jsycamore.api.mouse.SyMouseButton.MOUSE_BUTTON_RIGHT; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -308,14 +308,13 @@ public void testThumbDragNotButton() } /** - * The ALWAYS_ENABLED presence policy works. + * The bar is disabled if the full amount is shown. */ @Test - public void testPresencePolicyAlwaysActive() + public void testDisabledIfFullyShown() { final var c = this.newComponent(); - c.presencePolicy().set(ALWAYS_ENABLED); final var t = c.thumb(); final var l = c.buttonUp(); @@ -331,9 +330,9 @@ public void testPresencePolicyAlwaysActive() assertTrue(r.isActive()); c.setScrollAmountShown(1.0); - assertTrue(t.isActive()); - assertTrue(l.isActive()); - assertTrue(r.isActive()); + assertFalse(t.isActive()); + assertFalse(l.isActive()); + assertFalse(r.isActive()); c.setScrollAmountShown(0.0); assertTrue(t.isActive()); @@ -342,36 +341,21 @@ public void testPresencePolicyAlwaysActive() } /** - * The DISABLED_IF_ENTIRE_RANGE_SHOWN presence policy works. + * The bar is disabled if the full amount is shown. */ @Test - public void testPresencePolicyDisabledIfFullyShown() + public void testCollapsedIfDisabled() { final var c = this.newComponent(); - c.presencePolicy().set(DISABLED_IF_ENTIRE_RANGE_SHOWN); - final var t = c.thumb(); - final var l = c.buttonUp(); - final var r = c.buttonDown(); + c.setHideIfDisabled(HIDE_IF_DISABLED); + c.setActive(INACTIVE); this.windowContentArea().childAdd(c); this.window().layout(this.layoutContext); - this.screen().mouseMoved(Z); - - c.setScrollAmountShown(0.0); - assertTrue(t.isActive()); - assertTrue(l.isActive()); - assertTrue(r.isActive()); - - c.setScrollAmountShown(1.0); - assertFalse(t.isActive()); - assertFalse(l.isActive()); - assertFalse(r.isActive()); - c.setScrollAmountShown(0.0); - assertTrue(t.isActive()); - assertTrue(l.isActive()); - assertTrue(r.isActive()); + assertEquals(0, c.size().get().sizeX()); + assertEquals(0, c.size().get().sizeY()); } } diff --git a/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyTextAreaDemo.java b/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyTextAreaDemo.java index 89011d04..8f9be3e8 100644 --- a/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyTextAreaDemo.java +++ b/com.io7m.jsycamore.tests/src/main/java/com/io7m/jsycamore/tests/SyTextAreaDemo.java @@ -17,6 +17,7 @@ package com.io7m.jsycamore.tests; import com.io7m.jregions.core.parameterized.sizes.PAreaSizeI; +import com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled; import com.io7m.jsycamore.api.mouse.SyMouseButton; import com.io7m.jsycamore.api.screens.SyScreenType; import com.io7m.jsycamore.api.spaces.SySpaceViewportType; @@ -54,6 +55,7 @@ import java.util.List; import java.util.concurrent.Executors; +import static com.io7m.jsycamore.api.components.SyScrollBarHideIfDisabled.HIDE_IF_DISABLED; import static com.io7m.jsycamore.api.windows.SyWindowCloseBehaviour.HIDE_ON_CLOSE_BUTTON; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.concurrent.TimeUnit.SECONDS; @@ -211,7 +213,7 @@ public void componentResized(final ComponentEvent e) final var c = SyTextLayoutDemo.class; final var u = - c.getResource("/com/io7m/jsycamore/tests/arctic.txt"); + c.getResource("/com/io7m/jsycamore/tests/arcticLarge.txt"); try (var s = u.openStream()) { this.sections = new String(s.readAllBytes(), UTF_8).lines().toList(); @@ -226,6 +228,8 @@ public void componentResized(final ComponentEvent e) for (final var section : this.sections) { textArea.textSectionAppend(section); } + textArea.scrollbarVertical().setHideIfDisabled(HIDE_IF_DISABLED); + textArea.scrollbarHorizontal().setHideIfDisabled(HIDE_IF_DISABLED); margin.childAdd(textArea); this.window0.contentArea().childAdd(margin); @@ -269,6 +273,7 @@ public void paint(final Graphics g) window.layout(layoutContext); // this.renderer.nodeRenderer().setDebugBoundsRendering(true); this.renderer.render(g2, this.screen, window); + this.repaint(); } } } diff --git a/com.io7m.jsycamore.tests/src/main/resources/com/io7m/jsycamore/tests/arcticLarge.txt b/com.io7m.jsycamore.tests/src/main/resources/com/io7m/jsycamore/tests/arcticLarge.txt new file mode 100644 index 00000000..e332e74b --- /dev/null +++ b/com.io7m.jsycamore.tests/src/main/resources/com/io7m/jsycamore/tests/arcticLarge.txt @@ -0,0 +1,7 @@ +The history of the Polar Regions, of those vast areas, difficult of access, which include millions of square miles of land and ocean at either extreme of our planet, is of surpassing interest and importance. It is not only that we here meet with examples of heroism and devotion which must entrance mankind for all time. It is not only that there are dangers to be encountered and difficulties to be overcome which call forth the best qualities of our race. These, no doubt, are the main reasons for the deep interest which polar exploration has always excited. But there are others of almost equal importance. These regions offer great scientific problems. They present wide fields of research in almost all departments of knowledge. They have in the past yielded vast wealth, and have been the sources of commercial prosperity to many communities, and they may be so again. Their history is a history of noble and persevering effort; extending over a thousand years in the Arctic where the work is well-nigh finished, but only just beginning in the Antarctic regions, where it will have to be completed by our descendants. + +In approaching the subject it is well to have before our minds the extent of these great areas, the history of which we would grasp and understand. At the polar circle, which is 1410 geographical miles from the centre, they have a periphery of 8460 miles, and each includes 6,000,000 square miles. The Arctic and Antarctic circles are in 66° 32′ North and South, but these parallels are merely conventional. It is more convenient, as will be seen hereafter, to take the Polar regions as beginning at about the 70th parallel, the Sub-arctic and Sub-antarctic regions extending from 60° to 70°, a zone in which the fauna is richer and more varied. + +The division of these polar regions into quadrants is useful because it facilitates geographical description and impresses the relative positions of the different parts on the mind. In the Arctic regions a line may be drawn from the Lofoten Islands to Bering Strait, with another crossing it from the head of Hudson’s Bay to Cape Chelyuskin; thus forming four quadrants. + +At the present day a fringe of coast lines forming the northern shores of the three great continents, with a deep interior polar sea, are the main features of the Arctic regions, but it was not always so. Looking back into remote geological periods, we have evidence of marvellous changes in the Arctic regions since the globe was a gradually cooling mass of vapour. In this process, extending over vast ages, the polar regions must have been, as they are now, cooler than the equatorial regions, and for the same reason. It was, therefore, in the polar regions that life first became possible, and here the life of the Silurian age arose. There is evidence of a continent in Jurassic and Tertiary (Miocene) times where now there is a polar ocean of great depth, save where Spitsbergen and Franz Josef Land exist as the sole remaining fragments of that continent. There is evidence that forests once flourished where now nothing higher than the dwarf willow can exist. There is evidence, too, of tremendous volcanic eruptions, covering great areas with sheets of basalt. In contemplating these mighty revolutions, and the gradual changes through long æons of ages, the leading fact connected with the polar regions is that here life first became possible. Here it was first possible that man could exist. The evidence that the arboreal vegetation of the miocene period originated round the north pole appears to be quite conclusive. The exploration of the Arctic area has disclosed proofs of wondrous secular changes which no imagination, however vivid, could surpass. Alike in the far south, as in the far north, there is food for the imagination--lights thrown here and there on the history of a marvellous past. Such speculations are a fitting introduction to a study of the existing state of things, which has lasted through the historical period, and probably for ages before the dawn of history. diff --git a/com.io7m.jsycamore.theme.primal/src/main/java/com/io7m/jsycamore/theme/primal/internal/SyPrimalTextArea.java b/com.io7m.jsycamore.theme.primal/src/main/java/com/io7m/jsycamore/theme/primal/internal/SyPrimalTextArea.java index c05bf23c..0b6fe2d4 100644 --- a/com.io7m.jsycamore.theme.primal/src/main/java/com/io7m/jsycamore/theme/primal/internal/SyPrimalTextArea.java +++ b/com.io7m.jsycamore.theme.primal/src/main/java/com/io7m/jsycamore/theme/primal/internal/SyPrimalTextArea.java @@ -74,51 +74,9 @@ public SyRenderNodeType render( PAreasI.cast(PAreasI.moveToOrigin(area)) ); - final var rectArea = - rectangle.area(); - final var values = this.theme().values(); - final var embossed = - SyEmbossedRectangle.emboss( - rectArea, - values.fillFlat(EMBOSS_SOUTH), - values.fillFlat(EMBOSS_WEST), - values.fillFlat(EMBOSS_NORTH), - values.fillFlat(EMBOSS_EAST), - 1, - 1 - ); - - final SyRenderNodeShape embossW = - new SyRenderNodeShape( - Optional.empty(), - Optional.of(embossed.fillWest()), - embossed.shapeWest() - ); - - final SyRenderNodeShape embossS = - new SyRenderNodeShape( - Optional.empty(), - Optional.of(embossed.fillSouth()), - embossed.shapeSouth() - ); - - final SyRenderNodeShape embossN = - new SyRenderNodeShape( - Optional.empty(), - Optional.of(embossed.fillNorth()), - embossed.shapeNorth() - ); - - final SyRenderNodeShape embossE = - new SyRenderNodeShape( - Optional.empty(), - Optional.of(embossed.fillEast()), - embossed.shapeEast() - ); - final var mainFill = new SyRenderNodeShape( Optional.empty(), @@ -133,9 +91,7 @@ public SyRenderNodeType render( rectangle ); - return SyRenderNodeComposite.composite( - mainFill, embossN, embossE, embossS, embossW, mainEdge - ); + return SyRenderNodeComposite.composite(mainFill, mainEdge); } catch (final SyThemeValueException e) { throw new IllegalStateException(e); }