GCC Code Coverage Report


Directory: src/gate/
File: src/gate/ui/graphics.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 188 277 67.9%
Functions: 19 42 45.2%
Branches: 34 68 50.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. 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 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/ui/graphics.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_UI_WINAPI)
33
34 #include "gate/ui/gateui_winapi.h"
35 #include "gate/platforms.h"
36 #include "gate/debugging.h"
37 #include <shellapi.h>
38
39 #if !defined(GATE_SYS_WIN16)
40 #include <commctrl.h>
41 #endif
42
43 #define GATE_UI_GRAPHICS_HDC(graph) ((HDC)(graph)->resources[0])
44 #define GATE_UI_GRAPHICS_BACKUP(graph) ((HBITMAP)(graph)->resources[1])
45 #define GATE_UI_GRAPHICS_WINDOW(graph) ((HWND)(graph)->resources[2])
46 #define GATE_UI_GRAPHICS_BYTEBUFFER(graph) ((void*)(graph)->resources[3])
47
48 gate_result_t gate_ui_graphics_create_virtual(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_uint32_t width, gate_uint32_t height)
49 {
50 HWND desk = GetDesktopWindow();
51 HDC deskdc = GetDC(desk);
52 HDC dc;
53 HBITMAP bmp;
54 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
55 dc = CreateCompatibleDC(deskdc);
56 if (dc == NULL)
57 {
58 ReleaseDC(desk, deskdc);
59 return GATE_RESULT_FAILED;
60 }
61 bmp = CreateCompatibleBitmap(deskdc, (int)width, (int)height);
62 ReleaseDC(desk, deskdc);
63 if (bmp == NULL)
64 {
65 DeleteDC(dc);
66 return GATE_RESULT_OUTOFRESOURCES;
67 }
68 graph->host = host;
69 graph->width = width;
70 graph->height = height;
71 graph->resources[0] = dc;
72 graph->resources[1] = SelectObject(dc, (HGDIOBJ)bmp);
73 return GATE_RESULT_OK;
74 }
75
76 typedef struct gate_ui_bitmap_header_class
77 {
78 BITMAPINFO info;
79 RGBQUAD palette[256];
80 } gate_ui_bitmap_header_t;
81
82 static gate_size_t resolve_color_index(gate_uint8_t r, gate_uint8_t g, gate_uint8_t b)
83 {
84 const gate_size_t nr = ((gate_size_t)r + 26u) / 51u;
85 const gate_size_t ng = ((gate_size_t)g + 26u) / 51u;
86 const gate_size_t nb = ((gate_size_t)b + 26u) / 51u;
87
88 const gate_size_t ndx = nr * 36u + ng * 6u + nb;
89 return ndx;
90 }
91
92 static DWORD create_palette_8(RGBQUAD* ptr_quad)
93 {
94 unsigned short r, g, b;
95 for (r = 0; r < 6; ++r)
96 {
97 for (g = 0; g < 6; ++g)
98 {
99 for (b = 0; b < 6; ++b)
100 {
101 ptr_quad->rgbBlue = (unsigned char)(b * 51);
102 ptr_quad->rgbGreen = (unsigned char)(g * 51);
103 ptr_quad->rgbRed = (unsigned char)(r * 51);
104 ptr_quad->rgbReserved = 0;
105 ++ptr_quad;
106 }
107 }
108 }
109 return 216;
110 }
111
112 gate_result_t gate_ui_graphics_create_image(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_uint32_t width, gate_uint32_t height, gate_uint32_t depth)
113 {
114 gate_result_t ret;
115 HWND desk = GetDesktopWindow();
116 HDC deskdc = GetDC(desk);
117 HDC dc = NULL;
118 HBITMAP hbitmap;
119 HBITMAP hbackup;
120 gate_ui_bitmap_header_t bitmapinfo;
121 gate_uint8_t r;
122 gate_size_t linelen;
123 gate_size_t bufferlen;
124 void* buffer;
125 RGBQUAD* ptr_quad;
126
127 do
128 {
129 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
130
131 if (deskdc == NULL)
132 {
133 ret = GATE_RESULT_OUTOFRESOURCES;
134 break;
135 }
136 dc = CreateCompatibleDC(deskdc);
137 if (dc == NULL)
138 {
139 ret = GATE_RESULT_OUTOFRESOURCES;
140 break;
141 }
142
143
144 bitmapinfo.info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
145 bitmapinfo.info.bmiHeader.biWidth = width;
146 bitmapinfo.info.bmiHeader.biHeight = height;
147 bitmapinfo.info.bmiHeader.biPlanes = 1;
148 bitmapinfo.info.bmiHeader.biBitCount = depth;
149 bitmapinfo.info.bmiHeader.biCompression = BI_RGB;
150 bitmapinfo.info.bmiHeader.biSizeImage = 0;
151 bitmapinfo.info.bmiHeader.biXPelsPerMeter = 0;
152 bitmapinfo.info.bmiHeader.biYPelsPerMeter = 0;
153 bitmapinfo.info.bmiHeader.biClrImportant = 0;
154
155 if (depth == 1)
156 {
157 bitmapinfo.info.bmiHeader.biClrUsed = 2;
158
159 /* black */
160 bitmapinfo.info.bmiColors[0].rgbBlue = 0;
161 bitmapinfo.info.bmiColors[0].rgbGreen = 0;
162 bitmapinfo.info.bmiColors[0].rgbRed = 0;
163 bitmapinfo.info.bmiColors[0].rgbReserved = 0;
164
165 /* white */
166 bitmapinfo.info.bmiColors[1].rgbBlue = 255;
167 bitmapinfo.info.bmiColors[1].rgbGreen = 255;
168 bitmapinfo.info.bmiColors[1].rgbRed = 255;
169 bitmapinfo.info.bmiColors[1].rgbReserved = 0;
170 }
171 else if (depth < 8)
172 {
173 static gate_color_rgb_t vga_pal[16];
174 static gate_bool_t vga_pal_init = false;
175 if (!vga_pal_init)
176 {
177 gate_color_palette_rgb4_create(vga_pal);
178 vga_pal_init = true;
179 }
180
181 bitmapinfo.info.bmiHeader.biClrUsed = 16;
182 ptr_quad = &bitmapinfo.info.bmiColors[0];
183 for (r = 0; r < 16; ++r)
184 {
185 ptr_quad->rgbBlue = vga_pal[r].b;
186 ptr_quad->rgbGreen = vga_pal[r].g;
187 ptr_quad->rgbRed = vga_pal[r].r;
188 ptr_quad->rgbReserved = 0;
189 ++ptr_quad;
190 }
191 }
192 else if (depth < 16)
193 {
194 ptr_quad = &bitmapinfo.info.bmiColors[0];
195 bitmapinfo.info.bmiHeader.biClrUsed = create_palette_8(ptr_quad);
196 }
197 else
198 {
199 bitmapinfo.info.bmiHeader.biClrUsed = 0;
200 }
201
202 linelen = (bitmapinfo.info.bmiHeader.biWidth * bitmapinfo.info.bmiHeader.biBitCount + 7) / 8;
203 if (linelen % 4 != 0)
204 {
205 linelen += (4 - (linelen % 4));
206 }
207 bufferlen = linelen * bitmapinfo.info.bmiHeader.biHeight;
208 #if defined(GATE_SYS_WIN16)
209 buffer = gate_mem_alloc(bufferlen);
210 gate_mem_clear(buffer, bufferlen);
211 hbitmap = CreateDIBitmap(deskdc, &bitmapinfo.info.bmiHeader, CBM_INIT, buffer, &bitmapinfo.info, DIB_RGB_COLORS);
212 #else
213 buffer = NULL;
214 hbitmap = CreateDIBSection(deskdc, &bitmapinfo.info, DIB_RGB_COLORS, &buffer, NULL, 0);
215 #endif
216 if (hbitmap == NULL)
217 {
218 ret = GATE_RESULT_FAILED;
219 break;
220 }
221 hbackup = SelectObject(dc, hbitmap);
222
223 graph->width = width;
224 graph->height = height;
225 graph->host = host;
226 graph->resources[0] = dc;
227 graph->resources[1] = hbackup;
228 graph->resources[2] = NULL;
229 graph->resources[3] = buffer;
230 ret = GATE_RESULT_OK;
231
232 } while (0);
233
234 if (deskdc != NULL)
235 {
236 ReleaseDC(desk, deskdc);
237 }
238
239 return ret;
240 }
241
242 gate_result_t gate_ui_graphics_create_image_from(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_rasterimage_t const* rasterimage)
243 {
244
245 gate_uint32_t x, y;
246 gate_result_t ret;
247 #if defined(GATE_WIN32_ANSI)
248
249 # if 0
250 /* use 8-bit DIB */
251 ret = gate_ui_graphics_create_image(graph, host, rasterimage->width, rasterimage->height, 8);
252 if (GATE_SUCCEEDED(ret))
253 {
254 gate_uint8_t* ptrbytes = (gate_uint8_t*)GATE_UI_GRAPHICS_BYTEBUFFER(graph);
255 unsigned line_patch = (unsigned)(rasterimage->width % 4);
256 if (line_patch != 0)
257 {
258 line_patch = 4 - line_patch;
259 }
260 for (y = 0; y != rasterimage->height; ++y)
261 {
262 gate_color_t const* ptrpixels = (gate_color_t const*)gate_rasterimage_get_line_ptr(rasterimage, (rasterimage->height - 1 - y));
263 for (x = 0; x != rasterimage->width; ++x)
264 {
265 gate_uint16_t col16;
266 col16 = (((gate_uint16_t)ptrpixels->r + 25) / 51) * 36;
267 col16 += (((gate_uint16_t)ptrpixels->g + 25) / 51) * 6;
268 col16 += (((gate_uint16_t)ptrpixels->b + 25) / 51);
269
270 *(ptrbytes++) = (gate_uint8_t)(col16 & 0xff);
271 ++ptrpixels;
272 }
273 ptrbytes += line_patch;
274 }
275 }
276 # else
277 /* use 16-bit DIB */
278 ret = gate_ui_graphics_create_image(graph, host, rasterimage->width, rasterimage->height, 16);
279 if (GATE_SUCCEEDED(ret))
280 {
281 gate_uint8_t* ptrbytes = (gate_uint8_t*)GATE_UI_GRAPHICS_BYTEBUFFER(graph);
282 unsigned line_patch = (unsigned)(rasterimage->width % 2) * 2;
283 for (y = 0; y != rasterimage->height; ++y)
284 {
285 gate_color_t const* ptrpixels = (gate_color_t const*)gate_rasterimage_get_line_ptr(rasterimage, (rasterimage->height - 1 - y));
286 for (x = 0; x != rasterimage->width; ++x)
287 {
288 gate_uint16_t col16
289 = ((gate_uint16_t)(ptrpixels->b & 0xF8) >> 3)
290 | ((gate_uint16_t)(ptrpixels->g & 0xF8) << 2)
291 | ((gate_uint16_t)(ptrpixels->r & 0xF8) << 7);
292
293 *(ptrbytes++) = (gate_uint8_t)(col16 & 0xff);
294 *(ptrbytes++) = (gate_uint8_t)(col16 >> 8);
295 ++ptrpixels;
296 }
297 ptrbytes += line_patch;
298 }
299 }
300 # endif
301
302 #else
303 ret = gate_ui_graphics_create_image(graph, host, rasterimage->width, rasterimage->height, 32);
304 if (GATE_SUCCEEDED(ret))
305 {
306 gate_uint8_t* ptrbytes = (gate_uint8_t*)GATE_UI_GRAPHICS_BYTEBUFFER(graph);
307 for (y = 0; y != rasterimage->height; ++y)
308 {
309 gate_color_t const* ptrpixels = (gate_color_t const*)gate_rasterimage_get_line_ptr(rasterimage, (rasterimage->height - 1 - y));
310 for (x = 0; x != rasterimage->width; ++x)
311 {
312 *(ptrbytes++) = ptrpixels->b;
313 *(ptrbytes++) = ptrpixels->g;
314 *(ptrbytes++) = ptrpixels->r;
315 *(ptrbytes++) = ptrpixels->a;
316 ++ptrpixels;
317 }
318 }
319 }
320 #endif
321 return ret;
322 }
323
324
325 gate_result_t gate_ui_graphics_create_ctrl(gate_ui_graphics_t* graph, gate_ui_ctrl_t* ctrl)
326 {
327 HWND hwnd = (HWND)GATE_UI_WINAPI_GET_HWND(ctrl);
328 RECT rect;
329
330 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
331
332 GetClientRect(hwnd, &rect);
333
334 graph->host = GATE_UI_WINAPI_GET_HOST(ctrl);
335 graph->width = rect.right - rect.left;
336 graph->height = rect.bottom - rect.top;
337 graph->resources[0] = GetDC(hwnd);
338 graph->resources[2] = hwnd;
339 return GATE_RESULT_OK;
340 }
341 gate_result_t gate_ui_graphics_create_native(gate_ui_graphics_t* graph, gate_ui_host_t* host, void* graphics, void* param, gate_int32_t width, gate_int32_t height)
342 {
343 GATE_UNUSED_ARG(param);
344 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
345 graph->host = host;
346 graph->resources[0] = graphics;
347 graph->resources[3] = (void*)(gate_intptr_t)(-1); ///< no-release flag
348 graph->width = width;
349 graph->height = height;
350 return GATE_RESULT_OK;
351 }
352 gate_result_t gate_ui_graphics_destroy(gate_ui_graphics_t* graph)
353 {
354 gate_bool_t success = true;
355 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
356 HBITMAP hbmp = GATE_UI_GRAPHICS_BACKUP(graph);
357 HWND hwnd = GATE_UI_GRAPHICS_WINDOW(graph);
358 void* buffer_ptr = GATE_UI_GRAPHICS_BYTEBUFFER(graph);
359
360 if (-1 == (gate_intptr_t)buffer_ptr)
361 {
362 // no-release flag is active
363 }
364 else
365 {
366 if (hbmp != NULL)
367 {
368 success &= (FALSE != DeleteObject(SelectObject(hdc, (HGDIOBJ)hbmp)));
369 }
370
371 if (hwnd != NULL)
372 {
373 success &= (0 != ReleaseDC(hwnd, hdc));
374 }
375 else
376 {
377 success &= (FALSE != DeleteDC(hdc));
378 }
379
380 if (buffer_ptr != NULL)
381 {
382 #if defined(GATE_SYS_WIN16)
383 gate_mem_dealloc(buffer_ptr);
384 #else
385 /* win32 dib section will release the buffer bits automatically */
386 #endif
387 }
388
389 }
390
391 return success ? GATE_RESULT_OK : GATE_RESULT_FAILED;
392 }
393
394 gate_int32_t gate_ui_graphics_width(gate_ui_graphics_t* graph)
395 {
396 return (graph != NULL) ? graph->width : 0;
397 }
398 gate_int32_t gate_ui_graphics_height(gate_ui_graphics_t* graph)
399 {
400 return (graph != NULL) ? graph->height : 0;
401 }
402
403 #ifndef CLR_INVALID
404 #define CLR_INVALID 0xffffffff
405 #endif
406
407 gate_result_t gate_ui_graphics_set_pixel(gate_ui_graphics_t* graph, gate_ui_point_t pos, gate_ui_color_t col)
408 {
409 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
410 COLORREF colref = RGB(col.r, col.g, col.b);
411 COLORREF result = SetPixel(hdc, (int)pos.x, (int)pos.y, colref);
412 if (result == CLR_INVALID)
413 {
414 return GATE_RESULT_FAILED;
415 }
416 else
417 {
418 return GATE_RESULT_OK;
419 }
420 }
421 gate_result_t gate_ui_graphics_get_pixel(gate_ui_graphics_t* graph, gate_ui_point_t pos, gate_ui_color_t* col)
422 {
423 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
424 COLORREF colref = GetPixel(hdc, (int)pos.x, (int)pos.y);
425 if (colref == CLR_INVALID)
426 {
427 return GATE_RESULT_FAILED;
428 }
429 else
430 {
431 col->r = GetRValue(colref);
432 col->g = GetGValue(colref);
433 col->b = GetBValue(colref);
434 col->a = 255;
435 return GATE_RESULT_OK;
436 }
437 }
438 gate_result_t gate_ui_graphics_draw(gate_ui_graphics_t* graph, gate_ui_graphics_t* srcgraph,
439 gate_ui_point_t const* dst, gate_ui_size_t const* size, gate_ui_point_t const* srcpos)
440 {
441 HDC hdc_dst = GATE_UI_GRAPHICS_HDC(graph);
442 HDC hdc_src = GATE_UI_GRAPHICS_HDC(srcgraph);
443 int dst_x = dst ? dst->x : 0;
444 int dst_y = dst ? dst->y : 0;
445 int width = size ? size->width : -1;
446 int height = size ? size->height : -1;
447 int src_x = srcpos ? srcpos->x : 0;
448 int src_y = srcpos ? srcpos->y : 0;
449
450 if (width < 0)
451 {
452 width += gate_ui_graphics_width(srcgraph) + 1;
453 }
454 if (height < 0)
455 {
456 height += gate_ui_graphics_height(srcgraph) + 1;
457 }
458
459 if (FALSE == BitBlt(hdc_dst, dst_x, dst_y, width, height, hdc_src, src_x, src_y, SRCCOPY))
460 {
461 return GATE_RESULT_FAILED;
462 }
463 else
464 {
465 return GATE_RESULT_OK;
466 }
467 }
468
469 gate_result_t gate_ui_graphics_draw_ex(gate_ui_graphics_t* graph, gate_ui_graphics_t* src_graph,
470 gate_ui_position_t const* dest_rect, gate_ui_position_t const* src_rect)
471 {
472 HDC hdc_dst = GATE_UI_GRAPHICS_HDC(graph);
473 HDC hdc_src = GATE_UI_GRAPHICS_HDC(src_graph);
474 int dst_x = dest_rect ? dest_rect->pos.x : 0;
475 int dst_y = dest_rect ? dest_rect->pos.y : 0;
476 int dst_width = dest_rect ? dest_rect->size.width : -1;
477 int dst_height = dest_rect ? dest_rect->size.height : -1;
478 int src_x = src_rect ? src_rect->pos.x : 0;
479 int src_y = src_rect ? src_rect->pos.y : 0;
480 int src_width = src_rect ? src_rect->size.width : -1;
481 int src_height = src_rect ? src_rect->size.height : -1;
482
483 if (dst_width < 0)
484 {
485 dst_width += gate_ui_graphics_width(graph) + 1;
486 }
487 if (dst_height < 0)
488 {
489 dst_height += gate_ui_graphics_height(graph) + 1;
490 }
491
492 if (src_width < 0)
493 {
494 src_width += gate_ui_graphics_width(src_graph) + 1;
495 }
496 if (src_height < 0)
497 {
498 src_height += gate_ui_graphics_height(src_graph) + 1;
499 }
500 #if defined(COLORONCOLOR) && !defined(__MINGW32CE__)
501 SetStretchBltMode(hdc_dst, COLORONCOLOR);
502 #endif
503
504 if (FALSE == StretchBlt(hdc_dst, dst_x, dst_y, dst_width, dst_height, hdc_src,
505 src_x, src_y, src_width, src_height, SRCCOPY))
506 {
507 return GATE_RESULT_FAILED;
508 }
509 else
510 {
511 return GATE_RESULT_OK;
512 }
513 }
514
515 gate_result_t gate_ui_graphics_draw_image(gate_ui_graphics_t* graph, gate_rasterimage_t const* srcimage,
516 gate_ui_point_t const* dst, gate_ui_size_t const* size, gate_ui_point_t const* srcpos)
517 {
518 gate_ui_graphics_t src_graph;
519 gate_result_t ret = gate_ui_graphics_create_image_from(&src_graph, graph->host, srcimage);
520 if (GATE_SUCCEEDED(ret))
521 {
522 ret = gate_ui_graphics_draw(graph, &src_graph, dst, size, srcpos);
523 gate_ui_graphics_destroy(&src_graph);
524 }
525 return ret;
526 }
527
528
529 gate_result_t gate_ui_graphics_line(gate_ui_graphics_t* graph, gate_ui_point_t from, gate_ui_point_t to, gate_ui_color_t col, gate_uint32_t linewidth)
530 {
531 gate_result_t ret = GATE_RESULT_FAILED;
532 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
533 COLORREF colref = RGB(col.r, col.g, col.b);
534 HPEN hpen = CreatePen(PS_SOLID, linewidth, colref);
535 HGDIOBJ hselpen = SelectObject(hdc, (HGDIOBJ)hpen);
536 if (MoveToEx(hdc, (int)from.x, (int)from.y, NULL))
537 {
538 if (LineTo(hdc, (int)to.x, (int)to.y))
539 {
540 SetPixel(hdc, (int)to.x, (int)to.y, colref);
541 ret = GATE_RESULT_OK;
542 }
543 }
544 DeleteObject(SelectObject(hdc, hselpen));
545 return ret;
546 }
547 gate_result_t gate_ui_graphics_rect(gate_ui_graphics_t* graph, gate_ui_position_t rect, gate_ui_color_t const* colline, gate_uint32_t linewidth, gate_ui_color_t const* colfill)
548 {
549 gate_result_t success = true;
550 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
551 RECT r;
552 HGDIOBJ hbackup;
553 HBRUSH hbrush;
554 HPEN hpen;
555 COLORREF colref;
556
557 if (colfill != NULL)
558 {
559 colref = RGB(colfill->r, colfill->g, colfill->b);
560 hbrush = CreateSolidBrush(colref);
561 r.left = rect.pos.x;
562 r.top = rect.pos.y;
563 r.right = rect.pos.x + rect.size.width + 1;
564 r.bottom = rect.pos.y + rect.size.height + 1;
565 success &= (0 != FillRect(hdc, &r, hbrush));
566 DeleteObject(hbrush);
567 }
568 if (colline != NULL)
569 {
570 colref = RGB(colline->r, colline->g, colline->b);
571 hpen = CreatePen(PS_SOLID, (int)linewidth, colref);
572 hbackup = SelectObject(hdc, hpen);
573 success &= (FALSE != MoveToEx(hdc, rect.pos.x, rect.pos.y, NULL));
574 success &= (FALSE != LineTo(hdc, rect.pos.x + rect.size.width, rect.pos.y));
575 success &= (FALSE != LineTo(hdc, rect.pos.x + rect.size.width, rect.pos.y + rect.size.height));
576 success &= (FALSE != LineTo(hdc, rect.pos.x, rect.pos.y + rect.size.height));
577 success &= (FALSE != LineTo(hdc, rect.pos.x, rect.pos.y));
578 DeleteObject(SelectObject(hdc, hbackup));
579 }
580 return success ? GATE_RESULT_OK : GATE_RESULT_FAILED;
581 }
582 gate_result_t gate_ui_graphics_polygon(gate_ui_graphics_t* graph, gate_ui_point_t const* points, gate_size_t pointcount, gate_ui_color_t const* colline, gate_uint32_t linewidth, gate_ui_color_t const* colfill)
583 {
584 gate_result_t success = true;
585 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
586 HGDIOBJ hbackup;
587 HGDIOBJ hbackup2;
588 HPEN hpen;
589 HBRUSH hbrush;
590 COLORREF colref;
591 gate_size_t ndx;
592 POINT pnts[1024];
593
594 if (colfill != NULL)
595 {
596 colref = RGB(colfill->r, colfill->g, colfill->b);
597 if (pointcount > sizeof(pnts) / sizeof(pnts[0]))
598 {
599 pointcount = sizeof(pnts) / sizeof(pnts[0]);
600 }
601 for (ndx = 0; ndx < pointcount; ++ndx)
602 {
603 pnts[ndx].x = (int)points[ndx].x;
604 pnts[ndx].y = (int)points[ndx].y;
605 }
606 hpen = CreatePen(PS_NULL, 0, 0);
607 hbackup = SelectObject(hdc, (HGDIOBJ)hpen);
608 hbrush = CreateSolidBrush(colref);
609 hbackup2 = SelectObject(hdc, (HGDIOBJ)hbrush);
610
611 success &= (FALSE != Polygon(hdc, pnts, (int)pointcount));
612
613 DeleteObject(SelectObject(hdc, hbackup2));
614 DeleteObject(SelectObject(hdc, hbackup));
615 }
616
617 if (colline != NULL)
618 {
619 colref = RGB(colline->r, colline->g, colline->b);
620 hpen = CreatePen(PS_SOLID, linewidth, colref);
621 hbackup = SelectObject(hdc, (HGDIOBJ)hpen);
622 success &= (FALSE != MoveToEx(hdc, (int)points[0].x, (int)points[0].y, NULL));
623 for (ndx = 1; ndx != pointcount; ++ndx)
624 {
625 success &= (FALSE != LineTo(hdc, (int)points[ndx].x, (int)points[ndx].y));
626 }
627 success &= (FALSE != LineTo(hdc, (int)points[0].x, (int)points[0].y));
628 DeleteObject(SelectObject(hdc, hbackup));
629 }
630 return success ? GATE_RESULT_OK : GATE_RESULT_FAILED;
631 }
632
633 #if defined(GATE_SYS_WIN16)
634
635 static BOOL GetTextExtentExPoint(HDC hdc, LPCSTR lpszString, int cchString, int nMaxExtent, LPINT lpnFit, LPINT lpnDx, LPSIZE lpSize)
636 {
637 SIZE sz;
638 SIZE szchr;
639 GATE_UNUSED_ARG(nMaxExtent);
640 GATE_UNUSED_ARG(lpnFit);
641 sz.cx = 0;
642 sz.cy = 0;
643 while (cchString-- > 0)
644 {
645 GetTextExtentPoint(hdc, lpszString, 1, &szchr);
646 sz.cx += szchr.cx;
647 *lpnDx = szchr.cx;
648
649 ++lpszString;
650 ++lpnDx;
651 }
652 lpSize->cx = sz.cx;
653 lpSize->cy = sz.cy;
654 return TRUE;
655 }
656
657 #define GetTextExtentPoint32 GetTextExtentPoint
658
659 #endif
660
661 gate_result_t gate_ui_graphics_get_char_size(gate_ui_graphics_t* graph, gate_ui_font_t const* font,
662 gate_char32_t const* chars, gate_size_t charcount, gate_int32_t* charlens)
663 {
664 /* NOTICE: this function only supports up to 2048 characters! */
665 gate_result_t ret = GATE_RESULT_FAILED;
666 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
667 TCHAR buffer[2048];
668 int lengths[2048];
669 gate_size_t bufferused = gate_win32_utf32_2_winstr(chars, charcount, buffer, sizeof(buffer) / sizeof(buffer[0]));
670 HGDIOBJ hbackup;
671 HFONT hfont = (HFONT)gate_ui_winapi_create_font(font);
672 SIZE sz = { 0, 0 };
673 gate_size_t index;
674
675 hbackup = SelectObject(hdc, (HGDIOBJ)hfont);
676
677 if (FALSE == GetTextExtentExPoint(hdc, buffer, (int)bufferused, 0, NULL, lengths, &sz))
678 {
679 gate_win32_print_lasterror(&ret, NULL, 0);
680 }
681 else
682 {
683 for (index = 0; index != bufferused; ++index)
684 {
685 charlens[index] = lengths[index];
686 }
687 ret = GATE_RESULT_OK;
688 }
689
690 DeleteObject(SelectObject(hdc, hbackup));
691 return ret;
692 }
693 gate_result_t gate_ui_graphics_get_text_size(gate_ui_graphics_t* graph, gate_ui_font_t const* font,
694 gate_string_t const* txt, gate_int32_t* width, gate_int32_t* height)
695 {
696 gate_result_t ret = GATE_RESULT_FAILED;
697 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
698 HGDIOBJ hbackup = NULL;
699 TCHAR buffer[4096];
700 gate_size_t bufferused = gate_win32_utf8_2_winstr(txt->str, txt->length, buffer, sizeof(buffer) / sizeof(buffer[0]));
701 HFONT hfont = (HFONT)gate_ui_winapi_create_font(font);
702 SIZE sz = { 0, 0 };
703
704 hbackup = SelectObject(hdc, (HGDIOBJ)hfont);
705
706 if (FALSE == GetTextExtentPoint32(hdc, buffer, (int)bufferused, &sz))
707 {
708 gate_win32_print_lasterror(&ret, NULL, 0);
709 }
710 else
711 {
712 if (width)
713 {
714 *width = (gate_int32_t)sz.cx;
715 }
716 if (height)
717 {
718 *height = (gate_int32_t)sz.cy;
719 }
720 ret = GATE_RESULT_OK;
721 }
722
723 DeleteObject(SelectObject(hdc, hbackup));
724 return ret;
725 }
726 gate_result_t gate_ui_graphics_print(gate_ui_graphics_t* graph, gate_ui_font_t const* font,
727 gate_string_t const* text, gate_ui_position_t const* pos)
728 {
729 gate_bool_t success = true;
730 HDC hdc = GATE_UI_GRAPHICS_HDC(graph);
731 HGDIOBJ hbackup;
732 HFONT hfont = (HFONT)gate_ui_winapi_create_font(font);
733 TCHAR buffer[4096];
734 RECT rect;
735 UINT flags = DT_LEFT | DT_NOPREFIX | DT_NOCLIP;
736 gate_size_t bufferused = gate_win32_utf8_2_winstr(text->str, text->length, buffer, sizeof(buffer) / sizeof(buffer[0]));
737 rect.left = pos->pos.x;
738 rect.top = pos->pos.y;
739 if ((pos->size.width == 0) && (pos->size.height == 0))
740 {
741 rect.bottom = graph->width;
742 rect.right = graph->height;
743 }
744 else
745 {
746 rect.bottom = pos->pos.x + pos->size.width + 1;
747 rect.right = pos->pos.y + pos->size.height + 1;
748 flags |= DT_VCENTER;
749 }
750 SetTextColor(hdc, RGB(font->color.r, font->color.g, font->color.b));
751 SetBkMode(hdc, TRANSPARENT);
752 hbackup = SelectObject(hdc, (HGDIOBJ)hfont);
753 success &= ((0 != DrawText(hdc, buffer, (int)bufferused, &rect, flags)) ? true : false);
754 DeleteObject(SelectObject(hdc, hbackup));
755 return success ? GATE_RESULT_OK : GATE_RESULT_FAILED;
756 }
757
758 void* gate_ui_graphics_handle(gate_ui_graphics_t* graph)
759 {
760 return (void*)GATE_UI_GRAPHICS_HDC(graph);
761 }
762 void* gate_ui_graphics_surface(gate_ui_graphics_t* graph)
763 {
764 return (void*)GATE_UI_GRAPHICS_WINDOW(graph);
765 }
766
767
768 /*****************************
769 * icon WIN32 implementation *
770 *****************************/
771
772 gate_result_t gate_ui_icon_create_native(gate_ui_icon_t* icon, gate_ui_host_t* host, void* handle, gate_uint32_t flags)
773 {
774 icon->host = host;
775 icon->resources[0] = handle;
776 icon->flags = flags;
777 return GATE_RESULT_OK;
778 }
779
780 typedef UINT(WINAPI* ExtractIconEx_funcptr_t)(LPCTSTR lpszFile, int nIconIndex, HICON* phiconLarge, HICON* phiconSmall, UINT nIcons);
781 static ExtractIconEx_funcptr_t ExtractIconEx_function = NULL;
782
783 static HICON gate_ui_extract_icon(LPCTSTR file, int icon_index, gate_uint32_t flags)
784 {
785 gate_bool_t is_small = GATE_FLAG_ENABLED(flags, GATE_UI_ICON_FLAG_SMALL);
786 HICON hicon = NULL;
787 HMODULE hmod;
788 UINT extracted;
789 do
790 {
791 if (ExtractIconEx_function == NULL)
792 {
793 hmod = gate_win32_get_shell_module();
794 if (hmod != NULL)
795 {
796 gate_win32_get_proc_address(hmod, GATE_WINAPI_DUAL_NAME("ExtractIconEx"), &ExtractIconEx_function);
797 }
798 }
799 if (ExtractIconEx_function != NULL)
800 {
801 extracted = ExtractIconEx_function(file, icon_index, is_small ? NULL : &hicon, is_small ? &hicon : NULL, 1);
802 if (extracted == 0)
803 {
804 hicon = NULL;
805 }
806 }
807 } while (0);
808 return hicon;
809 }
810
811 gate_result_t gate_ui_icon_create_stock(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_uint32_t stock_id, gate_uint32_t flags)
812 {
813 gate_result_t ret = GATE_RESULT_FAILED;
814 HICON hicon = NULL;
815
816 #if defined(GATE_SYS_WINCE)
817 hicon = LoadCursor(NULL, IDC_APPSTARTING);
818 #else
819 LPCTSTR icon_source_file = _T("shell32.dll");
820 int icon_source_index = -1;
821 int icon_source_index_alt = -1;
822
823 switch (stock_id)
824 {
825 case GATE_UI_ICON_STOCK_APP: icon_source_index = 2; break;
826 case GATE_UI_ICON_STOCK_DOCUMENT: icon_source_index = 1; break;
827 case GATE_UI_ICON_STOCK_FOLDER: icon_source_index = 3; break;
828 case GATE_UI_ICON_STOCK_FOLDEROPEN: icon_source_index = 4; break;
829 case GATE_UI_ICON_STOCK_NEWFILE: icon_source_index = 70; icon_source_index_alt = 1; break;
830 case GATE_UI_ICON_STOCK_OPENFILE: icon_source_index = 126; icon_source_index_alt = 85; break;
831 case GATE_UI_ICON_STOCK_SAVEFILE: icon_source_index = 258; icon_source_index_alt = 6; break;
832 case GATE_UI_ICON_STOCK_PRINTER: icon_source_index = 16; break;
833 case GATE_UI_ICON_STOCK_CUT: icon_source_index = 259; icon_source_index_alt = 65; break;
834 case GATE_UI_ICON_STOCK_COPY: icon_source_index = 134; icon_source_index_alt = 54; break;
835 case GATE_UI_ICON_STOCK_PASTE: icon_source_index = 260; icon_source_index_alt = 66; break;
836 case GATE_UI_ICON_STOCK_DELETE: icon_source_index = 131; icon_source_index_alt = 105; break;
837 case GATE_UI_ICON_STOCK_FIND: icon_source_index = 22; break;
838 case GATE_UI_ICON_STOCK_HELP: icon_source_index = 23; break;
839
840 case GATE_UI_ICON_STOCK_STORAGE: icon_source_index = 8; icon_source_index_alt = 8; break;
841 case GATE_UI_ICON_STOCK_COMPUTER: icon_source_index = 15; icon_source_index_alt = 15; break;
842 case GATE_UI_ICON_STOCK_NETWORK: icon_source_index = 18; icon_source_index_alt = 18; break;
843 case GATE_UI_ICON_STOCK_GLOBE: icon_source_index = 13; icon_source_index_alt = 13; break;
844 case GATE_UI_ICON_STOCK_SETTINGS: icon_source_index = 90; icon_source_index_alt = 21; break;
845 case GATE_UI_ICON_STOCK_HOME: icon_source_index = 150; icon_source_index_alt = 39; break;
846 case GATE_UI_ICON_STOCK_IMAGE: icon_source_index = 117; icon_source_index_alt = 34; break;
847 case GATE_UI_ICON_STOCK_AUDIO: icon_source_index = 116; icon_source_index_alt = 40; break;
848 case GATE_UI_ICON_STOCK_VIDEO: icon_source_index = 115; icon_source_index_alt = 79; break;
849 case GATE_UI_ICON_STOCK_MAIL: icon_source_index = 156; icon_source_index_alt = 91; break;
850
851 default: break;
852 }
853
854 if (icon_source_index < 0)
855 {
856 return GATE_RESULT_NOMATCH;
857 }
858
859 hicon = gate_ui_extract_icon(icon_source_file, icon_source_index, flags);
860 if ((hicon == NULL) && (icon_source_index_alt >= 0))
861 {
862 hicon = gate_ui_extract_icon(icon_source_file, icon_source_index_alt, flags);
863 }
864 #endif
865
866 if (hicon == NULL)
867 {
868 return GATE_RESULT_NOTAVAILABLE;
869 }
870
871 ret = gate_ui_icon_create_native(icon, host, (void*)hicon, (flags & GATE_UI_ICON_FLAG_SMALL) | GATE_UI_ICON_FLAG_STOCK);
872 if (GATE_FAILED(ret))
873 {
874 DestroyIcon(hicon);
875 }
876 else
877 {
878 icon->resources[1] = (void*)(gate_uintptr_t)stock_id;
879 }
880 return ret;
881 }
882
883 #if defined(GATE_SYS_WIN16)
884
885 static HICON gate_ui_icon_create_from_image(gate_ui_host_t* host, gate_rasterimage_t const* image, gate_uint32_t hx, gate_uint32_t hy)
886 {
887 /* TODO */
888 return CreateIcon(NULL, 32, 32, 2, 2, NULL, NULL);
889 }
890
891 #else /* GATE_SYS_WIN16 */
892
893 static HICON gate_ui_icon_create_from_image(gate_ui_host_t* host, gate_rasterimage_t const* image, gate_uint32_t hx, gate_uint32_t hy)
894 {
895 HICON ret = NULL;
896
897 do
898 {
899 gate_ui_position_t imagerect;
900 gate_ui_color_t maskcolor = { 255, 255, 255, 255 };
901 gate_ui_point_t pos;
902 gate_uint32_t icon_flags = 0;
903 static COLORREF color_black = RGB(0, 0, 0);
904 static COLORREF color_white = RGB(255, 255, 255);
905 COLORREF color_bg = GetSysColor(COLOR_3DFACE);
906
907 ICONINFO iconinfo;
908
909 HBITMAP hbmptmp1 = NULL;
910 HBITMAP hbmptmp2 = NULL;
911 HBITMAP bmpmask = NULL;
912 HBITMAP bmpimage = NULL;
913 HDC desk = NULL;
914 HDC hmask = NULL;
915 HDC himage = NULL;
916 gate_color_t const* ptrpixels;
917
918 iconinfo.fIcon = TRUE;
919 iconinfo.xHotspot = hx;
920 iconinfo.yHotspot = hy;
921 iconinfo.hbmMask = NULL;
922 iconinfo.hbmColor = NULL;
923
924 imagerect.pos.x = 0;
925 imagerect.pos.y = 0;
926 imagerect.size.width = image->width;
927 imagerect.size.height = image->height;
928
929 desk = GetDC(NULL);
930 hmask = CreateCompatibleDC(desk);
931 himage = CreateCompatibleDC(desk);
932
933 bmpmask = CreateBitmap(image->width, image->height, 1, 1, NULL);
934 bmpimage = CreateCompatibleBitmap(desk, image->width, image->height);
935
936 hbmptmp1 = (HBITMAP)SelectObject(hmask, bmpmask);
937 hbmptmp2 = (HBITMAP)SelectObject(himage, bmpimage);
938
939 ptrpixels = (gate_color_t const*)gate_rasterimage_get_line_ptr(image, 0);
940 for (pos.y = 0; pos.y != image->height; ++pos.y)
941 {
942 for (pos.x = 0; pos.x != image->width; ++pos.x)
943 {
944 SetPixel(hmask, pos.x, pos.y, (ptrpixels->a > 127) ? color_black : color_white);
945 SetPixel(himage, pos.x, pos.y, (ptrpixels->a > 127) ? RGB(ptrpixels->r, ptrpixels->g, ptrpixels->b) : color_black);
946 ++ptrpixels;
947 }
948 }
949 SelectObject(hmask, hbmptmp1);
950 SelectObject(himage, hbmptmp2);
951 DeleteDC(hmask);
952 DeleteDC(himage);
953 ReleaseDC(NULL, desk);
954
955 if (image->height < 24)
956 {
957 icon_flags |= GATE_UI_ICON_FLAG_SMALL;
958 }
959 if (image->height > 40)
960 {
961 icon_flags |= GATE_UI_ICON_FLAG_LARGE;
962 }
963
964 iconinfo.hbmMask = bmpmask;
965 iconinfo.hbmColor = bmpimage;
966
967 ret = CreateIconIndirect(&iconinfo);
968 GATE_DEBUG_ASSERT(ret != NULL);
969
970 DeleteObject(bmpmask);
971 DeleteObject(bmpimage);
972 } while (0);
973
974 return ret;
975 }
976
977 #endif /* GATE_SYS_WIN16 */
978
979 gate_result_t gate_ui_icon_create_image(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_rasterimage_t const* image)
980 {
981 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
982 HICON hicon = gate_ui_icon_create_from_image(host, image, 0, 0);
983 if (hicon == NULL)
984 {
985 ret = GATE_RESULT_FAILED;
986 }
987 else
988 {
989 icon->resources[0] = hicon;
990 icon->resources[1] = NULL;
991 icon->host = host;
992 if (image->height < 28)
993 {
994 icon->flags = GATE_UI_ICON_FLAG_SMALL;
995 }
996 else if (image->height > 36)
997 {
998 icon->flags = GATE_UI_ICON_FLAG_LARGE;
999 }
1000
1001 ret = GATE_RESULT_OK;
1002 }
1003 return ret;
1004 }
1005 gate_result_t gate_ui_icon_create_file(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_string_t const* filepath)
1006 {
1007 gate_result_t ret = GATE_RESULT_NOTIMPLEMENTED;
1008 /* TODO */
1009 return ret;
1010 }
1011 gate_result_t gate_ui_icon_copy(gate_ui_icon_t* dsticon, gate_ui_icon_t const* srcicon)
1012 {
1013 gate_result_t ret = GATE_RESULT_OK;
1014 dsticon->host = srcicon->host;
1015
1016 #if !defined(GATE_SYS_WINCE)
1017 if (!GATE_FLAG_ENABLED(srcicon->flags, GATE_UI_ICON_FLAG_STOCK))
1018 {
1019 /* managed icon */
1020 dsticon->flags = srcicon->flags;
1021 #if defined(GATE_SYS_WIN16)
1022 dsticon->resources[0] = (void*)CopyIcon(NULL, (HICON)srcicon->resources[0]);
1023 #else
1024 dsticon->resources[0] = (void*)CopyIcon((HICON)srcicon->resources[0]);
1025 #endif
1026 if (dsticon->resources[0] == NULL)
1027 {
1028 ret = GATE_RESULT_FAILED;
1029 }
1030 dsticon->resources[1] = NULL;
1031 }
1032 else
1033 #endif
1034 {
1035 dsticon->resources[0] = srcicon->resources[0];
1036 dsticon->resources[1] = srcicon->resources[1];
1037 }
1038 return ret;
1039 }
1040
1041 gate_result_t gate_ui_icon_destroy(gate_ui_icon_t* icon)
1042 {
1043 gate_result_t ret = GATE_RESULT_OK;
1044 if (!GATE_FLAG_ENABLED(icon->flags, GATE_UI_ICON_FLAG_STOCK))
1045 {
1046 /* managed icon */
1047 if (!DestroyIcon((HICON)icon->resources[0]))
1048 {
1049 ret = GATE_RESULT_FAILED;
1050 }
1051 }
1052 return ret;
1053 }
1054
1055
1056
1057 /******************
1058 * iconlist WIN32 *
1059 ******************/
1060 #if !defined(ILC_COLOR16) && defined(ILC_COLOR)
1061 # define ILC_COLOR16 ILC_COLOR
1062 #endif
1063
1064 gate_result_t gate_ui_iconlist_create(gate_ui_iconlist_t* ilst, gate_ui_host_t* host, gate_int32_t width, gate_int32_t height)
1065 {
1066 #if defined(GATE_SYS_WIN16)
1067 return GATE_RESULT_NOTIMPLEMENTED;
1068 #else
1069 int const x = (int)width;
1070 int const y = (int)height;
1071 static UINT const flags = ILC_COLOR16 | ILC_MASK;
1072 HIMAGELIST hlst = (HIMAGELIST)gate_ui_winapi_imagelist_create(x, y, flags, 1, 1);
1073 if (!hlst)
1074 {
1075 return GATE_RESULT_FAILED;
1076 }
1077 gate_ui_winapi_imagelist_set_bkcolor(hlst, NULL);
1078 gate_mem_clear(ilst, sizeof(gate_ui_iconlist_t));
1079 ilst->host = host;
1080 ilst->flags = 0;
1081 ilst->width = width;
1082 ilst->height = height;
1083 ilst->resources[0] = hlst;
1084 return GATE_RESULT_OK;
1085 #endif
1086 }
1087
1088 gate_result_t gate_ui_iconlist_destroy(gate_ui_iconlist_t* ilst)
1089 {
1090 #if defined(GATE_SYS_WIN16)
1091 return GATE_RESULT_NOTIMPLEMENTED;
1092 #else
1093 if (ilst->resources[0] != NULL)
1094 {
1095 gate_ui_winapi_imagelist_destroy((HIMAGELIST)ilst->resources[0]);
1096 }
1097 gate_mem_clear(ilst, sizeof(gate_ui_iconlist_t));
1098 return GATE_RESULT_OK;
1099 #endif
1100 }
1101 gate_size_t gate_ui_iconlist_count(gate_ui_iconlist_t* ilst)
1102 {
1103 return 0;
1104 }
1105 gate_result_t gate_ui_iconlist_add(gate_ui_iconlist_t* ilst, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
1106 {
1107 #if defined(GATE_SYS_WIN16)
1108 return GATE_RESULT_NOTIMPLEMENTED;
1109 #else
1110 HIMAGELIST hlst = (HIMAGELIST)ilst->resources[0];
1111 int index;
1112
1113 if (!hlst)
1114 {
1115 return GATE_RESULT_INVALIDSTATE;
1116 }
1117
1118 index = gate_ui_winapi_imagelist_replace_icon(hlst, -1, (HICON)icon->resources[0]);
1119 if (index < 0)
1120 {
1121 return GATE_RESULT_FAILED;
1122 }
1123 else
1124 {
1125 if (icon_key)
1126 {
1127 *icon_key = index;
1128 }
1129 return GATE_RESULT_OK;
1130 }
1131 #endif
1132 }
1133
1134 gate_result_t gate_ui_iconlist_add_image(gate_ui_iconlist_t* ilst, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
1135 {
1136 #if defined(GATE_SYS_WIN16)
1137 return GATE_RESULT_NOTIMPLEMENTED;
1138 #else
1139 gate_ui_icon_t icon = GATE_INIT_EMPTY;
1140 gate_result_t ret = gate_ui_icon_create_image(&icon, ilst->host, image);
1141 if (GATE_SUCCEEDED(ret))
1142 {
1143 ret = gate_ui_iconlist_add(ilst, &icon, icon_key);
1144 gate_ui_icon_destroy(&icon);
1145 }
1146 return ret;
1147 #endif
1148 }
1149
1150 gate_result_t gate_ui_iconlist_get(gate_ui_iconlist_t* ilst, gate_intptr_t icon_key, gate_ui_icon_t* icon)
1151 {
1152 #if defined(GATE_SYS_WIN16)
1153 return GATE_RESULT_NOTIMPLEMENTED;
1154 #else
1155 UINT flags = ILD_TRANSPARENT;
1156 gate_uint32_t icon_flags;
1157 HICON hicon = (HICON)gate_ui_winapi_imagelist_get_icon((HIMAGELIST)ilst->resources[0], (int)icon_key, flags);
1158 if (!hicon)
1159 {
1160 return GATE_RESULT_FAILED;
1161 }
1162 else
1163 {
1164 icon_flags = GATE_UI_ICON_FLAG_STOCK;
1165 if (ilst->height < 24)
1166 {
1167 icon_flags |= GATE_UI_ICON_FLAG_SMALL;
1168 }
1169 if (ilst->height > 40)
1170 {
1171 icon_flags |= GATE_UI_ICON_FLAG_LARGE;
1172 }
1173 return gate_ui_icon_create_native(icon, ilst->host, hicon, icon_flags);
1174 }
1175 #endif
1176 }
1177
1178
1179
1180
1181 /****************
1182 * cursor WIN32 *
1183 ****************/
1184
1185 #ifndef IDC_APPSTARTING
1186 #define IDC_APPSTARTING IDC_WAIT
1187 #endif
1188
1189 #ifndef IDC_NO
1190 #define IDC_NO IDC_ICON
1191 #endif
1192
1193 gate_result_t gate_ui_cursor_create_stock(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_uint32_t stock_id)
1194 {
1195 LPCTSTR resourceId = NULL;
1196 HCURSOR hcursor = NULL;
1197
1198 switch (stock_id)
1199 {
1200 case GATE_UI_CURSOR_STOCK_POINTER: resourceId = IDC_ARROW; break;
1201 case GATE_UI_CURSOR_STOCK_BUSY: resourceId = IDC_WAIT; break;
1202 case GATE_UI_CURSOR_STOCK_STARTING: resourceId = IDC_APPSTARTING; break;
1203 case GATE_UI_CURSOR_STOCK_HAND: resourceId = /*IDC_HAND*/ IDC_UPARROW; break;
1204 case GATE_UI_CURSOR_STOCK_TEXT: resourceId = IDC_IBEAM; break;
1205 case GATE_UI_CURSOR_STOCK_REJECTED: resourceId = IDC_NO; break;
1206 case GATE_UI_CURSOR_STOCK_SIZE_ALL: resourceId = IDC_SIZE; break;
1207 case GATE_UI_CURSOR_STOCK_SIZE_LEFTRIGHT: resourceId = IDC_SIZEWE; break;
1208 case GATE_UI_CURSOR_STOCK_SIZE_UPDOWN: resourceId = IDC_SIZENS; break;
1209 case GATE_UI_CURSOR_STOCK_SIZE_LEFTUPRIGHTDOWN: resourceId = IDC_SIZENWSE; break;
1210 case GATE_UI_CURSOR_STOCK_SIZE_RIGHTUPKEFTDOWN: resourceId = IDC_SIZENESW; break;
1211 default: return GATE_RESULT_INVALIDARG;
1212 }
1213
1214 hcursor = LoadCursor(NULL, resourceId);
1215 if (NULL == hcursor)
1216 {
1217 return GATE_RESULT_FAILED;
1218 }
1219 cursor->host = host;
1220 cursor->resources[0] = (void*)hcursor;
1221 cursor->resources[1] = NULL;
1222 cursor->flags = GATE_UI_CURSOR_FLAG_STOCK;
1223 return GATE_RESULT_OK;
1224 }
1225 gate_result_t gate_ui_cursor_create_native(gate_ui_cursor_t* cursor, gate_ui_host_t* host, void* handle, gate_uint32_t flags)
1226 {
1227 cursor->host = host;
1228 cursor->resources[0] = handle;
1229 cursor->resources[1] = NULL;
1230 cursor->flags = flags;
1231 return GATE_RESULT_OK;
1232 }
1233 gate_result_t gate_ui_cursor_create_image(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_rasterimage_t const* image, gate_uint16_t x, gate_uint16_t y)
1234 {
1235 gate_result_t ret = GATE_RESULT_FAILED;
1236 HCURSOR hcursor = (HCURSOR)gate_ui_icon_create_from_image(host, image, x, y);
1237 if (hcursor)
1238 {
1239 cursor->resources[0] = (void*)hcursor;
1240 cursor->resources[1] = NULL;
1241 cursor->host = host;
1242 cursor->flags = 0;
1243 ret = GATE_RESULT_OK;
1244 }
1245 return ret;
1246 }
1247 gate_result_t gate_ui_cursor_create_file(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_string_t const* filepath)
1248 {
1249 return GATE_RESULT_NOTIMPLEMENTED;
1250 }
1251
1252 gate_result_t gate_ui_cursor_copy(gate_ui_cursor_t* dsticon, gate_ui_cursor_t const* srcicon)
1253 {
1254 gate_result_t ret = GATE_RESULT_FAILED;
1255 #if !defined(GATE_SYS_WINCE) && !defined(GATE_SYS_WIN16)
1256 if (!GATE_FLAG_ENABLED(srcicon->flags, GATE_UI_CURSOR_FLAG_STOCK))
1257 {
1258 dsticon->resources[0] = (void*)CopyImage((HANDLE)srcicon->resources[0], IMAGE_CURSOR, 0, 0, 0);
1259 if (dsticon->resources[0])
1260 {
1261 dsticon->resources[1] = NULL;
1262 dsticon->host = srcicon->host;
1263 dsticon->flags = 0;
1264 }
1265 }
1266 else
1267 #endif /* ! GATE_SYS_WINCE */
1268 {
1269 gate_mem_copy(dsticon, srcicon, sizeof(gate_ui_cursor_t));
1270 }
1271 return ret;
1272 }
1273 gate_result_t gate_ui_cursor_destroy(gate_ui_cursor_t* cursor)
1274 {
1275 gate_result_t ret = GATE_RESULT_FAILED;
1276 if (cursor)
1277 {
1278 ret = GATE_RESULT_OK;
1279 if (!GATE_FLAG_ENABLED(cursor->flags, GATE_UI_CURSOR_FLAG_STOCK))
1280 {
1281 #if !defined(GATE_SYS_WINCE)
1282 if (!DestroyCursor((HCURSOR)cursor->resources[0]))
1283 {
1284 ret = GATE_RESULT_FAILED;
1285 }
1286 #endif
1287 }
1288 }
1289 return ret;
1290 }
1291
1292
1293
1294 #endif /* GATE_UI_WINAPI */
1295
1296
1297 #if defined(GATE_UI_GTK)
1298
1299 #include "gate/ui/gateui_gtk.h"
1300
1301 gate_result_t gate_ui_graphics_create_virtual(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_uint32_t width, gate_uint32_t height)
1302 {
1303 return gate_ui_graphics_create_image(graph, host, width, height, 32);
1304 }
1305
1306 static cairo_format_t gate_ui_graphics_resolve_format(gate_uint32_t depth)
1307 {
1308 if ((depth == 0) || (depth > 24))
1309 {
1310 return CAIRO_FORMAT_ARGB32;
1311 }
1312 else if (depth > 16)
1313 {
1314 return CAIRO_FORMAT_RGB24;
1315 }
1316 else if (depth > 8)
1317 {
1318 return CAIRO_FORMAT_RGB16_565;
1319 }
1320 else if (depth > 2)
1321 {
1322 return CAIRO_FORMAT_A8;
1323 }
1324 else
1325 {
1326 return CAIRO_FORMAT_A1;
1327 }
1328
1329 }
1330
1331 gate_result_t gate_ui_graphics_create_image(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_uint32_t width, gate_uint32_t height, gate_uint32_t depth)
1332 {
1333 gate_result_t ret = GATE_RESULT_FAILED;
1334 cairo_t* cr = NULL;
1335 cairo_surface_t* surface = NULL;
1336 cairo_format_t format;
1337
1338 do
1339 {
1340 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
1341 format = gate_ui_graphics_resolve_format(depth);
1342
1343 surface = cairo_image_surface_create(format, width, height);
1344 if (surface == NULL)
1345 {
1346 ret = GATE_RESULT_OUTOFRESOURCES;
1347 break;
1348 }
1349 cr = cairo_create(surface);
1350 if (cr == NULL)
1351 {
1352 cairo_surface_destroy(surface);
1353 ret = GATE_RESULT_OUTOFRESOURCES;
1354 break;
1355 }
1356
1357 graph->host = host;
1358 graph->width = width;
1359 graph->height = height;
1360 graph->resources[0] = cr;
1361 graph->resources[1] = surface;
1362
1363 ret = GATE_RESULT_OK;
1364 } while (0);
1365
1366 return ret;
1367 }
1368 gate_result_t gate_ui_graphics_create_image_from(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_rasterimage_t const* rasterimage)
1369 {
1370 gate_result_t ret = gate_ui_graphics_create_image(graph, host, rasterimage->width, rasterimage->height, 32);
1371
1372 if (GATE_SUCCEEDED(ret))
1373 {
1374 gate_ui_point_t pnt = { 0, 0 };
1375 gate_ui_size_t sz = { rasterimage->width, rasterimage->height };
1376 ret = gate_ui_graphics_draw_image(graph, rasterimage, &pnt, &sz, &pnt);
1377 if (GATE_FAILED(ret))
1378 {
1379 gate_ui_graphics_destroy(graph);
1380 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
1381 }
1382 }
1383 return ret;
1384 }
1385 gate_result_t gate_ui_graphics_create_ctrl(gate_ui_graphics_t* graph, gate_ui_ctrl_t* ctrl)
1386 {
1387 gate_result_t ret = GATE_RESULT_FAILED;
1388 cairo_surface_t* surface = NULL;
1389 cairo_t* cr = NULL;
1390
1391 do
1392 {
1393 gate_ui_host_t* host = GATE_UI_GTK_GET_CTRL_HOST(ctrl);
1394 GtkWidget* widget = GATE_UI_GTK_GET_CTRL_WIDGET(ctrl);
1395 GdkWindow* window = NULL;
1396 int width, height;
1397
1398 if (!host || !widget)
1399 {
1400 ret = GATE_RESULT_NOTAVAILABLE;
1401 break;
1402 }
1403
1404 window = gtk_widget_get_window(widget);
1405 width = gtk_widget_get_allocated_width(widget);
1406 height = gtk_widget_get_allocated_height(widget);
1407 surface = gdk_window_create_similar_surface(window, CAIRO_CONTENT_COLOR, width, height);
1408 if (!surface)
1409 {
1410 ret = GATE_RESULT_OUTOFRESOURCES;
1411 break;
1412 }
1413 cr = cairo_create(surface);
1414 if (!cr)
1415 {
1416 ret = GATE_RESULT_FAILED;
1417 break;
1418 }
1419
1420 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
1421 graph->host = host;
1422 graph->width = width;
1423 graph->height = height;
1424 graph->resources[0] = cr;
1425 graph->resources[1] = surface;
1426 cr = NULL;
1427 surface = NULL;
1428 ret = GATE_RESULT_OK;
1429 } while (0);
1430
1431 if (cr)
1432 {
1433 cairo_destroy(cr);
1434 }
1435 if (surface)
1436 {
1437 cairo_surface_destroy(surface);
1438 }
1439 return ret;
1440 }
1441 gate_result_t gate_ui_graphics_create_native(gate_ui_graphics_t* graph, gate_ui_host_t* host, void* graphics, void* param, gate_int32_t width, gate_int32_t height)
1442 {
1443 gate_result_t ret = GATE_RESULT_FAILED;
1444
1445 do
1446 {
1447 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
1448 graph->host = host;
1449 graph->resources[0] = cairo_reference((cairo_t*)graphics); /**< cairo_t */
1450 graph->resources[1] = param; /**< surface */
1451 graph->width = width;
1452 graph->height = height;
1453 ret = GATE_RESULT_OK;
1454 } while (0);
1455
1456 return ret;
1457 }
1458 gate_result_t gate_ui_graphics_destroy(gate_ui_graphics_t* graph)
1459 {
1460 cairo_t* cr = graph->resources[0];
1461 cairo_surface_t* surface = graph->resources[1];
1462
1463 if (surface)
1464 {
1465 cairo_surface_destroy(surface);
1466 }
1467 if (cr)
1468 {
1469 cairo_destroy(cr);
1470 }
1471 return GATE_RESULT_OK;
1472 }
1473
1474
1475 gate_int32_t gate_ui_graphics_width(gate_ui_graphics_t* graph)
1476 {
1477 return graph->width;
1478 }
1479 gate_int32_t gate_ui_graphics_height(gate_ui_graphics_t* graph)
1480 {
1481 return graph->height;
1482 }
1483 gate_result_t gate_ui_graphics_set_pixel(gate_ui_graphics_t* graph, gate_ui_point_t pos, gate_ui_color_t col)
1484 {
1485 cairo_t* cr = (cairo_t*)graph->resources[0];
1486 cairo_set_source_rgb(cr, col.r, col.g, col.b);
1487 cairo_rectangle(cr, (double)pos.x, (double)pos.y, 1.0, 1.0);
1488 cairo_fill(cr);
1489 return GATE_RESULT_OK;
1490 }
1491 gate_result_t gate_ui_graphics_get_pixel(gate_ui_graphics_t* graph, gate_ui_point_t pos, gate_ui_color_t* col)
1492 {
1493 return GATE_RESULT_NOTIMPLEMENTED;
1494 }
1495 gate_result_t gate_ui_graphics_draw(gate_ui_graphics_t* graph, gate_ui_graphics_t* srcgraph,
1496 gate_ui_point_t const* dst, gate_ui_size_t const* size, gate_ui_point_t const* src)
1497 {
1498 cairo_t* cr = (cairo_t*)graph->resources[0];
1499 cairo_surface_t* src_surface = srcgraph->resources[1];
1500 if (src_surface == NULL)
1501 {
1502 return GATE_RESULT_INVALIDINPUT;
1503 }
1504
1505 cairo_set_source_surface(cr, src_surface, dst ? dst->x : 0, dst ? dst->y : 0);
1506 /* TODO: dst/src */
1507 cairo_paint(cr);
1508 return GATE_RESULT_OK;
1509 }
1510
1511 gate_result_t gate_ui_graphics_draw_ex(gate_ui_graphics_t* graph, gate_ui_graphics_t* src_graph,
1512 gate_ui_position_t const* dest_rect, gate_ui_position_t const* src_rect)
1513 {
1514 cairo_t* cr = (cairo_t*)graph->resources[0];
1515 cairo_surface_t* src_surface = src_graph->resources[1];
1516 if (src_surface == NULL)
1517 {
1518 return GATE_RESULT_INVALIDINPUT;
1519 }
1520
1521 cairo_set_source_surface(cr, src_surface, 0, 0);
1522 /* TODO: dst/src */
1523 cairo_paint(cr);
1524 return GATE_RESULT_OK;
1525 }
1526
1527 static GdkPixbuf* gate_ui_gtk_raster_to_pixbuf(gate_rasterimage_t const* srcimage,
1528 gate_int32_t src_x, gate_int32_t src_y, gate_int32_t width, gate_int32_t height)
1529 {
1530 GdkPixbuf* buf;
1531 gate_int32_t x, y;
1532
1533 if (src_x + width > (gate_int32_t)srcimage->width)
1534 {
1535 width = (gate_int32_t)srcimage->width - src_x;
1536 }
1537 if (src_y + height > (gate_int32_t)srcimage->height)
1538 {
1539 height = (gate_int32_t)srcimage->height - src_y;
1540 }
1541
1542 buf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, (int)width, (int)height);
1543 if (buf != NULL)
1544 {
1545 guchar* pixels = gdk_pixbuf_get_pixels(buf);
1546
1547 for (y = 0; y < height; ++y)
1548 {
1549 guchar* dst_pixels = pixels + (y * width) * 4;
1550 gate_color_t const* src_pixels = (((gate_color_t*)gate_rasterimage_get_line_ptr(srcimage, (src_y + y))) + src_x);
1551 for (x = 0; x < width; ++x)
1552 {
1553 dst_pixels[0] = src_pixels->r;
1554 dst_pixels[1] = src_pixels->g;
1555 dst_pixels[2] = src_pixels->b;
1556 dst_pixels[3] = src_pixels->a;
1557 dst_pixels += 4;
1558 src_pixels++;
1559 }
1560 }
1561 }
1562 return buf;
1563 }
1564
1565 gate_result_t gate_ui_graphics_draw_image(gate_ui_graphics_t* graph, gate_rasterimage_t const* srcimage,
1566 gate_ui_point_t const* dst, gate_ui_size_t const* size, gate_ui_point_t const* srcpos)
1567 {
1568 cairo_t* cr = (cairo_t*)graph->resources[0];
1569 int width, height;
1570 GdkPixbuf* buf;
1571 gate_int32_t src_x = 0;
1572 gate_int32_t src_y = 0;
1573 gate_int32_t dst_x = 0;
1574 gate_int32_t dst_y = 0;
1575
1576 width = srcimage->width;
1577 height = srcimage->height;
1578 if (size)
1579 {
1580 width = size->width;
1581 height = size->height;
1582 }
1583 if (dst)
1584 {
1585 dst_x = dst->x;
1586 dst_y = dst->y;
1587 }
1588 if (srcpos)
1589 {
1590 src_x = srcpos->x;
1591 src_y = srcpos->y;
1592 }
1593
1594 buf = gate_ui_gtk_raster_to_pixbuf(srcimage, src_x, src_y, width, height);
1595 if (buf == NULL)
1596 {
1597 return GATE_RESULT_OUTOFRESOURCES;
1598 }
1599
1600 gdk_cairo_set_source_pixbuf(cr, buf, dst_x, dst_y);
1601 cairo_paint(cr);
1602 g_object_unref(buf);
1603
1604 return GATE_RESULT_OK;
1605 }
1606
1607
1608 gate_result_t gate_ui_graphics_line(gate_ui_graphics_t* graph, gate_ui_point_t from, gate_ui_point_t to, gate_ui_color_t col, gate_uint32_t linewidth)
1609 {
1610 cairo_t* cr = (cairo_t*)graph->resources[0];
1611
1612 cairo_set_source_rgba(cr, (double)col.r / 255.0, (double)col.g / 255.0, (double)col.b / 255.0, (double)col.a / 255.0);
1613 cairo_set_line_width(cr, (double)linewidth);
1614 cairo_move_to(cr, from.x, from.y);
1615 cairo_line_to(cr, to.x, to.y);
1616 cairo_stroke(cr);
1617 return GATE_RESULT_OK;
1618 }
1619 gate_result_t gate_ui_graphics_rect(gate_ui_graphics_t* graph, gate_ui_position_t rect, gate_ui_color_t const* colline, gate_uint32_t linewidth, gate_ui_color_t const* colfill)
1620 {
1621 cairo_t* cr = (cairo_t*)graph->resources[0];
1622
1623 if (colfill)
1624 {
1625 cairo_set_source_rgba(cr, (double)colfill->r / 255.0, (double)colfill->g / 255.0, (double)colfill->b / 255.0, (double)colfill->a / 255.0);
1626 cairo_rectangle(cr, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
1627 cairo_fill(cr);
1628 }
1629
1630 if (colline)
1631 {
1632 cairo_set_source_rgba(cr, (double)colline->r / 255.0, (double)colline->g / 255.0, (double)colline->b / 255.0, (double)colline->a / 255.0);
1633 cairo_set_line_width(cr, (double)linewidth);
1634 cairo_rectangle(cr, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
1635 cairo_stroke(cr);
1636 }
1637
1638 return GATE_RESULT_OK;
1639 }
1640 gate_result_t gate_ui_graphics_polygon(gate_ui_graphics_t* graph, gate_ui_point_t const* points, gate_size_t pointcount, gate_ui_color_t const* colline, gate_uint32_t linewidth, gate_ui_color_t const* colfill)
1641 {
1642 cairo_t* cr = (cairo_t*)graph->resources[0];
1643
1644 if (pointcount > 2)
1645 {
1646 cairo_move_to(cr, points->x, points->y);
1647 --pointcount;
1648 ++points;
1649
1650 while (pointcount-- != 0)
1651 {
1652 cairo_line_to(cr, points->x, points->y);
1653 cairo_move_to(cr, points->x, points->y);
1654 ++points;
1655 }
1656
1657 if (colfill)
1658 {
1659 cairo_set_source_rgba(cr, (double)colfill->r / 255.0, (double)colfill->g / 255.0, (double)colfill->b / 255.0, (double)colfill->a / 255.0);
1660 if (colline)
1661 {
1662 cairo_fill_preserve(cr);
1663 }
1664 else
1665 {
1666 cairo_fill(cr);
1667 }
1668 }
1669
1670 if (colline)
1671 {
1672 cairo_set_source_rgba(cr, (double)colline->r / 255.0, (double)colline->g / 255.0, (double)colline->b / 255.0, (double)colline->a / 255.0);
1673 cairo_set_line_width(cr, (double)linewidth);
1674 cairo_stroke(cr);
1675 }
1676
1677 }
1678 return GATE_RESULT_OK;
1679 }
1680
1681 gate_result_t gate_ui_graphics_get_char_size(gate_ui_graphics_t* graph, gate_ui_font_t const* font, gate_char32_t const* chars, gate_size_t charcount, gate_int32_t* textlens)
1682 {
1683 return GATE_RESULT_NOTIMPLEMENTED;
1684 }
1685
1686 gate_result_t gate_ui_graphics_get_text_size(gate_ui_graphics_t* graph, gate_ui_font_t const* font, gate_string_t const* text, gate_int32_t* width, gate_int32_t* height)
1687 {
1688 cairo_t* cr = (cairo_t*)graph->resources[0];
1689 cairo_scaled_font_t* sf = cairo_get_scaled_font(cr);
1690 cairo_text_extents_t extents;
1691 gate_cstrbuffer_t buffer;
1692 if(NULL == gate_cstrbuffer_create_string(&buffer, text, false))
1693 {
1694 return GATE_RESULT_OUTOFMEMORY;
1695 }
1696 cairo_set_font_size(cr, font->size);
1697 cairo_text_extents(cr, gate_cstrbuffer_get(&buffer), &extents);
1698 if (width) *width = (gate_int32_t)extents.width + 0.5;
1699 if (height) *height = (gate_int32_t)extents.height + 0.5;
1700 return GATE_RESULT_OK;
1701 }
1702
1703 gate_result_t gate_ui_graphics_print(gate_ui_graphics_t* graph, gate_ui_font_t const* font, gate_string_t const* text, gate_ui_position_t const* pos)
1704 {
1705 cairo_t* cr = (cairo_t*)graph->resources[0];
1706 gate_cstrbuffer_t buffer;
1707 if(NULL == gate_cstrbuffer_create_string(&buffer, text, false))
1708 {
1709 return GATE_RESULT_OUTOFMEMORY;
1710 }
1711 cairo_set_source_rgb(cr, font->color.r / 255.0, font->color.g / 255.0, font->color.b / 255.0);
1712 cairo_set_font_size(cr, font->size);
1713 cairo_move_to(cr, (double)pos->pos.x, (double)pos->pos.y);
1714 cairo_show_text(cr, gate_cstrbuffer_get(&buffer));
1715 /*
1716 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
1717
1718 cairo_select_font_face(cr, "Purisa",
1719 CAIRO_FONT_SLANT_NORMAL,
1720 CAIRO_FONT_WEIGHT_BOLD);
1721
1722 cairo_set_font_size(cr, 13);
1723
1724 cairo_move_to(cr, 20, 30);
1725 cairo_show_text(cr, "Most relationships seem so transitory");
1726 cairo_move_to(cr, 20, 60);
1727 cairo_show_text(cr, "They're all good but not the permanent one");
1728
1729 cairo_move_to(cr, 20, 120);
1730 cairo_show_text(cr, "Who doesn't long for someone to hold");
1731
1732 cairo_move_to(cr, 20, 150);
1733 cairo_show_text(cr, "Who knows how to love you without being told");
1734 cairo_move_to(cr, 20, 180);
1735 cairo_show_text(cr, "Somebody tell me why I'm on my own");
1736 cairo_move_to(cr, 20, 210);
1737 cairo_show_text(cr, "If there's a soulmate for everyone");
1738
1739 */
1740 return GATE_RESULT_OK;
1741 }
1742
1743 void* gate_ui_graphics_handle(gate_ui_graphics_t* graph)
1744 {
1745 return graph->resources[0];
1746 }
1747 void* gate_ui_graphics_surface(gate_ui_graphics_t* graph)
1748 {
1749 return graph->resources[1];
1750 }
1751
1752
1753
1754
1755
1756 /************
1757 * icon GTK *
1758 ************/
1759
1760 /* https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html */
1761
1762 gate_result_t gate_ui_icon_create_stock(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_uint32_t stock_id, gate_uint32_t flags)
1763 {
1764 gate_result_t ret = GATE_RESULT_OK;
1765 char const* gtk_stock_id = NULL;
1766 GtkIconTheme* theme = NULL;
1767 GtkIconInfo* info = NULL;
1768 gint size;
1769 GError* error = NULL;
1770 GdkPixbuf* pixbuf = NULL;
1771
1772 do
1773 {
1774 if (GATE_FLAG_ENABLED(flags, GATE_UI_ICON_FLAG_LARGE))
1775 {
1776 size = 48;
1777 }
1778 else if (GATE_FLAG_ENABLED(flags, GATE_UI_ICON_FLAG_SMALL))
1779 {
1780 size = 16;
1781 }
1782 else
1783 {
1784 size = 32;
1785 }
1786
1787 theme = gtk_icon_theme_get_default();
1788 if (theme == NULL)
1789 {
1790 ret = GATE_RESULT_NOTAVAILABLE;
1791 break;
1792 }
1793
1794 switch (stock_id)
1795 {
1796 case GATE_UI_ICON_STOCK_APP: gtk_stock_id = "system-run"; break;
1797 case GATE_UI_ICON_STOCK_DOCUMENT: gtk_stock_id = "document-properties"; break;
1798 case GATE_UI_ICON_STOCK_FOLDER: gtk_stock_id = "folder"; break;
1799 case GATE_UI_ICON_STOCK_FOLDEROPEN: gtk_stock_id = "folder-open"; break;
1800 case GATE_UI_ICON_STOCK_NEWFILE: gtk_stock_id = "document-new"; break;
1801 case GATE_UI_ICON_STOCK_OPENFILE: gtk_stock_id = "document-open"; break;
1802 case GATE_UI_ICON_STOCK_SAVEFILE: gtk_stock_id = "document-save"; break;
1803 case GATE_UI_ICON_STOCK_PRINTER: gtk_stock_id = "document-print"; break;
1804 case GATE_UI_ICON_STOCK_CUT: gtk_stock_id = "edit-cut"; break;
1805 case GATE_UI_ICON_STOCK_COPY: gtk_stock_id = "edit-copy"; break;
1806 case GATE_UI_ICON_STOCK_PASTE: gtk_stock_id = "edit-paste"; break;
1807 case GATE_UI_ICON_STOCK_DELETE: gtk_stock_id = "edit-delete"; break;
1808
1809 case GATE_UI_ICON_STOCK_FIND: gtk_stock_id = "edit-find"; break;
1810 case GATE_UI_ICON_STOCK_HELP: gtk_stock_id = "help-contents"; break;
1811
1812 case GATE_UI_ICON_STOCK_STORAGE: gtk_stock_id = "drive-harddisk"; break;
1813 case GATE_UI_ICON_STOCK_COMPUTER: gtk_stock_id = "computer"; break;
1814 case GATE_UI_ICON_STOCK_NETWORK: gtk_stock_id = "network-wired"; break;
1815 case GATE_UI_ICON_STOCK_GLOBE: gtk_stock_id = "applications-internet"; break;
1816 case GATE_UI_ICON_STOCK_SETTINGS: gtk_stock_id = "preferences-system"; break;
1817 case GATE_UI_ICON_STOCK_HOME: gtk_stock_id = "go-home"; break;
1818 case GATE_UI_ICON_STOCK_IMAGE: gtk_stock_id = "image-x-generic"; break;
1819 case GATE_UI_ICON_STOCK_AUDIO: gtk_stock_id = "audio-x-generic"; break;
1820 case GATE_UI_ICON_STOCK_VIDEO: gtk_stock_id = "video-x-generic"; break;
1821 case GATE_UI_ICON_STOCK_MAIL: gtk_stock_id = "mail-send-receive"; break;
1822 default: break;
1823 }
1824
1825 info = gtk_icon_theme_lookup_icon(theme, gtk_stock_id, size, GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_GENERIC_FALLBACK);
1826 if (info == NULL)
1827 {
1828 ret = GATE_RESULT_NOMATCH;
1829 break;
1830 }
1831
1832 pixbuf = gtk_icon_info_load_icon(info, &error);
1833 if (pixbuf == NULL)
1834 {
1835 ret = GATE_RESULT_FAILED;
1836 break;
1837 }
1838
1839 gate_mem_clear(icon, sizeof(gate_ui_icon_t));
1840 icon->host = host;
1841 icon->flags = flags & (GATE_UI_ICON_FLAG_SMALL | GATE_UI_ICON_FLAG_LARGE);
1842 icon->resources[0] = pixbuf;
1843
1844 ret = GATE_RESULT_OK;
1845 } while (0);
1846
1847 return ret;
1848 }
1849 gate_result_t gate_ui_icon_create_native(gate_ui_icon_t* icon, gate_ui_host_t* host, void* handle, gate_uint32_t flags)
1850 {
1851 gate_mem_clear(icon, sizeof(gate_ui_icon_t));
1852 icon->host = host;
1853 icon->flags = flags;
1854 icon->resources[0] = handle;
1855 return GATE_RESULT_OK;
1856 }
1857 gate_result_t gate_ui_icon_create_image(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_rasterimage_t const* image)
1858 {
1859 GdkPixbuf* buf = gate_ui_gtk_raster_to_pixbuf(image, 0, 0, image->width, image->height);
1860 if (buf == NULL)
1861 {
1862 return GATE_RESULT_OUTOFRESOURCES;
1863 }
1864 gate_mem_clear(icon, sizeof(gate_ui_icon_t));
1865 icon->host = host;
1866 icon->flags = 0;
1867 icon->resources[0] = buf;
1868 return GATE_RESULT_OK;
1869 }
1870 gate_result_t gate_ui_icon_create_file(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_string_t const* filepath)
1871 {
1872 gate_result_t ret = GATE_RESULT_FAILED;
1873 char file_buffer[GATE_MAX_FILEPATH_LENGTH];
1874 GtkWidget* image_widget = NULL;
1875 gint pix_size = 0;
1876 gate_uint32_t flags = 0;
1877
1878 GATE_STRING_TO_BUFFER(filepath, file_buffer);
1879 image_widget = gtk_image_new_from_file(file_buffer);
1880 if (image_widget != NULL)
1881 {
1882 pix_size = gtk_image_get_pixel_size(GTK_IMAGE(image_widget));
1883 if (pix_size < 24) flags |= GATE_UI_ICON_FLAG_SMALL;
1884 if (pix_size > 40) flags |= GATE_UI_ICON_FLAG_LARGE;
1885 ret = gate_ui_icon_create_native(icon, host, image_widget, flags);
1886 if (GATE_FAILED(ret))
1887 {
1888 gtk_widget_destroy(image_widget);
1889 }
1890 }
1891 return ret;
1892 }
1893 gate_result_t gate_ui_icon_copy(gate_ui_icon_t* dsticon, gate_ui_icon_t const* srcicon)
1894 {
1895 gate_mem_copy(dsticon, srcicon, sizeof(gate_ui_icon_t));
1896 if (!GATE_FLAG_ENABLED(srcicon->flags, GATE_UI_ICON_FLAG_STOCK))
1897 {
1898 if (srcicon->resources[0])
1899 {
1900 dsticon->resources[0] = g_object_ref((gpointer)srcicon->resources[0]);
1901 }
1902 }
1903 return GATE_RESULT_OK;
1904 }
1905 gate_result_t gate_ui_icon_destroy(gate_ui_icon_t* icon)
1906 {
1907 if (icon->resources[0])
1908 {
1909 g_object_unref((gpointer)icon->resources[0]);
1910 }
1911 gate_mem_clear(icon, sizeof(gate_ui_icon_t));
1912 return GATE_RESULT_OK;
1913 }
1914
1915
1916
1917
1918
1919 /****************
1920 * iconlist GTK *
1921 ****************/
1922
1923 gate_result_t gate_ui_iconlist_create(gate_ui_iconlist_t* ilst, gate_ui_host_t* host, gate_int32_t width, gate_int32_t height)
1924 {
1925 gate_result_t ret = GATE_RESULT_FAILED;
1926 do
1927 {
1928 gate_mem_clear(ilst, sizeof(gate_ui_iconlist_t));
1929 ilst->resources[0] = gate_arraylist_create(sizeof(gate_ui_icon_t), NULL, 8, NULL, NULL);
1930 if (NULL == ilst->resources[0])
1931 {
1932 ret = GATE_RESULT_OUTOFMEMORY;
1933 break;
1934 }
1935 ilst->host = host;
1936 ilst->width = width;
1937 ilst->height = height;
1938 ilst->flags = 0;
1939 ret = GATE_RESULT_OK;
1940 } while (0);
1941 return ret;
1942 }
1943 gate_result_t gate_ui_iconlist_destroy(gate_ui_iconlist_t* ilst)
1944 {
1945 gate_result_t ret = GATE_RESULT_OK;
1946 gate_ui_icon_t* ptr_icon;
1947 gate_size_t count;
1948 gate_arraylist_t arr;
1949 do
1950 {
1951 arr = (gate_arraylist_t)ilst->resources[0];
1952 if (!arr)
1953 {
1954 break;
1955 }
1956 count = gate_arraylist_length(arr);
1957 if (count != 0)
1958 {
1959 ptr_icon = gate_arraylist_get(arr, 0);
1960 while (count-- != 0)
1961 {
1962 gate_ui_icon_destroy(ptr_icon);
1963 ++ptr_icon;
1964 }
1965 }
1966 gate_arraylist_release(arr);
1967 ret = GATE_RESULT_OK;
1968 } while (0);
1969 return ret;
1970 }
1971 gate_size_t gate_ui_iconlist_count(gate_ui_iconlist_t* ilst)
1972 {
1973 gate_size_t ret = 0;
1974 gate_arraylist_t arr = (gate_arraylist_t)ilst->resources[0];
1975 if (arr)
1976 {
1977 ret = gate_arraylist_length(arr);
1978 }
1979 return ret;
1980 }
1981 gate_result_t gate_ui_iconlist_add(gate_ui_iconlist_t* ilst, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
1982 {
1983 gate_ui_icon_t new_icon = GATE_INIT_EMPTY;
1984 gate_arraylist_t arr = (gate_arraylist_t)ilst->resources[0];
1985 gate_result_t ret = gate_ui_icon_copy(&new_icon, icon);
1986 gate_size_t index;
1987 if (GATE_SUCCEEDED(ret))
1988 {
1989 index = gate_arraylist_length(arr);
1990 if (NULL == gate_arraylist_add(arr, &new_icon))
1991 {
1992 ret = GATE_RESULT_OUTOFMEMORY;
1993 gate_ui_icon_destroy(&new_icon);
1994 }
1995 else
1996 {
1997 if (icon_key)
1998 {
1999 *icon_key = (gate_intptr_t)index;
2000 }
2001 }
2002 }
2003 return ret;
2004 }
2005 gate_result_t gate_ui_iconlist_add_image(gate_ui_iconlist_t* ilst, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
2006 {
2007 gate_ui_icon_t new_icon = GATE_INIT_EMPTY;
2008 gate_arraylist_t arr = (gate_arraylist_t)ilst->resources[0];
2009 gate_result_t ret = gate_ui_icon_create_image(&new_icon, ilst->host, image);
2010 gate_size_t index;
2011 if (GATE_SUCCEEDED(ret))
2012 {
2013 index = gate_arraylist_length(arr);
2014 if (NULL == gate_arraylist_add(arr, &new_icon))
2015 {
2016 ret = GATE_RESULT_OUTOFMEMORY;
2017 gate_ui_icon_destroy(&new_icon);
2018 }
2019 else
2020 {
2021 if (icon_key)
2022 {
2023 *icon_key = (gate_intptr_t)index;
2024 }
2025 }
2026 }
2027 return ret;
2028 }
2029 gate_result_t gate_ui_iconlist_get(gate_ui_iconlist_t* ilst, gate_intptr_t icon_key, gate_ui_icon_t* icon)
2030 {
2031 gate_result_t ret = GATE_RESULT_FAILED;
2032 gate_ui_icon_t new_icon = GATE_INIT_EMPTY;
2033 gate_arraylist_t arr = (gate_arraylist_t)ilst->resources[0];
2034 gate_ui_icon_t const* ptr_icon = NULL;
2035
2036 ptr_icon = (gate_ui_icon_t const*)gate_arraylist_get(arr, (gate_size_t)icon_key);
2037 if (NULL == ptr_icon)
2038 {
2039 ret = GATE_RESULT_NOTAVAILABLE;
2040 }
2041 else
2042 {
2043 ret = gate_ui_icon_copy(icon, ptr_icon);
2044 }
2045 return ret;
2046 }
2047
2048
2049
2050 /**************
2051 * cursor GTK *
2052 **************/
2053
2054 gate_result_t gate_ui_cursor_create_stock(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_uint32_t stock_id)
2055 {
2056 gate_result_t ret = GATE_RESULT_FAILED;
2057 char const* cursor_name = NULL;
2058 GdkCursor* gdk_cursor = NULL;
2059 GdkDisplay* display = NULL;
2060
2061 switch (stock_id)
2062 {
2063 case GATE_UI_CURSOR_STOCK_POINTER: cursor_name = "default"; break;
2064 case GATE_UI_CURSOR_STOCK_BUSY: cursor_name = "wait"; break;
2065 case GATE_UI_CURSOR_STOCK_STARTING: cursor_name = "progress"; break;
2066 case GATE_UI_CURSOR_STOCK_HAND: cursor_name = "pointer"; break;
2067 case GATE_UI_CURSOR_STOCK_TEXT: cursor_name = "text"; break;
2068 case GATE_UI_CURSOR_STOCK_REJECTED: cursor_name = "not-allowed"; break;
2069 case GATE_UI_CURSOR_STOCK_SIZE_ALL: cursor_name = "all-scroll"; break;
2070 case GATE_UI_CURSOR_STOCK_SIZE_LEFTRIGHT: cursor_name = "ew-resize"; break;
2071 case GATE_UI_CURSOR_STOCK_SIZE_UPDOWN: cursor_name = "ns-resize"; break;
2072 case GATE_UI_CURSOR_STOCK_SIZE_LEFTUPRIGHTDOWN: cursor_name = "nwse-resize"; break;
2073 case GATE_UI_CURSOR_STOCK_SIZE_RIGHTUPKEFTDOWN: cursor_name = "nesw-resize"; break;
2074 }
2075 if (cursor_name == NULL)
2076 {
2077 ret = GATE_RESULT_NOTSUPPORTED;
2078 }
2079 else
2080 {
2081 gdk_cursor = gdk_cursor_new_from_name(display, cursor_name);
2082 if (NULL == gdk_cursor)
2083 {
2084 ret = GATE_RESULT_FAILED;
2085 }
2086 else
2087 {
2088 cursor->resources[0] = gdk_cursor;
2089 cursor->resources[1] = display;
2090 cursor->host = host;
2091 cursor->flags = GATE_UI_CURSOR_FLAG_STOCK;
2092 ret = GATE_RESULT_OK;
2093 }
2094 }
2095 return ret;
2096 }
2097 gate_result_t gate_ui_cursor_create_native(gate_ui_cursor_t* cursor, gate_ui_host_t* host, void* handle, gate_uint32_t flags)
2098 {
2099 cursor->resources[0] = handle;
2100 cursor->resources[1] = gdk_cursor_get_image((GdkCursor*)handle);
2101 cursor->host = host;
2102 cursor->flags = flags;
2103 return GATE_RESULT_OK;
2104 }
2105 gate_result_t gate_ui_cursor_create_image(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_rasterimage_t const* image,
2106 gate_uint16_t x, gate_uint16_t y)
2107 {
2108 return GATE_RESULT_NOTIMPLEMENTED;
2109 }
2110 gate_result_t gate_ui_cursor_create_file(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_string_t const* filepath)
2111 {
2112 return GATE_RESULT_NOTIMPLEMENTED;
2113 }
2114 gate_result_t gate_ui_cursor_copy(gate_ui_cursor_t* dstcursor, gate_ui_cursor_t const* srccursor)
2115 {
2116 GdkCursor* gdk_src_cursor = (GdkCursor*)dstcursor->resources[0];
2117 GdkCursor* gdk_dst_cursor = gdk_cursor_new_from_pixbuf((GdkDisplay*)srccursor->resources[1], gdk_cursor_get_image(gdk_src_cursor), -1, -1);
2118 if (gdk_dst_cursor)
2119 {
2120 dstcursor->resources[0] = gdk_dst_cursor;
2121 dstcursor->resources[1] = srccursor->resources[1];
2122 dstcursor->host = srccursor->host;
2123 dstcursor->flags = srccursor->flags;
2124 return GATE_RESULT_OK;
2125 }
2126 else
2127 {
2128 return GATE_RESULT_FAILED;
2129 }
2130 }
2131 gate_result_t gate_ui_cursor_destroy(gate_ui_cursor_t* cursor)
2132 {
2133 GdkCursor* gdk_cursor = (GdkCursor*)cursor->resources[0];
2134 if (gdk_cursor)
2135 {
2136 g_object_unref(gdk_cursor);
2137 }
2138 gate_mem_clear(cursor, sizeof(gate_ui_cursor_t));
2139 return GATE_RESULT_OK;
2140 }
2141
2142 #endif /* GATE_UI_GTK */
2143
2144
2145
2146 #if defined(GATE_UI_MOTIF)
2147
2148 #include "gate/ui/gateui_motif.h"
2149
2150 2 gate_result_t gate_ui_graphics_create_virtual(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_uint32_t width, gate_uint32_t height)
2151 {
2152 2 return gate_ui_graphics_create_image(graph, host, width, height, 0);
2153 }
2154 5 gate_result_t gate_ui_graphics_create_image(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_uint32_t width, gate_uint32_t height, gate_uint32_t depth)
2155 {
2156 5 gate_result_t ret = GATE_RESULT_FAILED;
2157
2158 do
2159 {
2160 Display* display;
2161 int screen;
2162 int xdepth;
2163 Window root_window;
2164 Pixmap pixmap;
2165 GC context;
2166
2167 5 gate_mem_clear(graph, sizeof(gate_ui_graphics_t));
2168
2169 5 display = GATE_UI_MOTIF_GET_HOST_DISPLAY(host);
2170 5 screen = XDefaultScreen(display);
2171
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 xdepth = (depth == 0) ? XDefaultDepth(display, screen) : depth;
2172 5 root_window = XDefaultRootWindow(display);
2173 5 pixmap = XCreatePixmap(display, root_window, width, height, xdepth);
2174 5 context = XCreateGC(display, root_window, 0, 0);
2175 5 XFillRectangle(display, pixmap, context, 0, 0, width, height);
2176
2177 5 graph->host = host;
2178 5 graph->resources[0] = (void*)context;
2179 5 graph->resources[1] = (void*)(Drawable)pixmap;
2180 5 graph->width = width;
2181 5 graph->height = height;
2182
2183 5 XSetGraphicsExposures(display, context, 0);
2184 5 ret = GATE_RESULT_OK;
2185 } while (0);
2186 5 return ret;
2187 }
2188 2 gate_result_t gate_ui_graphics_create_image_from(gate_ui_graphics_t* graph, gate_ui_host_t* host, gate_rasterimage_t const* rasterimage)
2189 {
2190 gate_result_t ret;
2191 do
2192 {
2193 2 ret = gate_ui_graphics_create_image(graph, host, rasterimage->width, rasterimage->height, 0);
2194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
2195
2196 2 ret = gate_ui_graphics_draw_image(graph, rasterimage, NULL, NULL, NULL);
2197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (GATE_FAILED(ret))
2198 {
2199 gate_ui_graphics_destroy(graph);
2200 break;
2201 }
2202
2203 2 ret = GATE_RESULT_OK;
2204 } while (0);
2205
2206 2 return ret;
2207 }
2208 2 gate_result_t gate_ui_graphics_create_ctrl(gate_ui_graphics_t* graph, gate_ui_ctrl_t* ctrl)
2209 {
2210 2 gate_result_t ret = GATE_RESULT_FAILED;
2211 do
2212 {
2213 2 gate_ui_host_t* host = GATE_UI_MOTIF_GET_CTRL_HOST(ctrl);
2214 2 Display* display = GATE_UI_MOTIF_GET_HOST_DISPLAY(host);
2215 2 Widget w = GATE_UI_MOTIF_GET_CTRL_WIDGET(ctrl);
2216 2 Window wnd = XtWindow(w);
2217 2 Dimension xwidth = 0, xheight = 0;
2218 2 GC context = XCreateGC(display, wnd, 0, NULL);
2219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!context)
2220 {
2221 ret = GATE_RESULT_OUTOFRESOURCES;
2222 break;
2223 }
2224 2 XtVaGetValues(w, XtNwidth, &xwidth, XtNheight, &xheight, NULL, NULL);
2225
2226 2 graph->host = host;
2227 2 graph->resources[0] = (void*)context;
2228 2 graph->resources[1] = (void*)(Drawable)wnd;
2229 2 graph->resources[2] = (void*)wnd;
2230 2 graph->width = xwidth;
2231 2 graph->height = xheight;
2232
2233 2 XSetGraphicsExposures(display, context, 0);
2234 2 ret = GATE_RESULT_OK;
2235 } while (0);
2236 2 return ret;
2237 }
2238 gate_result_t gate_ui_graphics_create_native(gate_ui_graphics_t* graph, gate_ui_host_t* host, void* graphics, void* param, gate_int32_t width, gate_int32_t height)
2239 {
2240 return GATE_RESULT_NOTIMPLEMENTED;
2241 }
2242 7 gate_result_t gate_ui_graphics_destroy(gate_ui_graphics_t* graph)
2243 {
2244 7 Display* display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2245 7 GC context = (GC)graph->resources[0];
2246 7 Drawable drawable = (Drawable)graph->resources[1];
2247 7 Window window = (Window)graph->resources[2];
2248
2249
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (display)
2250 {
2251
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (window == 0)
2252 {
2253 /* no window, expect a Pixmap surface */
2254
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (drawable != 0)
2255 {
2256 4 XFreePixmap(display, (Pixmap)drawable);
2257 }
2258 }
2259 else
2260 {
2261 }
2262
2263
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (context)
2264 {
2265 7 XFreeGC(display, context);
2266 }
2267 }
2268
2269 7 return GATE_RESULT_NOTIMPLEMENTED;
2270 }
2271
2272 407 static unsigned long XGetRgbPixel(Display* display, gate_uint8_t r, gate_uint8_t g, gate_uint8_t b)
2273 {
2274 407 int screen = XDefaultScreen(display);
2275 407 Colormap cmap = XDefaultColormap(display, screen);
2276 XColor col;
2277 407 col.pixel = 0;
2278 407 col.red = ((gate_uint16_t)r) << 8;
2279 407 col.green = ((gate_uint16_t)g) << 8;
2280 407 col.blue = ((gate_uint16_t)b) << 8;
2281 407 col.flags = DoRed | DoGreen | DoBlue;
2282 407 XAllocColor(display, cmap, &col);
2283 407 return col.pixel;
2284 }
2285
2286 2 gate_int32_t gate_ui_graphics_width(gate_ui_graphics_t* graph)
2287 {
2288 2 return graph->width;
2289 }
2290
2291 2 gate_int32_t gate_ui_graphics_height(gate_ui_graphics_t* graph)
2292 {
2293 2 return graph->height;
2294 }
2295
2296 2 gate_result_t gate_ui_graphics_set_pixel(gate_ui_graphics_t* graph, gate_ui_point_t pos, gate_ui_color_t col)
2297 {
2298 2 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2299 2 GC const context = (GC)graph->resources[0];
2300 2 Drawable const drawable = (Drawable)graph->resources[1];
2301
2302 2 XSetForeground(display, context, XGetRgbPixel(display, col.r, col.g, col.b));
2303 2 XDrawPoint(display, drawable, context, pos.x, pos.y);
2304 2 return GATE_RESULT_OK;
2305 }
2306
2307 2 gate_result_t gate_ui_graphics_get_pixel(gate_ui_graphics_t* graph, gate_ui_point_t pos, gate_ui_color_t* col)
2308 {
2309 2 return GATE_RESULT_NOTIMPLEMENTED;
2310 }
2311
2312 2 gate_result_t gate_ui_graphics_draw(gate_ui_graphics_t* graph, gate_ui_graphics_t* srcgraph,
2313 gate_ui_point_t const* dst, gate_ui_size_t const* size, gate_ui_point_t const* srcpos)
2314 {
2315 2 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2316 2 GC const context = (GC)graph->resources[0];
2317 2 Drawable const target = (Drawable)graph->resources[1];
2318 2 Drawable const source = (Drawable)srcgraph->resources[1];
2319 int src_x, src_y, width, height, dst_x, dst_y;
2320 2 dst_x = dst->x;
2321 2 dst_y = dst->y;
2322 2 src_x = srcpos->x;
2323 2 src_y = srcpos->y;
2324 2 width = size->width;
2325 2 height = size->height;
2326
2327 2 XCopyArea(display, source, target, context, src_x, src_y, width, height, dst_x, dst_y);
2328 2 return GATE_RESULT_OK;
2329 }
2330
2331 2 gate_result_t gate_ui_graphics_draw_ex(gate_ui_graphics_t* graph, gate_ui_graphics_t* src_graph,
2332 gate_ui_position_t const* dest_rect, gate_ui_position_t const* src_rect)
2333 {
2334 2 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2335 2 GC const context = (GC)graph->resources[0];
2336 2 Drawable const target = (Drawable)graph->resources[1];
2337 2 Drawable const source = (Drawable)src_graph->resources[1];
2338 int src_x, src_y, width, height, dst_x, dst_y;
2339 2 dst_x = dest_rect->pos.x;
2340 2 dst_y = dest_rect->pos.y;
2341 2 src_x = src_rect->pos.x;
2342 2 src_y = src_rect->pos.y;
2343 /* TODO */
2344 2 width = dest_rect->size.width;
2345 2 height = dest_rect->size.height;
2346
2347 2 XCopyArea(display, source, target, context, src_x, src_y, width, height, dst_x, dst_y);
2348 2 return GATE_RESULT_OK;
2349 }
2350
2351 3 gate_result_t gate_ui_graphics_draw_image(gate_ui_graphics_t* graph, gate_rasterimage_t const* srcimage,
2352 gate_ui_point_t const* dst, gate_ui_size_t const* size, gate_ui_point_t const* srcpos)
2353 {
2354 3 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2355 3 GC const context = (GC)graph->resources[0];
2356 3 Drawable const drawable = (Drawable)graph->resources[1];
2357
2358 gate_color_t pixel;
2359 3 gate_uint32_t pixel_cache = 0;
2360 int src_x, src_y, width, height, dst_x, dst_y;
2361 int x, y;
2362
2363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (srcpos)
2364 {
2365 src_x = srcpos->x;
2366 src_y = srcpos->y;
2367 }
2368 else
2369 {
2370 3 src_x = 0;
2371 3 src_y = 0;
2372 }
2373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (size)
2374 {
2375 width = size->width;
2376 height = size->height;
2377 }
2378 else
2379 {
2380 3 width = srcimage->width;
2381 3 height = srcimage->height;
2382 }
2383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (dst)
2384 {
2385 dst_x = dst->x;
2386 dst_y = dst->y;
2387 }
2388 else
2389 {
2390 3 dst_x = 0;
2391 3 dst_y = 0;
2392 }
2393
2394
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 3 times.
51 for (y = 0; y != height; ++y)
2395 {
2396
2/2
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 48 times.
816 for (x = 0; x != width; ++x)
2397 {
2398 768 gate_rasterimage_get_pixel(srcimage, src_x + x, src_y + y, &pixel);
2399
2/2
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 189 times.
768 if (pixel.a > 127)
2400 {
2401
2/2
✓ Branch 0 taken 393 times.
✓ Branch 1 taken 186 times.
579 if (pixel.rgba != pixel_cache)
2402 {
2403 393 unsigned long x11_color = XGetRgbPixel(display, pixel.r, pixel.g, pixel.b);
2404 393 pixel_cache = pixel.rgba;
2405 393 XSetForeground(display, context, x11_color);
2406 }
2407 579 XDrawPoint(display, drawable, context, dst_x + x, dst_y + y);
2408 }
2409 }
2410 }
2411 3 return GATE_RESULT_OK;
2412 }
2413
2414 4 gate_result_t gate_ui_graphics_line(gate_ui_graphics_t* graph, gate_ui_point_t from, gate_ui_point_t to, gate_ui_color_t col, gate_uint32_t linewidth)
2415 {
2416 4 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2417 4 GC const context = (GC)graph->resources[0];
2418 4 Drawable const drawable = (Drawable)graph->resources[1];
2419
2420 4 XSetForeground(display, context, XGetRgbPixel(display, col.r, col.g, col.b));
2421 4 XDrawLine(display, drawable, context, from.x, from.y, to.x, to.y);
2422 4 return GATE_RESULT_OK;
2423 }
2424
2425 3 gate_result_t gate_ui_graphics_rect(gate_ui_graphics_t* graph, gate_ui_position_t rect, gate_ui_color_t const* colline, gate_uint32_t linewidth, gate_ui_color_t const* colfill)
2426 {
2427 3 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2428 3 GC const context = (GC)graph->resources[0];
2429 3 Drawable const drawable = (Drawable)graph->resources[1];
2430 unsigned long pixel;
2431
2432
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (colfill)
2433 {
2434 3 pixel = XGetRgbPixel(display, colfill->r, colfill->g, colfill->b);
2435 3 XSetForeground(display, context, pixel);
2436 3 XFillRectangle(display, drawable, context, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
2437 }
2438
2439
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (colline)
2440 {
2441 3 pixel = XGetRgbPixel(display, colline->r, colline->g, colline->b);
2442 3 XSetForeground(display, context, pixel);
2443 3 XDrawRectangle(display, drawable, context, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
2444 }
2445 3 return GATE_RESULT_OK;
2446 }
2447
2448 2 gate_result_t gate_ui_graphics_polygon(gate_ui_graphics_t* graph, gate_ui_point_t const* points, gate_size_t pointcount, gate_ui_color_t const* colline, gate_uint32_t linewidth, gate_ui_color_t const* colfill)
2449 {
2450 2 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2451 2 GC const context = (GC)graph->resources[0];
2452 2 Drawable const drawable = (Drawable)graph->resources[1];
2453 unsigned long pixel;
2454 gate_size_t ndx;
2455 XPoint xp[64];
2456
2457
2/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 if ((pointcount < 3) || ((colline == NULL) && (colfill == NULL)))
2458 {
2459 /* nothing to do */
2460 return GATE_RESULT_OK;
2461 }
2462
2463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (pointcount > 64)
2464 {
2465 pointcount = 64;
2466 }
2467
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 for (ndx = 0; ndx != pointcount; ++ndx)
2468 {
2469 10 xp[ndx].x = points[ndx].x;
2470 10 xp[ndx].y = points[ndx].y;
2471 }
2472
2473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (colfill)
2474 {
2475 pixel = XGetRgbPixel(display, colfill->r, colfill->g, colfill->b);
2476 XSetForeground(display, context, pixel);
2477 XFillPolygon(display, drawable, context, xp, (int)pointcount, Complex, CoordModeOrigin);
2478 }
2479
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (colline)
2480 {
2481 2 pixel = XGetRgbPixel(display, colline->r, colline->g, colline->b);
2482 2 XSetForeground(display, context, pixel);
2483
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for (ndx = 0; ndx != pointcount - 1; ++ndx)
2484 {
2485 8 XDrawLine(display, drawable, context, xp[ndx].x, xp[ndx].y, xp[ndx + 1].x, xp[ndx + 1].y);
2486 }
2487 2 XDrawLine(display, drawable, context, xp[pointcount - 1].x, xp[pointcount - 1].y, xp[0].x, xp[0].y);
2488 }
2489 2 return GATE_RESULT_OK;
2490 }
2491
2492 static gate_bool_t find_best_font_name(Display* display, gate_ui_font_t* font)
2493 {
2494 gate_bool_t ret = false;
2495 int max_fonts = 1024;
2496 int fonts_returned = 0;
2497 char** fonts = XListFonts(display, "*", max_fonts, &fonts_returned);
2498
2499 do
2500 {
2501 int ndx;
2502 char const* pattern = font->font_name;
2503 gate_size_t pattern_len = gate_str_length(font->font_name);
2504
2505 if (fonts == NULL)
2506 {
2507 break;
2508 }
2509 for (ndx = 0; ndx < fonts_returned; ++ndx)
2510 {
2511 char* font_name = fonts[ndx];
2512 gate_size_t font_name_len = gate_str_length(font_name);
2513 gate_size_t pos;
2514 if(font_name_len == 0)
2515 {
2516 continue;
2517 }
2518 pos = gate_str_pos(font_name, font_name_len, pattern, pattern_len, 0);
2519 if(pos != GATE_STR_NPOS)
2520 {
2521 gate_str_print_text(font->font_name, sizeof(font->font_name), font_name, font_name_len);
2522 ret = true;
2523 break;
2524 }
2525 }
2526 /* code */
2527 } while (0);
2528
2529 if(fonts != NULL)
2530 {
2531 XFreeFontNames(fonts);
2532 }
2533
2534 return ret;
2535 }
2536
2537 gate_result_t gate_ui_graphics_get_char_size(gate_ui_graphics_t* graph, gate_ui_font_t const* font, gate_char32_t const* chars, gate_size_t charcount, gate_int32_t* charlens)
2538 {
2539 return GATE_RESULT_NOTIMPLEMENTED;
2540 }
2541
2542
2543
2544 static void print_font_name(char* name_buffer, gate_size_t name_capacity, gate_ui_font_t const* font)
2545 {
2546 gate_strbuilder_t builder;
2547
2548 gate_strbuilder_create_static(&builder, name_buffer, name_capacity, 0);
2549 gate_strbuilder_append_cstr(&builder, "-");
2550 gate_strbuilder_append_cstr(&builder, font->font_name);
2551 gate_strbuilder_append_cstr(&builder, font->bold ? "-bold" : "-medium");
2552 gate_strbuilder_append_cstr(&builder, font->italic ? "-i" : "-r");
2553 gate_strbuilder_append_cstr(&builder, "-*-");
2554 gate_strbuilder_append_int32(&builder, font->size);
2555 gate_strbuilder_append_cstr(&builder, "-*");
2556 }
2557
2558 2 gate_result_t gate_ui_graphics_get_text_size(gate_ui_graphics_t* graph, gate_ui_font_t const* font, gate_string_t const* txt, gate_int32_t* width, gate_int32_t* height)
2559 {
2560 2 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2561 2 GC const context = (GC)graph->resources[0];
2562 2 Drawable const drawable = (Drawable)graph->resources[1];
2563
2564 XFontStruct* fontstruct;
2565
2566 2 fontstruct = XLoadQueryFont(display, "fixed");
2567
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (width) *width = XTextWidth(fontstruct, gate_string_ptr(txt, 0), (int)gate_string_length(txt));
2568
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (height) *height = fontstruct->ascent + fontstruct->descent;
2569 2 XFreeFont(display, fontstruct);
2570 2 return GATE_RESULT_OK;
2571 }
2572
2573 2 gate_result_t gate_ui_graphics_print(gate_ui_graphics_t* graph, gate_ui_font_t const* font, gate_string_t const* text, gate_ui_position_t const* pos)
2574 {
2575 2 Display* const display = GATE_UI_MOTIF_GET_HOST_DISPLAY(graph->host);
2576 2 GC const context = (GC)graph->resources[0];
2577 2 Drawable const drawable = (Drawable)graph->resources[1];
2578 gate_ui_font_t updated_font;
2579
2580 XFontStruct* fontstruct;
2581
2582 2 fontstruct = XLoadQueryFont(display, "fixed");
2583
2584 2 XSetFont(display, context, fontstruct->fid);
2585 2 XDrawString(display, drawable, context, pos->pos.x, pos->pos.y + fontstruct->ascent, text->str, text->length);
2586
2587 2 XFreeFont(display, fontstruct);
2588 2 return GATE_RESULT_OK;
2589 }
2590
2591 void* gate_ui_graphics_handle(gate_ui_graphics_t* graph)
2592 {
2593 return graph->resources[0];
2594 }
2595 1 void* gate_ui_graphics_surface(gate_ui_graphics_t* graph)
2596 {
2597 1 return graph->resources[1];
2598 }
2599
2600
2601
2602
2603 gate_result_t gate_ui_icon_create_stock(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_uint32_t stock_id, gate_uint32_t flags)
2604 {
2605 return GATE_RESULT_NOTIMPLEMENTED;
2606 }
2607 gate_result_t gate_ui_icon_create_native(gate_ui_icon_t* icon, gate_ui_host_t* host, void* handle, gate_uint32_t flags)
2608 {
2609 return GATE_RESULT_NOTIMPLEMENTED;
2610 }
2611 gate_result_t gate_ui_icon_create_image(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_rasterimage_t const* image)
2612 {
2613 return GATE_RESULT_NOTIMPLEMENTED;
2614 }
2615 gate_result_t gate_ui_icon_create_file(gate_ui_icon_t* icon, gate_ui_host_t* host, gate_string_t const* filepath)
2616 {
2617 return GATE_RESULT_NOTIMPLEMENTED;
2618 }
2619 gate_result_t gate_ui_icon_copy(gate_ui_icon_t* dsticon, gate_ui_icon_t const* srcicon)
2620 {
2621 return GATE_RESULT_NOTIMPLEMENTED;
2622 }
2623 gate_result_t gate_ui_icon_destroy(gate_ui_icon_t* icon)
2624 {
2625 return GATE_RESULT_NOTIMPLEMENTED;
2626 }
2627
2628
2629
2630 gate_result_t gate_ui_iconlist_create(gate_ui_iconlist_t* ilst, gate_ui_host_t* host, gate_int32_t width, gate_int32_t height)
2631 {
2632 return GATE_RESULT_NOTIMPLEMENTED;
2633 }
2634 gate_result_t gate_ui_iconlist_destroy(gate_ui_iconlist_t* ilst)
2635 {
2636 return GATE_RESULT_NOTIMPLEMENTED;
2637 }
2638 gate_size_t gate_ui_iconlist_count(gate_ui_iconlist_t* ilst)
2639 {
2640 return 0;
2641 }
2642 gate_result_t gate_ui_iconlist_add(gate_ui_iconlist_t* ilst, gate_ui_icon_t const* icon, gate_intptr_t* icon_key)
2643 {
2644 return GATE_RESULT_NOTIMPLEMENTED;
2645 }
2646 gate_result_t gate_ui_iconlist_add_image(gate_ui_iconlist_t* ilst, gate_rasterimage_t const* image, gate_intptr_t* icon_key)
2647 {
2648 return GATE_RESULT_NOTIMPLEMENTED;
2649 }
2650 gate_result_t gate_ui_iconlist_get(gate_ui_iconlist_t* ilst, gate_intptr_t icon_key, gate_ui_icon_t* icon)
2651 {
2652 return GATE_RESULT_NOTIMPLEMENTED;
2653 }
2654
2655
2656
2657
2658
2659 gate_result_t gate_ui_cursor_create_stock(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_uint32_t stock_id)
2660 {
2661 return GATE_RESULT_NOTIMPLEMENTED;
2662 }
2663 gate_result_t gate_ui_cursor_create_native(gate_ui_cursor_t* cursor, gate_ui_host_t* host, void* handle, gate_uint32_t flags)
2664 {
2665 return GATE_RESULT_NOTIMPLEMENTED;
2666 }
2667 gate_result_t gate_ui_cursor_create_image(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_rasterimage_t const* image,
2668 gate_uint16_t x, gate_uint16_t y)
2669 {
2670 return GATE_RESULT_NOTIMPLEMENTED;
2671 }
2672 gate_result_t gate_ui_cursor_create_file(gate_ui_cursor_t* cursor, gate_ui_host_t* host, gate_string_t const* filepath)
2673 {
2674 return GATE_RESULT_NOTIMPLEMENTED;
2675 }
2676 gate_result_t gate_ui_cursor_copy(gate_ui_cursor_t* dstcursor, gate_ui_cursor_t const* srccursor)
2677 {
2678 return GATE_RESULT_NOTIMPLEMENTED;
2679 }
2680 gate_result_t gate_ui_cursor_destroy(gate_ui_cursor_t* cursor)
2681 {
2682 return GATE_RESULT_NOTIMPLEMENTED;
2683 }
2684
2685
2686 #endif /* GATE_UI_MOTIF */
2687