-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New ComboBox component #601
base: main
Are you sure you want to change the base?
Conversation
42b2943
to
dcfddd9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I managed to break the component pretty easily, so I feel there is some work to do still.
First breakage: non-editable ComboBoxes do not remain single line when their content is long.
Second breakage, while I was typing in the editable one, I managed to get a crash, not sure how (may be macOS only, given the stack trace):
java.lang.reflect.InvocationTargetException
at java.desktop/sun.lwawt.macosx.LWCToolkit.checkException(LWCToolkit.java:940)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:903)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:834)
at java.desktop/sun.lwawt.macosx.CInputMethod.invokeAndWaitNoThrow(CInputMethod.java:911)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.invoke(CInputMethod.java:896)
at java.desktop/sun.lwawt.macosx.CInputMethod.firstRectForCharacterRange(CInputMethod.java:740)
Caused by: java.lang.NullPointerException: Cannot read field "x" because "r" is null
at java.desktop/sun.lwawt.macosx.CInputMethod.lambda$firstRectForCharacterRange$0(CInputMethod.java:746)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.lambda$invoke$0(CInputMethod.java:899)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:308)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.lambda$dispatch$3(AWTThreading.java:311)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.completeIfNotYet(AWTThreading.java:324)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.dispatch(AWTThreading.java:311)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:766)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:764)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:763)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
java.lang.reflect.InvocationTargetException
at java.desktop/sun.lwawt.macosx.LWCToolkit.checkException(LWCToolkit.java:940)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:903)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:834)
at java.desktop/sun.lwawt.macosx.CInputMethod.invokeAndWaitNoThrow(CInputMethod.java:911)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.invoke(CInputMethod.java:896)
at java.desktop/sun.lwawt.macosx.CInputMethod.firstRectForCharacterRange(CInputMethod.java:740)
Caused by: java.lang.NullPointerException: Cannot read field "x" because "r" is null
at java.desktop/sun.lwawt.macosx.CInputMethod.lambda$firstRectForCharacterRange$0(CInputMethod.java:746)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.lambda$invoke$0(CInputMethod.java:899)
Caused by: java.lang.NullPointerException: Cannot read field "x" because "r" is null
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:308)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.lambda$dispatch$3(AWTThreading.java:311)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.completeIfNotYet(AWTThreading.java:324)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.dispatch(AWTThreading.java:311)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:766)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:764)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:763)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
java.lang.reflect.InvocationTargetException
at java.desktop/sun.lwawt.macosx.LWCToolkit.checkException(LWCToolkit.java:940)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:903)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:834)
at java.desktop/sun.lwawt.macosx.CInputMethod.invokeAndWaitNoThrow(CInputMethod.java:911)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.invoke(CInputMethod.java:896)
at java.desktop/sun.lwawt.macosx.CInputMethod.firstRectForCharacterRange(CInputMethod.java:740)
Caused by: java.lang.NullPointerException: Cannot read field "x" because "r" is null
at java.desktop/sun.lwawt.macosx.CInputMethod.lambda$firstRectForCharacterRange$0(CInputMethod.java:746)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.lambda$invoke$0(CInputMethod.java:899)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:308)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.lambda$dispatch$3(AWTThreading.java:311)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.completeIfNotYet(AWTThreading.java:324)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.dispatch(AWTThreading.java:311)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:766)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:764)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:763)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
java.lang.reflect.InvocationTargetException
at java.desktop/sun.lwawt.macosx.LWCToolkit.checkException(LWCToolkit.java:940)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:903)
at java.desktop/sun.lwawt.macosx.LWCToolkit.invokeAndWait(LWCToolkit.java:834)
at java.desktop/sun.lwawt.macosx.CInputMethod.invokeAndWaitNoThrow(CInputMethod.java:911)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.invoke(CInputMethod.java:896)
at java.desktop/sun.lwawt.macosx.CInputMethod.firstRectForCharacterRange(CInputMethod.java:740)
Caused by: java.lang.NullPointerException: Cannot read field "x" because "r" is null
at java.desktop/sun.lwawt.macosx.CInputMethod.lambda$firstRectForCharacterRange$0(CInputMethod.java:746)
at java.desktop/sun.lwawt.macosx.CInputMethod$FxInvoker.lambda$invoke$0(CInputMethod.java:899)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:308)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.lambda$dispatch$3(AWTThreading.java:311)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.completeIfNotYet(AWTThreading.java:324)
at java.desktop/sun.awt.AWTThreading$TrackedInvocationEvent.dispatch(AWTThreading.java:311)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:792)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:739)
at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:733)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:766)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:764)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:763)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)
PS: I don't think the component should get wider as the content gets longer (see first screenshot, the Warning one should not have grown and taken over all the space)
@@ -489,7 +489,7 @@ private fun readDividerStyle() = | |||
DividerStyle(color = JBColor.border().toComposeColorOrUnspecified(), metrics = DividerMetrics.defaults()) | |||
|
|||
private fun readDefaultDropdownStyle(menuStyle: MenuStyle): DropdownStyle { | |||
val normalBackground = retrieveColorOrUnspecified("ComboBox.nonEditableBackground") | |||
val normalBackground = retrieveColorOrUnspecified("ComboBox.background") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How come we changed this? Was it resolving to the wrong colour?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. I iterated on colors more, expanding on the existing insufficient DropdownColors
.
I have also added more screenshots to the PR description.
Reference commit is 25e5f1a.
val zoomLevels = arrayOf("100%", "125%", "150%", "175%", "200%", "300%") | ||
|
||
JPanel() | ||
.apply { | ||
layout = BoxLayout(this, BoxLayout.Y_AXIS) | ||
add(JLabel("Not editable").apply { alignmentX = Component.LEFT_ALIGNMENT }) | ||
add( | ||
ComboBox(DefaultComboBoxModel(zoomLevels)).apply { | ||
isEditable = false | ||
alignmentX = Component.LEFT_ALIGNMENT | ||
} | ||
) | ||
} | ||
.run { cell(this).align(AlignY.TOP) } | ||
|
||
val itemsComboBox = arrayOf("Cat", "Elephant", "Sun", "Book", "Laughter") | ||
JPanel() | ||
.apply { | ||
layout = BoxLayout(this, BoxLayout.Y_AXIS) | ||
add(JLabel("Editable").apply { alignmentX = Component.LEFT_ALIGNMENT }) | ||
add( | ||
ComboBox(DefaultComboBoxModel(itemsComboBox)).apply { | ||
isEditable = true | ||
alignmentX = Component.LEFT_ALIGNMENT | ||
} | ||
) | ||
} | ||
.run { cell(this).align(AlignY.TOP) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use the Kotlin UI DSL for this, not just dump a bunch of JPanels in it :) The label()
and comboBox()
APIs are available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try again later. That bunch of JPanels works. The DSL was wasting my time.
modifier | ||
.clickable( | ||
onClick = { | ||
// TODO: Trick to skip click event when close menu by click dropdown |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this still need to be addressed? If not, it should not be a TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's something we inherited from the Dropdown
. It wires the Popup
and the clickable area of the ComboBox
, covering some focus/click edge-case. I'll remove the TODO
because there is nothing to do here, keeping the code.
indication = null, | ||
) | ||
.background(colors.backgroundFor(comboBoxState).value, shape) | ||
.thenIf(outline == Outline.None) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have hasNoOutline
, you should use it — however:
- You should join identical, consecutive
thenIf
calls (you can chain modifiers in there!) - I am not sure why this is needed, the outline modifier below will draw on top of this anyway (but maybe this results in a slightly cleaner draw output)
- I am not sure why the next
thenIf
check is needed, either, as that can just be moved above the focus outline, and the focus outline should be drawing on top of the border at that point
outlineShape = shape, | ||
alignment = Stroke.Alignment.Center, | ||
) | ||
.width(IntrinsicSize.Max) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed?
ui/src/main/kotlin/org/jetbrains/jewel/ui/component/ComboBox.kt
Outdated
Show resolved
Hide resolved
contentAlignment = Alignment.CenterStart, | ||
) { | ||
CompositionLocalProvider(LocalContentColor provides colors.contentFor(comboBoxState).value) { | ||
Box( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow why the content is not just a Row that contains the content, optionally the vertical line, and the arrow. The box-based approach seems a bit finicky and you're trying to implement a Row-like behaviour anyway
thickness = metrics.borderWidth, | ||
color = colors.border, | ||
modifier = | ||
Modifier.align(Alignment.CenterStart).thenIf(comboBoxState.isFocused) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that you need an extra padding if the component is focused smells a bit to me. Why does the interior "occupiable" size of the component change with focus? That should not happen, as it could cause things jumping around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed, this is necessary to mirror the same look and feel that Swing has.
textStyle: TextStyle = JewelTheme.defaultTextStyle, | ||
menuContent: MenuScope.() -> Unit, | ||
) { | ||
var skipNextClick by remember { mutableStateOf(false) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this hack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got rid of it 👍🏻
659abff
to
d573cd5
Compare
Nice catch. In Swing is a bit harder to reproduce in the sample because we use a static list there. In Compose I used a single Anyway, Swing uses a middle ellipsis: We don't have it in Compose right now, but it's coming in 1.8.0, it seems: https://issuetracker.google.com/issues/185418980 |
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
It doesn't expand if you provide a |
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
b71e006
to
83434b1
Compare
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
ae12a4d
to
0d4f527
Compare
Blocking issue: when the popup is open, users can't type anything in the editable variant. |
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
It's not happening in the IDE sample Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (review) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
reference: #601 (comment) Signed-off-by: Ivan Morgillo <imorgillo@gmail.com>
Overview
This PR adds the new
ComboBox
composable. It mirrors SwingComboBox
. AComboBox
can be editable or not. A not-editableComboBox
in Swing acts just about like our currentDropdown
composable, but the UI is slightly different. OurDropdown
should be replaced by the not-editableComboBox
to enforce consistency between Swing and Compose.An example of editable
ComboBox
can be found in IntelliJ Settings → Appearance screen: Zoom and Font size areComboBox
es. AComboBox
can be made editable using theisEditable
parameter.The UI for editable and not-editable
ComboBox
is slightly different, as shown in the following screenshots.Checklist
Pre-push
Gradle taskHow Has This Been Tested?
Screenshots