diff --git a/demos/draw.c b/demos/draw.c index bacaa29..048e397 100644 --- a/demos/draw.c +++ b/demos/draw.c @@ -5,12 +5,17 @@ #define RAD(deg) ((deg) * ((float)M_PI / 180.0f)) +#define FONT_SIZE 80.0f + struct demo_application { struct gral_application *application; }; struct demo_window { struct gral_window *window; + struct gral_text *text; + float ascent; + float descent; }; static void destroy(void *user_data) { @@ -81,22 +86,57 @@ static void add_star(struct gral_draw_context *draw_context, float x, float y, f gral_draw_context_close_path(draw_context); } -static void draw(struct gral_draw_context *draw_context, int x, int y, int width, int height, void *user_data) { - add_rectangle(draw_context, 20.0f, 20.0f, 160.0f, 160.0f); - gral_draw_context_fill(draw_context, 0.9f, 0.1f, 0.1f, 1.0f); - add_rectangle(draw_context, 220.0f, 20.0f, 160.0f, 160.0f); - gral_draw_context_stroke(draw_context, 4.0f, 0.1f, 0.1f, 0.9f, 1.0f); - add_rectangle(draw_context, 420.0f, 20.0f, 160.0f, 160.0f); - struct gral_gradient_stop stops[] = { - {0.0f, 0.9f, 0.1f, 0.1f, 1.0f}, - {0.3f, 0.9f, 0.9f, 0.1f, 1.0f}, - {1.0f, 0.1f, 0.9f, 0.1f, 1.0f} - }; - gral_draw_context_fill_linear_gradient(draw_context, 420.0f, 20.0f, 580.0f, 100.0f, stops, 3); +static void add_shapes(struct gral_draw_context *draw_context) { add_circle(draw_context, 20.0f, 220.0f, 160.0f); add_rounded_rectangle(draw_context, 220.0f, 220.0f, 160.0f, 160.0f, 20.0f); add_star(draw_context, 420.0f, 220.0f, 160.0f); - gral_draw_context_fill(draw_context, 0.1f, 0.1f, 0.9f, 1.0f); +} + +static void draw(struct gral_draw_context *draw_context, int x, int y, int width, int height, void *user_data) { + struct demo_window *window = user_data; + float text_width = gral_text_get_width(window->text, draw_context); + float text_height = window->ascent + window->descent; + float text_x = (600.0f - text_width) / 2.0f; + float text_y = (200.0f - text_height) / 2.0f + window->ascent; + + // background + add_rectangle(draw_context, 0.0f, 0.0f, width, height); + gral_draw_context_fill(draw_context, 0.2f, 0.2f, 0.2f, 1.0f); + + // grid + add_rectangle(draw_context, 0.0f, roundf(text_y), 600.0f, 1.0f); + add_rectangle(draw_context, 0.0f, roundf(text_y - window->ascent), 600.0f, 1.0f); + add_rectangle(draw_context, 0.0f, roundf(text_y + window->descent), 600.0f, 1.0f); + int i; + for (i = 0; i <= 7; i++) { + float x = gral_text_index_to_x(window->text, i); + add_rectangle(draw_context, roundf(text_x + x), 0.f, 1.0f, 200.0f); + } + static struct gral_gradient_stop const grid_stops[] = { + {0.0f, 0.4f, 0.4f, 0.4f, 1.0f}, + {1.0f, 0.2f, 0.2f, 0.2f, 1.0f} + }; + gral_draw_context_fill_linear_gradient(draw_context, 0.0f, 0.0f, 0.0f, 200.0f, grid_stops, 2); + + // text and shapes + gral_draw_context_add_text(draw_context, window->text, roundf(text_x), roundf(text_y)); + add_shapes(draw_context); + static struct gral_gradient_stop const fill_stops[] = { + {0.00f, 0.7f, 0.7f, 0.0f, 1.0f}, // yellow + {0.35f, 0.7f, 0.4f, 0.0f, 1.0f}, // orange + {0.65f, 0.7f, 0.0f, 0.0f, 1.0f}, // red + {1.00f, 0.7f, 0.0f, 0.4f, 1.0f} // purple + }; + gral_draw_context_fill_linear_gradient(draw_context, 20.0f, 0.0f, 580.0f, 0.0f, fill_stops, 4); + gral_draw_context_add_text(draw_context, window->text, roundf(text_x), roundf(text_y)); + add_shapes(draw_context); + static struct gral_gradient_stop const stroke_stops[] = { + {0.00f, 1.0f, 1.0f, 0.0f, 1.0f}, // yellow + {0.35f, 1.0f, 0.5f, 0.0f, 1.0f}, // orange + {0.65f, 1.0f, 0.0f, 0.0f, 1.0f}, // red + {1.00f, 1.0f, 0.0f, 0.5f, 1.0f} // purple + }; + gral_draw_context_stroke_linear_gradient(draw_context, 2.0f, 20.0f, 0.0f, 580.0f, 0.0f, stroke_stops, 4); } static void resize(int width, int height, void *user_data) { @@ -178,6 +218,10 @@ static void create_window(void *user_data) { &focus_leave }; window->window = gral_window_create(application->application, 600, 400, "gral draw demo", &window_interface, window); + struct gral_font *font = gral_font_create_default(window->window, FONT_SIZE); + window->text = gral_text_create(window->window, "libgral", font); + gral_font_get_metrics(window->window, font, &window->ascent, &window->descent); + gral_font_delete(font); gral_window_set_minimum_size(window->window, 600, 400); gral_window_show(window->window); } diff --git a/gral.h b/gral.h index 5a00574..fe7c586 100644 --- a/gral.h +++ b/gral.h @@ -139,6 +139,7 @@ int gral_text_x_to_index(struct gral_text *text, float x); void gral_draw_context_draw_image(struct gral_draw_context *draw_context, struct gral_image *image, float x, float y); void gral_draw_context_draw_text(struct gral_draw_context *draw_context, struct gral_text *text, float x, float y, float red, float green, float blue, float alpha); +void gral_draw_context_add_text(struct gral_draw_context *draw_context, struct gral_text *text, float x, float y); void gral_draw_context_close_path(struct gral_draw_context *draw_context); void gral_draw_context_move_to(struct gral_draw_context *draw_context, float x, float y); void gral_draw_context_line_to(struct gral_draw_context *draw_context, float x, float y); diff --git a/gral_linux.c b/gral_linux.c index 00c1deb..6682d55 100644 --- a/gral_linux.c +++ b/gral_linux.c @@ -221,6 +221,12 @@ void gral_draw_context_draw_text(struct gral_draw_context *draw_context, struct pango_cairo_show_layout_line((cairo_t *)draw_context, line); } +void gral_draw_context_add_text(struct gral_draw_context *draw_context, struct gral_text *text, float x, float y) { + cairo_move_to((cairo_t *)draw_context, x, y); + PangoLayoutLine *line = pango_layout_get_line_readonly(PANGO_LAYOUT(text), 0); + pango_cairo_layout_line_path((cairo_t *)draw_context, line); +} + void gral_draw_context_close_path(struct gral_draw_context *draw_context) { cairo_close_path((cairo_t *)draw_context); } diff --git a/gral_macos.m b/gral_macos.m index 26e5b2c..a2a6b99 100644 --- a/gral_macos.m +++ b/gral_macos.m @@ -270,6 +270,30 @@ void gral_draw_context_draw_text(struct gral_draw_context *draw_context, struct CFRelease(line); } +void gral_draw_context_add_text(struct gral_draw_context *draw_context, struct gral_text *text, float x, float y) { + CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)text); + CGContextTranslateCTM((CGContextRef)draw_context, x, y); + CGContextSetTextMatrix((CGContextRef)draw_context, CGAffineTransformMakeScale(1.0f, -1.0f)); + CFArrayRef glyphRuns = CTLineGetGlyphRuns(line); + for (int i = 0; i < CFArrayGetCount(glyphRuns); i++) { + CTRunRef run = CFArrayGetValueAtIndex(glyphRuns, i); + CGPoint const *positions = CTRunGetPositionsPtr(run); + CGGlyph const *glyphs = CTRunGetGlyphsPtr(run); + int count = CTRunGetGlyphCount(run); + CFDictionaryRef attributes = CTRunGetAttributes(run); + CTFontRef font = CFDictionaryGetValue(attributes, kCTFontAttributeName); + for (int j = 0; j < count; j++) { + CGContextSetTextPosition((CGContextRef)draw_context, positions[j].x, positions[j].y); + CGAffineTransform matrix = CGContextGetTextMatrix((CGContextRef)draw_context); + CGPathRef path = CTFontCreatePathForGlyph(font, glyphs[j], &matrix); + CGContextAddPath((CGContextRef)draw_context, path); + CGPathRelease(path); + } + } + CGContextTranslateCTM((CGContextRef)draw_context, -x, -y); + CFRelease(line); +} + void gral_draw_context_close_path(struct gral_draw_context *draw_context) { CGContextClosePath((CGContextRef)draw_context); } diff --git a/gral_windows.cpp b/gral_windows.cpp index edbd4c4..e1cbaf5 100644 --- a/gral_windows.cpp +++ b/gral_windows.cpp @@ -797,6 +797,10 @@ void gral_draw_context_draw_text(gral_draw_context *draw_context, gral_text *tex text->layout->Draw(draw_context, renderer, x, y-line_metrics.baseline); } +void gral_draw_context_add_text(gral_draw_context *draw_context, gral_text *text, float x, float y) { + // TODO: implement +} + void gral_draw_context_close_path(gral_draw_context *draw_context) { draw_context->sink->EndFigure(D2D1_FIGURE_END_CLOSED); draw_context->open = false;