## Components - in-ribbon galleries
In-ribbon galleries are the third type of content that can be placed in a ribbon band. In the screenshot above the "Quick Styles" band shows an in-ribbon gallery. In-ribbon galleries are configured to display a certain (usually small) number of selections, with a vertical strip right next to them to scroll the selections inline up and down, and display the available selections in a larger popup:
Let's take a look at the various moving pieces involved in configuring an in-ribbon gallery.
### Main gallery content
We start by configuring the main gallery content - commands shown in the scrollable area of the gallery when it is shown in its ribbon band, or shown in the larger popup as in the last screenshot.
```kotlin
val stylesGalleryCommandList = CommandGroup(
title = resourceBundle.getString("StylesGallery.textGroupTitle1"),
commands = (1..10).map { index ->
Command(
text = mfButtonText.format(arrayOf(index)),
icon = DecoratedIcon(main = font_x_generic(),
decoration = object : Painter() {
override val intrinsicSize: Size = Size.Unspecified
override fun DrawScope.onDraw() {
this.drawIntoCanvas { canvas ->
val nativeCanvas = canvas.nativeCanvas
nativeCanvas.drawTextLine(
line = TextLine.make(
text = "$index",
font = overlayFont
),
x = 2.0f,
y = size.height - 4.0f,
paint = Paint().also { skiaPaint ->
skiaPaint.color4f = Color4f(
r = 0f,
g = 0f,
b = 0f,
a = 1.0f
)
}
)
}
}
}),
isActionToggle = true,
isActionToggleSelected = (ribbonState.documentStyle == DocumentStyle.entries[index - 1]),
onTriggerActionToggleSelectedChange = {
if (it) {
println("Activating $index")
onRibbonStateUpdate.invoke(ribbonState.copy(documentStyle = DocumentStyle.entries[index - 1]))
}
},
actionPreview = styleGalleryCommandPreview
)
}
)
val stylesGalleryCommandList2 = CommandGroup(
title = resourceBundle.getString("StylesGallery.textGroupTitle1"),
commands = (11..30).map { index ->
Command(
text = mfButtonText.format(arrayOf(index)),
icon = DecoratedIcon(main = font_x_generic(),
decoration = object : Painter() {
override val intrinsicSize: Size = Size.Unspecified
override fun DrawScope.onDraw() {
this.drawIntoCanvas { canvas ->
val nativeCanvas = canvas.nativeCanvas
nativeCanvas.drawTextLine(
line = TextLine.make(
text = "$index",
font = overlayFont
),
x = 2.0f,
y = size.height - 4.0f,
paint = Paint().also { skiaPaint ->
skiaPaint.color4f = Color4f(
r = 0f,
g = 0f,
b = 0f,
a = 1.0f
)
}
)
}
}
}),
isActionToggle = true,
isActionToggleSelected = (ribbonState.documentStyle == DocumentStyle.entries[index - 1]),
onTriggerActionToggleSelectedChange = {
if (it) {
onRibbonStateUpdate.invoke(ribbonState.copy(documentStyle = DocumentStyle.entries[index - 1]))
}
},
actionPreview = styleGalleryCommandPreview
)
}
)
val styleGalleryContentModel = RibbonGalleryContentModel(
icon = font_x_generic(),
commandGroups = listOf(stylesGalleryCommandList, stylesGalleryCommandList2),
extraPopupGroups = listOf(
CommandGroup(commands = listOf(this.menuSaveSelection, this.menuClearSelection)),
CommandGroup(commands = listOf(this.applyStyles))
)
)
```
Here we've built a `RibbonGalleryContentModel` from two `CommandGroup`s, one with 10 commands and the other with 20 commands.
### Extra popup content
These are commands shown below the expanded scrollable panel of gallery commands in the popup:
```kotlin
val menuSaveSelection = Command(
text = resourceBundle.getString("Format.menuSaveSelection.text"),
icon = ColorSolidIcon(Color(red = 0xFB, green = 0xC0, blue = 0x2D)),
action = { println("Save Selection activated") }
)
val menuClearSelection = Command(
text = resourceBundle.getString("Format.menuClearSelection.text"),
icon = ColorSolidIcon(Color(red = 0xFF, green = 0xA0, blue = 0x00)),
action = { println("Clear Selection activated") }
)
val applyStyles = Command(
text = resourceBundle.getString("Format.applyStyles.text"),
icon = ColorSolidIcon(Color(red = 0xF5, green = 0x7C, blue = 0x00)),
action = { println("Apply Styles activated") }
)
```
These are added to the `extraPopupGroups` of our `RibbonGalleryContentModel` created above.
### Tracking command preview and selection
Same as with [commands](Command.md) and [color selector popup menus](ColorSelectorCommand.md), you can register listeners to be notified when the user previews and / or changes selection in the gallery content:
```kotlin
val styleGalleryCommandPreview = object : CommandActionPreview {
override fun onCommandPreviewActivated(command: BaseCommand) {
println("Preview activated for '${command.text}'")
}
override fun onCommandPreviewCanceled(command: BaseCommand) {
println("Preview canceled for '${command.text}'")
}
}
```
### Gallery projection
Now it's time to create our [projection](ModelProjectionOverview.md). We configure our `RibbonGalleryPresentationModel` with the following properties:
* `popupLayoutSpec` for how many rows and columns of content we want to see in the popup. In our case we want 3 columns and at most 3 visible rows (kicking in vertical scrolling if necessary).
* `commandButtonPresentationState` for the presentation state for projected commands inline, as well as in the popup. Using `Small` presentation state will display three rows of small buttons inline.
* `expandKeyTip` with the key tip for the expand button of the gallery.
* `collapsedVisibleCountXyz` for how many commands we want to see displayed inline (not in popup) under different presentation priorities. The mapping defined above is the reason this particular in-ribbon gallery displays 2 items (from `collapsedVisibleCountTop`) when there is enough horizontal space for everything.
```kotlin
val styleGalleryInlineMetaPresentationModel = RibbonGalleryPresentationModel(
popupLayoutSpec = MenuPopupPanelLayoutSpec(
columnCount = 3, visibleRowCount = 3
),
commandButtonPresentationState = RibbonBandCommandButtonPresentationStates.BigFixedLandscape,
commandButtonTextOverflow = TextOverflow.Ellipsis,
expandKeyTip = "L",
collapsedVisibleCountLow = 1,
collapsedVisibleCountMedium = 2,
collapsedVisibleCountTop = 2
)
```
And now we can create and add our gallery projection:
```kotlin
val styleGalleryInlineProjection = RibbonGalleryProjection(
contentModel = styleGalleryContentModel,
presentationModel = styleGalleryInlineMetaPresentationModel,
inlineState = ribbonState.documentStyleGalleryInlineState
secondaryOverlays = mapOf(
menuSaveSelection to BaseCommandButtonPresentationModel.Overlay(actionKeyTip = "SS"),
menuClearSelection to BaseCommandButtonPresentationModel.Overlay(actionKeyTip = "SC"),
applyStyles to BaseCommandButtonPresentationModel.Overlay(actionKeyTip = "SA"),
)
)
RibbonBand(
title = resourceBundle.getString("QuickStyles.textBandTitle"),
icon = preferences_desktop_theme(),
collapsedStateKeyTip = "ZS",
resizePolicies = CoreRibbonResizePolicies.getCorePoliciesRestrictive(),
groups = listOf(
RibbonBandCommandGroup(
commandProjections = listOf(...),
galleries = listOf(
styleGalleryProjection at PresentationPriority.Top
)
)
)
)
```
With our `RibbonGalleryContentModel` as the content model and `RibbonGalleryPresentationModel` as the presentation model, we create `RibbonGalleryProjection` with its `secondaryOverlays` for the extra popup content - and that is passed to the `galleries` property of the `RibbonBandCommandGroup` at `Top` presentation priority.
### Next
Continue to the [keytips](RibbonKeytips.md).