first attempt for the layout class and property system
This commit is contained in:
commit
29b5bda326
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/.idea
|
||||
/cmake-*
|
35
CMakeLists.txt
Normal file
35
CMakeLists.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
cmake_minimum_required(VERSION 3.24)
|
||||
project(clay C)
|
||||
|
||||
set(CMAKE_C_STANDARD 17)
|
||||
|
||||
|
||||
# todo: use FetchContent instead https://cmake.org/cmake/help/latest/module/FetchContent.html#examples
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_CAIRO QUIET cairo)
|
||||
|
||||
find_path(CAIRO_INCLUDE_DIRS
|
||||
NAMES cairo.h
|
||||
HINTS ${PC_CAIRO_INCLUDEDIR}
|
||||
${PC_CAIRO_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES cairo
|
||||
)
|
||||
|
||||
find_library(CAIRO_LIBRARIES
|
||||
NAMES cairo
|
||||
HINTS ${PC_CAIRO_LIBDIR}
|
||||
${PC_CAIRO_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
|
||||
add_library(clay src/clay.c src/clay-base.c src/clay-context.c src/clay-layout.c src/clay-property.c src/clay-text.c
|
||||
src/clay-flex.c src/clay-document.c src/clay-color.c)
|
||||
target_include_directories(clay PUBLIC include)
|
||||
target_include_directories(clay PRIVATE ${CAIRO_INCLUDE_DIRS})
|
||||
target_link_libraries(clay PRIVATE ${CAIRO_LIBRARIES})
|
||||
target_compile_options(clay PRIVATE -Wall -Werror)
|
||||
|
||||
if(PROJECT_IS_TOP_LEVEL)
|
||||
add_executable(clay-demo src/demo.c)
|
||||
target_link_libraries(clay-demo PRIVATE clay)
|
||||
endif()
|
18
include/clay-base.h
Normal file
18
include/clay-base.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef CLAYOUT_CLAY_BASE_H
|
||||
#define CLAYOUT_CLAY_BASE_H
|
||||
|
||||
|
||||
typedef struct clay_ctx_t *clay_ctx;
|
||||
typedef struct clay_t *clay;
|
||||
|
||||
|
||||
clay_ctx clay_create_context(void);
|
||||
void clay_destroy_context(clay_ctx);
|
||||
|
||||
|
||||
void clay_set(clay, const char*, ...);
|
||||
|
||||
clay clay_clone(clay);
|
||||
|
||||
|
||||
#endif //CLAYOUT_CLAY_BASE_H
|
40
include/clay-flex.h
Normal file
40
include/clay-flex.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#ifndef CLAYOUT_CLAY_FLEX_H
|
||||
#define CLAYOUT_CLAY_FLEX_H
|
||||
|
||||
|
||||
enum clay_flex_direction_e {
|
||||
CLAY_FLEX_DIRECTION_ROW = 0,
|
||||
CLAY_FLEX_DIRECTION_ROW_REVERSE = 1,
|
||||
CLAY_FLEX_DIRECTION_COLUMN = 2,
|
||||
CLAY_FLEX_DIRECTION_COLUMN_REVERSE = 3,
|
||||
};
|
||||
|
||||
enum clay_flex_wrap_e {
|
||||
CLAY_FLEX_WRAP_NO_WRAP = 0,
|
||||
CLAY_FLEX_WRAP_WRAP = 1,
|
||||
CLAY_FLEX_WRAP_WRAP_REVERSE = 2,
|
||||
};
|
||||
|
||||
enum clay_flex_align_items_e {
|
||||
CLAY_FLEX_ALIGN_ITEMS_START = 0,
|
||||
CLAY_FLEX_ALIGN_ITEMS_END = 1,
|
||||
CLAY_FLEX_ALIGN_ITEMS_CENTER = 2,
|
||||
CLAY_FLEX_ALIGN_ITEMS_STRETCH = 3,
|
||||
};
|
||||
|
||||
enum clay_flex_align_content_e {
|
||||
CLAY_FLEX_ALIGN_CONTENT_START = 0,
|
||||
CLAY_FLEX_ALIGN_CONTENT_END = 1,
|
||||
CLAY_FLEX_ALIGN_CONTENT_CENTER = 2,
|
||||
CLAY_FLEX_ALIGN_CONTENT_STRETCH = 3,
|
||||
CLAY_FLEX_ALIGN_CONTENT_SPACE_BETWEEN = 4,
|
||||
CLAY_FLEX_ALIGN_CONTENT_SPACE_AROUND = 5,
|
||||
CLAY_FLEX_ALIGN_CONTENT_SPACE_EVENLY = 6,
|
||||
};
|
||||
|
||||
|
||||
clay clay_create_flex(clay_ctx);
|
||||
|
||||
void clay_flex_register_props(clay_ctx ctx); // todo: should be private
|
||||
|
||||
#endif //CLAYOUT_CLAY_FLEX_H
|
23
include/clay-properties.h
Normal file
23
include/clay-properties.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef CLAYOUT_CLAY_PROPERTIES_H
|
||||
#define CLAYOUT_CLAY_PROPERTIES_H
|
||||
|
||||
|
||||
#define CLAY_PROPERTY_TEXT 1
|
||||
#define CLAY_PROPERTY_BG_COLOR 2
|
||||
#define CLAY_PROPERTY_WIDTH 3
|
||||
#define CLAY_PROPERTY_FLEX_GROW 4
|
||||
#define CLAY_PROPERTY_FLEX_SHRINK 5
|
||||
#define CLAY_PROPERTY_TEXT_ALIGN 6
|
||||
#define CLAY_PROPERTY_TEXT_VERTICAL_ALIGN 7
|
||||
#define CLAY_PROPERTY_FLEX_DIRECTION 8
|
||||
#define CLAY_PROPERTY_FLEX_WRAP 9
|
||||
#define CLAY_PROPERTY_FLEX_ALIGN_ITEMS 10
|
||||
#define CLAY_PROPERTY_FLEX_ALIGN_CONTENT 11
|
||||
#define CLAY_PROPERTY_FLEX_GAP 12
|
||||
#define CLAY_PROPERTY_PADDING 13
|
||||
#define CLAY_PROPERTY_CONTENTS 14
|
||||
#define CLAY_PROPERTY_HEIGHT 15
|
||||
#define CLAY_PROPERTY_CONTENT 16
|
||||
|
||||
|
||||
#endif
|
20
include/clay-text.h
Normal file
20
include/clay-text.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef CLAYOUT_CLAY_TEXT_H
|
||||
#define CLAYOUT_CLAY_TEXT_H
|
||||
|
||||
enum clay_text_align_e {
|
||||
CLAY_TEXT_ALIGN_LEFT = 0,
|
||||
CLAY_TEXT_ALIGN_CENTER = 1,
|
||||
CLAY_TEXT_ALIGN_RIGHT = 2,
|
||||
};
|
||||
|
||||
enum clay_text_vertical_align_e {
|
||||
CLAY_TEXT_VERTICAL_ALIGN_TOP = 0,
|
||||
CLAY_TEXT_VERTICAL_ALIGN_MIDDLE = 1,
|
||||
CLAY_TEXT_VERTICAL_ALIGN_BOTTOM = 2,
|
||||
};
|
||||
|
||||
clay clay_create_text(clay_ctx);
|
||||
|
||||
void clay_text_register_props(clay_ctx ctx); // todo: should be private
|
||||
|
||||
#endif //CLAYOUT_CLAY_TEXT_H
|
20
include/clay.h
Normal file
20
include/clay.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef CLAYOUT_CLAY_H
|
||||
#define CLAYOUT_CLAY_H
|
||||
|
||||
|
||||
#include "clay-base.h"
|
||||
#include "clay-properties.h"
|
||||
#include "clay-flex.h"
|
||||
#include "clay-text.h"
|
||||
|
||||
|
||||
clay clay_create_document(clay_ctx);
|
||||
|
||||
void clay_render_to_png(clay, const char *);
|
||||
|
||||
void clay_debug_layout(clay doc);
|
||||
|
||||
void clay_document_register_props(clay_ctx ctx); // todo: should be private
|
||||
|
||||
|
||||
#endif //CLAYOUT_CLAY_H
|
7
src/clay-base.c
Normal file
7
src/clay-base.c
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "clay-base.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
|
10
src/clay-color.c
Normal file
10
src/clay-color.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
//
|
||||
// Created by gwendolyn on 2/2/23.
|
||||
//
|
||||
|
||||
#include "clay-color.h"
|
||||
|
||||
clay_color clay_color_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
clay_color color = {.r = r, .g = g, .b = b, .a = a};
|
||||
return color;
|
||||
}
|
15
src/clay-color.h
Normal file
15
src/clay-color.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef CLAY_CLAY_COLOR_H
|
||||
#define CLAY_CLAY_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
} clay_color;
|
||||
|
||||
clay_color clay_color_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
|
||||
#endif //CLAY_CLAY_COLOR_H
|
125
src/clay-context.c
Normal file
125
src/clay-context.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
#include <clay.h>
|
||||
#include <stddef.h>
|
||||
#include <malloc.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "clay-layout.h"
|
||||
|
||||
#include "clay-context.h"
|
||||
|
||||
// todo: thread safety? maybe as an option CLAY_ENABLE_THREADSAFE
|
||||
|
||||
struct clay_ctx_t {
|
||||
clay *layouts_ptrs;
|
||||
size_t layouts_length;
|
||||
size_t layouts_size;
|
||||
clay_property_desc_s *property_descs;
|
||||
size_t property_descs_length;
|
||||
size_t property_descs_size;
|
||||
int property_tag_cnt;
|
||||
};
|
||||
|
||||
|
||||
clay_ctx clay_create_context(void) {
|
||||
clay_ctx ctx = malloc(sizeof *ctx);
|
||||
assert(ctx != NULL);
|
||||
ctx->layouts_size = 16;
|
||||
ctx->layouts_length = 0;
|
||||
ctx->layouts_ptrs = malloc(sizeof(*ctx->layouts_ptrs) * ctx->layouts_size);
|
||||
assert(ctx->layouts_ptrs != NULL);
|
||||
ctx->property_tag_cnt = 0;
|
||||
ctx->property_descs_size = 16;
|
||||
ctx->property_descs_length = 0;
|
||||
ctx->property_descs = malloc(sizeof(*ctx->property_descs) * ctx->property_descs_size);
|
||||
assert(ctx->property_descs != NULL);
|
||||
|
||||
|
||||
clay_text_register_props(ctx);
|
||||
clay_flex_register_props(ctx);
|
||||
clay_document_register_props(ctx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void clay_destroy_context(clay_ctx ctx) {
|
||||
// TODO: free everything owned by ctx
|
||||
for (size_t i = 0; i < ctx->layouts_length; ++i) {
|
||||
clay layout = ctx->layouts_ptrs[i];
|
||||
clay_cleanup_layout(layout);
|
||||
free(layout);
|
||||
}
|
||||
free(ctx->layouts_ptrs);
|
||||
free(ctx->property_descs);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
|
||||
void clay_ctx_register_layout(clay_ctx ctx, clay layout) {
|
||||
assert(ctx->layouts_length <= ctx->layouts_size);
|
||||
if (ctx->layouts_length == ctx->layouts_size) {
|
||||
size_t new_size = ctx->layouts_size * 2;
|
||||
ctx->layouts_ptrs = realloc(ctx->layouts_ptrs, sizeof(*ctx->layouts_ptrs) * new_size);
|
||||
assert(ctx->layouts_ptrs != NULL);
|
||||
ctx->layouts_size = new_size;
|
||||
}
|
||||
ctx->layouts_length += 1;
|
||||
ctx->layouts_ptrs[ctx->layouts_length - 1] = layout;
|
||||
}
|
||||
|
||||
void clay_ctx_unregister_layout(clay_ctx ctx, clay layout) {
|
||||
for (size_t i = 0; i < ctx->layouts_length; ++i) {
|
||||
if (ctx->layouts_ptrs[i] == layout) {
|
||||
ctx->layouts_ptrs[i] = ctx->layouts_ptrs[ctx->layouts_length - 1];
|
||||
ctx->layouts_length -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int clay_ctx_register_property(clay_ctx ctx, const char *name, clay_property_type type) {
|
||||
assert (!clay_ctx_has_property(ctx, name));
|
||||
int tag = ++ctx->property_tag_cnt;
|
||||
assert(ctx->property_descs_length <= ctx->property_descs_size);
|
||||
if (ctx->property_descs_length == ctx->property_descs_size) {
|
||||
size_t new_size = ctx->property_descs_size * 2;
|
||||
ctx->property_descs = realloc(ctx->property_descs, sizeof(*ctx->property_descs) * new_size);
|
||||
assert(ctx->property_descs != NULL);
|
||||
ctx->property_descs_size = new_size;
|
||||
}
|
||||
ctx->property_descs_length += 1;
|
||||
ctx->property_descs[ctx->property_descs_length - 1] = (clay_property_desc_s) {
|
||||
.type = type,
|
||||
.tag = tag,
|
||||
.name = name
|
||||
};
|
||||
return tag;
|
||||
}
|
||||
|
||||
void clay_ctx_unregister_property(clay_ctx ctx, int tag) {
|
||||
for (size_t i = 0; i < ctx->property_descs_length; ++i) {
|
||||
if (ctx->property_descs[i].tag == tag) {
|
||||
ctx->property_descs[i] = ctx->property_descs[ctx->property_descs_length - 1];
|
||||
ctx->property_descs_length -= 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool clay_ctx_has_property(clay_ctx ctx, const char *name) {
|
||||
for (size_t i = 0; i < ctx->property_descs_length; ++i) {
|
||||
if (strcmp(ctx->property_descs[i].name, name) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
clay_property_desc clay_ctx_get_property_desc(clay_ctx ctx, const char *name) {
|
||||
for (size_t i = 0; i < ctx->property_descs_length; ++i) {
|
||||
if (strcmp(ctx->property_descs[i].name, name) == 0) {
|
||||
return &ctx->property_descs[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
23
src/clay-context.h
Normal file
23
src/clay-context.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef CLAY_CLAY_CONTEXT_H
|
||||
#define CLAY_CLAY_CONTEXT_H
|
||||
|
||||
#include "clay-property.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
const char * name;
|
||||
int tag;
|
||||
clay_property_type type;
|
||||
} clay_property_desc_s, *clay_property_desc;
|
||||
// TODO: properties should not keep track of the type and allow any type, or something?
|
||||
|
||||
|
||||
void clay_ctx_register_layout(clay_ctx ctx, clay layout);
|
||||
void clay_ctx_unregister_layout(clay_ctx ctx, clay layout);
|
||||
|
||||
int clay_ctx_register_property(clay_ctx ctx, const char * name, clay_property_type type);
|
||||
void clay_ctx_unregister_property(clay_ctx ctx, int tag);
|
||||
bool clay_ctx_has_property(clay_ctx ctx, const char *name);
|
||||
clay_property_desc clay_ctx_get_property_desc(clay_ctx ctx, const char * name);
|
||||
|
||||
#endif //CLAY_CLAY_CONTEXT_H
|
70
src/clay-document.c
Normal file
70
src/clay-document.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "clay.h"
|
||||
#include "clay-layout.h"
|
||||
#include "clay-context.h"
|
||||
#include "clay-color.h"
|
||||
|
||||
static void cleanup_document(clay layout);
|
||||
|
||||
static void init_document(clay layout);
|
||||
|
||||
static void debug_document(clay layout);
|
||||
|
||||
static struct layout_class layout_class_document = {
|
||||
.init = &init_document,
|
||||
.cleanup = &cleanup_document,
|
||||
.debug = &debug_document,
|
||||
};
|
||||
|
||||
static void init_document(clay layout) {
|
||||
// todo: anything?
|
||||
}
|
||||
|
||||
static void cleanup_document(clay layout) {
|
||||
// todo: anything?
|
||||
}
|
||||
|
||||
static void debug_document(clay layout) {
|
||||
printf("document:\n");
|
||||
clay_property_value width_prop = clay_get_prop(layout, "width");
|
||||
clay_property_value height_prop = clay_get_prop(layout, "height");
|
||||
clay_property_value content_prop = clay_get_prop(layout, "content");
|
||||
clay_property_value bgcolor_prop = clay_get_prop(layout, "bg-color");
|
||||
|
||||
if (width_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" width: %d\n", width_prop->int_val);
|
||||
}
|
||||
if (height_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" height: %d\n", height_prop->int_val);
|
||||
}
|
||||
if (bgcolor_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
clay_color *color = (clay_color*)bgcolor_prop->pointer_val;
|
||||
printf(" bg-color: (%d, %d, %d, %d)\n", color->r, color->g, color->b, color->a);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (content_prop->type == CLAY_PROPERTY_POINTER && content_prop->pointer_val != NULL) {
|
||||
clay content = (clay) content_prop->pointer_val;
|
||||
content->class.debug(content);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
clay clay_create_document(clay_ctx ctx) {
|
||||
return clay_create_layout(ctx, layout_class_document);
|
||||
}
|
||||
|
||||
void clay_render_to_png(clay doc, const char *path) {
|
||||
// todo
|
||||
}
|
||||
void clay_debug_layout(clay doc) {
|
||||
doc->class.debug(doc);
|
||||
}
|
||||
|
||||
|
||||
void clay_document_register_props(clay_ctx ctx) {
|
||||
clay_ctx_register_property(ctx, "width", CLAY_PROPERTY_INT);
|
||||
clay_ctx_register_property(ctx, "height", CLAY_PROPERTY_INT);
|
||||
clay_ctx_register_property(ctx, "content", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "bg-color", CLAY_PROPERTY_POINTER);
|
||||
}
|
82
src/clay-flex.c
Normal file
82
src/clay-flex.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "clay.h"
|
||||
#include "clay-layout.h"
|
||||
#include "clay-context.h"
|
||||
|
||||
static void cleanup_flex(clay layout);
|
||||
|
||||
static void init_flex(clay layout);
|
||||
|
||||
static void debug_flex(clay layout);
|
||||
|
||||
static struct layout_class layout_class_flex = {
|
||||
.init = &init_flex,
|
||||
.cleanup = &cleanup_flex,
|
||||
.debug = &debug_flex,
|
||||
};
|
||||
|
||||
static void init_flex(clay layout) {
|
||||
// todo: anything?
|
||||
}
|
||||
|
||||
static void cleanup_flex(clay layout) {
|
||||
// todo: anything?
|
||||
}
|
||||
|
||||
static void debug_flex(clay layout) {
|
||||
printf("flex:\n");
|
||||
clay_property_value direction_prop = clay_get_prop(layout, "direction");
|
||||
clay_property_value wrap_prop = clay_get_prop(layout, "wrap");
|
||||
clay_property_value align_items_prop = clay_get_prop(layout, "align-items");
|
||||
clay_property_value align_content_prop = clay_get_prop(layout, "align-content");
|
||||
clay_property_value gap_prop = clay_get_prop(layout, "gap");
|
||||
clay_property_value padding_prop = clay_get_prop(layout, "padding");
|
||||
clay_property_value contents_prop = clay_get_prop(layout, "contents");
|
||||
|
||||
if (direction_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" direction: %s\n", (char*)direction_prop->pointer_val);
|
||||
}
|
||||
if (wrap_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" wrap: %s\n", (char*)wrap_prop->pointer_val);
|
||||
}
|
||||
if (align_items_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" align-items: %s\n", (char*)align_items_prop->pointer_val);
|
||||
}
|
||||
if (align_content_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" align-content: %s\n", (char*)align_content_prop->pointer_val);
|
||||
}
|
||||
if (gap_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" gap: %d\n", gap_prop->int_val);
|
||||
}
|
||||
if (padding_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" padding: %d\n", padding_prop->int_val);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (contents_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
clay* ptr = (clay*)contents_prop->pointer_val;
|
||||
while(*ptr != NULL) {
|
||||
clay content = *ptr;
|
||||
content->class.debug(content);
|
||||
ptr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
clay clay_create_flex(clay_ctx ctx) {
|
||||
return clay_create_layout(ctx, layout_class_flex);
|
||||
}
|
||||
|
||||
|
||||
void clay_flex_register_props(clay_ctx ctx) {
|
||||
clay_ctx_register_property(ctx, "direction", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "wrap", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "align-items", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "align-content", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "gap", CLAY_PROPERTY_INT);
|
||||
clay_ctx_register_property(ctx, "padding", CLAY_PROPERTY_INT);
|
||||
clay_ctx_register_property(ctx, "contents", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "flex:grow", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "flex:shrink", CLAY_PROPERTY_POINTER);
|
||||
}
|
78
src/clay-layout.c
Normal file
78
src/clay-layout.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <malloc.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include "clay-layout.h"
|
||||
#include "clay-context.h"
|
||||
#include "clay-property.h"
|
||||
|
||||
|
||||
clay clay_create_layout(clay_ctx ctx, struct layout_class class) {
|
||||
clay layout = malloc(sizeof(*layout));
|
||||
assert(layout != NULL);
|
||||
layout->properties = clay_propset_create();
|
||||
layout->class = class;
|
||||
layout->ctx = ctx;
|
||||
if (layout->class.init != NULL) {
|
||||
layout->class.init(layout);
|
||||
}
|
||||
clay_ctx_register_layout(ctx, layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
void clay_destroy_layout(clay layout) {
|
||||
clay_ctx_unregister_layout(layout->ctx, layout);
|
||||
clay_cleanup_layout(layout);
|
||||
free(layout);
|
||||
}
|
||||
|
||||
void clay_cleanup_layout(clay layout) {
|
||||
if (layout->class.cleanup != NULL) {
|
||||
layout->class.cleanup(layout);
|
||||
}
|
||||
clay_propset_destroy(layout->properties);
|
||||
}
|
||||
|
||||
clay clay_clone(clay layout) {
|
||||
clay cloned = malloc(sizeof(*cloned));
|
||||
cloned->class = layout->class;
|
||||
cloned->ctx = layout->ctx;
|
||||
cloned->properties = clay_propset_clone(layout->properties);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
clay_property_value clay_get_prop(clay layout, const char *prop) {
|
||||
clay_ctx ctx = layout->ctx;
|
||||
clay_property_desc desc = clay_ctx_get_property_desc(ctx, prop);
|
||||
assert(desc != NULL);
|
||||
assert(desc->type != CLAY_PROPERTY_NOT_SET);
|
||||
return clay_property_get_by_tag(layout->properties, desc->tag);
|
||||
}
|
||||
|
||||
void clay_set(clay layout, const char *prop, ...) {
|
||||
// TODO: use a macro so that a property can have values of different types
|
||||
// the property registry should not keep the type then
|
||||
// also the property registry can have some kind of alias mechanism for translating strings to enums or something
|
||||
clay_ctx ctx = layout->ctx;
|
||||
clay_property_desc desc = clay_ctx_get_property_desc(ctx, prop);
|
||||
assert(desc != NULL);
|
||||
assert(desc->type != CLAY_PROPERTY_NOT_SET);
|
||||
struct clay_property_value value;
|
||||
value.type = desc->type;
|
||||
va_list args;
|
||||
va_start(args, prop);
|
||||
switch (desc->type) {
|
||||
case CLAY_PROPERTY_NOT_SET:
|
||||
break;
|
||||
case CLAY_PROPERTY_INT:
|
||||
value.int_val = va_arg(args, int);
|
||||
break;
|
||||
case CLAY_PROPERTY_FLOAT:
|
||||
value.float_val = va_arg(args, double);
|
||||
break;
|
||||
case CLAY_PROPERTY_POINTER:
|
||||
value.pointer_val = va_arg(args, void*);
|
||||
break;
|
||||
}
|
||||
va_end(args);
|
||||
clay_property_set_by_tag(layout->properties, desc->tag, value);
|
||||
}
|
33
src/clay-layout.h
Normal file
33
src/clay-layout.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef CLAY_CLAY_LAYOUT_H
|
||||
#define CLAY_CLAY_LAYOUT_H
|
||||
|
||||
#include "clay.h"
|
||||
#include "clay-property.h"
|
||||
|
||||
typedef void (*init_fn)(clay);
|
||||
|
||||
typedef void (*cleanup_fn)(clay);
|
||||
typedef void (*debug_fn)(clay);
|
||||
|
||||
|
||||
struct layout_class {
|
||||
init_fn init;
|
||||
cleanup_fn cleanup;
|
||||
debug_fn debug;
|
||||
};
|
||||
|
||||
struct clay_t {
|
||||
struct layout_class class;
|
||||
clay_property_set properties;
|
||||
clay_ctx ctx;
|
||||
};
|
||||
|
||||
clay clay_create_layout(clay_ctx ctx, struct layout_class class);
|
||||
|
||||
void clay_destroy_layout(clay layout);
|
||||
|
||||
void clay_cleanup_layout(clay layout);
|
||||
|
||||
clay_property_value clay_get_prop(clay layout, const char *prop);
|
||||
|
||||
#endif //CLAY_CLAY_LAYOUT_H
|
87
src/clay-property.c
Normal file
87
src/clay-property.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include <string.h>
|
||||
#include "clay-property.h"
|
||||
|
||||
|
||||
struct clay_property {
|
||||
int tag;
|
||||
struct clay_property_value value;
|
||||
};
|
||||
|
||||
struct clay_property_set_t {
|
||||
struct clay_property *props;
|
||||
size_t length;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static struct clay_property_value empty_property_value = {
|
||||
.type = CLAY_PROPERTY_NOT_SET,
|
||||
};
|
||||
|
||||
|
||||
clay_property_set clay_propset_create(void) {
|
||||
clay_property_set propset = malloc(sizeof(*propset));
|
||||
assert(propset != NULL);
|
||||
propset->length = 0;
|
||||
propset->size = 16;
|
||||
propset->props = malloc(sizeof(*propset->props) * 16);
|
||||
assert(propset->props != NULL);
|
||||
return propset;
|
||||
}
|
||||
|
||||
clay_property_set clay_propset_clone(clay_property_set propset) {
|
||||
clay_property_set cloned = malloc(sizeof(*cloned));
|
||||
assert(propset != NULL);
|
||||
cloned->length = propset->length;
|
||||
cloned->size = propset->size;
|
||||
cloned->props = malloc(sizeof(*cloned->props) * cloned->size);
|
||||
memcpy(cloned->props, propset->props, sizeof(*cloned->props) * cloned->size);
|
||||
return cloned;
|
||||
}
|
||||
|
||||
void clay_propset_destroy(clay_property_set propset) {
|
||||
free(propset->props);
|
||||
free(propset);
|
||||
}
|
||||
|
||||
|
||||
clay_property_value clay_property_get_by_tag(clay_property_set propset, int tag) {
|
||||
for (size_t i = 0; i < propset->length; ++i) {
|
||||
struct clay_property *prop = &propset->props[i];
|
||||
if (prop->tag == tag) {
|
||||
return &prop->value;
|
||||
}
|
||||
}
|
||||
return &empty_property_value;
|
||||
}
|
||||
|
||||
void clay_property_set_by_tag(clay_property_set propset, int tag, struct clay_property_value value) {
|
||||
struct clay_property *prop = NULL;
|
||||
for (size_t i = 0; i < propset->length; ++i) {
|
||||
if (propset->props[i].tag == tag) {
|
||||
prop = &propset->props[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prop == NULL) {
|
||||
assert(propset->length <= propset->size);
|
||||
if (propset->length == propset->size) {
|
||||
size_t new_size = propset->size * 2;
|
||||
propset->props = realloc(propset->props, sizeof(*propset->props) * new_size);
|
||||
assert(propset->props != NULL);
|
||||
propset->size = new_size;
|
||||
}
|
||||
propset->length += 1;
|
||||
prop = &propset->props[propset->length - 1];
|
||||
}
|
||||
prop->tag = tag;
|
||||
prop->value = value;
|
||||
}
|
||||
|
||||
void clay_property_delete_by_tag(clay_property_set propset, int tag) {
|
||||
for (size_t i = 0; i < propset->length; ++i) {
|
||||
struct clay_property *prop = &propset->props[i];
|
||||
if (prop->tag == tag) {
|
||||
prop->value = empty_property_value;
|
||||
}
|
||||
}
|
||||
}
|
41
src/clay-property.h
Normal file
41
src/clay-property.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef CLAY_CLAY_PROPERTY_H
|
||||
#define CLAY_CLAY_PROPERTY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
|
||||
|
||||
typedef enum {
|
||||
CLAY_PROPERTY_NOT_SET,
|
||||
CLAY_PROPERTY_INT,
|
||||
CLAY_PROPERTY_FLOAT,
|
||||
CLAY_PROPERTY_POINTER,
|
||||
} clay_property_type;
|
||||
|
||||
struct clay_property_value {
|
||||
clay_property_type type;
|
||||
union {
|
||||
int int_val;
|
||||
double float_val;
|
||||
void *pointer_val;
|
||||
};
|
||||
};
|
||||
|
||||
typedef const struct clay_property_value *clay_property_value;
|
||||
|
||||
typedef struct clay_property_set_t *clay_property_set;
|
||||
|
||||
|
||||
clay_property_set clay_propset_create(void);
|
||||
clay_property_set clay_propset_clone(clay_property_set);
|
||||
void clay_propset_destroy(clay_property_set propset);
|
||||
|
||||
clay_property_value clay_property_get_by_tag(clay_property_set propset, int tag);
|
||||
|
||||
void clay_property_set_by_tag(clay_property_set propset, int tag, struct clay_property_value value);
|
||||
|
||||
void clay_property_delete_by_tag(clay_property_set propset, int tag);
|
||||
|
||||
|
||||
#endif //CLAY_CLAY_PROPERTY_H
|
67
src/clay-text.c
Normal file
67
src/clay-text.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "clay.h"
|
||||
#include "clay-layout.h"
|
||||
#include "clay-context.h"
|
||||
#include "clay-color.h"
|
||||
|
||||
static void cleanup_text(clay layout);
|
||||
|
||||
static void init_text(clay layout);
|
||||
static void debug_text(clay layout);
|
||||
|
||||
static struct layout_class layout_class_text = {
|
||||
.cleanup = &cleanup_text,
|
||||
.init = &init_text,
|
||||
.debug = &debug_text,
|
||||
};
|
||||
|
||||
static void init_text(clay layout) {
|
||||
// todo: anything?
|
||||
}
|
||||
|
||||
static void cleanup_text(clay layout) {
|
||||
// todo: anything?
|
||||
}
|
||||
|
||||
static void debug_text(clay layout) {
|
||||
printf("text:\n");
|
||||
clay_property_value content_prop = clay_get_prop(layout, "content");
|
||||
clay_property_value bgcolor_prop = clay_get_prop(layout, "bg-color");
|
||||
clay_property_value width_prop = clay_get_prop(layout, "width");
|
||||
clay_property_value flex_grow_prop = clay_get_prop(layout, "flex:grow");
|
||||
clay_property_value flex_shrink_prop = clay_get_prop(layout, "flex:shrink");
|
||||
clay_property_value align_prop = clay_get_prop(layout, "align");
|
||||
clay_property_value vertical_align_prop = clay_get_prop(layout, "vertical-align");
|
||||
|
||||
if (content_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" content: %s\n", (char*)content_prop->pointer_val);
|
||||
}
|
||||
if (bgcolor_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
clay_color *color = (clay_color*)bgcolor_prop->pointer_val;
|
||||
printf(" bg-color: (%d, %d, %d, %d)\n", color->r, color->g, color->b, color->a);
|
||||
}
|
||||
if (width_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" width: %d\n", width_prop->int_val);
|
||||
}
|
||||
if (flex_grow_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" flex-grow: %d\n", flex_grow_prop->int_val);
|
||||
}
|
||||
if (flex_shrink_prop->type == CLAY_PROPERTY_INT) {
|
||||
printf(" flex-shrink: %d\n", flex_shrink_prop->int_val);
|
||||
}
|
||||
if (align_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" align: %s\n", (char*)align_prop->pointer_val);
|
||||
}
|
||||
if (vertical_align_prop->type == CLAY_PROPERTY_POINTER) {
|
||||
printf(" vertical-align: %s\n", (char*)vertical_align_prop->pointer_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
clay clay_create_text(clay_ctx ctx) {
|
||||
return clay_create_layout(ctx, layout_class_text);
|
||||
}
|
||||
|
||||
void clay_text_register_props(clay_ctx ctx) {
|
||||
clay_ctx_register_property(ctx, "align", CLAY_PROPERTY_POINTER);
|
||||
clay_ctx_register_property(ctx, "vertical-align", CLAY_PROPERTY_POINTER);
|
||||
}
|
20
src/clay.c
Normal file
20
src/clay.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "clay.h"
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void hello(void) {
|
||||
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 240, 80);
|
||||
cairo_t *cr = cairo_create (surface);
|
||||
|
||||
cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_font_size (cr, 10.0);
|
||||
cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
|
||||
cairo_move_to (cr, 10.0, 50.0);
|
||||
cairo_show_text (cr, "Hello, world");
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_write_to_png (surface, "hello.png");
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
65
src/demo.c
Normal file
65
src/demo.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <stddef.h>
|
||||
#include "clay.h"
|
||||
#include "clay-color.h"
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
clay_ctx ctx = clay_create_context();
|
||||
|
||||
clay_color c1 = clay_color_rgba(4, 231, 98, 128);
|
||||
clay_color c2 = clay_color_rgba(34, 49, 39, 128);
|
||||
clay_color c3 = clay_color_rgba(220, 0, 115, 128);
|
||||
clay_color c4 = clay_color_rgba(0, 139, 248, 128);
|
||||
clay_color c5 = clay_color_rgba(71, 0, 99, 128);
|
||||
clay_color cbg = clay_color_rgba(206, 249, 242, 255);
|
||||
|
||||
clay t1 = clay_create_text(ctx);
|
||||
clay_set(t1, "content", "ITEM 1");
|
||||
clay_set(t1, "bg-color", &c1);
|
||||
clay_set(t1, "width", 100);
|
||||
clay_set(t1, "flex:grow", 1);
|
||||
clay_set(t1, "flex:shrink", 1);
|
||||
clay_set(t1, "align", "center");
|
||||
clay_set(t1, "vertical-align", "middle");
|
||||
|
||||
clay t2 = clay_clone(t1);
|
||||
|
||||
clay_set(t2, "content", "ITEM 2");
|
||||
clay_set(t2, "bg-color", &c2);
|
||||
clay_set(t2, "width", 300);
|
||||
|
||||
clay t3 = clay_clone(t1);
|
||||
clay_set(t3, "content", "ITEM 3");
|
||||
clay_set(t3, "bg-color", &c3);
|
||||
clay_set(t3, "width", 200);
|
||||
|
||||
clay t4 = clay_clone(t1);
|
||||
clay_set(t4, "content", "ITEM 4");
|
||||
clay_set(t4, "bg-color", &c4);
|
||||
clay_set(t4, "width", 400);
|
||||
|
||||
clay t5 = clay_clone(t1);
|
||||
clay_set(t5, "content", "ITEM 5");
|
||||
clay_set(t5, "bg-color", &c5);
|
||||
clay_set(t5, "width", 250);
|
||||
|
||||
|
||||
clay flex = clay_create_flex(ctx);
|
||||
clay_set(flex, "direction", "row");
|
||||
clay_set(flex, "wrap", "wrap");
|
||||
clay_set(flex, "align-items", "stretch");
|
||||
clay_set(flex, "align-content", "stretch");
|
||||
clay_set(flex, "gap", 20);
|
||||
clay_set(flex, "padding", 20);
|
||||
clay_set(flex, "contents", (clay[]) {t1, t2, t3, t4, t5, NULL});
|
||||
|
||||
clay doc = clay_create_document(ctx);
|
||||
clay_set(doc, "width", 800);
|
||||
clay_set(doc, "height", 400);
|
||||
clay_set(doc, "bg-color", &cbg);
|
||||
clay_set(doc, "content", flex);
|
||||
|
||||
clay_debug_layout(doc);
|
||||
|
||||
clay_destroy_context(ctx);
|
||||
}
|
Loading…
Reference in a new issue