From b16d90e035bcae7db900ec4016e11043069f55a1 Mon Sep 17 00:00:00 2001 From: Kirill Grouchnikov Date: Tue, 12 Sep 2023 17:07:21 -0400 Subject: [PATCH] More wiring of basic key tip data * Propagate the gallery expand key tip to the matching button * Wire key tips on meta components For #56 --- .../aurora/component/AuroraCommandButton.kt | 4 - .../component/ribbon/RibbonMetaComponent.kt | 110 ++++++++++++++---- .../component/ribbon/impl/BoundsTracker.kt | 4 +- .../component/ribbon/impl/KeyTipTracker.kt | 2 +- .../component/ribbon/impl/RibbonGallery.kt | 3 +- .../aurora/demo/ribbon/AuroraRibbonDemo.kt | 4 +- 6 files changed, 97 insertions(+), 30 deletions(-) diff --git a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/AuroraCommandButton.kt b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/AuroraCommandButton.kt index d5c974ec..6352bb18 100644 --- a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/AuroraCommandButton.kt +++ b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/AuroraCommandButton.kt @@ -1937,10 +1937,6 @@ private class CommandButtonLocator( ) : OnGloballyPositionedModifier { override fun onGloballyPositioned(coordinates: LayoutCoordinates) { - if (projection.presentationModel.actionKeyTip.equals("FY")) { - println("Position!") - } - // Convert the top left corner of the component to the root coordinates val converted = coordinates.localToRoot(Offset.Zero) topLeftOffset.x = converted.x diff --git a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/RibbonMetaComponent.kt b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/RibbonMetaComponent.kt index 9dbbcf02..9e0363ba 100644 --- a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/RibbonMetaComponent.kt +++ b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/RibbonMetaComponent.kt @@ -30,16 +30,15 @@ import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.resolveDefaults import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import org.pushingpixels.aurora.common.AuroraInternalApi +import org.pushingpixels.aurora.common.AuroraRect import org.pushingpixels.aurora.component.model.* import org.pushingpixels.aurora.component.projection.IconProjection import org.pushingpixels.aurora.component.projection.LabelProjection import org.pushingpixels.aurora.component.projection.Projection -import org.pushingpixels.aurora.component.ribbon.impl.BoundsTracker -import org.pushingpixels.aurora.component.ribbon.impl.LocalRibbonBandRowHeight -import org.pushingpixels.aurora.component.ribbon.impl.LocalRibbonTrackBounds -import org.pushingpixels.aurora.common.AuroraRect +import org.pushingpixels.aurora.component.ribbon.impl.* import org.pushingpixels.aurora.component.utils.getLabelPreferredHeight import org.pushingpixels.aurora.component.utils.getLabelPreferredSingleLineWidth import org.pushingpixels.aurora.theming.IconFilterStrategy @@ -70,6 +69,7 @@ class RibbonMetaComponentProjection RibbonMetaComponent( modifier: Modifier, + originalProjection: RibbonMetaComponentProjection, projection: Projection, enabled: () -> Boolean, ribbonComponentPresentationModel: RibbonComponentPresentationModel @@ -176,10 +178,11 @@ internal fun RibbonMetaComponent( val heightNeededForComponent = projection.intrinsicHeight(widthNeededForComponent) val trackBounds = LocalRibbonTrackBounds.current + val trackKeyTips = LocalRibbonTrackKeyTips.current Layout( modifier = if (trackBounds) { - modifier.metaComponentLocator(projection) + modifier.metaComponentLocator(originalProjection, trackBounds, trackKeyTips) } else { modifier }, @@ -220,9 +223,9 @@ internal fun RibbonMetaComponent( val iconPlaceable = if (hasIcon) measurables[index++].measure(Constraints()) else null val captionPlaceable = if (hasCaption) measurables[index++].measure(Constraints()) else null - var componentWidth: Int = 0 - var componentOffsetX: Int = 0 - var fullWidth: Int = 0 + var componentWidth = 0 + var componentOffsetX = 0 + var fullWidth = 0 if (constraints.hasFixedWidth) { val width = constraints.maxWidth @@ -288,6 +291,56 @@ internal fun RibbonMetaComponent( ) ) + if (originalProjection.ribbonComponentPresentationModel.keyTip != null) { + // Key tip offset logic: + // If the meta component has caption, the key tip is horizontally centered at the start + // edge of the caption. Otherwise, it is horizontally centered at the horizontal center + // of the main component. + if (hasCaption) { + val captionMid = if (layoutDirection == LayoutDirection.Ltr) { + if (hasIcon) { + iconPlaceable!!.measuredWidth + DefaultMetaComponentIconTextLayoutGap.toPx() + } else { + 0 + } + } else { + if (hasIcon) { + fullWidth - iconPlaceable!!.measuredWidth - DefaultMetaComponentIconTextLayoutGap.toPx() + } else { + fullWidth + } + } + KeyTipTracker.trackKeyTipOffset( + originalProjection, + originalProjection.ribbonComponentPresentationModel.keyTip, + captionMid.toFloat(), + height / 2.0f + ) + } else { + val componentMid = if (layoutDirection == LayoutDirection.Ltr) { + if (hasIcon) { + val iconSpace = iconPlaceable!!.measuredWidth + componentOffsetX + iconSpace + (fullWidth - iconSpace) / 2.0f + } else { + fullWidth / 2.0f + } + } else { + if (hasIcon) { + val iconSpace = iconPlaceable!!.measuredWidth + componentOffsetX + (fullWidth - iconSpace) / 2.0f + } else { + fullWidth / 2.0f + } + } + KeyTipTracker.trackKeyTipOffset( + originalProjection, + originalProjection.ribbonComponentPresentationModel.keyTip, + componentMid, + height / 2.0f + ) + } + } + layout(width = fullWidth, height = height) { var x = 0 if (hasIcon) { @@ -312,33 +365,50 @@ internal fun RibbonMetaComponent( DisposableEffect(projection) { onDispose { - BoundsTracker.untrackBounds(projection) + BoundsTracker.untrackBounds(originalProjection) + KeyTipTracker.untrackKeyTip(originalProjection) } } } @OptIn(AuroraInternalApi::class) -private class MetaComponentLocator(val projection: Projection) : +private class MetaComponentLocator( + val projection: RibbonMetaComponentProjection<*, *>, + val trackBounds: Boolean, + val trackKeyTips: Boolean +) : OnGloballyPositionedModifier { override fun onGloballyPositioned(coordinates: LayoutCoordinates) { // Convert the top left corner of the component to the root coordinates val converted = coordinates.localToRoot(Offset.Zero) - BoundsTracker.trackBounds( - projection, - AuroraRect( - x = converted.x, - y = converted.y, - width = coordinates.size.width.toFloat(), - height = coordinates.size.height.toFloat() - ) + val bounds = AuroraRect( + x = converted.x, + y = converted.y, + width = coordinates.size.width.toFloat(), + height = coordinates.size.height.toFloat() ) + if (trackBounds) { + BoundsTracker.trackBounds(projection, bounds) + } + if (trackKeyTips) { + if (projection.presentationModel.ribbonComponentPresentationModel.keyTip != null) { + KeyTipTracker.trackKeyTipBase( + projection, + projection.presentationModel.ribbonComponentPresentationModel.keyTip!!, + bounds + ) + } + } } } @Composable -private fun Modifier.metaComponentLocator(projection: Projection) = - this.then(MetaComponentLocator(projection)) +private fun Modifier.metaComponentLocator( + projection: RibbonMetaComponentProjection<*, *>, + trackBounds: Boolean, + trackKeyTips: Boolean +) = this.then(MetaComponentLocator(projection, trackBounds, trackKeyTips)) private val DefaultMetaComponentIconTextLayoutGap = 4.dp private val DefaultMetaComponentLayoutGap = 6.dp diff --git a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/BoundsTracker.kt b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/BoundsTracker.kt index 28a1d0d3..6d153e7c 100644 --- a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/BoundsTracker.kt +++ b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/BoundsTracker.kt @@ -26,13 +26,13 @@ import androidx.compose.ui.graphics.StrokeJoin import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.unit.Dp import org.pushingpixels.aurora.common.AuroraInternalApi +import org.pushingpixels.aurora.common.AuroraRect +import org.pushingpixels.aurora.common.contains import org.pushingpixels.aurora.component.model.ContentModel import org.pushingpixels.aurora.component.model.PresentationModel import org.pushingpixels.aurora.component.projection.BaseCommandButtonProjection import org.pushingpixels.aurora.component.projection.Projection import org.pushingpixels.aurora.component.ribbon.RibbonGalleryProjection -import org.pushingpixels.aurora.common.AuroraRect -import org.pushingpixels.aurora.common.contains @AuroraInternalApi object BoundsTracker { diff --git a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt index 19db4236..04bb9b34 100644 --- a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt +++ b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/KeyTipTracker.kt @@ -37,10 +37,10 @@ import org.jetbrains.skia.Font import org.jetbrains.skia.TextLine import org.jetbrains.skia.Typeface import org.pushingpixels.aurora.common.AuroraInternalApi +import org.pushingpixels.aurora.common.AuroraRect import org.pushingpixels.aurora.component.model.ContentModel import org.pushingpixels.aurora.component.model.PresentationModel import org.pushingpixels.aurora.component.projection.Projection -import org.pushingpixels.aurora.common.AuroraRect import org.pushingpixels.aurora.theming.* import org.pushingpixels.aurora.theming.shaper.ClassicButtonShaper import org.pushingpixels.aurora.theming.utils.MutableColorScheme diff --git a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/RibbonGallery.kt b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/RibbonGallery.kt index 8bdb466b..eea6d8c2 100644 --- a/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/RibbonGallery.kt +++ b/component/src/desktopMain/kotlin/org/pushingpixels/aurora/component/ribbon/impl/RibbonGallery.kt @@ -357,7 +357,8 @@ internal fun RibbonGallery( offset = galleryTopLeftOffset.asOffset(density), size = Size(width = gallerySize.value.width / density.density, height = 0.0f) ) - } + }, + popupKeyTip = presentationModel.expandKeyTip ) ) ).project(modifier = Modifier.weight(1.0f / 3.0f)) diff --git a/demo/src/desktopMain/kotlin/org/pushingpixels/aurora/demo/ribbon/AuroraRibbonDemo.kt b/demo/src/desktopMain/kotlin/org/pushingpixels/aurora/demo/ribbon/AuroraRibbonDemo.kt index 5c846896..ba657e90 100644 --- a/demo/src/desktopMain/kotlin/org/pushingpixels/aurora/demo/ribbon/AuroraRibbonDemo.kt +++ b/demo/src/desktopMain/kotlin/org/pushingpixels/aurora/demo/ribbon/AuroraRibbonDemo.kt @@ -1893,12 +1893,12 @@ internal class RibbonBuilder( RibbonMetaComponentProjection( projection = RadioButtonProjection(contentModel = cozyContentModel), enabled = { cozyContentModel.enabled }, - ribbonComponentPresentationModel = RibbonComponentPresentationModel(keyTip = "LA") + ribbonComponentPresentationModel = RibbonComponentPresentationModel(keyTip = "LB") ), RibbonMetaComponentProjection( projection = RadioButtonProjection(contentModel = compactContentModel), enabled = { compactContentModel.enabled }, - ribbonComponentPresentationModel = RibbonComponentPresentationModel(keyTip = "LA") + ribbonComponentPresentationModel = RibbonComponentPresentationModel(keyTip = "LC") ), ) )