source: mainline/uspace/app/fontedit/fontedit.c@ 414020d9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 414020d9 was 414020d9, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Select painting or clearing pixels using '1' / '2'

Cannot erase with right mouse button since it's occupied by window
management for the time being.

  • Property mode set to 100644
File size: 10.6 KB
Line 
1/*
2 * Copyright (c) 2020 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fontedit
30 * @{
31 */
32/** @file Font editor
33 */
34
35#include <canvas.h>
36#include <draw/surface.h>
37#include <fibril.h>
38#include <guigfx/canvas.h>
39#include <gfx/color.h>
40#include <gfx/font.h>
41#include <gfx/glyph.h>
42#include <gfx/render.h>
43#include <gfx/typeface.h>
44#include <stdbool.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <str.h>
48#include <task.h>
49#include <window.h>
50#include "fontedit.h"
51
52enum {
53 glyph_scale = 8,
54 glyph_orig_x = 100,
55 glyph_orig_y = 100
56};
57
58static errno_t font_edit_paint(font_edit_t *);
59
60/** Clear screen.
61 *
62 * @param gc Graphic context
63 * @param w Screen width
64 * @param h Screen height
65 */
66static errno_t clear_scr(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
67{
68 gfx_color_t *color = NULL;
69 gfx_rect_t rect;
70 errno_t rc;
71
72 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
73 if (rc != EOK)
74 goto error;
75
76 rc = gfx_set_color(gc, color);
77 if (rc != EOK)
78 goto error;
79
80 rect.p0.x = 0;
81 rect.p0.y = 0;
82 rect.p1.x = w;
83 rect.p1.y = h;
84
85 rc = gfx_fill_rect(gc, &rect);
86 if (rc != EOK)
87 goto error;
88
89 gfx_color_delete(color);
90 return EOK;
91error:
92 if (color != NULL)
93 gfx_color_delete(color);
94 return rc;
95}
96
97/** Handle font editor position event.
98 *
99 * @param widget Canvas widget
100 * @param data Position event
101 */
102static void font_edit_pos_event(widget_t *widget, void *data)
103{
104 pos_event_t *event = (pos_event_t *) data;
105 font_edit_t *fedit;
106 int x, y;
107
108 fedit = (font_edit_t *) widget_get_data(widget);
109
110 if (event->type == POS_PRESS) {
111 x = gfx_coord_div_rneg((int)event->hpos - glyph_orig_x,
112 glyph_scale);
113 y = gfx_coord_div_rneg((int)event->vpos - glyph_orig_y,
114 glyph_scale);
115
116 printf("x=%d y=%d\n", x, y);
117 gfx_glyph_bmp_setpix(fedit->gbmp, x, y, fedit->pen_color);
118 font_edit_paint(fedit);
119 }
120}
121
122/** Handle font editor keyboard event.
123 *
124 * @param widget Canvas widget
125 * @param data Position event
126 */
127static void font_edit_kbd_event(widget_t *widget, void *data)
128{
129 kbd_event_t *event = (kbd_event_t *) data;
130 font_edit_t *fedit;
131
132 fedit = (font_edit_t *) widget_get_data(widget);
133
134 if (event->type == KEY_PRESS) {
135 switch (event->key) {
136 case KC_S:
137 printf("Save!\n");
138 (void) gfx_glyph_bmp_save(fedit->gbmp);
139 font_edit_paint(fedit);
140 break;
141 case KC_1:
142 printf("Set pixels\n");
143 fedit->pen_color = 1;
144 break;
145 case KC_2:
146 printf("Clear pixels\n");
147 fedit->pen_color = 0;
148 break;
149 default:
150 break;
151 }
152 }
153}
154
155/** Convert glyph pixel coordinates to displayed rectangle.
156 *
157 * Since we upscale the glyph a pixel in the glyph corresponds to a rectangle
158 * on the screen.
159 *
160 * @param fedit Font editor
161 * @param x X coordinate in glyph
162 * @param y Y coordinate in glyph
163 * @param drect Place to store displayed rectangle coordinates
164 */
165static void font_edit_gpix_to_disp(font_edit_t *fedit, int x, int y,
166 gfx_rect_t *drect)
167{
168 (void) fedit;
169
170 drect->p0.x = glyph_orig_x + x * glyph_scale;
171 drect->p0.y = glyph_orig_y + y * glyph_scale;
172 drect->p1.x = glyph_orig_x + (x + 1) * glyph_scale;
173 drect->p1.y = glyph_orig_y + (y + 1) * glyph_scale;
174}
175
176/** Paint font preview.
177 *
178 * @param fedit Font editor
179 */
180static errno_t font_edit_paint_preview(font_edit_t *fedit)
181{
182 gfx_glyph_metrics_t gmetrics;
183 size_t stradv;
184 const char *cp;
185 gfx_glyph_t *glyph;
186 gfx_coord2_t pos;
187 errno_t rc;
188
189 cp = "ABCD";
190 pos.x = 20;
191 pos.y = 20;
192
193 while (*cp != '\0') {
194 rc = gfx_font_search_glyph(fedit->font, cp, &glyph, &stradv);
195 if (rc != EOK) {
196 ++cp;
197 continue;
198 }
199
200 gfx_glyph_get_metrics(glyph, &gmetrics);
201
202 rc = gfx_glyph_render(glyph, &pos);
203 if (rc != EOK)
204 return rc;
205
206 cp += stradv;
207 pos.x += gmetrics.advance;
208 }
209
210 return EOK;
211}
212
213/** Paint glyph bitmap.
214 *
215 * @param fedit Font editor
216 */
217static errno_t font_edit_paint_gbmp(font_edit_t *fedit)
218{
219 gfx_color_t *color = NULL;
220 gfx_rect_t rect;
221 gfx_rect_t grect;
222 errno_t rc;
223 int x, y;
224 int pix;
225
226 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
227 if (rc != EOK)
228 goto error;
229
230 rc = gfx_set_color(fedit->gc, color);
231 if (rc != EOK)
232 goto error;
233
234 gfx_glyph_bmp_get_rect(fedit->gbmp, &grect);
235 printf("grect=%d,%d,%d,%d\n", grect.p0.x, grect.p0.y,
236 grect.p1.x, grect.p1.y);
237
238 for (y = grect.p0.y; y < grect.p1.y; y++) {
239 for (x = grect.p0.x; x < grect.p1.x; x++) {
240 pix = gfx_glyph_bmp_getpix(fedit->gbmp, x, y);
241
242 if (pix != 0) {
243 font_edit_gpix_to_disp(fedit, x, y, &rect);
244
245 rc = gfx_fill_rect(fedit->gc, &rect);
246 if (rc != EOK)
247 goto error;
248 }
249 }
250 }
251
252 gfx_color_delete(color);
253
254 /* Display glyph origin */
255
256 rc = gfx_color_new_rgb_i16(0, 0xffff, 0, &color);
257 if (rc != EOK)
258 goto error;
259
260 rc = gfx_set_color(fedit->gc, color);
261 if (rc != EOK)
262 goto error;
263
264 font_edit_gpix_to_disp(fedit, 0, 0, &rect);
265
266 rc = gfx_fill_rect(fedit->gc, &rect);
267 if (rc != EOK)
268 goto error;
269
270 gfx_color_delete(color);
271
272 return EOK;
273error:
274 if (color != NULL)
275 gfx_color_delete(color);
276 return rc;
277}
278
279/** Paint font editor.
280 *
281 * @param fedit Font editor
282 */
283static errno_t font_edit_paint(font_edit_t *fedit)
284{
285 int w, h;
286 errno_t rc;
287
288 w = fedit->width;
289 h = fedit->height;
290
291 rc = clear_scr(fedit->gc, w, h);
292 if (rc != EOK)
293 return rc;
294
295 rc = font_edit_paint_gbmp(fedit);
296 if (rc != EOK)
297 return rc;
298
299 rc = font_edit_paint_preview(fedit);
300 if (rc != EOK)
301 return rc;
302
303 return EOK;
304}
305
306/** Create font editor.
307 *
308 * @param display_svc Display service
309 * @param rfedit Place to store pointer to new font editor
310 * @return EOK on success or an error code
311 */
312static errno_t font_edit_create(const char *display_svc, font_edit_t **rfedit)
313{
314 canvas_gc_t *cgc = NULL;
315 window_t *window = NULL;
316 pixel_t *pixbuf = NULL;
317 surface_t *surface = NULL;
318 canvas_t *canvas = NULL;
319 font_edit_t *fedit = NULL;
320 gfx_typeface_t *tface = NULL;
321 gfx_font_t *font = NULL;
322 gfx_font_props_t props;
323 gfx_font_metrics_t metrics;
324 gfx_glyph_metrics_t gmetrics;
325 gfx_glyph_t *glyph;
326 gfx_glyph_bmp_t *bmp;
327 gfx_coord_t vw, vh;
328 gfx_context_t *gc;
329 errno_t rc;
330
331 fedit = calloc(1, sizeof(font_edit_t));
332 if (fedit == NULL) {
333 rc = ENOMEM;
334 goto error;
335 }
336
337 printf("Init canvas..\n");
338
339 window = window_open(display_svc, NULL,
340 WINDOW_MAIN | WINDOW_DECORATED, "Font Editor");
341 if (window == NULL) {
342 printf("Error creating window.\n");
343 rc = ENOMEM;
344 goto error;
345 }
346
347 vw = 400;
348 vh = 300;
349
350 pixbuf = calloc(vw * vh, sizeof(pixel_t));
351 if (pixbuf == NULL) {
352 printf("Error allocating memory for pixel buffer.\n");
353 rc = ENOMEM;
354 goto error;
355 }
356
357 surface = surface_create(vw, vh, pixbuf, 0);
358 if (surface == NULL) {
359 printf("Error creating surface.\n");
360 rc = ENOMEM;
361 goto error;
362 }
363
364 /* Memory block pixbuf is now owned by surface */
365 pixbuf = NULL;
366
367 canvas = create_canvas(window_root(window), fedit, vw, vh,
368 surface);
369 if (canvas == NULL) {
370 printf("Error creating canvas.\n");
371 rc = ENOMEM;
372 goto error;
373 }
374
375 window_resize(window, 0, 0, vw + 10, vh + 30, WINDOW_PLACEMENT_ANY);
376 window_exec(window);
377
378 printf("Create canvas GC\n");
379 rc = canvas_gc_create(canvas, surface, &cgc);
380 if (rc != EOK) {
381 printf("Error creating canvas GC.\n");
382 goto error;
383 }
384
385 gc = canvas_gc_get_ctx(cgc);
386
387 rc = gfx_typeface_create(gc, &tface);
388 if (rc != EOK) {
389 printf("Error creating typeface.\n");
390 goto error;
391 }
392
393 gfx_font_props_init(&props);
394 gfx_font_metrics_init(&metrics);
395
396 rc = gfx_font_create(tface, &props, &metrics, &font);
397 if (rc != EOK) {
398 printf("Error creating font.\n");
399 goto error;
400 }
401
402 gfx_glyph_metrics_init(&gmetrics);
403
404 rc = gfx_glyph_create(font, &gmetrics, &glyph);
405 if (rc != EOK) {
406 printf("Error creating glyph.\n");
407 goto error;
408 }
409
410 rc = gfx_glyph_set_pattern(glyph, "A");
411 if (rc != EOK) {
412 printf("Error setting glyph pattern.\n");
413 goto error;
414 }
415
416 rc = gfx_glyph_bmp_open(glyph, &bmp);
417 if (rc != EOK) {
418 printf("Error opening glyph bitmap.\n");
419 goto error;
420 }
421
422 sig_connect(&canvas->position_event, &canvas->widget,
423 font_edit_pos_event);
424 sig_connect(&canvas->keyboard_event, &canvas->widget,
425 font_edit_kbd_event);
426
427 fedit->cgc = cgc;
428 fedit->gc = gc;
429 fedit->width = vw;
430 fedit->height = vh;
431 fedit->pen_color = 1;
432 fedit->typeface = tface;
433 fedit->font = font;
434 fedit->glyph = glyph;
435 fedit->gbmp = bmp;
436
437 *rfedit = fedit;
438 return EOK;
439error:
440 /*
441 * Once the window is created it would be probably more correct
442 * to leave destruction of these resources to a window destroy
443 * handler (which we have no way of registering)
444 */
445 if (bmp != NULL)
446 gfx_glyph_bmp_close(bmp);
447 if (glyph != NULL)
448 gfx_glyph_destroy(glyph);
449 if (font != NULL)
450 gfx_font_close(font);
451 if (tface != NULL)
452 gfx_typeface_destroy(tface);
453 if (surface != NULL)
454 surface_destroy(surface);
455 if (pixbuf != NULL)
456 free(pixbuf);
457 if (window != NULL)
458 window_close(window);
459 if (fedit != NULL)
460 free(fedit);
461 return rc;
462}
463
464static void print_syntax(void)
465{
466 printf("Syntax: fontedit [-d <display>]\n");
467}
468
469int main(int argc, char *argv[])
470{
471 errno_t rc;
472 const char *display_svc = DISPLAY_DEFAULT;
473 font_edit_t *fedit;
474 int i;
475
476 i = 1;
477 while (i < argc && argv[i][0] == '-') {
478 if (str_cmp(argv[i], "-d") == 0) {
479 ++i;
480 if (i >= argc) {
481 printf("Argument missing.\n");
482 print_syntax();
483 return 1;
484 }
485
486 display_svc = argv[i++];
487 } else {
488 printf("Invalid option '%s'.\n", argv[i]);
489 print_syntax();
490 return 1;
491 }
492 }
493
494 rc = font_edit_create(display_svc, &fedit);
495 if (rc != EOK)
496 return 1;
497
498 (void) font_edit_paint(fedit);
499
500 task_retval(0);
501 async_manager();
502
503 return 0;
504}
505
506/** @}
507 */
Note: See TracBrowser for help on using the repository browser.