Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

GUI framework for the C9 language

License

NotificationsYou must be signed in to change notification settings

1jss/C9-gui

Repository files navigation

C9 gui is a performant and flexible GUI library built on SDL2. C9 gui primarily targets theC9 language, which is a C99 subset.

Features

  • Flexible element tree structure (with dynamic loading of children)
  • Padding, border and gutter around elements and between children
  • Superellipse rounded corners (with anti-aliasing)
  • Gradient backgrounds (smoothed with blue noise dithering)
  • Image backgrounds (png)
  • Event handling (click, blur, key press)
  • Layout engine (flex or scroll children in any direction)
  • Lazy loading of elements (if outside of window bounds)
  • Text rendering (single line with alignment or multiline)
  • Easy table layout (automatic column sizing)
  • Text input (single and multi line with selection and undo history)
  • Event driven rendering (only rerender on user input)
  • Partial rendering (only rerender elements that have changed)
  • Buffered rendering (all elements are cached as textures)
  • Element tags for easy element selection

Screenshots

image_1image_1image_1image_1

Architecture

Element tree

C9 gui uses a tree structure to store the retained "document model". Every node in the tree is anelement that can have their own children. The list of children is a flexible C9 array, so the number of children (and thus the tree itself), can be changed at runtime.

Element

An element is a struct that contains all the properties of a child. The structure is initalized with default values, so only the changed or used properties need to be set. In other words, all items are optional.

TypeNameComment
u8element_tagid or group id
u16widthfixed width of the element
u16heightfixed height of the element
Paddingpaddingpadding inside element (4 values)
Borderborderborder around element (4 values)
u8corner_radiusradius of superellipse corners
u8gutterspace between children
u8overflowcontain or scroll children
u8layout_directiondirection of flex layout
u8background_typenone, color, gradient, image
RGBAbackground.colorused if background_type is color
C9_Gradientbackground.gradientused if background_type is gradient
s8background.imageused if background_type is image
RGBAtext_colorcolor of rendered text
RGBAborder_colorcolor of border
s8texttext label
u8text_alignhorizontal text alignment
InputData*inputtext input object (new_input)
Array*childrenflexible array of child elements
OnEventon_clickfunction pointer called on click
OnEventon_blurfunction pointer called on blur
OnEventon_key_pressfunction pointer called on input
LayoutPropslayoutprops set by the layout engine
RenderPropsrendertexture cache for the renderer

New elements can be created in two ways. Either as children of an existing element(add_new_element) or as a standalone element(new_element). The standalone element can then dynamically be added to an element in the tree by callingadd_element.

Example of creating a standalone card element with text:

Element*card_element=new_element(arena);*card_element= (Element){    .background_type=background_type.color,    .background.color=0xFFFFFFFF,    .border= (Border){1,1,1,1},    .border_color=0xF2F3F4FF,    .corner_radius=15,    .padding= (Padding){10,10,10,10},    .layout_direction=layout_direction.vertical,  };Element*title_element=add_new_element(arena,card_element);*title_element= (Element){    .text=to_s8("Card title"),    .text_color=0x555555FF,    .font_variant=font_variant.large,  };Element*text_element=add_new_element(arena,card_element);*text_element= (Element){    .text=to_s8("Some text in the card"),    .text_color=0x555555FF,  };

Event handling

Events are handled in the main loop and if an element has an event handler function set for the event type (on_click,on_blur,on_key_press), it will be called.

If the event is a mouse down event, the element that is both under the pointer and has an on_click function will be set as active element and the on_click function will be called. The formerly active element will have its on_blur function called. If the element has a text input object, the text cursor will be set at the position of the mouse pointer.

If the event is a key press event, the active element will have its on_key_press function called, if it has one. On element with input objects the key press is automatically handled.

If the event is a scroll event, the entire tree will be searched for scrollable elements under the pointer and the scroll event will be applied to them, starting with the outermost element, so that children get scrolled before parents. The active element is not changed on scroll.

Rendering

The interface is only rendered when thererender flag of the element tree is set to true. The render function will then traverse the tree and redraw all child elements. All element are cached as textures, so only the elements that have new dimensions or are marked as changed will be redrawn from scratch. This means that scrolling and moving elements around is very efficient.

Components

Components are reusable standalone elements that can dynamically be added and removed from the tree. They are implemented as global Element references (pointers) that get initalized on their first use. This way no more memory is used than needed and the already initalized component can be removed and readded to the tree without loosing its state and rendering cache.

Project navigation

The project starts frommain.c and all C9 includes are header only. The base library implementation is located in theinclude folder. These do not need to be altered by the library user. The example components and helpers are located in thecomponents,helpers, andconstants folders. These are just for reference and should be replaced.

The foundational layer of drawing is handled indraw_shapes.h, where functions for directly drawing superellipses of different types. These should normaly not be used directly by the library user, but only by the rendereer (renderer.h) that draws the Element tree. The layout of the tree is calculated inlayout.h.

Prerequisites

SDL2 is required to compile and run this project.

MacOS

Download SDL2 from official releases and move it to/Library/Frameworks

Compiling and running

Clang

Compiling with SDL2:clang -std=c99 -Wall -Wextra -F /Library/Frameworks -framework SDL2 main.c -o main

Running:./main

Todo

  • Mac .app packaging
  • To-Do example app
  • Input rerenders when added to layout
    • Only rerender lines that have changed
      • Compare newline list length with child element list length. If different, rerender.
      • Compare text length with child element text length. If different, rerender.
      • Compare text content with child element text content. If different, rerender.
  • Better boolean values? boolean.TRUE, boolean.FALSE
  • Make SFT_MeasureUTF8 return u8 indexes instead of utf8 characters
  • Make stb_image.h and schrift.h more C9 conformant
  • Switches as texts? C9_SWITCH_ON, C9_SWITCH_OFF plus onclick that changes between them?
  • Debug: Endless loop on input sometimes rapid input?
  • Auto linebroken text parents does not shrink correctly on window resize
  • Extra newline in search panel result items

Notes

  • If element has background image, it has no border, other background or corner radius
  • If element has input it has has no label (text)
  • prop text_align only applies to label
  • prop font_variant only applies to label
  • text_color only applies to label and input

Releases

No releases published

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp