GFXprim
2D bitmap graphics library with emphasis on speed and correctness
Loading...
Searching...
No Matches
Functions
gp_widget_pixmap.h File Reference

A pixmap widget. More...

#include <widgets/gp_widget_size_units.h>

Go to the source code of this file.

Functions

gp_widgetgp_widget_pixmap_new (gp_widget_size min_w, gp_widget_size min_h, int(*on_event)(gp_widget_event *ev), void *priv)
 Create pixmap widget.
 
void gp_widget_pixmap_redraw (gp_widget *self, gp_coord x, gp_coord y, gp_size w, gp_size h)
 Requests partial update of the image.
 
static gp_size gp_widget_pixmap_w (gp_widget *self)
 Returns pixmap width in pixels.
 
static gp_size gp_widget_pixmap_h (gp_widget *self)
 Returns pixmap height in pixels.
 
void gp_widget_pixmap_redraw_all (gp_widget *self)
 Marks the whole pixmap to be repainted.
 

Detailed Description

A pixmap widget.

Pixmap repaint modes

The pixmap widget is allocated as an empty container and there are two different repaint strategies for pixmap widget.

Buffered mode

In this mode a pixmap of the size of the widget is allocated, by the application, before any drawing is done. The content of the pixmap is preserved i.e. not modified by the library.

The allocation is deffered for when the application has been started and the pixel format, we are using for drawing, is known. Only then the library will call the pixmap event handler with a resize event and gp_widget_render_ctx pointer, which could be used to allocate right backing gp_pixmap and set the pixmap pointer in the struct gp_widget_pixmap.

Note
The pixmap has to be resized properly on each resize event as well.
Attention
The GP_WIDGET_EVENT_RESIZE has to be unmasked by gp_widget_events_unmask() before the application starts.
//SPDX-License-Identifier: LGPL-2.0-or-later
/*
Copyright (c) 2014-2020 Cyril Hrubis <metan@ucw.cz>
*/
#include <gfxprim.h>
static gp_htable *uids;
static gp_pixel fg_rgb;
static gp_pixel bg_rgb;
static void draw(gp_widget *pixmap, gp_event *ev)
{
if (ev->type != GP_EV_KEY ||
(ev->key.key != GP_BTN_LEFT &&
ev->key.key != GP_BTN_TOUCH))
return;
gp_coord x = ev->st->cursor_x;
gp_coord y = ev->st->cursor_y;
gp_pixmap *p = pixmap->pixmap->pixmap;
gp_pixel col = gp_rgb_to_pixmap_pixel((fg_rgb >> 16) & 0xff, (fg_rgb >> 8) & 0xff, fg_rgb & 0xff, p);
gp_putpixel(p, x, y, col);
gp_circle(p, x, y, 10, col);
/* Request partiall update */
gp_widget_pixmap_redraw(pixmap, x - 10, y - 10, 20, 20);
}
static void fill_pixmap(gp_pixmap *p)
{
gp_pixel col = gp_rgb_to_pixmap_pixel((bg_rgb >> 16) & 0xff, (bg_rgb >> 8) & 0xff, bg_rgb & 0xff, p);
gp_fill(p, col);
}
static void allocate_backing_pixmap(gp_widget_event *ev)
{
gp_widget *w = ev->self;
gp_pixmap_free(w->pixmap->pixmap);
w->pixmap->pixmap = gp_pixmap_alloc(w->w, w->h, ev->ctx->pixel_type);
fill_pixmap(w->pixmap->pixmap);
}
int pixmap_on_event(gp_widget_event *ev)
{
switch (ev->type) {
draw(ev->self, ev->input_ev);
break;
allocate_backing_pixmap(ev);
break;
printf("Color scheme change!\n");
break;
default:
break;
}
return 0;
}
static void set_color(gp_pixel *col, const char *val, const char *name)
{
*col = strtol(val, NULL, 16);
printf("%s = 0x%x\n", name, *col);
}
int set_fg_color(gp_widget_event *ev)
{
switch (ev->type) {
ev->self->tbox->filter = GP_TBOX_FILTER_HEX;
set_color(&fg_rgb, gp_widget_tbox_text(ev->self), "fg_color");
break;
return 0;
set_color(&fg_rgb, gp_widget_tbox_text(ev->self), "fg_color");
break;
default:
break;
}
return 0;
}
int set_bg_color(gp_widget_event *ev)
{
gp_widget *pixmap;
switch (ev->type) {
ev->self->tbox->filter = GP_TBOX_FILTER_HEX;
set_color(&bg_rgb, gp_widget_tbox_text(ev->self), "bg_color");
break;
switch (ev->sub_type) {
set_color(&bg_rgb, gp_widget_tbox_text(ev->self), "bg_color");
break;
pixmap = gp_widget_by_uid(uids, "pixmap", GP_WIDGET_PIXMAP);
if (pixmap) {
fill_pixmap(pixmap->pixmap->pixmap);
}
break;
}
break;
default:
break;
}
return 0;
}
int button_on_event(gp_widget_event *ev)
{
return 0;
gp_widget *pixmap = gp_widget_by_uid(uids, "pixmap", GP_WIDGET_PIXMAP);
(void)ev;
if (pixmap) {
fill_pixmap(pixmap->pixmap->pixmap);
}
return 0;
}
int main(int argc, char *argv[])
{
gp_widget *layout = gp_widget_layout_json("pixmap_example.json", NULL, &uids);
if (!layout)
return 0;
gp_widget *pixmap = gp_widget_by_uid(uids, "pixmap", GP_WIDGET_PIXMAP);
gp_widgets_main_loop(layout, NULL, argc, argv);
return 0;
}
uint32_t gp_pixel
Pixel integer value.
Definition gp_types.h:33
int gp_coord
Integer type for coordinates i.e. x, y, ...
Definition gp_types.h:19
void gp_ev_dump(gp_event *ev)
Dumps event into a stdout.
@ GP_EV_KEY
A key or button press event.
Definition gp_event.h:27
@ GP_BTN_TOUCH
A touch screen touched event.
@ GP_BTN_LEFT
Left Mouse Button.
@ GP_WIDGET_PIXMAP
A pixmap widget.
Definition gp_widget.h:223
void gp_widget_events_unmask(gp_widget *self, enum gp_widget_event_type evs)
Unmasks widget event.
@ GP_WIDGET_EVENT_INPUT
An input event.
@ GP_WIDGET_EVENT_WIDGET
Widget specific event.
@ GP_WIDGET_EVENT_COLOR_SCHEME
A color scheme has changed.
@ GP_WIDGET_EVENT_NEW
Widget was created and initialized.
@ GP_WIDGET_EVENT_RESIZE
Widget was resized.
void gp_widget_event_dump(gp_widget_event *ev)
Prints event details into stdout.
gp_widget * gp_widget_layout_json(const char *fname, const gp_widget_json_callbacks *const callbacks, gp_htable **uids)
Loads a widget layout given a path to a JSON layout description.
void gp_widget_redraw(gp_widget *self)
Requests widget repaint.
void gp_widget_pixmap_redraw(gp_widget *self, gp_coord x, gp_coord y, gp_size w, gp_size h)
Requests partial update of the image.
void gp_widgets_main_loop(struct gp_widget *layout, void(*init)(int argc, char *argv[]), int argc, char *argv[]) __attribute__((noreturn))
Widgets main loop.
const char * gp_widget_tbox_text(gp_widget *self)
Returns a tbox string.
@ GP_WIDGET_TBOX_EDIT
Emitted after text is entered.
@ GP_WIDGET_TBOX_TRIGGER
Emitted when enter is pressed.
gp_widget * gp_widget_by_uid(gp_htable *uids, const char *uid, enum gp_widget_type type)
Gets a widget pointer given UIDs hash, an id and type.
void gp_fill(gp_pixmap *pixmap, gp_pixel val)
Fills pixmap with given pixel value.
void gp_putpixel(gp_pixmap *pixmap, gp_coord x, gp_coord y, gp_pixel p)
Puts a pixel value.
void gp_circle(gp_pixmap *pixmap, gp_coord xcenter, gp_coord ycenter, gp_size r, gp_pixel pixel)
Draws a circle.
gp_pixmap * gp_pixmap_alloc(gp_size w, gp_size h, gp_pixel_type type)
Allocates a pixmap.
void gp_pixmap_free(gp_pixmap *self)
Frees a pixmap.
An input event.
Definition gp_event.h:153
struct gp_ev_key key
A keyboard or mouse key.
Definition gp_event.h:163
struct gp_events_state * st
Pointer to overall state, pressed keys, cursor position etc.
Definition gp_event.h:180
uint16_t type
enum gp_event_type
Definition gp_event.h:155
uint32_t cursor_y
Current cursor y coordinate.
Definition gp_event.h:142
uint32_t cursor_x
Current cursor x coordinate.
Definition gp_event.h:140
A hash table.
Definition gp_htable.h:40
A pixmap buffer.
Definition gp_pixmap.h:33
Event structure passed to widget event handler.
struct gp_event * input_ev
An input event.
gp_widget * self
The widget the event is for.
uint16_t type
An event type, enum gp_widget_event_type.
uint16_t sub_type
Widget specific subtype defined by widgets.
gp_pixel_type pixel_type
Pixel type used for drawing.
A widget base.
Definition gp_widget.h:28
unsigned int w
Current widget size in pixels.
Definition gp_widget.h:79
{
"info": {"version": 1, "license": "GPL-2.0-or-later"},
"layout": {
"cols": 3,
"widgets": [
{"cols": 2, "rows": 2,
"widgets": [
{"type": "label", "text": "fg:"},
{"type": "label", "text": "bg:"},
{
"type": "tbox",
"text": "ffffff",
"max_len" : 6,
"tattr": "mono",
"on_event": "set_fg_color"},
{
"type": "tbox",
"text": "000000",
"max_len" : 6,
"tattr": "mono",
"on_event": "set_bg_color"}
]
},
{
"type": "pixmap",
"w": 100, "h": 100,
"on_event": "pixmap_on_event",
"uid": "pixmap"
},
{
"type": "button",
"label": "clear",
"on_event": "button_on_event"
}
]
}
}

Unbuffered mode

In this mode the application is passed a temporary buffer in the size of the widget and a gp_bbox that describes an inner rectangle that has to be repainted. To pass the pointer the pixmap member in struct gp_widget_pixmap is set temporarily, for the duration of the event handler, and the gp_bbox is passed down in the gp_widget_event::bbox.

The application is free to ignore the bounding box and repaint the whole pixmap.

Note
In this mode the content of the pixmap buffer is not preserved between events so this is mostly useful when pixmap is repainted periodically and the data is not worth caching.
Attention
The GP_WIDGET_EVENT_REDRAW has to be unmasked by gp_widget_events_unmask() before the application starts.

The GP_WIDGET_EVENT_RESIZE can be unmasked as well if you want to be notified when the pixmap is resized, but it's not strictly required in this mode.

//SPDX-License-Identifier: LGPL-2.0-or-later
/*
Copyright (c) 2007-2023 Cyril Hrubis <metan@ucw.cz>
*/
#include <math.h>
#include <time.h>
#include <widgets/gp_widgets.h>
static void draw(gp_widget *pixmap, const gp_widget_render_ctx *ctx, gp_size line_w)
{
gp_pixmap *pix = pixmap->pixmap->pixmap;
gp_pixel red = gp_rgb_to_pixmap_pixel(0xff, 0x00, 0x00, pix);
gp_pixel fg = ctx->text_color;
gp_fill(pix, ctx->bg_color);
int w = pix->w;
int h = pix->h;
int r = GP_MIN(w, h)/2 - 1;
int cx = r + (w - 2 * r)/2;
int cy = r + (h - 2 * r)/2;
gp_fill_circle(pix, cx, cy, r, ctx->fg_color);
gp_fill_ring(pix, cx, cy, r, r-2*line_w, fg);
gp_line_th(pix, cx, cy - r, cx, cy - r + 8 * line_w, line_w, fg);
gp_line_th(pix, cx, cy + r, cx, cy + r - 8 * line_w, line_w, fg);
gp_line_th(pix, cx - r, cy, cx - r + 8 * line_w, cy, line_w, fg);
gp_line_th(pix, cx + r, cy, cx + r - 8 * line_w, cy, line_w, fg);
int csa = r * sin(M_PI/6);
int cca = r * cos(M_PI/6);
int csb = (r - 4 * line_w) * sin(M_PI/6);
int ccb = (r - 4 * line_w) * cos(M_PI/6);
gp_line_th(pix, cx - csa, cy - cca, cx - csb, cy - ccb, line_w, fg);
gp_line_th(pix, cx + csa, cy - cca, cx + csb, cy - ccb, line_w, fg);
gp_line_th(pix, cx - csa, cy + cca, cx - csb, cy + ccb, line_w, fg);
gp_line_th(pix, cx + csa, cy + cca, cx + csb, cy + ccb, line_w, fg);
gp_line_th(pix, cx - cca, cy - csa, cx - ccb, cy - csb, line_w, fg);
gp_line_th(pix, cx + cca, cy - csa, cx + ccb, cy - csb, line_w, fg);
gp_line_th(pix, cx - cca, cy + csa, cx - ccb, cy + csb, line_w, fg);
gp_line_th(pix, cx + cca, cy + csa, cx + ccb, cy + csb, line_w, fg);
time_t timestamp;
struct tm *tm;
time(&timestamp);
tm = localtime(&timestamp);
float angle;
angle = 2 * M_PI * (tm->tm_hour%12) / 12 - M_PI/2;
gp_line_th(pix, cx, cy,
cx + 0.6 * r * cos(angle), cy + 0.6 * r * sin(angle), line_w, fg);
angle = 2 * M_PI * tm->tm_min / 60 - M_PI/2;
gp_line_th(pix, cx, cy,
cx + 0.8 * r * cos(angle), cy + 0.8 * r * sin(angle), line_w, fg);
angle = 2 * M_PI * tm->tm_sec / 60 - M_PI/2;
gp_line_th(pix, cx, cy,
cx + 0.9 * r * cos(angle), cy + 0.8 * r * sin(angle), line_w, red);
}
int pixmap_on_event(gp_widget_event *ev)
{
switch (ev->type) {
draw(ev->self, ev->ctx, ev->ctx->fr_thick);
printf("BBOX " GP_BBOX_FMT "\n", GP_BBOX_PARS((*ev->bbox)));
return 1;
default:
return 0;
}
}
static uint32_t timer_callback(gp_timer *self)
{
gp_widget *pixmap = self->priv;
return 1000;
}
static gp_timer tmr = {
.expires = 1000,
.callback = timer_callback,
.id = "Clock redraw"
};
gp_app_info app_info = {
.name = "Analog Clock",
.desc = "Simple analog clock",
.version = "1.0",
.license = "GPL-2.0-or-later",
.url = "http://gfxprim.ucw.cz",
.authors = (gp_app_info_author []) {
{.name = "Cyril Hrubis", .email = "metan@ucw.cz", .years = "2007-2023"},
{}
}
};
int main(int argc, char *argv[])
{
gp_widget *layout = gp_widget_grid_new(1, 1, 0);
GP_WIDGET_SIZE(100, 0, 0),
pixmap_on_event, NULL);
gp_widget_grid_put(layout, 0, 0, pixmap);
layout->align = GP_FILL;
pixmap->align = GP_FILL;
tmr.priv = pixmap;
gp_widgets_main_loop(layout, NULL, argc, argv);
}
#define GP_MIN(a, b)
Returns a minimum of the two numbers.
Definition gp_common.h:31
unsigned int gp_size
Integer type for sizes i.e. w, h, ...
Definition gp_types.h:24
#define GP_BBOX_PARS(bbox)
A bounding box printf parameters.
Definition gp_bbox.h:148
#define GP_BBOX_FMT
A bounding box printf format string.
Definition gp_bbox.h:146
@ GP_FILL
Shortcut for setting both hfill and vfill.
Definition gp_widget.h:386
@ GP_WIDGET_EVENT_REDRAW
Pixmap redraw event.
gp_widget * gp_widget_grid_put(gp_widget *self, unsigned int col, unsigned int row, gp_widget *child)
Puts a child widget into a frame widget.
gp_widget * gp_widget_grid_new(unsigned int cols, unsigned int rows, enum gp_widget_grid_flags flags)
Allocates and initializes a widget grid.
gp_widget * gp_widget_pixmap_new(gp_widget_size min_w, gp_widget_size min_h, int(*on_event)(gp_widget_event *ev), void *priv)
Create pixmap widget.
#define GP_WIDGET_SIZE(px_val, pad_val, asc_val)
An initializer for gp_widget_size.
void gp_widgets_timer_ins(gp_timer *timer)
Inserts a timer into the widgets timer queue.
void gp_line_th(gp_pixmap *pixmap, gp_coord x0, gp_coord y0, gp_coord x1, gp_coord y1, gp_size r, gp_pixel pixel)
Murphy thick line drawing algorithm.
void gp_fill_ring(gp_pixmap *pixmap, gp_coord xcenter, gp_coord ycenter, gp_size r1, gp_size r2, gp_pixel pixel)
Draws a filled ring.
void gp_fill_circle(gp_pixmap *pixmap, gp_coord xcenter, gp_coord ycenter, gp_size r, gp_pixel pixel)
Draws a filled circle.
Description of the app author.
Definition gp_app_info.h:31
An application information.
Definition gp_app_info.h:64
const char * name
Application name.
Definition gp_app_info.h:66
uint32_t h
Pixmap height in pixels.
Definition gp_pixmap.h:46
uint32_t w
Pixmap width in pixels.
Definition gp_pixmap.h:44
A timer.
Definition gp_timer.h:26
void * priv
Definition gp_timer.h:59
uint64_t expires
Definition gp_timer.h:33
struct gp_bbox * bbox
Optional bounding box.
Global widget (rendering) context.
uint8_t fr_thick
Frame thickness 0 == 1px.
gp_pixel text_color
A text color.
gp_pixel fg_color
A foreground color.
gp_pixel bg_color
A background color.
unsigned int align
Widget alignment in parent container, enum gp_widget_alignment.
Definition gp_widget.h:87

Pixmap widget JSON attributes

Attribute Type Default Description
w uint Minimal pixmap width parsed by gp_widget_size_units_parse().
h uint Minimal pixmap height parsed by gp_widget_size_units_parse().

Definition in file gp_widget_pixmap.h.

Function Documentation

◆ gp_widget_pixmap_h()

static gp_size gp_widget_pixmap_h ( gp_widget self)
inlinestatic

Returns pixmap height in pixels.

Parameters
selfA pixmap widget.
Returns
A pixmap height.

Definition at line 153 of file gp_widget_pixmap.h.

◆ gp_widget_pixmap_new()

gp_widget * gp_widget_pixmap_new ( gp_widget_size  min_w,
gp_widget_size  min_h,
int(*)(gp_widget_event *ev)  on_event,
void *  priv 
)

Create pixmap widget.

If pixmap widget has align set to fill the widget will grow into available space, otherwise it will be always precisely min_w x min_h in size.

There are two modes of operation:

Either you allocate a backing pixmap in the resize event. Then you draw into it and the library will simply copy the buffer when application requests the widget to be repainted.

Or you can leave the pixmap pointer to be NULL in which case the library will fill it just for the duration of redraw event.

Parameters
min_wMinimal pixmap width
min_hMinimal pixmap height
on_eventA widget event handler.
privA widget event handler private pointer.
Returns
A newly allocated and initialized pixmap widget.

◆ gp_widget_pixmap_redraw()

void gp_widget_pixmap_redraw ( gp_widget self,
gp_coord  x,
gp_coord  y,
gp_size  w,
gp_size  h 
)

Requests partial update of the image.

This function is useful in the case that the application renders into pre-allocated pixmap and only the part of the buffer should be repainted. If called more than once before pixmap update on the screen the areas are merged into one that contains both bounding boxes.

Parameters
selfA pixmap widget.
xAn x offset into the pixmap
yAn y offset into the pixmap
wA width of a rectangle at offset x,y
hA heigth of a rectangle at offset x,y

◆ gp_widget_pixmap_redraw_all()

void gp_widget_pixmap_redraw_all ( gp_widget self)

Marks the whole pixmap to be repainted.

Parameters
selfA pixmap widget.

◆ gp_widget_pixmap_w()

static gp_size gp_widget_pixmap_w ( gp_widget self)
inlinestatic

Returns pixmap width in pixels.

Parameters
selfA pixmap widget.
Returns
A pixmap width.

Definition at line 141 of file gp_widget_pixmap.h.

References gp_widget::w.