Skip to content

Commit

Permalink
Fix tree crashing in sample (see #114)
Browse files Browse the repository at this point in the history
Also reformat/cleanup after rebase on main
  • Loading branch information
rock3r committed Sep 15, 2023
1 parent 4234e8a commit e166b42
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 125 deletions.
4 changes: 2 additions & 2 deletions core/src/main/kotlin/org/jetbrains/jewel/LazyTree.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ fun <T> LazyTree(
onSelectionChange = onSelectionChange,
keyActions = keyActions,
chevronContent = { elementState ->
val painterProvider = style.icons.nodeChevron(elementState.isExpanded)
val painter by painterProvider.getPainter(resourceLoader, elementState)
val painterProvider = style.icons.chevron(elementState.isExpanded, elementState.isSelected)
val painter by painterProvider.getPainter(resourceLoader)
Icon(painter = painter, contentDescription = null)
},
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ open class DefaultSelectableColumnKeybindings : SelectableColumnKeybindings {
override val PointerKeyboardModifiers.isKeyboardMultiSelectionKeyPressed: Boolean
get() = isShiftPressed


override fun KeyEvent.selectFirstItem() =
key == Key.Home && !isKeyboardMultiSelectionKeyPressed

Expand Down Expand Up @@ -141,5 +140,4 @@ open class DefaultSelectableColumnKeybindings : SelectableColumnKeybindings {

override fun KeyEvent.selectAll(): Boolean? =
key == Key.A && isKeyboardCtrlMetaKeyPressed

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -30,8 +29,8 @@ import org.jetbrains.jewel.foundation.tree.KeyBindingActions
import org.jetbrains.jewel.foundation.tree.PointerEventActions

/**
* A composable that displays a scrollable and selectable list of items in a column arrangement.
*
* A composable that displays a scrollable and selectable list of items in
* a column arrangement.
*/
@Composable
fun SelectableLazyColumn(
Expand All @@ -49,8 +48,6 @@ fun SelectableLazyColumn(
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: SelectableLazyListScope.() -> Unit,
) {
val scope = rememberCoroutineScope()

val container = remember(content) {
SelectableLazyListScopeContainer().apply(content)
}
Expand All @@ -77,7 +74,7 @@ fun SelectableLazyColumn(
.focusRequester(focusRequester)
.focusable(interactionSource = interactionSource)
.onPreviewKeyEvent { event ->
state.lastActiveItemIndex?.let { _ ->
if (state.lastActiveItemIndex != null) {
keyActions.handleOnKeyEvent(event, keys, state, selectionMode).invoke(event)
}
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,15 @@ fun <T : Any> SelectableLazyListScope.itemsIndexed(
contentType: (index: Int, item: T) -> Any? = { _, item -> item },
selectable: (index: Int, item: T) -> Boolean = { _, _ -> true },
itemContent: @Composable SelectableLazyItemScope.(index: Int, item: T) -> Unit,
) = items(
count = items.size,
key = { key(it, items[it]) },
contentType = { contentType(it, items[it]) },
selectable = { selectable(it, items[it]) },
itemContent = { itemContent(it, items[it]) }
)
) {
items(
count = items.size,
key = { key(it, items[it]) },
contentType = { contentType(it, items[it]) },
selectable = { selectable(it, items[it]) },
itemContent = { itemContent(it, items[it]) },
)
}

@Composable
fun LazyItemScope.SelectableLazyItemScope(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fun <T> BasicLazyTree(
.asSequence()
.filter { it.id in treeState.delegate.selectedKeys }
.map { element -> element as Tree.Element<T> }
.toList()
.toList(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,19 @@ interface LazyTreeMetrics {
@Immutable
interface LazyTreeIcons {

val nodeChevronCollapsed: PainterProvider<TreeElementState>
val nodeChevronExpanded: PainterProvider<TreeElementState>
val chevronCollapsed: PainterProvider<Unit>
val chevronExpanded: PainterProvider<Unit>
val chevronSelectedCollapsed: PainterProvider<Unit>
val chevronSelectedExpanded: PainterProvider<Unit>

@Composable
fun nodeChevron(isExpanded: Boolean) =
if (isExpanded) nodeChevronExpanded else nodeChevronCollapsed
fun chevron(isExpanded: Boolean, isSelected: Boolean) =
when {
isSelected && isExpanded -> chevronSelectedExpanded
isSelected && !isExpanded -> chevronSelectedCollapsed
!isSelected && isExpanded -> chevronExpanded
else -> chevronCollapsed
}
}

val LocalLazyTreeStyle = staticCompositionLocalOf<LazyTreeStyle> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,29 @@ import androidx.compose.ui.res.ResourceLoader
@Immutable
interface PainterProvider<T> {

/**
* Obtain a painter, with no extra data. It is equivalent to calling
* [getPainter] with a `null` value for the `extraData` argument. This
* overload should only be used for stateless painter providers (i.e., when
* [T] is [Unit]).
*
* A [resourceLoader] that allows loading the corresponding resource must
* be loading. For example, if your resource is in module `my-module`'s
* resources, the [resourceLoader] must be pointing to `my-module`s
* classloader.
*
* Passing the wrong [ResourceLoader] will cause your resources not to
* load, and you will get cryptic errors. Please also note that using
* [ResourceLoader.Default] will probably cause loading to fail if you are
* trying to load the icons from a different module. For example, if Jewel
* is running in the IDE and you use [ResourceLoader.Default] to try and
* load a default IDE resource, it will fail.
*
* @see getPainter
*/
@Composable
fun getPainter(resourceLoader: ResourceLoader): State<Painter> = getPainter(resourceLoader, null)

/**
* Obtain a painter for the provided [extraData].
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ internal class BridgeIconData(

fun readFromLaF(): BridgeIconData {
val uiTheme = currentUiThemeOrNull()
val iconMap = uiTheme?.icons ?: emptyMap()
val selectedIconColorPalette = uiTheme?.selectedIconColorPalette ?: emptyMap()
val iconMap = uiTheme?.icons.orEmpty()
val selectedIconColorPalette = uiTheme?.selectedIconColorPalette.orEmpty()

val colorPalette = UITheme.getColorPalette()
return BridgeIconData(iconMap, colorPalette, selectedIconColorPalette)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,28 +728,33 @@ private fun readLazyTreeStyle(iconData: IntelliJThemeIconData, svgLoader: SvgLoa
elementBackgroundSelectedFocused = selectedElementBackground,
)

val chevronCollapsed = retrieveStatelessIcon(
iconPath = "${iconsBasePath}general/chevron-right.svg",
iconData = iconData,
svgLoader = svgLoader,
)
val chevronExpanded = retrieveStatelessIcon(
iconPath = "${iconsBasePath}general/chevron-down.svg",
iconData = iconData,
svgLoader = svgLoader,
)

return IntUiLazyTreeStyle(
colors = colors,
metrics = IntUiLazyTreeMetrics(
indentSize = retrieveIntAsDpOrUnspecified("Tree.leftChildIndent").takeOrElse { 7.dp } +
retrieveIntAsDpOrUnspecified("Tree.rightChildIndent").takeOrElse { 11.dp },
retrieveIntAsDpOrUnspecified("Tree.rightChildIndent").takeOrElse { 11.dp },
elementBackgroundCornerSize = CornerSize(JBUI.CurrentTheme.Tree.ARC.dp / 2),
elementPadding = PaddingValues(horizontal = 12.dp),
elementContentPadding = PaddingValues(4.dp),
elementMinHeight = retrieveIntAsDpOrUnspecified("Tree.rowHeight").takeOrElse { 24.dp },
chevronContentGap = 2.dp, // See com.intellij.ui.tree.ui.ClassicPainter.GAP
),
icons = IntUiLazyTreeIcons(
nodeChevronCollapsed = retrieveStatefulIcon(
iconPath = "${iconsBasePath}general/chevron-right.svg",
iconData = iconData,
svgLoader = svgLoader,
),
nodeChevronExpanded = retrieveStatefulIcon(
iconPath = "${iconsBasePath}general/chevron-down.svg",
iconData = iconData,
svgLoader = svgLoader,
),
chevronCollapsed = chevronCollapsed,
chevronExpanded = chevronExpanded,
chevronSelectedCollapsed = chevronCollapsed,
chevronSelectedExpanded = chevronExpanded,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal val UITheme.icons: Map<String, String>

internal val UITheme.iconColorPalette: Map<String, String>
get() = readMapField<Map<String, String>>(classUITheme.getDeclaredField("icons"))
.get("ColorPalette") ?: emptyMap()
.get("ColorPalette").orEmpty()

internal val UITheme.selectedIconColorPalette: Map<String, String>
get() = readMapField(classUITheme.getDeclaredField("iconColorsOnSelection"))
Expand All @@ -32,7 +32,7 @@ private fun <T> UITheme.readMapField(field: Field): Map<String, T> {

return try {
@Suppress("UNCHECKED_CAST")
field.get(this) as? Map<String, T> ?: emptyMap()
(field.get(this) as? Map<String, T>).orEmpty()
} catch (e: IllegalAccessException) {
logger.warn("Error while retrieving LaF", e)
emptyMap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import org.jetbrains.jewel.TextField
import org.jetbrains.jewel.bridge.SwingBridgeTheme
import org.jetbrains.jewel.bridge.addComposeTab
import org.jetbrains.jewel.bridge.toComposeColor
import org.jetbrains.jewel.foundation.tree.InitialNodeStatus
import org.jetbrains.jewel.foundation.tree.buildTree
import org.jetbrains.jewel.themes.intui.standalone.IntUiTheme

Expand Down Expand Up @@ -212,7 +211,6 @@ internal class JewelDemoToolWindow : ToolWindowFactory, DumbAware {
}
LazyTree(
tree = tree,
initialNodeStatus = InitialNodeStatus.Open,
resourceLoader = resourceLoader,
modifier = Modifier.height(200.dp).fillMaxWidth(),
onElementClick = {},
Expand Down
Loading

0 comments on commit e166b42

Please sign in to comment.