Skip to content

Commit

Permalink
Improving the interaction with ribbon task buttons in minimized mode
Browse files Browse the repository at this point in the history
For #56
  • Loading branch information
kirill-grouchnikov committed Jul 13, 2023
1 parent 96db8c7 commit b4fd86c
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class AuroraSwingPopupMenu(val toDismissPopupsOnActivation: Boolean) : JPopupMen
// following property change. Not ideal, but then this whole setup is like that.
if ((it.propertyName == "JPopupMenu.firePopupMenuCanceled") && (it.newValue as Boolean)) {
// Handle this as a signal to hide all the popups
AuroraPopupManager.hidePopups(null)
//println("***** FIRE MENU CANCELED *****")
//AuroraPopupManager.hidePopups(null)
}
}
}
Expand Down Expand Up @@ -124,8 +125,11 @@ private class AuroraPopupFactory : PopupFactory() {
}

object AuroraPopupManager {
enum class PopupKind {
Popup, RichTooltip
class PopupKind {
companion object {
val Popup = PopupKind()
val RichTooltip = PopupKind()
}
}

private data class PopupInfo(
Expand Down Expand Up @@ -232,7 +236,8 @@ object AuroraPopupManager {
fun dump() {
println("Popups")
for (link in shownPath) {
println("\tOriginator ${link.originatorPopup.javaClass.simpleName}@${link.originatorPopup.hashCode()}")
println("\tOriginator ${link.originatorPopup.javaClass.simpleName}@${link.originatorPopup.hashCode()} [${link.popupKind.javaClass.simpleName}]")
println("\t --- trigger area ${link.popupTriggerAreaInOriginatorWindow}")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,8 @@ internal fun <E> AuroraComboBox(
toDismissPopupsOnActivation = true,
popupPlacementStrategy = presentationModel.popupPlacementStrategy,
popupAnchorBoundsProvider = null,
overlays = emptyMap()
overlays = emptyMap(),
popupKind = AuroraPopupManager.PopupKind.Popup
)
coroutineScope.launch {
popupWindow?.opacity = 1.0f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,8 @@ internal fun <M : BaseCommandMenuContentModel,
toDismissPopupsOnActivation = presentationModel.toDismissPopupsOnActivation,
popupPlacementStrategy = presentationModel.popupPlacementStrategy,
popupAnchorBoundsProvider = presentationModel.popupAnchorBoundsProvider,
overlays = secondaryOverlays
overlays = secondaryOverlays,
popupKind = AuroraPopupManager.PopupKind.Popup
)
coroutineScope.launch {
popupWindow?.opacity = 1.0f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.resolveDefaults
import kotlinx.coroutines.launch
import org.pushingpixels.aurora.common.AuroraInternalApi
import org.pushingpixels.aurora.common.AuroraPopupManager
import org.pushingpixels.aurora.component.model.BaseCommandButtonPresentationModel
import org.pushingpixels.aurora.component.model.Command
import org.pushingpixels.aurora.component.model.CommandMenuContentModel
Expand Down Expand Up @@ -95,7 +96,8 @@ fun Modifier.auroraContextMenu(
toDismissPopupsOnActivation = presentationModel.toDismissOnCommandActivation,
popupPlacementStrategy = presentationModel.popupPlacementStrategy,
popupAnchorBoundsProvider = null,
overlays = overlays
overlays = overlays,
popupKind = AuroraPopupManager.PopupKind.Popup
)
coroutineScope.launch {
popupWindow?.opacity = 1.0f
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ interface CascadingCommandMenuHandler<in M : BaseCommandMenuContentModel,
toDismissPopupsOnActivation: Boolean,
popupPlacementStrategy: PopupPlacementStrategy,
popupAnchorBoundsProvider: (() -> Rect)?,
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>,
popupKind: AuroraPopupManager.PopupKind
): Window? {
val popupContentLayoutInfo = getPopupContentLayoutInfo(
menuContentModel = contentModel.value!!,
Expand Down Expand Up @@ -225,7 +226,7 @@ interface CascadingCommandMenuHandler<in M : BaseCommandMenuContentModel,
popup = popupMenu,
popupContent = popupContent,
popupRectOnScreen = popupRect,
popupKind = AuroraPopupManager.PopupKind.Popup,
popupKind = popupKind,
onActivatePopup = contentModel.value?.onActivatePopup,
onDeactivatePopup = contentModel.value?.onDeactivatePopup
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import org.pushingpixels.aurora.common.AuroraPopupManager
import org.pushingpixels.aurora.component.model.*
import org.pushingpixels.aurora.theming.AuroraPainters
import org.pushingpixels.aurora.theming.AuroraSkin
Expand Down Expand Up @@ -69,7 +70,8 @@ interface BaseCommandMenuHandler<in M : BaseCommandMenuContentModel,
toDismissPopupsOnActivation: Boolean,
popupPlacementStrategy: PopupPlacementStrategy,
popupAnchorBoundsProvider: (() -> Rect)?,
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>,
popupKind: AuroraPopupManager.PopupKind
): Window?

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ internal class RibbonApplicationMenuPopupHandler(
toDismissPopupsOnActivation: Boolean,
popupPlacementStrategy: PopupPlacementStrategy,
popupAnchorBoundsProvider: (() -> Rect)?,
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>,
popupKind: AuroraPopupManager.PopupKind
): Window? {
onLevel1ActionRollover.invoke(secondaryCommand)
return null
Expand Down Expand Up @@ -506,7 +507,8 @@ internal class RibbonApplicationMenuPopupHandler(
toDismissPopupsOnActivation: Boolean,
popupPlacementStrategy: PopupPlacementStrategy,
popupAnchorBoundsProvider: (() -> Rect)?,
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>
overlays: Map<Command, BaseCommandButtonPresentationModel.Overlay>,
popupKind: AuroraPopupManager.PopupKind
): Window? {
val level1ContentLayoutInfo = getLevel1ContentLayoutInfo(
menuContentModel = contentModel.value!!,
Expand Down Expand Up @@ -699,7 +701,7 @@ internal class RibbonApplicationMenuPopupHandler(
popup = popupMenu,
popupContent = popupContent,
popupRectOnScreen = popupRect,
popupKind = AuroraPopupManager.PopupKind.Popup,
popupKind = popupKind,
onActivatePopup = contentModel.value?.onActivatePopup,
onDeactivatePopup = contentModel.value?.onDeactivatePopup
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,19 +586,22 @@ private fun AuroraWindowScope.RibbonWindowInnerContent(
val selectedTask = ribbon.getSelectedTask()
val contentModelState = rememberUpdatedState(RibbonTaskCollapsedMenuContentModel(
ribbonTask = selectedTask,
onDeactivatePopup = { showSelectedTaskInPopup = false }
onDeactivatePopup = {
showSelectedTaskInPopup = false
}
))

val ribbonPrimaryBarTopLeftOffset = remember { RibbonOffset(0.0f, 0.0f) }
val ribbonPrimaryBarSize = remember { mutableStateOf(IntSize(0, 0)) }
val ribbonSelectedButtonTopLeftOffset = remember { RibbonOffset(0.0f, 0.0f) }
val ribbonSelectedButtonSize = remember { mutableStateOf(IntSize(0, 0)) }

Column(Modifier.fillMaxSize().auroraBackground()) {
RibbonWindowTitlePane(
title, icon, iconFilterStrategy, ribbon, contextualTaskGroupSpans,
windowTitlePaneConfiguration
)

println("Show selected task in popup $showSelectedTaskInPopup")
AuroraDecorationArea(decorationAreaType = DecorationAreaType.Header) {
Column(Modifier.fillMaxWidth().auroraBackground()) {
RibbonPrimaryBar(
Expand All @@ -610,9 +613,13 @@ private fun AuroraWindowScope.RibbonWindowInnerContent(
contextualTaskGroupSpans.addAll(it)
}
},
selectedTaskButtonModifier = Modifier.ribbonElementLocator(
ribbonSelectedButtonTopLeftOffset,
ribbonSelectedButtonSize
),
showSelectedTaskInPopup = showSelectedTaskInPopup,
onUpdateShowSelectedTaskInPopup = {
if (ribbon.isMinimized) {
if (ribbon.isMinimized) {
showSelectedTaskInPopup = it
}
}
Expand Down Expand Up @@ -651,7 +658,7 @@ private fun AuroraWindowScope.RibbonWindowInnerContent(
val bandTitleHeight = getBandTitleHeight(layoutDirection, density, resolvedTextStyle, fontFamilyResolver)
val bandFullHeight = (bandContentHeight + bandTitleHeight)

SideEffect {
LaunchedEffect(showSelectedTaskInPopup) {
if (showSelectedTaskInPopup) {
// TODO - need command overlays?
val popupWindow = RibbonTaskCollapsedCommandMenuPopupHandler.showPopupContent(
Expand All @@ -671,10 +678,10 @@ private fun AuroraWindowScope.RibbonWindowInnerContent(
),
popupTriggerAreaInWindow = Rect(
offset = RibbonOffset(
x = ribbonPrimaryBarTopLeftOffset.x + ribbonPrimaryBarTopLeftOffset.x,
y = ribbonPrimaryBarTopLeftOffset.y + ribbonPrimaryBarTopLeftOffset.y
x = ribbonSelectedButtonTopLeftOffset.x,
y = ribbonSelectedButtonTopLeftOffset.y
).asOffset(density),
size = ribbonPrimaryBarSize.value.asSize(density)
size = ribbonSelectedButtonSize.value.asSize(density)
),
contentModel = contentModelState,
presentationModel = RibbonTaskCollapsedCommandPopupMenuPresentationModel(
Expand All @@ -685,11 +692,17 @@ private fun AuroraWindowScope.RibbonWindowInnerContent(
toDismissPopupsOnActivation = true,
popupPlacementStrategy = PopupPlacementStrategy.Downward.HAlignStart,
popupAnchorBoundsProvider = null,
overlays = mapOf()
overlays = mapOf(),
popupKind = AuroraPopupManager.PopupKind.Popup
)
coroutineScope.launch {
popupWindow?.opacity = 1.0f
}
} else {
AuroraPopupManager.hidePopups(
originator = popupOriginator,
popupKind = AuroraPopupManager.PopupKind.Popup
)
}
}
}
Expand Down Expand Up @@ -740,28 +753,40 @@ fun AuroraWindowScope.AuroraRibbonWindowContent(
}
if ((event is MouseEvent) && (event.id == MouseEvent.MOUSE_PRESSED) && (src is Component)) {
// This can be in our custom popup menu or in the top-level window
val originator = SwingUtilities.getAncestorOfClass(AuroraSwingPopupMenu::class.java, src)
var originator = SwingUtilities.getAncestorOfClass(AuroraSwingPopupMenu::class.java, src)
?: SwingUtilities.getWindowAncestor(src)
if (originator is JFrame) {
originator = originator.rootPane
}
if (originator != null) {
val eventLocation = event.locationOnScreen
SwingUtilities.convertPointFromScreen(eventLocation, originator)

if (!AuroraPopupManager.isShowingPopupFrom(
val showingFromHere = AuroraPopupManager.isShowingPopupFrom(
originator = originator,
pointInOriginator = Offset(eventLocation.x.toFloat(), eventLocation.y.toFloat())
)
) {
if (!showingFromHere) {
// Mouse press on an area that doesn't have any popups originating in it.
// Hide popups.
AuroraPopupManager.hidePopups(originator)
}
}
}
if (event.javaClass.simpleName == "UngrabEvent") {
// Not the cleanest, but works for now
AuroraPopupManager.hidePopups(null)
}
}
}

DisposableEffect(this, window) {
// 0x80000000 is the mask for the internal sun.awt.SunToolkit.GRAB_EVENT_MASK which we need
// to detect when our window is "ungrabbed". When that happens, we should hide all popups
// shown from our window.
Toolkit.getDefaultToolkit().addAWTEventListener(
awtEventListener,
AWTEvent.KEY_EVENT_MASK or AWTEvent.MOUSE_EVENT_MASK or AWTEvent.MOUSE_WHEEL_EVENT_MASK
AWTEvent.KEY_EVENT_MASK or AWTEvent.MOUSE_EVENT_MASK or AWTEvent.MOUSE_WHEEL_EVENT_MASK or 0x80000000
)

onDispose {
Expand Down Expand Up @@ -886,4 +911,3 @@ private fun Modifier.ribbonElementLocator(topLeftOffset: RibbonOffset, size: Mut
private val TaskbarWidthMaxRatio = 0.25f
private val TaskbarContentPadding = PaddingValues(horizontal = 6.dp)
private val TaskbarContextualTaskGroupTitlePadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp)

Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ internal fun RibbonPrimaryBar(
modifier: Modifier,
ribbon: Ribbon,
onContextualTaskGroupSpansUpdated: (List<RibbonContextualTaskGroupLayoutInfo>) -> Unit,
selectedTaskButtonModifier: Modifier,
showSelectedTaskInPopup: Boolean,
onUpdateShowSelectedTaskInPopup: (Boolean) -> Unit
) {
Expand Down Expand Up @@ -111,25 +112,25 @@ internal fun RibbonPrimaryBar(
val ribbonTaskCommands: List<Pair<Command, RibbonContextualTaskGroup?>> = ribbon.tasks.map { task ->
Pair<Command, RibbonContextualTaskGroup?>(Command(text = task.title,
icon = null,
isActionToggle = true,
isActionToggleSelected = task.isActive,
onTriggerActionToggleSelectedChange = {
if (it) {
task.onClick.invoke()
action = {
if (!task.isActive) {
task.onClick.invoke()
}
}
},
isActionToggle = true,
isActionToggleSelected = task.isActive
), null)
} + ribbon.contextualTaskGroups.flatMap { contextualTaskGroup ->
contextualTaskGroup.tasks.map { contextualTask ->
Pair<Command, RibbonContextualTaskGroup?>(Command(text = contextualTask.title,
icon = null,
isActionToggle = true,
isActionToggleSelected = contextualTask.isActive,
onTriggerActionToggleSelectedChange = {
if (it) {
action = {
if (!contextualTask.isActive) {
contextualTask.onClick.invoke()
}
}
},
isActionToggle = true,
isActionToggleSelected = contextualTask.isActive
), contextualTaskGroup)
}
}
Expand Down Expand Up @@ -430,7 +431,11 @@ internal fun RibbonPrimaryBar(
)

RibbonTaskToggleButton(
modifier = Modifier,
modifier = if (ribbonTaskCommandPair.first.isActionToggleSelected) {
selectedTaskButtonModifier
} else {
Modifier
},
command = ribbonTaskCommandPair.first,
presentationModel = presentationForCurrent,
showSelectedTaskInPopup = showSelectedTaskInPopup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package org.pushingpixels.aurora.window.ribbon

import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
Expand Down Expand Up @@ -256,19 +257,22 @@ internal fun RibbonTaskToggleButton(
buttonTopLeftOffset = it.localToRoot(Offset.Zero)
},
content = {
val modifierAction: Modifier = Modifier.toggleable(
value = command.isActionToggleSelected,
// This button is a sort of in-between. It is toggleable in the sense that it can be
// selected, but it does not lose selection when it's clicked again. Modifier.toggleable
// has `onValueChanged` but it's not as good of an indicator that the button has been
// clicked as `Modifier.clickable` and its `onClick`.
val clickableModifier = Modifier.clickable(
enabled = isActionEnabled,
role = Role.Tab,
interactionSource = actionInteractionSource,
indication = null,
onValueChange = {
command.onTriggerActionToggleSelectedChange?.invoke(it)
onClick = {
command.action?.invoke()
onUpdateShowSelectedTaskInPopup.invoke(!showSelectedTaskInPopup)
}
)
Box(
modifier = modifierAction.auroraRichTooltip(
modifier = clickableModifier.auroraRichTooltip(
richTooltip = command.actionRichTooltip,
presentationModel = presentationModel.actionRichTooltipPresentationModel
)
Expand Down

0 comments on commit b4fd86c

Please sign in to comment.