Skip to content

Commit

Permalink
iconbutton impl (#164)
Browse files Browse the repository at this point in the history
* wip

(cherry picked from commit b51807c)

* draft

(cherry picked from commit ecbaa1a)

* lint

(cherry picked from commit da55acd)

* Replace IconButtonMetrics with IconButtonStyle for effective theming

The existing metric defining approach, IconButtonMetrics, was restricting the theming of the IconButton component effectively. Thus, the 'IconButtonMetrics' was replaced by 'IconButtonStyle' and the necessary changes for the field change were implemented. This would assist in providing the same theme across different platforms. The 'IconButton' has been made theme-aware by allowing access to theme and style via properties. Changes were made in implementations concerning IntelliJTheme, BaseIntUiTheme, and ComponentShowcaseTab. File names were also appropriately renamed.

* Refactor button state logic & tidy method declarations

Revised the button state logic of the IconButton component in IconButtonMetrics.kt with a more intuitive 'when' statement, improving readability. Likewise, method declarations in the IntUiBridge.kt file were reformatted for brevity. This maintenance will enhance the code's readability and thus its maintainability. Changes in IconButton.kt reflect the updated logic and background colour application.

The @stable annotation was attached to the IconButtonMetrics interface to indicate thread-safe and side-effect-free operations, a useful indicator for composing efficient composable functions in Jetpack Compose.

* Refactor IconButton state selection logic

The methodology for selecting the state of the IconButton was refactored from a 'when' statement to the 'chooseValue'

* Update button styling in IntUiDarkTheme

The IntUiDarkTheme now uses different colors for the "pressed" and "hovered" states of a button. Additionally, the background color selection logic has been refactored in IconButtonMetrics.kt to use a simpler and more readable 'when' construct.

* reverted wrong downgrade

* happy lint

* Change button icon and adjustments on display elements

This commit replaces the 'more' button icon with a 'close' button icon in ComponentShowcaseTab.kt. It also removes the 'propagateMinConstraints' property from IconButton.kt. In addition, it adjusts IconButton to not necessarily need 'Modifier.size' in Buttons.kt. These changes are made to improve the UI's look and functionality.

* updates improve visibility and user interaction by providing a more intuitive interface. Default background color for disabled buttons has been set

* "Add border styling to IconButton

This update adds border styling to the IconButton component. The main changes include importing 'border' from the compose foundation, defining border color for different button states, and applying the border in the IconButton component. This change was made to improve the overall visual appearance of the button, especially in different states, providing a more intuitive interface. It also helps better distinguish the buttons from the background, improving user interaction."

---------

Co-authored-by: fscarponi <[email protected]>
  • Loading branch information
edivad1999 and fscarponi authored Oct 12, 2023
1 parent 40833a2 commit aa8dc74
Show file tree
Hide file tree
Showing 11 changed files with 330 additions and 4 deletions.
82 changes: 82 additions & 0 deletions core/src/main/kotlin/org/jetbrains/jewel/IconButton.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.jetbrains.jewel

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.FocusInteraction
import androidx.compose.foundation.interaction.HoverInteraction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.semantics.Role
import org.jetbrains.jewel.styling.IconButtonStyle

@Composable
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
style: IconButtonStyle = IntelliJTheme.iconButtonStyle,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable (BoxScope.(ButtonState) -> Unit),
) {
var buttonState by remember(interactionSource) {
mutableStateOf(ButtonState.of(enabled = enabled))
}

remember(enabled) {
buttonState = buttonState.copy(enabled = enabled)
}

LaunchedEffect(interactionSource) {
interactionSource.interactions.collect { interaction ->
when (interaction) {
is PressInteraction.Press -> buttonState = buttonState.copy(pressed = true)
is PressInteraction.Cancel, is PressInteraction.Release ->
buttonState =
buttonState.copy(pressed = false)

is HoverInteraction.Enter -> buttonState = buttonState.copy(hovered = true)
is HoverInteraction.Exit -> buttonState = buttonState.copy(hovered = false)

is FocusInteraction.Focus -> buttonState = buttonState.copy(focused = true)
is FocusInteraction.Unfocus -> buttonState = buttonState.copy(focused = false)
}
}
}
val shape = RoundedCornerShape(style.metrics.cornerSize)
val background by style.colors.backgroundFor(buttonState)
val border by style.colors.borderFor(buttonState)
Box(
modifier = modifier
.defaultMinSize(style.metrics.minSize.width, style.metrics.minSize.height)
.clickable(
onClick = onClick,
enabled = enabled,
role = Role.Button,
interactionSource = interactionSource,
indication = NoIndication,
)
.clip(shape)
.padding(style.metrics.padding)
.background(background)
.border(style.metrics.borderWidth, border),
contentAlignment = Alignment.Center,
content = {
content(buttonState)
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.jetbrains.jewel.styling.DividerStyle
import org.jetbrains.jewel.styling.DropdownStyle
import org.jetbrains.jewel.styling.GroupHeaderStyle
import org.jetbrains.jewel.styling.HorizontalProgressBarStyle
import org.jetbrains.jewel.styling.IconButtonStyle
import org.jetbrains.jewel.styling.LabelledTextFieldStyle
import org.jetbrains.jewel.styling.LazyTreeStyle
import org.jetbrains.jewel.styling.LinkStyle
Expand Down Expand Up @@ -42,6 +43,7 @@ class IntelliJComponentStyling(
val textFieldStyle: TextFieldStyle,
val circularProgressStyle: CircularProgressStyle,
val tooltipStyle: TooltipStyle,
val iconButtonStyle: IconButtonStyle,
) {

override fun equals(other: Any?): Boolean {
Expand Down Expand Up @@ -70,6 +72,7 @@ class IntelliJComponentStyling(
if (textFieldStyle != other.textFieldStyle) return false
if (circularProgressStyle != other.circularProgressStyle) return false
if (tooltipStyle != other.tooltipStyle) return false
if (iconButtonStyle != other.iconButtonStyle) return false

return true
}
Expand All @@ -95,6 +98,7 @@ class IntelliJComponentStyling(
result = 31 * result + textFieldStyle.hashCode()
result = 31 * result + circularProgressStyle.hashCode()
result = 31 * result + tooltipStyle.hashCode()
result = 31 * result + iconButtonStyle.hashCode()
return result
}

Expand All @@ -106,5 +110,5 @@ class IntelliJComponentStyling(
"labelledTextFieldStyle=$labelledTextFieldStyle, lazyTreeStyle=$lazyTreeStyle, linkStyle=$linkStyle, " +
"menuStyle=$menuStyle, outlinedButtonStyle=$outlinedButtonStyle, radioButtonStyle=$radioButtonStyle, " +
"scrollbarStyle=$scrollbarStyle, textAreaStyle=$textAreaStyle, textFieldStyle=$textFieldStyle, " +
"circularProgressStyle=$circularProgressStyle, tooltipStyle=$tooltipStyle)"
"circularProgressStyle=$circularProgressStyle, tooltipStyle=$tooltipStyle, iconButtonStyle=$iconButtonStyle)"
}
6 changes: 6 additions & 0 deletions core/src/main/kotlin/org/jetbrains/jewel/IntelliJTheme.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import org.jetbrains.jewel.styling.DividerStyle
import org.jetbrains.jewel.styling.DropdownStyle
import org.jetbrains.jewel.styling.GroupHeaderStyle
import org.jetbrains.jewel.styling.HorizontalProgressBarStyle
import org.jetbrains.jewel.styling.IconButtonStyle
import org.jetbrains.jewel.styling.LabelledTextFieldStyle
import org.jetbrains.jewel.styling.LazyTreeStyle
import org.jetbrains.jewel.styling.LinkStyle
Expand All @@ -27,6 +28,7 @@ import org.jetbrains.jewel.styling.LocalDropdownStyle
import org.jetbrains.jewel.styling.LocalEditorTabStyle
import org.jetbrains.jewel.styling.LocalGroupHeaderStyle
import org.jetbrains.jewel.styling.LocalHorizontalProgressBarStyle
import org.jetbrains.jewel.styling.LocalIconButtonStyle
import org.jetbrains.jewel.styling.LocalLabelledTextFieldStyle
import org.jetbrains.jewel.styling.LocalLazyTreeStyle
import org.jetbrains.jewel.styling.LocalLinkStyle
Expand Down Expand Up @@ -196,6 +198,10 @@ interface IntelliJTheme {
@Composable
@ReadOnlyComposable
get() = LocalTooltipStyle.current
val iconButtonStyle: IconButtonStyle
@Composable
@ReadOnlyComposable
get() = LocalIconButtonStyle.current
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.jetbrains.jewel.styling

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import org.jetbrains.jewel.ButtonState

@Stable
interface IconButtonStyle {

val colors: IconButtonColors
val metrics: IconButtonMetrics
}

@Immutable
interface IconButtonColors {

val background: Color
val backgroundDisabled: Color
val backgroundFocused: Color
val backgroundPressed: Color
val backgroundHovered: Color

val border: Color
val borderDisabled: Color
val borderFocused: Color
val borderPressed: Color
val borderHovered: Color

@Composable
fun backgroundFor(state: ButtonState) = rememberUpdatedState(
when {
!state.isEnabled -> backgroundDisabled
state.isPressed -> backgroundPressed
state.isHovered -> backgroundHovered
state.isFocused -> backgroundFocused
else -> background
},
)

@Composable
fun borderFor(state: ButtonState) = rememberUpdatedState(
when {
!state.isEnabled -> borderDisabled
state.isPressed -> borderPressed
state.isHovered -> borderHovered
state.isFocused -> borderFocused
else -> border
},
)
}

@Stable
interface IconButtonMetrics {

val cornerSize: CornerSize
val borderWidth: Dp
val padding: PaddingValues
val minSize: DpSize
}

val LocalIconButtonStyle = staticCompositionLocalOf<IconButtonStyle> {
error("No IconButtonStyle provided")
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ import org.jetbrains.jewel.intui.standalone.styling.IntUiGroupHeaderStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiHorizontalProgressBarColors
import org.jetbrains.jewel.intui.standalone.styling.IntUiHorizontalProgressBarMetrics
import org.jetbrains.jewel.intui.standalone.styling.IntUiHorizontalProgressBarStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiIconButtonColors
import org.jetbrains.jewel.intui.standalone.styling.IntUiIconButtonMetrics
import org.jetbrains.jewel.intui.standalone.styling.IntUiIconButtonStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiLabelledTextFieldColors
import org.jetbrains.jewel.intui.standalone.styling.IntUiLabelledTextFieldMetrics
import org.jetbrains.jewel.intui.standalone.styling.IntUiLabelledTextFieldStyle
Expand Down Expand Up @@ -172,6 +175,7 @@ internal fun createSwingIntUiComponentStyling(
circularProgressStyle = readCircularProgressStyle(theme.isDark),
tooltipStyle = readTooltipStyle(),
textFieldStyle = textFieldStyle,
iconButtonStyle = readIconButtonStyle(),
)
}

Expand Down Expand Up @@ -915,7 +919,23 @@ private fun readTooltipStyle(): IntUiTooltipStyle {
content = retrieveColorOrUnspecified("ToolTip.foreground"),
background = retrieveColorOrUnspecified("ToolTip.background"),
border = retrieveColorOrUnspecified("ToolTip.borderColor"),
shadow = Color.Black.copy(alpha = .6f),
shadow = retrieveColorOrUnspecified("Notification.Shadow.bottom1Color"),
),
)
}

private fun readIconButtonStyle(): IntUiIconButtonStyle = IntUiIconButtonStyle(
metrics = IntUiIconButtonMetrics(CornerSize(DarculaUIUtil.BUTTON_ARC.dp / 2)),
colors = IntUiIconButtonColors(
background = Color.Unspecified,
backgroundDisabled = Color.Unspecified,
backgroundFocused = Color.Unspecified,
backgroundPressed = retrieveColorOrUnspecified("ActionButton.pressedBackground"),
backgroundHovered = retrieveColorOrUnspecified("ActionButton.hoverBackground"),
border = Color.Unspecified,
borderDisabled = Color.Unspecified,
borderFocused = retrieveColorOrUnspecified("ActionButton.focusedBorderColor"),
borderPressed = retrieveColorOrUnspecified("ActionButton.pressedBorderColor"),
borderHovered = retrieveColorOrUnspecified("ActionButton.hoverBorderColor"),
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import org.jetbrains.jewel.styling.LocalDropdownStyle
import org.jetbrains.jewel.styling.LocalEditorTabStyle
import org.jetbrains.jewel.styling.LocalGroupHeaderStyle
import org.jetbrains.jewel.styling.LocalHorizontalProgressBarStyle
import org.jetbrains.jewel.styling.LocalIconButtonStyle
import org.jetbrains.jewel.styling.LocalLabelledTextFieldStyle
import org.jetbrains.jewel.styling.LocalLazyTreeStyle
import org.jetbrains.jewel.styling.LocalLinkStyle
Expand Down Expand Up @@ -233,6 +234,7 @@ fun BaseIntUiTheme(
LocalIndication provides NoIndication,
LocalCircularProgressStyle provides componentStyling.circularProgressStyle,
LocalTooltipStyle provides componentStyling.tooltipStyle,
LocalIconButtonStyle provides componentStyling.iconButtonStyle,
) {
IntelliJTheme(theme, swingCompatMode, content)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import org.jetbrains.jewel.intui.standalone.styling.IntUiDividerStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiDropdownStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiGroupHeaderStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiHorizontalProgressBarStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiIconButtonStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiLabelledTextFieldStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiLazyTreeStyle
import org.jetbrains.jewel.intui.standalone.styling.IntUiLinkStyle
Expand All @@ -58,6 +59,7 @@ import org.jetbrains.jewel.styling.DividerStyle
import org.jetbrains.jewel.styling.DropdownStyle
import org.jetbrains.jewel.styling.GroupHeaderStyle
import org.jetbrains.jewel.styling.HorizontalProgressBarStyle
import org.jetbrains.jewel.styling.IconButtonStyle
import org.jetbrains.jewel.styling.LabelledTextFieldStyle
import org.jetbrains.jewel.styling.LazyTreeStyle
import org.jetbrains.jewel.styling.LinkStyle
Expand Down Expand Up @@ -136,6 +138,7 @@ object IntUiTheme : BaseIntUiTheme {
editorTabStyle: TabStyle = IntUiTabStyle.Editor.dark(svgLoader),
circularProgressStyle: CircularProgressStyle = IntUiCircularProgressStyle.dark(),
tooltipStyle: IntUiTooltipStyle = IntUiTooltipStyle.dark(),
iconButtonStyle: IconButtonStyle = IntUiIconButtonStyle.dark(),
) =
IntelliJComponentStyling(
checkboxStyle = checkboxStyle,
Expand All @@ -158,6 +161,7 @@ object IntUiTheme : BaseIntUiTheme {
textFieldStyle = textFieldStyle,
circularProgressStyle = circularProgressStyle,
tooltipStyle = tooltipStyle,
iconButtonStyle = iconButtonStyle,
)

@Composable
Expand All @@ -183,6 +187,7 @@ object IntUiTheme : BaseIntUiTheme {
editorTabStyle: TabStyle = IntUiTabStyle.Editor.light(svgLoader),
circularProgressStyle: CircularProgressStyle = IntUiCircularProgressStyle.light(),
tooltipStyle: IntUiTooltipStyle = IntUiTooltipStyle.light(),
iconButtonStyle: IconButtonStyle = IntUiIconButtonStyle.light(),
) = IntelliJComponentStyling(
checkboxStyle = checkboxStyle,
chipStyle = chipStyle,
Expand All @@ -204,6 +209,7 @@ object IntUiTheme : BaseIntUiTheme {
textFieldStyle = textFieldStyle,
circularProgressStyle = circularProgressStyle,
tooltipStyle = tooltipStyle,
iconButtonStyle = iconButtonStyle,
)
}

Expand Down
Loading

0 comments on commit aa8dc74

Please sign in to comment.