Skip to content

Commit

Permalink
More ribbon API prototyping
Browse files Browse the repository at this point in the history
Add color selector command and projection

For #56
  • Loading branch information
kirill-grouchnikov committed Dec 20, 2022
1 parent 3c019a2 commit fb1ac30
Show file tree
Hide file tree
Showing 8 changed files with 1,771 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2020-2022 Aurora, Kirill Grouchnikov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pushingpixels.aurora.component.model

import androidx.compose.ui.graphics.Color
import java.util.*

data class ColorSectionModel(
val title: String,
val colors: List<Color>
)

sealed interface ColorSelectorPopupMenuEntry

data class ColorSelectorPopupMenuCommand(val command: Command) : ColorSelectorPopupMenuEntry
data class ColorSelectorPopupMenuSection(val colorSectionModel: ColorSectionModel) : ColorSelectorPopupMenuEntry
data class ColorSelectorPopupMenuSectionWithDerived(val colorSectionModel: ColorSectionModel) :
ColorSelectorPopupMenuEntry

data class ColorSelectorPopupMenuRecentsSection(val colorSectionModel: ColorSectionModel) : ColorSelectorPopupMenuEntry

data class ColorSelectorPopupMenuGroupModel(val content: List<ColorSelectorPopupMenuEntry>)

/**
* Listener for tracking color preview events.
*/
interface ColorPreviewListener {
/**
* Invoked when the preview of a color in any of the color sections of this model is
* activated.
*
* @param color Color for which the preview has been activated.
*/
fun onColorPreviewActivated(color: Color)

/**
* Invoked when the color preview has been canceled.
*/
fun onColorPreviewCanceled()
}

data class ColorSelectorPopupMenuContentModel(
val menuGroups: List<ColorSelectorPopupMenuGroupModel>,
val onColorPreviewActivated: ColorPreviewListener,
val onColorActivated: (Color) -> Unit
) : BaseCommandMenuContentModel

object RecentlyUsed {
private val recentlySelected = LinkedList<Color>()

@Synchronized
fun getRecentlyUsedColors(): List<Color> {
return Collections.unmodifiableList(recentlySelected)
}

@Synchronized
fun addColorToRecentlyUsed(color: Color) {
// Is it already in?
if (recentlySelected.contains(color)) {
// Bump up to the top of the most recent
recentlySelected.remove(color)
recentlySelected.addLast(color)
return
}
if (recentlySelected.size == 100) {
// Too many in history, bump out the least recently used or added
recentlySelected.removeFirst()
}
recentlySelected.addLast(color)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,52 @@ interface CommandActionPreview {
fun onCommandPreviewCanceled(command: Command)
}

sealed interface BaseCommand<out M: BaseCommandMenuContentModel>: ContentModel {
val text: String
val extraText: String?
val icon: Painter?
val secondaryContentModel: M?
val isSecondaryEnabled: Boolean
val secondaryRichTooltip: RichTooltip?
}

data class Command(
val text: String,
val extraText: String? = null,
val icon: Painter? = null,
override val text: String,
override val extraText: String? = null,
override val icon: Painter? = null,
val action: (() -> Unit)? = null,
val actionPreview: CommandActionPreview? = null,
val isActionEnabled: Boolean = true,
val isActionToggle: Boolean = false,
val isActionToggleSelected: Boolean = false,
val actionRichTooltip: RichTooltip? = null,
val onTriggerActionToggleSelectedChange: ((Boolean) -> Unit)? = null,
val secondaryContentModel: CommandMenuContentModel? = null,
val isSecondaryEnabled: Boolean = true,
val secondaryRichTooltip: RichTooltip? = null
) : ContentModel
override val secondaryContentModel: CommandMenuContentModel? = null,
override val isSecondaryEnabled: Boolean = true,
override val secondaryRichTooltip: RichTooltip? = null
) : BaseCommand<CommandMenuContentModel>

data class ColorSelectorCommand(
override val text: String,
override val extraText: String? = null,
override val icon: Painter? = null,
override val secondaryContentModel: ColorSelectorPopupMenuContentModel,
override val isSecondaryEnabled: Boolean = true,
override val secondaryRichTooltip: RichTooltip? = null
) : BaseCommand<ColorSelectorPopupMenuContentModel>

data class CommandGroup(
val title: String? = null,
val commands: List<Command>
) : ContentModel

interface BaseCommandMenuContentModel

data class CommandMenuContentModel(
val groups: List<CommandGroup>,
val panelContentModel: CommandPanelContentModel? = null,
val highlightedCommand: Command? = null
) {
): BaseCommandMenuContentModel {
constructor(
group: CommandGroup,
panelContentModel: CommandPanelContentModel? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,21 @@ import org.pushingpixels.aurora.component.*
import org.pushingpixels.aurora.component.model.*
import org.pushingpixels.aurora.theming.LocalPopupMenu

abstract class Projection<out C: ContentModel, out P: PresentationModel>
abstract class Projection<out C : ContentModel, out P : PresentationModel>

sealed class BaseCommandButtonProjection<out P : BaseCommandMenuContentModel, out M : BaseCommand<P>>(
open val contentModel: M,
open val presentationModel: CommandButtonPresentationModel = CommandButtonPresentationModel(),
open val overlays: Map<Command, CommandButtonPresentationModel.Overlay>? = null
) : Projection<M, CommandButtonPresentationModel>()

class CommandButtonProjection(
val contentModel: Command,
val presentationModel: CommandButtonPresentationModel = CommandButtonPresentationModel(),
val overlays: Map<Command, CommandButtonPresentationModel.Overlay>? = null
): Projection<Command, CommandButtonPresentationModel>() {
contentModel: Command,
presentationModel: CommandButtonPresentationModel = CommandButtonPresentationModel(),
overlays: Map<Command, CommandButtonPresentationModel.Overlay>? = null
) : BaseCommandButtonProjection<CommandMenuContentModel, Command>(
contentModel, presentationModel, overlays
) {
@OptIn(AuroraInternalApi::class)
@Composable
fun project(
Expand All @@ -54,11 +62,27 @@ class CommandButtonProjection(
}
}

class ColorSelectorCommandButtonProjection(
contentModel: ColorSelectorCommand,
presentationModel: CommandButtonPresentationModel = CommandButtonPresentationModel(),
overlays: Map<Command, CommandButtonPresentationModel.Overlay>? = null
) : BaseCommandButtonProjection<ColorSelectorPopupMenuContentModel, ColorSelectorCommand>(
contentModel, presentationModel, overlays
) {
@OptIn(AuroraInternalApi::class)
@Composable
fun project(
modifier: Modifier = Modifier,
popupInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() }
) {
}
}

class CommandButtonStripProjection(
val contentModel: CommandGroup,
val presentationModel: CommandStripPresentationModel,
val overlays: Map<Command, CommandButtonPresentationModel.Overlay>? = null
): Projection<CommandGroup, CommandStripPresentationModel>() {
) : Projection<CommandGroup, CommandStripPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraCommandButtonStrip(
Expand All @@ -74,7 +98,7 @@ class CommandButtonPanelProjection(
val contentModel: CommandPanelContentModel,
val presentationModel: CommandPanelPresentationModel,
val overlays: Map<Command, CommandButtonPresentationModel.Overlay>? = null
): Projection<CommandPanelContentModel, CommandButtonPresentationModel>() {
) : Projection<CommandPanelContentModel, CommandButtonPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
require(
Expand All @@ -95,7 +119,7 @@ class CommandButtonPanelProjection(
class ComboBoxProjection<E>(
val contentModel: ComboBoxContentModel<E>,
val presentationModel: ComboBoxPresentationModel<E>
): Projection<ComboBoxContentModel<E>, ComboBoxPresentationModel<E>>() {
) : Projection<ComboBoxContentModel<E>, ComboBoxPresentationModel<E>>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -113,7 +137,7 @@ class ComboBoxProjection<E>(
class CheckBoxProjection(
val contentModel: SelectorContentModel,
val presentationModel: SelectorPresentationModel = SelectorPresentationModel()
): Projection<SelectorContentModel, SelectorPresentationModel>() {
) : Projection<SelectorContentModel, SelectorPresentationModel>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -131,7 +155,7 @@ class CheckBoxProjection(
class TriStateCheckBoxProjection(
val contentModel: TriStateSelectorContentModel,
val presentationModel: SelectorPresentationModel = SelectorPresentationModel()
): Projection<TriStateSelectorContentModel, SelectorPresentationModel>() {
) : Projection<TriStateSelectorContentModel, SelectorPresentationModel>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -149,7 +173,7 @@ class TriStateCheckBoxProjection(
class RadioButtonProjection(
val contentModel: SelectorContentModel,
val presentationModel: SelectorPresentationModel = SelectorPresentationModel()
): Projection<SelectorContentModel, SelectorPresentationModel>() {
) : Projection<SelectorContentModel, SelectorPresentationModel>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -167,7 +191,7 @@ class RadioButtonProjection(
class SwitchProjection(
val contentModel: SwitchContentModel,
val presentationModel: SwitchPresentationModel = SwitchPresentationModel()
): Projection<SwitchContentModel, SwitchPresentationModel>() {
) : Projection<SwitchContentModel, SwitchPresentationModel>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -185,7 +209,7 @@ class SwitchProjection(
class CircularProgressProjection(
val contentModel: ProgressIndeterminateContentModel = ProgressIndeterminateContentModel(),
val presentationModel: ProgressCircularPresentationModel = ProgressCircularPresentationModel()
): Projection<ProgressIndeterminateContentModel, ProgressCircularPresentationModel>() {
) : Projection<ProgressIndeterminateContentModel, ProgressCircularPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraCircularProgress(
Expand All @@ -199,7 +223,7 @@ class CircularProgressProjection(
class IndeterminateLinearProgressProjection(
val contentModel: ProgressIndeterminateContentModel = ProgressIndeterminateContentModel(),
val presentationModel: ProgressLinearPresentationModel = ProgressLinearPresentationModel()
): Projection<ProgressIndeterminateContentModel, ProgressLinearPresentationModel>() {
) : Projection<ProgressIndeterminateContentModel, ProgressLinearPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraIndeterminateLinearProgress(
Expand All @@ -213,7 +237,7 @@ class IndeterminateLinearProgressProjection(
class DeterminateLinearProgressProjection(
val contentModel: ProgressDeterminateContentModel,
val presentationModel: ProgressLinearPresentationModel = ProgressLinearPresentationModel()
): Projection<ProgressDeterminateContentModel, ProgressLinearPresentationModel>() {
) : Projection<ProgressDeterminateContentModel, ProgressLinearPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraDeterminateLinearProgress(
Expand All @@ -227,7 +251,7 @@ class DeterminateLinearProgressProjection(
class IconProjection(
val contentModel: IconContentModel,
val presentationModel: IconPresentationModel = IconPresentationModel()
): Projection<IconContentModel, IconPresentationModel>() {
) : Projection<IconContentModel, IconPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraIcon(
Expand All @@ -241,7 +265,7 @@ class IconProjection(
class LabelProjection(
val contentModel: LabelContentModel,
val presentationModel: LabelPresentationModel = LabelPresentationModel()
): Projection<LabelContentModel, LabelPresentationModel>() {
) : Projection<LabelContentModel, LabelPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraLabel(
Expand All @@ -255,7 +279,7 @@ class LabelProjection(
class VerticalSeparatorProjection(
val contentModel: SeparatorContentModel = SeparatorContentModel(),
val presentationModel: SeparatorPresentationModel = SeparatorPresentationModel()
): Projection<SeparatorContentModel, SeparatorPresentationModel>() {
) : Projection<SeparatorContentModel, SeparatorPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraVerticalSeparator(
Expand All @@ -269,7 +293,7 @@ class VerticalSeparatorProjection(
class HorizontalSeparatorProjection(
val contentModel: SeparatorContentModel = SeparatorContentModel(),
val presentationModel: SeparatorPresentationModel = SeparatorPresentationModel()
): Projection<SeparatorContentModel, SeparatorPresentationModel>() {
) : Projection<SeparatorContentModel, SeparatorPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraHorizontalSeparator(
Expand All @@ -283,7 +307,7 @@ class HorizontalSeparatorProjection(
class SliderProjection(
val contentModel: SliderContentModel,
val presentationModel: SliderPresentationModel = SliderPresentationModel()
): Projection<SliderContentModel, SliderPresentationModel>() {
) : Projection<SliderContentModel, SliderPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier) {
AuroraSlider(
Expand All @@ -297,7 +321,7 @@ class SliderProjection(
class TabsProjection(
val contentModel: TabsContentModel,
val presentationModel: TabsPresentationModel = TabsPresentationModel()
): Projection<TabsContentModel, TabsPresentationModel>() {
) : Projection<TabsContentModel, TabsPresentationModel>() {
@Composable
fun project(modifier: Modifier = Modifier, horizontalScrollState: ScrollState = rememberScrollState(0)) {
AuroraTabs(
Expand All @@ -312,7 +336,7 @@ class TabsProjection(
class TextFieldValueProjection(
val contentModel: TextFieldValueContentModel,
val presentationModel: TextFieldPresentationModel = TextFieldPresentationModel()
): Projection<TextFieldValueContentModel, TextFieldPresentationModel>() {
) : Projection<TextFieldValueContentModel, TextFieldPresentationModel>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -330,7 +354,7 @@ class TextFieldValueProjection(
class TextFieldStringProjection(
val contentModel: TextFieldStringContentModel,
val presentationModel: TextFieldPresentationModel = TextFieldPresentationModel()
): Projection<TextFieldStringContentModel, TextFieldPresentationModel>() {
) : Projection<TextFieldStringContentModel, TextFieldPresentationModel>() {
@Composable
fun project(
modifier: Modifier = Modifier,
Expand All @@ -344,3 +368,4 @@ class TextFieldStringProjection(
)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package org.pushingpixels.aurora.component.ribbon

import androidx.compose.ui.graphics.painter.Painter
import org.pushingpixels.aurora.component.model.*
import org.pushingpixels.aurora.component.projection.BaseCommandButtonProjection
import org.pushingpixels.aurora.component.projection.CommandButtonProjection
import org.pushingpixels.aurora.component.projection.Projection

Expand All @@ -31,8 +32,8 @@ enum class PresentationPriority {
Low
}

infix fun CommandButtonProjection.at(that: PresentationPriority):
Pair<CommandButtonProjection, PresentationPriority> = Pair(this, that)
infix fun <P : BaseCommandMenuContentModel, M : BaseCommand<P>> BaseCommandButtonProjection<P, M>.at(
that: PresentationPriority): Pair<BaseCommandButtonProjection<P, M>, PresentationPriority> = Pair(this, that)

data class RibbonComponentPresentationModel(
val caption: String? = null,
Expand Down
Loading

0 comments on commit fb1ac30

Please sign in to comment.