Skip to content

Commit

Permalink
Wire action / popup activation on command buttons via key tips
Browse files Browse the repository at this point in the history
For #56
  • Loading branch information
kirill-grouchnikov committed Nov 3, 2023
1 parent febbd0c commit 89561db
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,65 @@ internal fun <M : BaseCommandMenuContentModel,
val bandRowHeight = LocalRibbonBandRowHeight.current
val bandRow = LocalRibbonBandRow.current

// These two track the offset of action and popup area relative in
// the overall bounding box of the command button. To paint continuous
// visuals of the command button across two separate Box composables,
// we paint each as full-size area, along with clipping to the specific
// area (action or popup) and offsetting during the Canvas paint pass.
var actionAreaOffset = remember { Offset.Zero }
var popupAreaOffset = remember { Offset.Zero }
val popupAreaSize = remember { mutableStateOf(IntSize(0, 0)) }
val onActivatePopup: () -> Unit = {
val isShowingPopupFromHere = AuroraPopupManager.isShowingPopupFrom(
originator = popupOriginator,
pointInOriginator = AuroraOffset(
x = buttonTopLeftOffset.x + popupAreaOffset.x + popupAreaSize.value.width / 2.0f,
y = buttonTopLeftOffset.y + popupAreaOffset.y + popupAreaSize.value.height / 2.0f
).asOffset(density)
)
if (!isShowingPopupFromHere) {
// Display our popup content.
val popupWindow = popupHandler.showPopupContent(
popupOriginator = popupOriginator,
layoutDirection = layoutDirection,
density = density,
textStyle = resolvedTextStyle,
fontFamilyResolver = fontFamilyResolver,
skinColors = skinColors,
colorSchemeBundle = presentationModel.colorSchemeBundle,
skinPainters = painters,
decorationAreaType = decorationAreaType,
compositionLocalContext = compositionLocalContext,
anchorBoundsInWindow = Rect(
offset = buttonTopLeftOffset.asOffset(density),
size = buttonSize.value.asSize(density)
),
popupTriggerAreaInWindow = Rect(
offset = AuroraOffset(
x = buttonTopLeftOffset.x + popupAreaOffset.x,
y = buttonTopLeftOffset.y + popupAreaOffset.y
).asOffset(density),
size = popupAreaSize.value.asSize(density)
),
contentModel = secondaryContentModel,
presentationModel = presentationModel.popupMenuPresentationModel as P,
displayPrototypeCommand = null,
toDismissPopupsOnActivation = presentationModel.toDismissPopupsOnActivation,
popupPlacementStrategy = presentationModel.popupPlacementStrategy,
popupAnchorBoundsProvider = presentationModel.popupAnchorBoundsProvider,
overlays = secondaryOverlays,
popupKind = AuroraPopupManager.PopupKind.Popup
)
coroutineScope.launch {
popupWindow?.opacity = 1.0f
}
} else {
// Showing a popup that originates from the popup area of this command button.
// Hide it.
AuroraPopupManager.hidePopups(originator = popupOriginator)
}
}

Layout(
modifier = modifier.commandButtonLocator(
originalProjection,
Expand All @@ -893,7 +952,7 @@ internal fun <M : BaseCommandMenuContentModel,
trackBounds,
trackKeyTips,
keyTipChainRoot,
{ command.secondaryContentModel },
command.secondaryContentModel,
),
content = {
val modifierAction: Modifier
Expand Down Expand Up @@ -925,14 +984,6 @@ internal fun <M : BaseCommandMenuContentModel,
presentationModel = presentationModel
)
}
// These two track the offset of action and popup area relative in
// the overall bounding box of the command button. To paint continuous
// visuals of the command button across two separate Box composables,
// we paint each as full-size area, along with clipping to the specific
// area (action or popup) and offsetting during the Canvas paint pass.
var actionAreaOffset = remember { Offset.Zero }
var popupAreaOffset = remember { Offset.Zero }
val popupAreaSize = remember { mutableStateOf(IntSize(0, 0)) }
Box(
modifier = modifierAction.auroraRichTooltip(
richTooltip = command.actionRichTooltip,
Expand Down Expand Up @@ -1126,56 +1177,7 @@ internal fun <M : BaseCommandMenuContentModel,
Box(
modifier = Modifier.commandButtonPopupModifier(
enabled = isPopupEnabled,
onActivatePopup = {
val isShowingPopupFromHere = AuroraPopupManager.isShowingPopupFrom(
originator = popupOriginator,
pointInOriginator = AuroraOffset(
x = buttonTopLeftOffset.x + popupAreaOffset.x + popupAreaSize.value.width / 2.0f,
y = buttonTopLeftOffset.y + popupAreaOffset.y + popupAreaSize.value.height / 2.0f
).asOffset(density)
)
if (!isShowingPopupFromHere) {
// Display our popup content.
val popupWindow = popupHandler.showPopupContent(
popupOriginator = popupOriginator,
layoutDirection = layoutDirection,
density = density,
textStyle = resolvedTextStyle,
fontFamilyResolver = fontFamilyResolver,
skinColors = skinColors,
colorSchemeBundle = presentationModel.colorSchemeBundle,
skinPainters = painters,
decorationAreaType = decorationAreaType,
compositionLocalContext = compositionLocalContext,
anchorBoundsInWindow = Rect(
offset = buttonTopLeftOffset.asOffset(density),
size = buttonSize.value.asSize(density)
),
popupTriggerAreaInWindow = Rect(
offset = AuroraOffset(
x = buttonTopLeftOffset.x + popupAreaOffset.x,
y = buttonTopLeftOffset.y + popupAreaOffset.y
).asOffset(density),
size = popupAreaSize.value.asSize(density)
),
contentModel = secondaryContentModel,
presentationModel = presentationModel.popupMenuPresentationModel as P,
displayPrototypeCommand = null,
toDismissPopupsOnActivation = presentationModel.toDismissPopupsOnActivation,
popupPlacementStrategy = presentationModel.popupPlacementStrategy,
popupAnchorBoundsProvider = presentationModel.popupAnchorBoundsProvider,
overlays = secondaryOverlays,
popupKind = AuroraPopupManager.PopupKind.Popup
)
coroutineScope.launch {
popupWindow?.opacity = 1.0f
}
} else {
// Showing a popup that originates from the popup area of this command button.
// Hide it.
AuroraPopupManager.hidePopups(originator = popupOriginator)
}
},
onActivatePopup = onActivatePopup,
onDeactivatePopup = {
val isShowingPopupFromHere = AuroraPopupManager.isShowingPopupFrom(
originator = popupOriginator,
Expand Down Expand Up @@ -1609,7 +1611,6 @@ internal fun <M : BaseCommandMenuContentModel,

if (popupMenu == null) {
if ((presentationModel.actionKeyTip != null) && !layoutInfo.actionClickArea.isEmpty) {
val traversal: () -> Any
KeyTipTracker.trackKeyTipOffset(
originalProjection,
presentationModel.actionKeyTip!!,
Expand All @@ -1619,8 +1620,13 @@ internal fun <M : BaseCommandMenuContentModel,
row = bandRow,
rowHeight = bandRowHeight
),
{
coroutineScope.launch {
command.action?.invoke()
}
},
keyTipChainRoot,
command.secondaryContentModel
null
)
}
if ((presentationModel.popupKeyTip != null) && !layoutInfo.popupClickArea.isEmpty) {
Expand All @@ -1633,6 +1639,11 @@ internal fun <M : BaseCommandMenuContentModel,
row = bandRow,
rowHeight = bandRowHeight
),
{
coroutineScope.launch {
onActivatePopup.invoke()
}
},
keyTipChainRoot,
command.secondaryContentModel
)
Expand Down Expand Up @@ -2066,6 +2077,7 @@ private fun CommandButtonKeyTip(
isEnabled = isEnabled,
screenRect = AuroraRect(0.0f, 0.0f, buttonSize.width.toFloat(), buttonSize.height.toFloat()),
anchor = Offset(size.width / 2.0f, size.height / 2.0f),
onActivated = null,
chainRoot = null,
traversal = { null }
),
Expand Down Expand Up @@ -2093,7 +2105,7 @@ private class CommandButtonLocator(
val trackBounds: Boolean,
val trackKeyTips: Boolean,
val keyTipChainRoot: Any?,
val keyTipTraversal: () -> Any?,
val popupKeyTipTraversal: Any?,
) :
OnGloballyPositionedModifier {
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
Expand Down Expand Up @@ -2123,7 +2135,7 @@ private class CommandButtonLocator(
command.isActionEnabled,
bounds,
keyTipChainRoot,
keyTipTraversal
null
)
}
if (presentationModel.popupKeyTip != null) {
Expand All @@ -2133,7 +2145,7 @@ private class CommandButtonLocator(
command.isSecondaryEnabled,
bounds,
keyTipChainRoot,
keyTipTraversal
popupKeyTipTraversal
)
}
}
Expand All @@ -2151,7 +2163,7 @@ private fun Modifier.commandButtonLocator(
trackBounds: Boolean,
trackKeyTips: Boolean,
keyTipChainRoot: Any?,
keyTipTraversal: () -> Any?,
popupKeyTipTraversal: Any?,
) = this.then(
CommandButtonLocator(
originalProjection,
Expand All @@ -2162,6 +2174,6 @@ private fun Modifier.commandButtonLocator(
trackBounds,
trackKeyTips,
keyTipChainRoot,
keyTipTraversal
popupKeyTipTraversal
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ internal fun <C : ContentModel, P : PresentationModel> RibbonMetaComponent(
row = bandRow,
rowHeight = bandRowHeight
),
null,
keyTipChainRoot,
null
)
Expand Down Expand Up @@ -350,6 +351,7 @@ internal fun <C : ContentModel, P : PresentationModel> RibbonMetaComponent(
row = bandRow,
rowHeight = bandRowHeight
),
null,
keyTipChainRoot,
null
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ object KeyTipTracker {
val isEnabled: Boolean,
var screenRect: AuroraRect,
var anchor: Offset,
var onActivated: (() -> Unit)?,
val chainRoot: Any?,
val traversal: Any?
)
Expand Down Expand Up @@ -94,6 +95,7 @@ object KeyTipTracker {
isEnabled = isEnabled,
screenRect = screenRect,
anchor = Offset.Zero,
onActivated = null,
chainRoot = chainRoot,
traversal = traversal,
)
Expand All @@ -106,6 +108,7 @@ object KeyTipTracker {
keyTip: String,
isEnabled: Boolean,
anchor: Offset,
onActivated: (() -> Unit)?,
chainRoot: Any?,
traversal: Any?,
) {
Expand All @@ -114,6 +117,7 @@ object KeyTipTracker {
}
if (existing != null) {
existing.anchor = anchor.copy()
existing.onActivated = onActivated
} else {
keyTips.add(
KeyTipLink(
Expand All @@ -122,6 +126,7 @@ object KeyTipTracker {
isEnabled = isEnabled,
screenRect = AuroraRect(0.0f, 0.0f, 0.0f, 0.0f),
anchor = anchor.copy(),
onActivated = onActivated,
chainRoot = chainRoot,
traversal = traversal,
)
Expand Down Expand Up @@ -164,6 +169,7 @@ object KeyTipTracker {
chainRoots.clear()
visibleFlow.value = false
chainDepth.value = 0
println("Cleared all key tips, depth ${chainDepth.value}")
}

fun showRootKeyTipChain(ribbon: Ribbon) {
Expand All @@ -177,6 +183,7 @@ object KeyTipTracker {
if (!isShowingKeyTips()) {
return
}
println("Processing $char at depth ${chainDepth.value}")
val currChain = getCurrentlyShownKeyTipChain()!!
val currChainRoot = chainRoots.last()

Expand All @@ -187,6 +194,7 @@ object KeyTipTracker {
if (char.lowercaseChar() == keyTipString.get(0).lowercaseChar()) {
// Match!
if (link.isEnabled) {
link.onActivated?.invoke()
// TODO - activate the element
if (link.traversal != null) {
val nextChainRoot = link.traversal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.resolveDefaults
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
import kotlinx.coroutines.launch
import org.pushingpixels.aurora.common.*
import org.pushingpixels.aurora.component.auroraRichTooltip
import org.pushingpixels.aurora.component.model.BaseCommand
Expand Down Expand Up @@ -258,6 +259,8 @@ internal fun RibbonTaskToggleButton(
)
val buttonTopLeftOffset = remember { AuroraOffset(0.0f, 0.0f) }
val buttonSize = remember { mutableStateOf(IntSize(0, 0)) }
val coroutineScope = rememberCoroutineScope()

val trackBounds = LocalRibbonTrackBounds.current
val keyTipChainRoot = LocalRibbonKeyTipChainRoot.current
val trackKeyTips = LocalRibbonTrackKeyTips.current
Expand Down Expand Up @@ -566,6 +569,11 @@ internal fun RibbonTaskToggleButton(
presentationModel.actionKeyTip!!,
command.isActionEnabled,
layoutManager.getActionKeyTipAnchorCenterPoint(command, presentationModel, layoutInfo),
{
coroutineScope.launch {
command.action?.invoke()
}
},
keyTipChainRoot,
command.tag
)
Expand Down

0 comments on commit 89561db

Please sign in to comment.