Array of strings sys_dirs must be NULL-terminated
[helenos.git] / uspace / app / nav / panel.c
blob1d774488c8b62c06b82b919865b6216fe1630974
1 /*
2 * Copyright (c) 2023 Jiri Svoboda
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @addtogroup nav
30 * @{
32 /** @file Navigator panel.
34 * Displays a file listing.
37 #include <errno.h>
38 #include <gfx/render.h>
39 #include <gfx/text.h>
40 #include <stdlib.h>
41 #include <task.h>
42 #include <ui/control.h>
43 #include <ui/filelist.h>
44 #include <ui/paint.h>
45 #include <ui/resource.h>
46 #include "panel.h"
47 #include "nav.h"
49 static void panel_ctl_destroy(void *);
50 static errno_t panel_ctl_paint(void *);
51 static ui_evclaim_t panel_ctl_kbd_event(void *, kbd_event_t *);
52 static ui_evclaim_t panel_ctl_pos_event(void *, pos_event_t *);
54 /** Panel control ops */
55 static ui_control_ops_t panel_ctl_ops = {
56 .destroy = panel_ctl_destroy,
57 .paint = panel_ctl_paint,
58 .kbd_event = panel_ctl_kbd_event,
59 .pos_event = panel_ctl_pos_event
62 static void panel_flist_activate_req(ui_file_list_t *, void *);
63 static void panel_flist_selected(ui_file_list_t *, void *, const char *);
65 /** Panel file list callbacks */
66 static ui_file_list_cb_t panel_flist_cb = {
67 .activate_req = panel_flist_activate_req,
68 .selected = panel_flist_selected,
71 /** Create panel.
73 * @param window Containing window
74 * @param active @c true iff panel should be active
75 * @param rpanel Place to store pointer to new panel
76 * @return EOK on success or an error code
78 errno_t panel_create(ui_window_t *window, bool active, panel_t **rpanel)
80 panel_t *panel;
81 errno_t rc;
83 panel = calloc(1, sizeof(panel_t));
84 if (panel == NULL)
85 return ENOMEM;
87 rc = ui_control_new(&panel_ctl_ops, (void *)panel,
88 &panel->control);
89 if (rc != EOK) {
90 free(panel);
91 return rc;
94 rc = gfx_color_new_ega(0x07, &panel->color);
95 if (rc != EOK)
96 goto error;
98 rc = gfx_color_new_ega(0x0f, &panel->act_border_color);
99 if (rc != EOK)
100 goto error;
102 rc = ui_file_list_create(window, active, &panel->flist);
103 if (rc != EOK)
104 goto error;
106 ui_file_list_set_cb(panel->flist, &panel_flist_cb, (void *)panel);
108 panel->window = window;
109 panel->active = active;
110 *rpanel = panel;
111 return EOK;
112 error:
113 if (panel->color != NULL)
114 gfx_color_delete(panel->color);
115 if (panel->act_border_color != NULL)
116 gfx_color_delete(panel->act_border_color);
117 if (panel->flist != NULL)
118 ui_file_list_destroy(panel->flist);
119 ui_control_delete(panel->control);
120 free(panel);
121 return rc;
124 /** Destroy panel.
126 * @param panel Panel
128 void panel_destroy(panel_t *panel)
130 gfx_color_delete(panel->color);
131 gfx_color_delete(panel->act_border_color);
132 ui_control_delete(panel->control);
133 free(panel);
136 /** Set panel callbacks.
138 * @param panel Panel
139 * @param cb Callbacks
140 * @param arg Argument to callback functions
142 void panel_set_cb(panel_t *panel, panel_cb_t *cb, void *arg)
144 panel->cb = cb;
145 panel->cb_arg = arg;
148 /** Paint panel.
150 * @param panel Panel
152 errno_t panel_paint(panel_t *panel)
154 gfx_context_t *gc = ui_window_get_gc(panel->window);
155 ui_resource_t *res = ui_window_get_res(panel->window);
156 ui_box_style_t bstyle;
157 gfx_color_t *bcolor;
158 ui_control_t *ctl;
159 errno_t rc;
161 rc = gfx_set_color(gc, panel->color);
162 if (rc != EOK)
163 return rc;
165 rc = gfx_fill_rect(gc, &panel->rect);
166 if (rc != EOK)
167 return rc;
169 if (panel->active) {
170 bstyle = ui_box_double;
171 bcolor = panel->act_border_color;
172 } else {
173 bstyle = ui_box_single;
174 bcolor = panel->color;
177 rc = ui_paint_text_box(res, &panel->rect, bstyle, bcolor);
178 if (rc != EOK)
179 return rc;
181 ctl = ui_file_list_ctl(panel->flist);
182 rc = ui_control_paint(ctl);
183 if (rc != EOK)
184 return rc;
186 rc = gfx_update(gc);
187 if (rc != EOK)
188 return rc;
190 return EOK;
193 /** Handle panel keyboard event.
195 * @param panel Panel
196 * @param event Keyboard event
197 * @return ui_claimed iff event was claimed
199 ui_evclaim_t panel_kbd_event(panel_t *panel, kbd_event_t *event)
201 ui_control_t *ctl;
203 if (!panel->active)
204 return ui_unclaimed;
206 ctl = ui_file_list_ctl(panel->flist);
207 return ui_control_kbd_event(ctl, event);
210 /** Handle panel position event.
212 * @param panel Panel
213 * @param event Position event
214 * @return ui_claimed iff event was claimed
216 ui_evclaim_t panel_pos_event(panel_t *panel, pos_event_t *event)
218 gfx_coord2_t pos;
219 ui_control_t *ctl;
220 ui_evclaim_t claim;
222 pos.x = event->hpos;
223 pos.y = event->vpos;
224 if (!gfx_pix_inside_rect(&pos, &panel->rect))
225 return ui_unclaimed;
227 ctl = ui_file_list_ctl(panel->flist);
228 claim = ui_control_pos_event(ctl, event);
229 if (claim == ui_claimed)
230 return ui_claimed;
232 if (!panel->active && event->type == POS_PRESS)
233 panel_activate_req(panel);
235 return ui_claimed;
238 /** Get base control for panel.
240 * @param panel Panel
241 * @return Base UI control
243 ui_control_t *panel_ctl(panel_t *panel)
245 return panel->control;
248 /** Set panel rectangle.
250 * @param panel Panel
251 * @param rect Rectangle
253 void panel_set_rect(panel_t *panel, gfx_rect_t *rect)
255 gfx_rect_t irect;
257 panel->rect = *rect;
259 irect.p0.x = panel->rect.p0.x + 1;
260 irect.p0.y = panel->rect.p0.y + 1;
261 irect.p1.x = panel->rect.p1.x;
262 irect.p1.y = panel->rect.p1.y - 1;
264 ui_file_list_set_rect(panel->flist, &irect);
267 /** Determine if panel is active.
269 * @param panel Panel
270 * @return @c true iff panel is active
272 bool panel_is_active(panel_t *panel)
274 return panel->active;
277 /** Activate panel.
279 * @param panel Panel
281 * @return EOK on success or an error code
283 errno_t panel_activate(panel_t *panel)
285 errno_t rc;
287 rc = ui_file_list_activate(panel->flist);
288 if (rc != EOK)
289 return rc;
291 panel->active = true;
292 (void) panel_paint(panel);
293 return EOK;
296 /** Deactivate panel.
298 * @param panel Panel
300 void panel_deactivate(panel_t *panel)
302 ui_file_list_deactivate(panel->flist);
303 panel->active = false;
304 (void) panel_paint(panel);
307 /** Destroy panel control.
309 * @param arg Argument (panel_t *)
311 void panel_ctl_destroy(void *arg)
313 panel_t *panel = (panel_t *) arg;
315 panel_destroy(panel);
318 /** Paint panel control.
320 * @param arg Argument (panel_t *)
321 * @return EOK on success or an error code
323 errno_t panel_ctl_paint(void *arg)
325 panel_t *panel = (panel_t *) arg;
327 return panel_paint(panel);
330 /** Handle panel control keyboard event.
332 * @param arg Argument (panel_t *)
333 * @param kbd_event Keyboard event
334 * @return @c ui_claimed iff the event is claimed
336 ui_evclaim_t panel_ctl_kbd_event(void *arg, kbd_event_t *event)
338 panel_t *panel = (panel_t *) arg;
340 return panel_kbd_event(panel, event);
343 /** Handle panel control position event.
345 * @param arg Argument (panel_t *)
346 * @param pos_event Position event
347 * @return @c ui_claimed iff the event is claimed
349 ui_evclaim_t panel_ctl_pos_event(void *arg, pos_event_t *event)
351 panel_t *panel = (panel_t *) arg;
353 return panel_pos_event(panel, event);
356 /** Read directory into panel entry list.
358 * @param panel Panel
359 * @param dirname Directory path
360 * @return EOK on success or an error code
362 errno_t panel_read_dir(panel_t *panel, const char *dirname)
364 return ui_file_list_read_dir(panel->flist, dirname);
367 /** Request panel activation.
369 * Call back to request panel activation.
371 * @param panel Panel
373 void panel_activate_req(panel_t *panel)
375 if (panel->cb != NULL && panel->cb->activate_req != NULL)
376 panel->cb->activate_req(panel->cb_arg, panel);
379 /** Open panel file entry.
381 * Perform Open action on a file entry (i.e. try running it).
383 * @param panel Panel
384 * @param fname File name
386 * @return EOK on success or an error code
388 static errno_t panel_open_file(panel_t *panel, const char *fname)
390 task_id_t id;
391 task_wait_t wait;
392 task_exit_t texit;
393 int retval;
394 errno_t rc;
395 ui_t *ui;
397 ui = ui_window_get_ui(panel->window);
399 /* Free up and clean console for the child task. */
400 rc = ui_suspend(ui);
401 if (rc != EOK)
402 return rc;
404 rc = task_spawnl(&id, &wait, fname, fname, NULL);
405 if (rc != EOK)
406 goto error;
408 rc = task_wait(&wait, &texit, &retval);
409 if ((rc != EOK) || (texit != TASK_EXIT_NORMAL))
410 goto error;
412 /* Resume UI operation */
413 rc = ui_resume(ui);
414 if (rc != EOK)
415 return rc;
417 (void) ui_paint(ui_window_get_ui(panel->window));
418 return EOK;
419 error:
420 (void) ui_resume(ui);
421 (void) ui_paint(ui_window_get_ui(panel->window));
422 return rc;
425 /** File list in panel requests activation.
427 * @param flist File list
428 * @param arg Argument (panel_t *)
430 static void panel_flist_activate_req(ui_file_list_t *flist, void *arg)
432 panel_t *panel = (panel_t *)arg;
434 panel_activate_req(panel);
437 /** File in panel file list was selected.
439 * @param flist File list
440 * @param arg Argument (panel_t *)
441 * @param fname File name
443 static void panel_flist_selected(ui_file_list_t *flist, void *arg,
444 const char *fname)
446 panel_t *panel = (panel_t *)arg;
448 (void) panel_open_file(panel, fname);
451 /** @}