https://kotlinlang.org logo
Join SlackCommunities
Powered by
# doodle
  • j

    Johannes Wirde

    04/24/2024, 8:02 AM
    Also, how come I must disable CORS to get the examples in doodle-tutorial/docs to load?
    n
    • 2
    • 1
  • a

    Alessandro Marcolini

    04/27/2024, 9:38 PM
    I'm trying to put a
    TextField
    in a modal, but it only works on web. On desktop it renders fine, but I'm unable to interact with it. I've made sure it's enabled.
    n
    • 2
    • 2
  • a

    Alessandro Marcolini

    04/27/2024, 9:40 PM
    Also, the default canvas background is white, but when I increase the size of a desktop window (so not a problem on web), the new space is rendered with a black background. I can avoid it by filling the canvas with white. Is this intended behavior?
    n
    • 2
    • 8
  • a

    Alessandro Marcolini

    04/28/2024, 8:09 PM
    It seems that I've come across another issue. I have some UI components that I show/hide depending on the state of the application, and when I show/hide one specific component and then try to drag it, the application freezes. I'm not sure what exactly is causing this, but after some debugging it looks like the problem is here. Somehow some views are ending up in the
    pendingBoundsChange
    list, but they have been rendered and their size isn't empty, causing an infinite loop.
    n
    • 2
    • 19
  • n

    Nick

    05/03/2024, 3:50 PM
    Doodle 0.10.1 is now available. This release is focused on quality of life and includes many fixes. It also includes a new SweepGradientPaint that lets you fill regions with gradients that follow a line as it sweeps around a center point.
    🙌 1
  • n

    Nikky

    06/11/2024, 1:43 PM
    had a quick look over doodle.. looks neat and less overwhelming than compose for the relatively "simple" things i want to do and wanted to ask.. can i make input and output for existing logic that uses Stateflows / Flows ? (Lists and individual values) i have not found anything related to that in the docs on a first quick scan ie. can doodle re-render a list or text, button, etc when the value changes or would i have to build that from scratch? MY app is inteded to control some external programs with OSC messages, as it is right now i control it using TouchOSC (external drag and drop UI builder that sends OSC and MIDI).. but i would like to make the UI part less of a hassle to manage as it grows in complexity and size of elements
    n
    • 2
    • 2
  • n

    Nick

    06/21/2024, 3:04 AM
    I just published
    0.10.2-SNAPSHOT
    . Please try it out (and provide feedback) by pointing to
    maven { url = uri("<https://oss.sonatype.org/content/repositories/snapshots>") }
    . Here's what's included so far... Animation Chaining Animations can now be chained within an animation block using the new
    then
    method. This makes it easier to have sequential animations and avoids the need to explicitly track secondary animations for cancellation, since these are tied to their "parent" animation.
    Copy code
    // val animate: Animator
    
    val animation = animate {
        0f to 1f using (tweenFloat(easing, duration)) {                   // (1)
            // ...
        } then {
            0f to 1f using (after(delay, tweenFloat(easing, duration))) { // (2)
    
            } then {                                                      // (3)
                // ...
            }
        } then {                                                          // (4)
            // ...
        }
    }
    
    animation.completed += { /* ... */ }  // applies to entire chain
    animation.pause ()                    // applies to entire chain
    animation.cancel()                    // applies to entire chain
    Desktop Accessibility Support Doodle's web apps have had accessibility support for some time. Now those capabilities are available for desktop apps as well. You simply include the
    AccessibilityModule
    in your app and follow the guidelines of how to add roles, labels, etc. to your Views. SpinButton Accessibility `SpinButton`s now use the new
    SpinButtonRole
    that allows assistive tools to better read them. This role exposes the currently selected value based on a new
    valueAccessibilityLabeler
    function that converts the value to a
    String
    . Improved Sliders Sliders can now represent values of any
    Comparable
    type
    T
    between two
    start
    and
    end
    values. This is possible for `T`s that have some interpolation between a
    start
    and
    end
    based on some value between
    0
    and
    1
    . This is done via a new
    TypeConverter<T>
    that defines the interpolation (and its inverse). This means you can now create sliders for numeric types like
    Measure<T>
    directly and their
    value
    will by of the right type.
    Copy code
    val charSlider     = Slider('A' .. 'Z')
    val velocitySlider = Slider(10 * meters / seconds .. 100 * miles / hours)
    You can also create Sliders for any type
    T
    , as long as it is
    Comparable
    and you can create an
    Interpolator
    for it.
    Copy code
    fun <T: Comparable<T>> customSlider(model: ConfinedValueModel<T>, interpolator: Interpolator<T>) {
        val slider: Slider<T> = Slider(model, interpolator = interpolator)
    }
    These, more flexible Sliders can also be used in forms as expected.
    Copy code
    Form {this(
        + slider('A' .. 'Z'),
        + slider(10 * meters/seconds .. 10 * miles/hours),
        + slider(model, interpolator = interpolator),
        onInvalid = {}
    ) { _: Char, _: Measure<Velocity>, _: T ->
    
    }}
    Non-linear Sliders Sliders are linear by default, which means a change in their position translates to a linear change in their value. There are cases however, when it makes sense to have a slider's value change in a non-linear way. You can do this by providing a function that maps values between the slider's input and output spaces. These values are all within the [0-1] domain, and work very similarly to easing functions used for animations. The big difference is they have two forms: f(x) and f^-1(x).
    Copy code
    import io.nacular.doodle.controls.range.InvertibleFunction
    import io.nacular.doodle.controls.range.Slider
    import kotlin.math.log
    import kotlin.math.pow
    
    /**
     * Logarithmic function and inverse <https://www.desmos.com/calculator/qq59ey0bub>
     */
    private object LogFunction: InvertibleFunction {
        override fun invoke (value: Float) = log((10f - 1) * value + 1, 10f)
        override fun inverse(value: Float) = (10f.pow(value) - 1)/(10 - 1)
    }
    
    val logarithmicSlider = Slider(0.0 .. 1.0, function = LogFunction)
    APIs • General ◦ New
    after
    animation function that allows a delay before executing an
    AnimationPlan
    . ◦ Made
    Scene
    a public type since it is part of the public API for
    Theme
    ◦ New builders for creating Sliders for
    Char
    and
    Measure<T>
    ◦ New
    increment
    and
    decrement
    methods for sliders ◦ New methods for incrementing/decrementing start/end for
    RangeValueSlider
    ◦ Renamed
    Spinner
    to
    SpinButton
    (and related classes) and deprecated all old uses. ◦ New
    SpinButtonRole
    for accessibility. ◦
    ThemePicker
    now allows customization of accessible value labels via new
    valueAccessibilityLabeler
    property. ◦
    ListItemRole
    now has a
    selected
    state.
    ListItem
    (BasicTheme) now keeps this value up-to-date. ◦ New
    circumference
    extension for
    Circle
    ◦ New helper for calculating the interior angle between two
    Vector3D
    instances. ◦ New form methods for creating
    SpinButton
    form controls from a
    List
    of values or
    IntProgression
    . ◦ New functions for creating ease[In/Out]Bounce EasingFunctions with an `initialBounceFraction`:
    easeIn(0.15f)
    . ◦ New convenience methods for working with PathBuilders using x,y instead of Point. • Deprecations ◦ All animation functions that take a delay, since there is a new
    after
    function. ◦ Types and functions related to
    Spinner
    , which was renamed to
    SpinButton
    . ◦ Types and functions related to
    Dropdown
    , which was renamed to
    SelectBox
    . Fixes | Improvements • General ◦ Issue where item could be stuck in render loop if it requires a layout, but cannot render b/c it is not recursively visible (it and all ancestors visible). • Browser ◦ Fixed issue with Display pointer exit not being properly handled. ◦ Work-around for Safari giving incorrect clientX/Y values when the browser window is zoomed, which broke pointer location. ◦ Fixed edge case where old rendered vectors aren't cleaned up if a sub-frame happens where one wasn't before. ◦ Fixed bug in reading items from DataTransferItemList that broke file drag-drop Versions • Kotlin -> 1.9.23 • Kover -> 0.8.1 • Dokka -> 1.9.20
    alphabet yellow d 2
    🎉 2
    c
    • 2
    • 1
  • c

    Cherrio LLC

    06/21/2024, 6:10 PM
    Hello, What is the difference between
    size
    idealSize
    minimumSize
    . Like what role do they play and how do they affect each other?
    n
    • 2
    • 3
  • n

    Nick

    06/28/2024, 2:59 PM
    Hey folks, Doodle: 0.10.2 has been released. Some feature highlights: • Animation Chaining - Link animations together using the new then method. These sequences are all combined into a single cancelable animation. • Desktop Accessibility Support - Accessibility features now work on Desktop • `SpinButton`s now support basic Accessibility • Improved Sliders - Sliders can now represent values of any
    Comparable
    type
    T
    between two
    start
    and
    end
    values. • Non-linear Sliders Check out the docs for more details.
    🎉 2
  • c

    Cherrio LLC

    06/30/2024, 4:58 PM
    Hi nick, if we say we only wanna use a single view throughout the app and just draw children on the canvas. Will we be able to get away with that? Build interactive UI, I was thinking we’ll loose access to pointer inputs. Any gotcha we should know?
    n
    • 2
    • 16
  • k

    Kev Thompson

    08/02/2024, 9:52 AM
    Hi All, Im on a bit of a time limit evaluating a number of web frameworks so im asking questions id normally just work out. I've downloaded the doodle tutorial code, first off there is a compile error in there that I fixed up and will put in a PR later if I get chance. in the toml it references dateTimeVersion but its not defined. so the stupid question I have is how do I run the tutorials? I want to run "Todo" for example but there's no configurations available to run and no instructions ( that I have seen ) on what to set up in a config to run them. I've tried in Android studio and Intelij. Thanks in advance
    n
    • 2
    • 1
  • n

    Norris

    08/03/2024, 5:37 PM
    Hey Guys, my wasm target is now failing. I used to be able to run it before.
    n
    • 2
    • 17
  • n

    Norris

    08/03/2024, 6:05 PM
    pasting build,gradle file
    build.gradle.kts
  • n

    Norris

    08/04/2024, 12:39 AM
    If anyone here can help me with the previous issue in the wasm target. I would really appreciate. Otherwise, I will be forced to abandon this project and framework. I’ve spent so much time trying to fix this, I’m just looking to get some help. Thanks.
  • n

    Nick

    08/04/2024, 12:58 AM
    @Norris, did you try the gist i shared in the thread (based on the build script you shared)? would be good to see if you can get that working. worked for me from clean project. that could help narrow down the issue.
    n
    • 2
    • 11
  • n

    Norris

    08/04/2024, 2:57 PM
    After reviewing:
    Copy code
    val styledLabel = Label(
        bold("Lorem Ipsum").." is simply "..Yellow("dummy text", Background)..
        " of the printing and typesetting industry. It has been the industry's standard dummy text "..
        TextDecoration(setOf(Under), Red, Wavy) ("ever since the 1500s")..
        ", when an unknown printer took a galley of type and scrambled it to make a type specimen book."
    ).apply {
        width         = 250.0
        fitText       = setOf(Height)
        wrapsWords    = true
        lineSpacing   = 1f
        textAlignment = Start
        letterSpacing = 0.0
    }
    I think I am running into this issue because I am trying to build objects imperatively not declaratively. Is it possible to do this?
    n
    • 2
    • 8
  • n

    Norris

    08/04/2024, 2:58 PM
    Ex:
    Copy code
    val label = Label("Some Text")
            label.size = Size(200, 100)
            label.behavior = ??
  • c

    Cherrio LLC

    08/14/2024, 11:54 AM
    Is there a way to load SVG? and maybe tint it?. Solved
    👍 1
  • c

    Cherrio LLC

    08/14/2024, 6:23 PM
    We have a custom
    TextFieldBehaviour
    using NativeModifier, is there away to add padding to the text? It’s too close to the TextField border.
    n
    • 2
    • 1
  • s

    snowe

    08/15/2024, 10:20 PM
    I’m trying to get just a bare minimum doodle app running, but the tutorials are all incredibly complex. For someone that hasn’t touched component based dev like this in over a decade, it’s all impossible to understand. Are there any tutorials that just explain setting up something like a split view with text boxes? I mean, like bare bones, no element styling, nothing. Even just for the JVM so I can understand what in the world is going on. Even looking at the tutorials on the website vs the tutorial code it’s different and so I can’t understand what the docs are trying to say because when I go to run the actual code it’s different. I have a partially running app, but all it does is create two views next to each other and color them differently. Trying to add a textField to the views does nothing. No logs about errors, it just doesn’t work. And trying to use the
    constrain
    function also doesn’t seem to work. I have to set up the layout manually with rectangles.
    n
    • 2
    • 18
  • s

    snowe

    08/17/2024, 1:09 AM
    How do I get an app to not be full screen (jvm)?
    n
    • 2
    • 4
  • c

    Cherrio LLC

    08/17/2024, 7:33 PM
    I think we need a plug and play design system for doodle, that people can get up and running. Had a usecase to quickly get a poc up and running, I couldn’t. I was pained because it was slow 😪
    n
    r
    • 3
    • 16
  • n

    Nick

    09/11/2024, 7:04 PM
    hey folks. this is a good way to give input to the JB team and help improve the ecosystem we all love.
    👍 3
  • n

    Nick

    11/12/2024, 5:28 AM
    Doodle 0.10.3 has been released. This is a small set of fixes to hold things over while 0.11.0 is under development.
    🎉 2
  • n

    Nick

    11/29/2024, 7:33 AM
    Squashed a nasty touch event bug that only affected mobile web, and released it in 0.10.4.
    alphabet yellow d 1
  • n

    Nick

    02/01/2025, 7:21 AM
    I just published 0.11.0-SNAPSHOT. Please try it out (and provide feedback) by pointing to maven { url = uri(“https://oss.sonatype.org/content/repositories/snapshots“) }. Here’s what’s included so far... Features New Layout Paradigm A View’s bounds is no longer editable directly as it was in previous versions of Doodle. This is a major change to the way Doodle layout functions; but it is important to avoid some major pitfalls of the previous approach. Namely, it was very easy to write code that would get into infinite layout loops. This is a good example of something that would cause issues before: Doodle 0.10.x
    Copy code
    view {
        + Label("Hello") // Label fits its text by default
      
        layout = constrain(children.first(), fill) // :x: infinite loop
    }
    Doodle 0.11.0
    Copy code
    view {
        + Label("Hello") // Label fits its text by default
      
        layout = constrain(children.first(), fill) // :white_check_mark: works as expected
    }
    Now it just works as expected since View’s cannot override the
    Layout
    they are managed by. More specifically, a View is given a
    min
    and
    max
    size it can take by its parent’s
    Layout
    . It then picks a size it would like to take in that range and reports back to the
    Layout
    , which uses that information to position/size it and the other Views it manages. This means you cannot directly change a View’s bounds like before. However, you can still suggest changes that the View may use to determine its final size. This means code like this no longer works, and cannot be directly converted to the new suggestion system. That’s because bounds suggestions are not guaranteed in the way a normal setter would be. Doodle 0.10.x
    Copy code
    val view1 = view {}.apply { size = Size(10, 50) }
    val view2 = view {}.apply { size = view1.size   } // view2.size == Size(10, 50)
    Doodle 0.11.0
    Copy code
    val view1 = view {}.apply { suggestSize(10, 50) }
    val view2 = view {}.apply { size = view1.size   } // view2.size == Size.Empty since suggestion usually async
    Frosted Glass Paint New
    Paint
    that lets you create glass like material that blurs the underlying content. This, like all paints, can be used to fill any shape, stroke, or text.
    Copy code
    rect(
        rectangle = bounds.atOrigin.inset(borderThickness / 2),
        radius    = cardRadius,
        fill      = FrostedGlassPaint(Color(0x09008bu) opacity 0.2f, blurRadius = 10.0)
    )
    Text Outlining You can now outline text using `Stroke`s like other shapes. This includes
    StyledText
    , which now supports strokes for styled segments.
    Copy code
    render = {
        text(
            text   = "Hello Doodle!",
            at     = Origin,
            fill   = Transparent.paint,
            stroke = Stroke()
        )
    }
    Copy code
    val stroke = Stroke()
    
    render = {
        text(
            text = "Hello " .. stroke { "Doodle!" },
            at   = Origin,
        )
    }
    Inline Constraints for Forms Forms have api.Layout/s that you can specify explicitly. But now you can also define constraint-based layouts declaratively when defining a Form.
    Copy code
    Form { this (
        "Bob" to labeled("Name" ) { textField (                                  ) },
        21    to labeled("Age"  ) { spinButton(1..120                            ) },
        Green to labeled("Color") { colorStrip(Red, Green, Blue, BlueColor, Black) },
    
        layout = { name, age, color ->
            name.top      eq parent.insets.top
            name.left     eq parent.insets.left
            name.right    eq age.left - 12 strength Strong
            name.height   eq name.idealHeight
    
            age.top       eq name.top
            age.width     eq 80
            age.right     eq parent.right - parent.insets.right
            age.height    eq age.idealHeight
    
            color.left    eq name.top
            color.top     eq name.bottom + 12
            color.right   eq age.right strength Strong
            color.height  eq color.preferredSize(
                min = Empty,
                max = Size(parent.width.readOnly, POSITIVE_INFINITY)
            ).height
    
            parent.bottom eq color.bottom + parent.insets.bottom
        },
    
        onInvalid = {}
    
    ) { name: String, color: Int, age: Color ->
        // ...
    } }
    APIs • General •
    ScrollPanelVisualizer
    now takes a config that lets you modify the resulting panel • ScrollPanel’s
    contentWidthConstraints
    and
    contentHeightConstraints
    now provide
    IdealSizedProperty
    values, which have an
    idealValue
    field. This lets you constrain the property using its ideal value. • Layout now has preferredSize method, which returns the preferred size for the set of Views given the current context. •
    lerp
    for
    HsvColor
    • parent
    insets
    now available within constraint blocks •
    underline
    and
    lineThrough
    helpers for creating `TextDecoration`s • New
    Encoder
    utility types for Strings • New methods for scrolling a View horizontally and vertically • New infix
    strength
    method for constraint DSL (removed
    rangeTo
    operator option) • Removed
    Label.fitText
    • `Path`s can now be created by “extending” an existing one. This produces a builder based on the given path •
    PathBuilder
    has a new method to append a
    Path
    • CarouselItem now has a
    displayIndex
    property which indicates the item’s display order relative to
    nearestItem
    . • New
    MonthPanel.showMaxRows
    property that controls whether all 6 potential rows are shown for the panel. •
    TreeBehavior.RowPositioner
    now gets tree bounds info as an input for
    rowBounds
    and
    contentBounds
    • New
    Theme.selected
    and
    Theme.deselected
    events to indicate when a Theme has been selected/deselected. • MenuBehavior.SubMenuConfig now allows configuration of the menu’s anchor point, insets from the Display’s edges, and horizontal/vertical offsets from the parent menu. •
    TileLayout
    now takes an
    Orientation
    • New anchor property for
    SlicerPresenter
    that controls which part of the stack moves first. •
    ScrollPanelVisualizer
    now takes a config that lets you modify the resulting panel • ScrollPanel’s
    contentWidthConstraints
    and
    contentHeightConstraints
    now provide
    IdealSizedProperty
    values, which have an
    idealValue
    field. This lets you constrain the property using its ideal value. Fixes | Improvements • General • bug in
    interiorAngle
    function for 2 vectors •
    spinButton
    form field now adopts initial value set for it. •
    IntSpinButtonModel
    now clamps initial value • Issue in
    Resizer
    where pointer release was consumed (to avoid issues on touch devices) which caused strange behavior w/ other handlers. Changed to
    preventOsHandling
    instead. • Bugs in
    ConstrainedSizePolicy
    • Form switch layout • Label only re-measures text if text is actually changed • Some areas where wordSpacing and letterSpacing couldn’t be
    0
    • GridLayout issue due to new layout model • Issue where ConstraintLayoutImpl would unregister context for Views that were unconstrained even if they were still constrained in other blocks. • Issue where
    ScrollPanel
    scroll didn’t take scroll bar sizes into account • Selection bug in Lists, Tables, Tress, TreeTables related to selecting the previous item after a select all • Bug where
    MultiSelectionModel
    wouldn’t have correct
    last
    when selecting all while last item • Fixed sizing for many form controls that were incorrect under new layout scheme • Issue where
    List
    could reset size incorrectly if it’s parent has no layout •
    Label
    default lineSpacing •
    Label
    preferredSize now tracks bounds changes when
    wrapsWords
    set to
    true
    • The way offset/size-inset constraints work •
    BasicSelectBoxBehavior
    rendering •
    BasicSpinButtonBehavior
    rendering • Issue where
    Label.text
    wouldn’t update if changing from a
    StyledText
    with same text value • Edge case where Carousel wouldn’t transition if it only contained 1 item with wrapping • Menu selection issue caused by bad Kotlin compilation: https://youtrack.jetbrains.com/issue/KT-73130. • Edge case where items could be selected in a Menu if they were all disabled. • Issue where Carousel would incorrectly handle manual move cancellation if no movement had occurred • Bug in they way Views are selected, which caused disabled Views to get pointer events. • Render issues in
    CubePresenter
    • Issue where Carousel would incorrectly handle manual move cancellation if no movement had occurred • Issue where
    Carousel
    wouldn’t cancel skips properly and this resulted in janky rendering. •
    SlicerPresenter
    now caches bounds data to improve frame rate. • Issue with
    CubePresenter
    positioning of cube cap supplemental view. •
    BasicSelectBoxBehavior
    popup list size • Updated Dynamic Behaviors so they work w/
    List<BehaviorResolver>
    instead of Set to ensure proper ordering • bug in
    ProportionalSizePolicy
    that led to incorrect column sizing • Popup ordering in some edge cases • Stroke rendering with some paints • But where
    PatternPaint
    transform not updated in some edge cases • Render issue with some brushes when the content they render is clipped • Issue in native ScrollPanel behavior that prevented proper install/uninstall cycles • No longer returning 0 for empty string height • Issue with paint caching • Using browser’s default line-height instead of assuming a value of 1. • Incorrectly treating “simple” brushes as complex in some edge cases, which means they’d render using SVG when they didn’t need to • Ensure single line text has proper line height set • Various fixes for foreign object paints • Issue where some paints could fail to draw both strokes and fill when used at the same time • Issue where some paints would prevent fill from working when used as a Stroke • Issue in stroke rendering with SweepGradientPaint • Incorrect text indent for wrapped styled text in some cases. • Vertical alignment of SVG text so it matches HTML text. • SVG text backgrounds • Bug where touch events resulted in pointer enter being called after exit. This meant Views that were touched would always remain in the “pointer entered” state, which breaks many app interactions. • Browser • Text color not defaulting to black in some cases • Pointer up event consumed even if down event was not sent to the app • Bug in logic that decides when to use plain css for text • Bug in text width calculation for
    StyledText
    • Render bug where StyledText background would cover an entire line of text instead of the specific words. • Work-around for Safari’s CanvasRenderingContext2D not having proper Font support • Desktop • Default line height handling • Default line height handling • Opacity not used for image and image paints • Updating where skiko properties are set to ensure they take effect, this includes better integration of windows w/ Mac system appearance. • Issue with outer shadows not rendering properly • Issue where text could wrap incorrectly at small widths • Issue when rendering indent for wrapped, plain text. Build • Type-safe project accessors • Cleanup deprecations in buildSrc • Remove node version specification Versions • Kotlin -> 2.1.10 • Kover -> 0.9.1 • Mockk -> 1.13.13 • Skiko -> 0.8.19
    alphabet yellow d 1
    thank you color 1
    c
    • 2
    • 5
  • m

    Michal Landsman

    03/03/2025, 3:28 PM
    Hello guys, I have a kinda stupid question. Is there a way how to manipulate with browser window location api? I want to operate with query params, history in the app. Two way binding: browser -> app, app -> browser.
    n
    • 2
    • 1
  • n

    Nick

    03/03/2025, 8:39 PM
    Doodle 0.11.0 has been released. https://github.com/nacular/doodle/releases/tag/v0.11.0
  • n

    Nick

    03/15/2025, 7:01 PM
    Couple demos of Doodle apps running natively on Mac. Still a lot of work to do, but good progress to supporting the full suite of features already available for the awt desktop versions.
    Doodle-MacNative.movDoodle-MultiWindow-MacNative.mov
    alphabet yellow d 4
    c
    • 2
    • 4
  • n

    Nick

    03/30/2025, 4:29 AM
    Doodle 0.11.1 released. This is a small patch release with some important fixes. https://github.com/nacular/doodle/releases/tag/v0.11.1
    alphabet yellow d 5