source: mainline/uspace/app/viewer/viewer.c@ 2c9fdeed

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

Port viewer to UI

  • Property mode set to 100644
File size: 7.7 KB
RevLine 
[3e896e1]1/*
[2c9fdeed]2 * Copyright (c) 2020 Jiri Svoboda
[3e896e1]3 * Copyright (c) 2013 Martin Decky
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
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup viewer
31 * @{
32 */
33/** @file
34 */
35
[2bb6d04]36#include <draw/surface.h>
37#include <draw/codec.h>
[2c9fdeed]38#include <errno.h>
39#include <stdbool.h>
40#include <stdio.h>
41#include <stdlib.h>
[1d6dd2a]42#include <str.h>
[2c9fdeed]43#include <ui/image.h>
44#include <ui/ui.h>
45#include <ui/wdecor.h>
46#include <ui/window.h>
47#include <vfs/vfs.h>
[3e896e1]48
49#define NAME "viewer"
50
[2c9fdeed]51typedef struct {
52 ui_t *ui;
53} viewer_t;
[c064b58]54
[3e896e1]55static size_t imgs_count;
56static size_t imgs_current = 0;
57static char **imgs;
58
[2c9fdeed]59static ui_window_t *window;
[3e896e1]60static surface_t *surface = NULL;
[2c9fdeed]61static ui_image_t *image = NULL;
62static gfx_context_t *window_gc;
[3e896e1]63
[c064b58]64static surface_coord_t img_width;
65static surface_coord_t img_height;
66
67static bool img_load(const char *, surface_t **);
[2c9fdeed]68static bool img_setup(gfx_context_t *, surface_t *);
[3e896e1]69
[2c9fdeed]70static void wnd_close(ui_window_t *, void *);
71static void wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
72
73static ui_window_cb_t window_cb = {
74 .close = wnd_close,
75 .kbd = wnd_kbd_event
76};
77
78/** Window close request
79 *
80 * @param window Window
81 * @param arg Argument (calc_t *)
82 */
83static void wnd_close(ui_window_t *window, void *arg)
84{
85 viewer_t *viewer = (viewer_t *) arg;
86
87 ui_quit(viewer->ui);
88}
89
90static void wnd_kbd_event(ui_window_t *window, void *arg,
91 kbd_event_t *event)
[3e896e1]92{
93 bool update = false;
[a35b458]94
[3e896e1]95 if ((event->type == KEY_PRESS) && (event->c == 'q'))
96 exit(0);
[a35b458]97
[3e896e1]98 if ((event->type == KEY_PRESS) && (event->key == KC_PAGE_DOWN)) {
99 if (imgs_current == imgs_count - 1)
100 imgs_current = 0;
101 else
102 imgs_current++;
[a35b458]103
[3e896e1]104 update = true;
105 }
[a35b458]106
[3e896e1]107 if ((event->type == KEY_PRESS) && (event->key == KC_PAGE_UP)) {
108 if (imgs_current == 0)
109 imgs_current = imgs_count - 1;
110 else
111 imgs_current--;
[a35b458]112
[3e896e1]113 update = true;
114 }
[a35b458]115
[3e896e1]116 if (update) {
[c064b58]117 surface_t *lsface;
118
119 if (!img_load(imgs[imgs_current], &lsface)) {
[3e896e1]120 printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
[c064b58]121 exit(4);
122 }
[2c9fdeed]123 if (!img_setup(window_gc, lsface)) {
[c064b58]124 printf("Cannot setup image \"%s\".\n", imgs[imgs_current]);
125 exit(6);
[3e896e1]126 }
127 }
128}
129
[c064b58]130static bool img_load(const char *fname, surface_t **p_local_surface)
[3e896e1]131{
[f77c1c9]132 int fd;
[b7fd2a0]133 errno_t rc = vfs_lookup_open(fname, WALK_REGULAR, MODE_READ, &fd);
[f77c1c9]134 if (rc != EOK)
[3e896e1]135 return false;
[a35b458]136
[39330200]137 vfs_stat_t stat;
[f77c1c9]138 rc = vfs_stat(fd, &stat);
[23a0368]139 if (rc != EOK) {
[9c4cf0d]140 vfs_put(fd);
[3e896e1]141 return false;
142 }
[a35b458]143
[3e896e1]144 void *tga = malloc(stat.size);
145 if (tga == NULL) {
[9c4cf0d]146 vfs_put(fd);
[3e896e1]147 return false;
148 }
[58898d1d]149
[8e3498b]150 size_t nread;
[1433ecda]151 rc = vfs_read(fd, (aoff64_t []) { 0 }, tga, stat.size, &nread);
[8e3498b]152 if (rc != EOK || nread != stat.size) {
[3e896e1]153 free(tga);
[9c4cf0d]154 vfs_put(fd);
[3e896e1]155 return false;
156 }
[a35b458]157
[9c4cf0d]158 vfs_put(fd);
[a35b458]159
[2c9fdeed]160 *p_local_surface = decode_tga(tga, stat.size, SURFACE_FLAG_SHARED);
[c064b58]161 if (*p_local_surface == NULL) {
[3e896e1]162 free(tga);
163 return false;
164 }
[a35b458]165
[3e896e1]166 free(tga);
[c064b58]167
168 surface_get_resolution(*p_local_surface, &img_width, &img_height);
[a35b458]169
[c064b58]170 return true;
171}
172
[2c9fdeed]173static bool img_setup(gfx_context_t *gc, surface_t *local_surface)
[c064b58]174{
[2c9fdeed]175 surface_coord_t w, h;
176 gfx_bitmap_params_t params;
177 gfx_bitmap_alloc_t alloc;
178 gfx_bitmap_t *bmp;
179 gfx_rect_t arect;
180 gfx_rect_t irect;
181 ui_resource_t *ui_res;
182 errno_t rc;
183
184 ui_res = ui_window_get_res(window);
185
186 surface_get_resolution(local_surface, &w, &h);
187 gfx_bitmap_params_init(&params);
188 params.rect.p1.x = w;
189 params.rect.p1.y = h;
190
191 ui_window_get_app_rect(window, &arect);
192 gfx_rect_translate(&arect.p0, &params.rect, &irect);
193
194 alloc.pitch = sizeof(uint32_t) * w;
195 alloc.off0 = 0;
196 alloc.pixels = surface_direct_access(local_surface);
197
198 rc = gfx_bitmap_create(gc, &params, &alloc, &bmp);
199 if (rc != EOK) {
200 surface_destroy(local_surface);
201 return false;
202 }
203
204 if (image != NULL) {
205 ui_image_set_bmp(image, bmp, &params.rect);
206 (void) ui_image_paint(image);
207 ui_image_set_rect(image, &irect);
[3e896e1]208 } else {
[2c9fdeed]209 rc = ui_image_create(ui_res, bmp, &params.rect, &image);
210 if (rc != EOK) {
211 gfx_bitmap_destroy(bmp);
[3e896e1]212 surface_destroy(local_surface);
213 return false;
214 }
[a35b458]215
[2c9fdeed]216 ui_image_set_rect(image, &irect);
217 ui_window_add(window, ui_image_ctl(image));
[3e896e1]218 }
[a35b458]219
[3e896e1]220 if (surface != NULL)
221 surface_destroy(surface);
[a35b458]222
[3e896e1]223 surface = local_surface;
224 return true;
225}
226
[fd11144]227static void print_syntax(void)
228{
[2c9fdeed]229 printf("Syntax: %s [<options] <image-file>...\n", NAME);
230 printf("\t-d <display-spec> Use the specified display\n");
231 printf("\t-f Full-screen mode\n");
[fd11144]232}
233
[3e896e1]234int main(int argc, char *argv[])
235{
[2c9fdeed]236 const char *display_spec = DISPLAY_DEFAULT;
[c064b58]237 surface_t *lsface;
[2c9fdeed]238 bool fullscreen = false;
239 gfx_rect_t rect;
240 gfx_rect_t wrect;
241 gfx_coord2_t off;
242 ui_t *ui;
243 ui_wnd_params_t params;
244 viewer_t viewer;
245 errno_t rc;
[fd11144]246 int i;
247
248 i = 1;
249 while (i < argc && argv[i][0] == '-') {
250 if (str_cmp(argv[i], "-d") == 0) {
251 ++i;
252 if (i >= argc) {
253 printf("Argument missing.\n");
254 print_syntax();
255 return 1;
256 }
257
[2c9fdeed]258 display_spec = argv[i++];
259 } else if (str_cmp(argv[i], "-f") == 0) {
260 fullscreen = true;
[fd11144]261 } else {
262 printf("Invalid option '%s'.\n", argv[i]);
263 print_syntax();
264 return 1;
265 }
[3e896e1]266 }
[a35b458]267
[fd11144]268 if (i >= argc) {
[3e896e1]269 printf("No image files specified.\n");
[fd11144]270 print_syntax();
[3e896e1]271 return 1;
272 }
[c064b58]273
[fd11144]274 imgs_count = argc - i;
[3e896e1]275 imgs = calloc(imgs_count, sizeof(char *));
276 if (imgs == NULL) {
277 printf("Out of memory.\n");
[2c9fdeed]278 return 1;
[3e896e1]279 }
[a35b458]280
[fd11144]281 for (int j = 0; j < argc - i; j++) {
282 imgs[j] = str_dup(argv[i + j]);
283 if (imgs[j] == NULL) {
[3e896e1]284 printf("Out of memory.\n");
[c064b58]285 return 3;
[3e896e1]286 }
287 }
[c064b58]288
289 if (!img_load(imgs[imgs_current], &lsface)) {
[3e896e1]290 printf("Cannot load image \"%s\".\n", imgs[imgs_current]);
[2c9fdeed]291 return 1;
[c064b58]292 }
293
[2c9fdeed]294 // TODO Fullscreen mode
295 if (fullscreen) {
296 printf("Fullscreen mode not implemented.\n");
297 return 1;
298 }
299
300 rc = ui_create(display_spec, &ui);
301 if (rc != EOK) {
302 printf("Error creating UI on display %s.\n", display_spec);
303 return 1;
304 }
[c064b58]305
[2c9fdeed]306 viewer.ui = ui;
[c064b58]307
[2c9fdeed]308 rect.p0.x = 0;
309 rect.p0.y = 0;
310 rect.p1.x = img_width;
311 rect.p1.y = img_height;
312
313 ui_wnd_params_init(&params);
314 params.caption = "Viewer";
315 /*
316 * Compute window rectangle such that application area corresponds
317 * to rect
318 */
319 ui_wdecor_rect_from_app(&rect, &wrect);
320 off = wrect.p0;
321 gfx_rect_rtranslate(&off, &wrect, &params.rect);
322
323 rc = ui_window_create(ui, &params, &window);
324 if (rc != EOK) {
325 printf("Error creating window.\n");
326 return 1;
[3e896e1]327 }
[a35b458]328
[2c9fdeed]329 window_gc = ui_window_get_gc(window);
330
331 ui_window_set_cb(window, &window_cb, (void *) &viewer);
332
333 if (!img_setup(window_gc, lsface)) {
[c064b58]334 printf("Cannot setup image \"%s\".\n", imgs[imgs_current]);
[2c9fdeed]335 return 1;
[c064b58]336 }
337
[2c9fdeed]338 rc = ui_window_paint(window);
339 if (rc != EOK) {
340 printf("Error painting window.\n");
341 return 1;
[c064b58]342 }
343
[2c9fdeed]344 ui_run(ui);
[a35b458]345
[3e896e1]346 return 0;
347}
348
349/** @}
350 */
Note: See TracBrowser for help on using the repository browser.