Skip to content

Commit

Permalink
More preliminary work on key tips
Browse files Browse the repository at this point in the history
* Properly anchor the tips based on the anchor coordinates passed in
* Wire key tips on ribbon task toggle buttons
* Fix a few tips in the demo app

For #56
  • Loading branch information
kirill-grouchnikov committed Sep 12, 2023
1 parent 2e18c89 commit 031f4e2
Show file tree
Hide file tree
Showing 15 changed files with 295 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pushingpixels.aurora.component.utils
package org.pushingpixels.aurora.common

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize

internal data class AuroraOffset(var x: Float, var y: Float)
internal data class AuroraRect(var x: Float, var y: Float, var width: Float, var height: Float)
@AuroraInternalApi
data class AuroraOffset(var x: Float, var y: Float)
@AuroraInternalApi
data class AuroraRect(var x: Float, var y: Float, var width: Float, var height: Float)

internal fun AuroraRect.contains(x: Float, y: Float): Boolean {
@AuroraInternalApi
fun AuroraRect.contains(x: Float, y: Float): Boolean {
return (x >= this.x) && (x < (this.x + this.width)) && (y >= this.y) &&
(y < (this.y + this.height))
}

internal fun AuroraOffset.asOffset(density: Density): Offset {
@AuroraInternalApi
fun AuroraOffset.asOffset(density: Density): Offset {
return Offset(x / density.density, y / density.density)
}

internal fun IntSize.asSize(density: Density): Size {
@AuroraInternalApi
fun IntSize.asSize(density: Density): Size {
return Size(width / density.density, height / density.density)
}

internal fun IntSize.asSize(extraWidth: Int = 0, extraHeight: Int = 0) =
@AuroraInternalApi
fun IntSize.asSize(extraWidth: Int = 0, extraHeight: Int = 0) =
Size((width + extraWidth).toFloat(), (height + extraHeight).toFloat())
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.resolveDefaults
import androidx.compose.ui.unit.*
import kotlinx.coroutines.launch
import org.pushingpixels.aurora.common.AuroraInternalApi
import org.pushingpixels.aurora.common.AuroraPopupManager
import org.pushingpixels.aurora.common.withAlpha
import org.pushingpixels.aurora.common.*
import org.pushingpixels.aurora.component.model.*
import org.pushingpixels.aurora.component.utils.*
import org.pushingpixels.aurora.component.utils.popup.GeneralCommandMenuPopupHandler
Expand All @@ -59,6 +57,7 @@ private class ComboBoxDrawingCache(
)
)

@OptIn(AuroraInternalApi::class)
private class ComboBoxLocator(val topLeftOffset: AuroraOffset, val size: MutableState<IntSize>) :
OnGloballyPositionedModifier {
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
Expand All @@ -72,6 +71,7 @@ private class ComboBoxLocator(val topLeftOffset: AuroraOffset, val size: Mutable
}
}

@OptIn(AuroraInternalApi::class)
@Composable
private fun Modifier.comboBoxLocator(topLeftOffset: AuroraOffset, size: MutableState<IntSize>) = this.then(
ComboBoxLocator(topLeftOffset, size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,17 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.*
import org.pushingpixels.aurora.common.AuroraInternalApi
import org.pushingpixels.aurora.common.AuroraPopupManager
import org.pushingpixels.aurora.common.interpolateTowards
import org.pushingpixels.aurora.common.withAlpha
import org.pushingpixels.aurora.common.*
import org.pushingpixels.aurora.component.layout.CommandButtonLayoutManager
import org.pushingpixels.aurora.component.model.*
import org.pushingpixels.aurora.component.popup.BaseCommandMenuHandler
import org.pushingpixels.aurora.component.projection.BaseCommandButtonProjection
import org.pushingpixels.aurora.component.projection.HorizontalSeparatorProjection
import org.pushingpixels.aurora.component.projection.Projection
import org.pushingpixels.aurora.component.projection.VerticalSeparatorProjection
import org.pushingpixels.aurora.component.ribbon.impl.BoundsTracker
import org.pushingpixels.aurora.component.ribbon.impl.KeyTipTracker
import org.pushingpixels.aurora.component.ribbon.impl.LocalRibbonTrackBounds
import org.pushingpixels.aurora.component.ribbon.impl.LocalRibbonTrackKeyTips
import org.pushingpixels.aurora.component.utils.*
import org.pushingpixels.aurora.theming.*
import org.pushingpixels.aurora.theming.utils.MutableColorScheme
Expand Down Expand Up @@ -883,9 +880,16 @@ internal fun <M : BaseCommandMenuContentModel,
val coroutineScope = rememberCoroutineScope()

val trackBounds = LocalRibbonTrackBounds.current
val trackKeyTips = LocalRibbonTrackKeyTips.current

Layout(
modifier = modifier.commandButtonLocator(originalProjection, buttonTopLeftOffset, buttonSize, trackBounds),
modifier = modifier.commandButtonLocator(
originalProjection,
buttonTopLeftOffset,
buttonSize,
trackBounds,
trackKeyTips
),
content = {
val modifierAction: Modifier
if (isToggle) {
Expand Down Expand Up @@ -1550,22 +1554,19 @@ internal fun <M : BaseCommandMenuContentModel,
}

if ((presentationModel.actionKeyTip != null) && !layoutInfo.actionClickArea.isEmpty) {
if (originalProjection.contentModel.text.equals("Paste")) {
println("Action + Popup layout!")
}
KeyTipTracker.trackKeyTipOffset(
originalProjection,
presentationModel.actionKeyTip!!,
layoutInfo.actionClickArea.left,
layoutInfo.actionClickArea.top
layoutInfo.actionClickArea.left + layoutInfo.actionClickArea.width / 2,
layoutInfo.actionClickArea.top + layoutInfo.actionClickArea.height / 2
)
}
if ((presentationModel.popupKeyTip != null) && !layoutInfo.popupClickArea.isEmpty) {
KeyTipTracker.trackKeyTipOffset(
originalProjection,
presentationModel.popupKeyTip!!,
layoutInfo.popupClickArea.left,
layoutInfo.popupClickArea.top
layoutInfo.popupClickArea.left + layoutInfo.popupClickArea.width / 2,
layoutInfo.popupClickArea.top + layoutInfo.popupClickArea.height / 2
)
}

Expand Down Expand Up @@ -1926,15 +1927,17 @@ private fun CommandButtonPopupIconContent(
}
}

@OptIn(AuroraInternalApi::class)
private class CommandButtonLocator(
val projection: BaseCommandButtonProjection<*, *, *>,
val topLeftOffset: AuroraOffset,
val size: MutableState<IntSize>,
val trackBounds: Boolean
val trackBounds: Boolean,
val trackKeyTips: Boolean
) :
OnGloballyPositionedModifier {
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
if (projection.contentModel.text.equals("Paste")) {
if (projection.presentationModel.actionKeyTip.equals("FY")) {
println("Position!")
}

Expand All @@ -1946,16 +1949,17 @@ private class CommandButtonLocator(
// And store the component size
size.value = coordinates.size

val bounds = AuroraRect(
x = converted.x,
y = converted.y,
width = coordinates.size.width.toFloat(),
height = coordinates.size.height.toFloat()
)
if (trackBounds) {
val bounds = AuroraRect(
x = converted.x,
y = converted.y,
width = coordinates.size.width.toFloat(),
height = coordinates.size.height.toFloat()
)

BoundsTracker.trackBounds(projection, bounds)
}

if (trackKeyTips) {
if (projection.presentationModel.actionKeyTip != null) {
KeyTipTracker.trackKeyTipBase(
projection,
Expand All @@ -1974,10 +1978,12 @@ private class CommandButtonLocator(
}
}

@OptIn(AuroraInternalApi::class)
@Composable
private fun Modifier.commandButtonLocator(
projection: BaseCommandButtonProjection<*, *, *>,
topLeftOffset: AuroraOffset,
size: MutableState<IntSize>,
trackBounds: Boolean
) = this.then(CommandButtonLocator(projection, topLeftOffset, size, trackBounds))
trackBounds: Boolean,
trackKeyTips: Boolean
) = this.then(CommandButtonLocator(projection, topLeftOffset, size, trackBounds, trackKeyTips))
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ import org.pushingpixels.aurora.common.AuroraInternalApi
import org.pushingpixels.aurora.common.AuroraPopupManager
import org.pushingpixels.aurora.component.model.RichTooltip
import org.pushingpixels.aurora.component.model.RichTooltipPresentationModel
import org.pushingpixels.aurora.component.utils.AuroraOffset
import org.pushingpixels.aurora.component.utils.asOffset
import org.pushingpixels.aurora.component.utils.asSize
import org.pushingpixels.aurora.common.AuroraOffset
import org.pushingpixels.aurora.common.asOffset
import org.pushingpixels.aurora.common.asSize
import org.pushingpixels.aurora.component.utils.displayRichTooltipWindow
import org.pushingpixels.aurora.theming.*

Expand All @@ -53,6 +53,7 @@ private suspend fun PointerInputScope.detectDown(onDown: (Offset) -> Unit) {
}
}

@OptIn(AuroraInternalApi::class)
private class Locator(val topLeftOffset: AuroraOffset, val size: MutableState<IntSize>) :
OnGloballyPositionedModifier {
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
Expand All @@ -66,6 +67,7 @@ private class Locator(val topLeftOffset: AuroraOffset, val size: MutableState<In
}
}

@OptIn(AuroraInternalApi::class)
@Composable
private fun Modifier.locator(topLeftOffset: AuroraOffset, size: MutableState<IntSize>) = this.then(
Locator(topLeftOffset, size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ import androidx.compose.ui.platform.LocalLayoutDirection
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.common.contains
import org.pushingpixels.aurora.common.withAlpha
import org.pushingpixels.aurora.component.model.SliderContentModel
import org.pushingpixels.aurora.component.model.SliderPresentationModel
Expand All @@ -56,6 +58,7 @@ import org.pushingpixels.aurora.theming.utils.MutableColorScheme
import org.pushingpixels.aurora.theming.utils.getBaseOutline
import kotlin.math.roundToInt

@OptIn(AuroraInternalApi::class)
@Immutable
private class SliderDrawingCache(
val trackRect: AuroraRect = AuroraRect(0.0f, 0.0f, 0.0f, 0.0f),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ 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.component.utils.AuroraRect
import org.pushingpixels.aurora.common.AuroraRect
import org.pushingpixels.aurora.component.utils.getLabelPreferredHeight
import org.pushingpixels.aurora.component.utils.getLabelPreferredSingleLineWidth
import org.pushingpixels.aurora.theming.IconFilterStrategy
Expand Down Expand Up @@ -317,6 +317,7 @@ internal fun <C : ContentModel, P : PresentationModel> RibbonMetaComponent(
}
}

@OptIn(AuroraInternalApi::class)
private class MetaComponentLocator(val projection: Projection<ContentModel, PresentationModel>) :
OnGloballyPositionedModifier {
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ 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.component.ribbon.RibbonMetaComponentProjection
import org.pushingpixels.aurora.component.utils.AuroraRect
import org.pushingpixels.aurora.component.utils.contains
import org.pushingpixels.aurora.common.AuroraRect
import org.pushingpixels.aurora.common.contains

internal object BoundsTracker {
@AuroraInternalApi
object BoundsTracker {
private val bounds: MutableMap<Projection<ContentModel, PresentationModel>, AuroraRect> = hashMapOf()

fun trackBounds(projection: Projection<ContentModel, PresentationModel>, rect: AuroraRect) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.withTransform
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFontFamilyResolver
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.Paragraph
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.resolveDefaults
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
Expand All @@ -44,18 +40,19 @@ import org.pushingpixels.aurora.common.AuroraInternalApi
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.component.utils.AuroraRect
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

internal object KeyTipTracker {
@AuroraInternalApi
object KeyTipTracker {
data class KeyTipInfo(
var projection: Projection<ContentModel, PresentationModel>,
var keyTip: String,
var screenRect: AuroraRect,
var offsetX: Float,
var offsetY: Float
var anchorX: Float,
var anchorY: Float
)

private val keyTips: MutableList<KeyTipInfo> = arrayListOf()
Expand All @@ -78,17 +75,17 @@ internal object KeyTipTracker {
fun trackKeyTipOffset(
projection: Projection<ContentModel, PresentationModel>,
keyTip: String,
offsetX: Float,
offsetY: Float
anchorX: Float,
anchorY: Float
) {
val existing = keyTips.find {
(it.projection == projection) && (it.keyTip == keyTip)
}
if (existing != null) {
existing.offsetX = offsetX
existing.offsetY = offsetY
existing.anchorX = anchorX
existing.anchorY = anchorY
} else {
keyTips.add(KeyTipInfo(projection, keyTip, AuroraRect(0.0f, 0.0f, 0.0f, 0.0f), offsetX, offsetY))
keyTips.add(KeyTipInfo(projection, keyTip, AuroraRect(0.0f, 0.0f, 0.0f, 0.0f), anchorX, anchorY))
}
}

Expand Down Expand Up @@ -146,10 +143,9 @@ fun RibbonKeyTipOverlay(modifier: Modifier, insets: Dp) {
Canvas(modifier = modifier) {
val width = this.size.width
val height = this.size.height
println("KEY TIP TRACKER SIZE ${this.size}")
//println("KEY TIP TRACKER SIZE ${this.size}")

for (tracked in KeyTipTracker.getKeyTips()) {

val paragraph = Paragraph(
text = tracked.keyTip, style = textStyle, constraints = Constraints(maxWidth = Int.MAX_VALUE),
density = density, maxLines = 1, fontFamilyResolver = fontFamilyResolver
Expand All @@ -159,9 +155,16 @@ fun RibbonKeyTipOverlay(modifier: Modifier, insets: Dp) {
val tipWidth = leftPadding.toPx() + paragraph.maxIntrinsicWidth + rightPadding.toPx()
val tipHeight = topPadding.toPx() + paragraph.height + bottomPadding.toPx()

val fullOffsetX = tracked.screenRect.x + tracked.anchorX - tipWidth / 2 - insets.toPx()
val fullOffsetY = tracked.screenRect.y + tracked.anchorY - tipHeight / 2 - insets.toPx()
if (tracked.keyTip.equals("FY")) {
println("Key tip $tracked width=$tipWidth height=$tipHeight offsetX=$fullOffsetX")
}


//println("Drawing ${tracked.keyTip} at ${tracked.screenRect}")
withTransform({
translate(left = tracked.screenRect.x, top = tracked.screenRect.y)
translate(left = fullOffsetX, top = fullOffsetY)
}) {
val fillOutline = buttonShaper.getButtonOutline(
layoutDirection = layoutDirection,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ import androidx.compose.ui.text.resolveDefaults
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import org.pushingpixels.aurora.common.AuroraInternalApi
import org.pushingpixels.aurora.common.withAlpha
import org.pushingpixels.aurora.common.*
import org.pushingpixels.aurora.component.model.*
import org.pushingpixels.aurora.component.projection.CommandButtonProjection
import org.pushingpixels.aurora.component.projection.Projection
Expand Down Expand Up @@ -441,6 +440,7 @@ internal fun RibbonGallery(
}
}

@OptIn(AuroraInternalApi::class)
private class GalleryLocator(
val projection: Projection<RibbonGalleryContentModel, RibbonGalleryPresentationModel>,
val topLeftOffset: AuroraOffset,
Expand Down Expand Up @@ -471,6 +471,7 @@ private class GalleryLocator(
}
}

@OptIn(AuroraInternalApi::class)
@Composable
private fun Modifier.galleryLocator(
projection: Projection<RibbonGalleryContentModel, RibbonGalleryPresentationModel>,
Expand Down
Loading

0 comments on commit 031f4e2

Please sign in to comment.