Skip to content

greenya/SpaceLib

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SpaceLib

/core                       - core types and utilities
    /stack_trace            - debug stack trace
    /timed_scope            - evaluate scope execution time
    /tracking_allocator     - memory allocation tracker
/events                     - [planned] [maybe] event bus
/raylib                     - helpers when using Raylib
/sdl2 (3?)                  - [planned] helpers when using SDL
/terse                      - text layout calculation
/tweens                     - [planned] [maybe] tween manager
/ui                         - ui manager
/userfs                     - user file system: save/load a file in user data dir or localStorage
/userhttp                   - send HTTP requests using cURL or Fetch API

TODOs

TODO: userhttp: add abort_request(req: ^Request)

- user should be able to abort request by its pointer
- abort every running request on destroy()

TODO: userfs: expose error status

maybe not, as i hardly believe somebody would handle the error properly;
if in a web browser for some reason userfs fails, i guess the last thing we want to tell user about it;
so maybe just silently do nothing (don't load or save), the app should act like nothing previously
was saved and just use default preset, and any further writes will do nothing

anyway; if added, the developer can decided to handle error or don't; at the moment there is no way to know
that something went wrong

TODO: userfs: replace localStorage with indexedDB

TODO: terse: make line alignment to be stack-based (open and close) OR at least change line alignment when actual word is added

the problem at the moment is that using "left", "right" or "center" immediately sets current line alignment;
consider following formatting:

    Some text goes left aligned
    <center> -- this is already a new line
    centered text
    <left> -- another new line
    Left aligned text continues

To have no line skips we need to write:

    Some text goes left aligned
    <center>centered text
    <left>Left aligned text continues

Ugly and stupid :)

TODO: terse: add support for command

allow to have text fit to any size without need for scrollbar; very needed for dropdown boxes and similar limited space controls; at least to be able to use it for one liners (not wrapping text); ideally support two modes:
- overflow=ellipsis: [default] should truncate whole word (or chars) and add "..." to the end
- overflow=scrolling: should repeat smooth scrolling to the end (revealing whole text for reading) and faster to the start for repetition

TODO: terse: add ability to have a line with differently aligned parts -- ability to have a single line with text at left and at right, like in WOW's tooltips ("| Head <---> Leather |", "| Main Hand <---> Mace |")

TODO: terse: rework parse_f32, parse_int, parse_vec_i, parse_vec -- should be only parse_vec and parse f32, which just handle any f32 text value

TODO: terse: add support for "image" command

Maybe <image=name[:left][:right]>, add proc for query image size by name (Query_Image_Proc). Image should support alignment: center (default), left, right:
    - when "center", the image starts with new line, positioned at the center, text continues after image from next new line
    - when "left" or "right", image will stick to given size, text should flow on other size of the image, e.g. the image basically affects the following lines width, until image height end

[MAYBE] do not add "query" proc, but have format like: <image=name:200x200[:left][:right]> width and height are required, if width=0, the width will be input rect.w, if height=0 -- input rect.h

TODO: terse: investigate if text measuring of a word can be improved (performance wise) by caching font+text keys, so next time we measure same text with same font, we immediately know the size (Vec2)

TODO: ui: Grid: support other directions

TODO: ui: support multiple callbacks for some events

currently when we need to handle an event, we assign a callback, and if its already had some callback, that would just get replaced. Maybe we should add some way to add callbacks into list; maybe not for all, the draw and tick might be just pointers as they are called often (needs testing).

callbacks:
    - called every frame if .hidden not_in f.flags:
        - tick
        - draw
        - draw_after
    - called on demand:
        - show
        - hide
        - enter
        - leave
        - click
        - wheel
        - drag (called every frame when f.captured)

// this is how we could add "click" callback to some_frame without need of managing actual value of some_frame.click
ui.on_click(some_frame, proc (f: ^ui.Frame) {
    // ...
})

// it would do something like: append(&f.click, click_proc)
// and probably ensure() such callback is not in the list yet
// click list should be like: Frame.click: [dynamic] Frame_Proc

// extend arg list of add_frame() so it takes "click: Frame_Proc = nil", "enter:...", "leave:..." etc.
// and will call proper on_xxx(); just like with set_anchors()

maybe add some callback lists to the UI, so its possible to have global events, for example
    - on_ui_root_resize     // can be useful when frame want to support different layout depends on screen size
    - on_ui_capture_start
    - on_ui_capture_end
    - on_ui_click
    - on_ui_wheel
    - on_ui_drag

TODO: ui: key press handling

The idea is to be able express frame handles "Esc" or "A" and when that happens, the frame gets "click". Ideally, we want to add all the structure, which will include multiple elements wanting "Esc" (or any other button), but the UI should automatically route "click" to correct one, checking visibility and hierarchy of the frame; it should be possible to open dialog which would close by "Esc" and the "Esc" is also visible below, as dialog has semitransparent layer and the tree is visible below. Any single key can be handled only be single frame at any time, e.g. even if we have tab bar with "Q" and "E" navigation and another tab bar with same keys is shown, only one should consume the key input.

TODO: ui: fix hover_ratio(): fix twitching for large duration and short enter/leave times

maybe we should add a separate field -- Frame.hover: Hovering,

Hovering :: struct {
    enter_ease  : ease.Ease,
    enter_dur   : f32,
    leave_ease  : ease.Ease,
    leave_dur   : f32,
    ratio       : f32,
}

in tick() check if f.hover.enter_dur != 0 && f.hover.enter_dur != 0 -- calc hover.ratio; no need to use buggy hover_ratio(), now we have hover.ratio value, and we can ensure it changes smoothly.

TODO: [?] core: maybe consider changing Color to be 4 floats instead 4 bytes

we are doing a lot of alpha and brightness tweaking and every time we convert 1-3 values to f32 and back to u8

TODO: [?] ui: slider actor: add track click handling

maybe make it optional with some data.flag; clicking should set thumb to most close valid position;
[?] if added, i guess scrollbar also needs it [?]

TODO: [?] ui: add support for automatic child frames generation for each text_terse.groups item

- Frame.name should be group name
- updating terse should handle child frames (add/remove/update)
- the idea is to be able to have enter/leave/click for any group in terse
- maybe we need to add Frame.draw/enter/leave/click_terse_group for handling events for those dynamic children

TODO: [?] ui: maybe add support for logic resolution 1280x720

maybe we don't need it, as its possible to do following:
    - always report needed resolution, regardless of actual, e.g. call ui.tick() with {0,0,1280,720}
    - when drawing, user can scale frame's rect to actual resolution

TODO: [?] ui: add UI.drawing_frames and .updating phase should fill it to be later used in .drawing phase

TODO: [?] ui: add support for template loading

the idea is to reduce manual add_frame() calls and be able to describe ui in json (?), after its loaded (a tree), we need to hook draw, click etc.; each element could be retrieved by path (already supported). A template for simple dialog could look like below.
{
    "name": "dialog",
    "size": [ 640, 0 ],
    "layout": {
        // this is Flow, but somehow loader should understand it
        "dir": "down",
        "pad": 30,
        "auto_size": [ "height" ],
        "anchors": [
            { "point": "center" }
        ]
    },
    "children": [
        {
            "name": "title",
            "flags": [ "terse", "terse_height" ],
            "text_format": "<wrap,pad=30,font=text_4m,color=primary_d2>%s"
        },
        {
            "name": "message",
            "flags": [ "terse", "terse_height" ],
            "text_format": "<wrap,font=text_4l,color=primary_d2>%s"
        },
        {
            "name": "buttons",
            "size": [ 0, 90 ],
            "layout": { // Flow
                "dir": "right_center",
                "gap": 20,
                "align": "end"
            },
            "children": [
                {
                    {
                        "name": "button_1",
                        "text_format": "<pad=12:6,font=text_4l,color=primary>%s",
                        "flags": [ "capture", "terse", "terse_size" ]
                    },
                    {
                        "name": "button_2",
                        "text_format": "<pad=12:6,font=text_4l,color=primary>%s",
                        "flags": [ "capture", "terse", "terse_size" ]
                    }
                }
            ]
        }
    ],
}
the usage could be something like:
// hypothetical init (once)
dialog := ui.add_template(parent, "/* template text or simple loaded object is here */")
dialog.draw = draw_dialog_rect
for btn in ui.get(dialog, "buttons").children {
    btn.draw = draw_button
    btn.click = proc (f: ^ui.Frame) {
        fmt.printfln("%s was clicked!", f.name)
    }
}

// hypothetical use
ui.set_text(ui.get(dialog, "title"), "Quit Game?")
ui.set_text(ui.get(dialog, "message"), "Are you sure you want to quit?")
ui.set_text(ui.get(dialog, "buttons/button_1"), "Confirm")
ui.set_text(ui.get(dialog, "buttons/button_2"), "Cancel")
ui.show(dialog)

About

A collection of packages for Odin

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published