libxputty 0.1
Loading...
Searching...
No Matches
xmessage-dialog.c
Go to the documentation of this file.
1/*
2 * 0BSD
3 *
4 * BSD Zero Clause License
5 *
6 * Copyright (c) 2019 Hermann Meyer
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted.
10
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21#include "xmessage-dialog.h"
22
23void hyperlink_pressed(void *w_, void* button_, void* user_data) {
24 Widget_t *w = (Widget_t*)w_;
25 XButtonEvent *xbutton = (XButtonEvent*)button_;
26 if (xbutton->button == Button1) {
27 char *command;
28 asprintf(&command, "xdg-open '%s'",w->label);
29 if (system(NULL)) {
30 int ret = system(command);
31 if (ret) {
33 "Fail to open link", NULL);
34 }
35 }
36 free(command);
37 }
38}
39
40void draw_hyperlink(void *w_, void* user_data) {
41 Widget_t *w = (Widget_t*)w_;
42 Metrics_t metrics;
43 os_get_window_metrics(w, &metrics);
44 int width = metrics.width;
45 int height = metrics.height;
46
47 cairo_text_extents_t extents;
49 cairo_set_font_size (w->crb, w->app->normal_font/w->scale.ascale);
50 cairo_text_extents(w->crb,w->label , &extents);
51
52 cairo_move_to (w->crb, (width*0.5)-(extents.width/2), height-(extents.height/4));
53 cairo_show_text(w->crb, w->label);
54 cairo_new_path (w->crb);
55}
56
57Widget_t *create_hyperlink(Widget_t *w, char*label, int x, int y,
58 int width, int height) {
59 Widget_t *wid = create_widget(w->app, w, x, y, width, height);
60 wid->label = label;
61 wid->scale.gravity = ASPECT;
62#ifdef __linux__
63 Cursor c = XCreateFontCursor(wid->app->dpy, XC_hand2);
64 XDefineCursor (wid->app->dpy, wid->widget, c);
65 XFreeCursor(wid->app->dpy, c);
66#endif
71 return wid;
72}
73
74static void draw_message_label(Widget_t *w, int width, int height) {
76 cairo_text_extents_t extents;
78 cairo_set_font_size (w->crb, 12.0);
79 int i = 0;
80 for(;i<(int)mb->lin;i++) {
81 cairo_text_extents(w->crb,mb->message[i] , &extents);
82 if (strstr(mb->message[i], "http") != NULL) {
83 continue;
84 } else {
85 cairo_move_to (w->crb, 100, ((40)+(extents.height * (2*i))));
86 cairo_show_text(w->crb, mb->message[i]);
87 cairo_new_path (w->crb);
88 }
89 }
90}
91
92static void draw_message_window(void *w_, void* user_data) {
93 Widget_t *w = (Widget_t*)w_;
94 Metrics_t metrics;
95 os_get_window_metrics(w, &metrics);
96 int width_t = metrics.width;
97 int height_t = metrics.height;
98 if (!metrics.visible) return;
99
100 cairo_rectangle(w->crb,0,0,width_t,height_t);
102 cairo_fill (w->crb);
103
105 int width, height;
106 os_get_surface_size(w->image, &width, &height);
107 double x = 64.0/(double)(width);
108 double y = 64.0/(double)height;
109 double x1 = (double)height/64.0;
110 double y1 = (double)(width)/64.0;
111 cairo_scale(w->crb, x,y);
112 cairo_set_source_surface (w->crb, w->image, 50, 50);
113 cairo_rectangle(w->crb,50, 50, width, height);
114 cairo_fill(w->crb);
115 cairo_scale(w->crb, x1,y1);
116
117 draw_message_label(w,width_t,height_t);
119}
120
121static void draw_entry(void *w_, void* user_data) {
122 Widget_t *w = (Widget_t*)w_;
123 if (!w) return;
124 Metrics_t metrics;
125 os_get_window_metrics(w, &metrics);
126 int width = metrics.width;
127 int height = metrics.height;
128 if (!metrics.visible) return;
129
131 cairo_rectangle(w->cr,0,0,width,height);
132 cairo_fill_preserve (w->cr);
134 cairo_set_line_width(w->cr, 2.0);
135 cairo_stroke(w->cr);
136
137 cairo_set_font_size (w->cr, 9.0);
138
139 cairo_move_to (w->cr, 2, 9);
140 cairo_show_text(w->cr, " ");
141}
142
143static void entry_add_text(void *w_, void *label_) {
144 Widget_t *w = (Widget_t*)w_;
145 if (!w) return;
146 char *label = (char*)label_;
147 if (!label) {
148 label = (char*)"";
149 }
150 draw_entry(w,NULL);
151 cairo_text_extents_t extents;
153 cairo_set_font_size (w->cr, 11.0);
154 if (strlen( w->input_label))
155 w->input_label[strlen( w->input_label)-1] = 0;
156 if (strlen( w->input_label)<30) {
157 if (strlen(label))
158 strcat( w->input_label, label);
159 }
160 w->label = w->input_label;
161 strcat( w->input_label, "|");
162 cairo_set_font_size (w->cr, 12.0);
163 cairo_text_extents(w->cr, w->input_label , &extents);
164
165 cairo_move_to (w->cr, 2, 12.0+extents.height);
166 cairo_show_text(w->cr, w->input_label);
167
168}
169
170static void entry_clip(Widget_t *w) {
171 draw_entry(w,NULL);
172 cairo_text_extents_t extents;
174 cairo_set_font_size (w->cr, 11.0);
175
176 // check for UTF 8 char
177 if (strlen( w->input_label)>=2) {
178 int i = strlen( w->input_label)-1;
179 int j = 0;
180 int u = 0;
181 for(;i>0;i--) {
182 if(IS_UTF8(w->input_label[i])) {
183 u++;
184 }
185 j++;
186 if (u == 1) break;
187 if (j>2) break;
188 }
189 if (!u) j =2;
190
191 memset(&w->input_label[strlen( w->input_label)-(sizeof(char)*(j))],0,sizeof(char)*(j));
192 strcat( w->input_label, "|");
193 }
194 cairo_set_font_size (w->cr, 12.0);
195 cairo_text_extents(w->cr, w->input_label , &extents);
196
197 cairo_move_to (w->cr, 2, 12.0+extents.height);
198 cairo_show_text(w->cr, w->input_label);
199
200}
201
202static void message_okay_callback(void *w_, void* user_data) {
203 Widget_t *w = (Widget_t*)w_;
204 if (w->flags & HAS_POINTER && !*(int*)user_data){
205 Widget_t *p = (Widget_t*)w->parent;
206 MessageDialog *mb = (MessageDialog *)p->parent_struct;
207 if(mb->message_type == QUESTION_BOX || mb->message_type == SELECTION_BOX) {
208 Widget_t *pa = (Widget_t*)p->parent;
209 pa->func.dialog_callback(pa,&mb->response);
210 } else if(mb->message_type == ENTRY_BOX) {
211 Widget_t *pa = (Widget_t*)p->parent;
212 if (strlen( mb->text_entry->input_label))
213 mb->text_entry->input_label[strlen( mb->text_entry->input_label)-1] = 0;
214 mb->text_entry->label = mb->text_entry->input_label;
215 pa->func.dialog_callback(pa,&mb->text_entry->label);
216 }
217 destroy_widget(p, p->app);
218 }
219}
220
221static void message_no_callback(void *w_, void* user_data) {
222 Widget_t *w = (Widget_t*)w_;
223 if (w->flags & HAS_POINTER && !*(int*)user_data){
224 Widget_t *p = (Widget_t*)w->parent;
225 MessageDialog *mb = (MessageDialog *)p->parent_struct;
226 if(mb->message_type == QUESTION_BOX) {
227 Widget_t *pa = (Widget_t*)p->parent;
228 mb->response = -1;
229 pa->func.dialog_callback(pa,&mb->response);
230 }
231 destroy_widget(p, p->app);
232 }
233}
234
236 Widget_t * p = (Widget_t*)w->parent;
238 int response = 0;
239 int i = 0;
240 for(;i<p->childlist->elem;i++) {
241 Widget_t *wid = p->childlist->childs[i];
242 if (wid->adj && wid->flags & IS_RADIO) {
243 ++response;
244 if (wid != w) adj_set_value(wid->adj_y, 0.0);
245 else if (wid == w) mb->response = response;
246 }
247 }
248}
249
250static void radio_box_button_pressed(void *w_, void* button_, void* user_data) {
251 Widget_t *w = (Widget_t*)w_;
252 if (w->flags & HAS_FOCUS) {
254 }
255}
256
257static void create_checkboxes(Widget_t *w) {
259 int y = (mb->lin + 1) * 24 +12;
260 int i = 0;
261 for(;i<(int)mb->sel;i++) {
262 Widget_t *wid = add_check_box(w,mb->choices[i] , 100, y + (24*i), 15, 15);
263 wid->flags |= IS_RADIO;
264 wid->func.button_press_callback = radio_box_button_pressed;
265 }
266}
267
268static void entry_get_text(void *w_, void *key_, void *user_data) {
269 Widget_t *w = (Widget_t*)w_;
270 if (!w) return;
271 XKeyEvent *key = (XKeyEvent*)key_;
272 if (!key) return;
273 int nk = key_mapping(w->app->dpy, key);
274 if (nk) {
275 switch (nk) {
276 case 10:
277 {
278 Widget_t *p = (Widget_t*)w->parent;
279 MessageDialog *mb = (MessageDialog *)p->parent_struct;
280 Widget_t *pa = (Widget_t*)p->parent;
281 if (strlen( mb->text_entry->input_label))
282 mb->text_entry->input_label[strlen( mb->text_entry->input_label)-1] = 0;
283 mb->text_entry->label = mb->text_entry->input_label;
284 pa->func.dialog_callback(pa,&mb->text_entry->label);
285
286 destroy_widget(p, p->app);
287 }
288 break;
289 case 11: entry_clip(w);
290 break;
291 default:
292 break;
293 }
294 } else {
295 char buf[32];
296 bool status = os_get_keyboard_input(w, key, buf, sizeof(buf) - 1);
297 if(status){
298 entry_add_text(w, buf);
299 }
300 }
302}
303
304static void create_entry_box(Widget_t *w) {
306
307 mb->text_entry = create_widget(w->app, w, 20, mb->height-90, mb->width-40, 40);
308 memset(mb->text_entry->input_label, 0, 32 * (sizeof mb->text_entry->input_label[0]) );
309 mb->text_entry->func.expose_callback = entry_add_text;
310 mb->text_entry->func.key_press_callback = entry_get_text;
311 mb->text_entry->flags &= ~USE_TRANSPARENCY;
312 mb->text_entry->scale.gravity = CENTER;
313}
314
315static void check_for_message(MessageDialog *mb, const char *message) {
316 if(!message) return;
317 if(!strlen(message)) return;
318 int len = 0;
319 char *ms =strdup(message);
320 char * p = strtok (ms, "|");
321 while (p) {
322 mb->message = (char**)realloc (mb->message, sizeof (char*) * ++mb->lin);
323 mb->message[mb->lin-1] = strdup(p);
324 len = max(len, (int)strlen(mb->message[mb->lin-1]));
325 p = strtok (NULL, "|");
326 }
327 free(ms);
328 mb->width = len*12 ;
329 mb->height = mb->lin*16+150;
330}
331
332static void check_for_hyperlinks(Widget_t *w) {
334 if(!mb->message) return;
335 cairo_text_extents_t extents;
336 cairo_set_font_size (w->crb, 12.0);
337 int i = 0;
338 for(;i<(int)mb->lin;i++) {
339 if (strstr(mb->message[i], "http") != NULL) {
340 cairo_text_extents(w->crb,mb->message[i] , &extents);
341 create_hyperlink(w, mb->message[i], 100,
342 ((25)+(extents.height * (2*i))), extents.width, 16);
343 }
344 }
345}
346
347static void check_for_choices(MessageDialog *mb, const char *choices) {
348 if(!choices) return;
349 if(!strlen(choices)) return;
350 int len = 0;
351 char *ms =strdup(choices);
352 char * p = strtok (ms, "|");
353 while (p) {
354 mb->choices = (char**)realloc (mb->choices, sizeof (char*) * ++mb->sel);
355 mb->choices[mb->sel-1] = strdup(p);
356 len = max(len, (int)strlen(mb->choices[mb->sel-1]));
357 p = strtok (NULL, "|");
358 }
359 free(ms);
360 mb->width = max(len*12,(int)mb->width);
361 mb->height += mb->sel*12+50;
362}
363
364static void check_for_style(MessageDialog *mb, int style) {
365 if(style == ENTRY_BOX) {
366 mb->width = max(330,mb->width);
367 mb->height = max(140,mb->height+60);
368 }
369}
370
371static void mg_mem_free(void *w_, void* user_data) {
372 Widget_t *w = (Widget_t*)w_;
374 int i = 0;
375 for(;i<(int)mb->lin;i++) {
376 free(mb->message[i]);
377 }
378 i = 0;
379 for(;i<(int)mb->sel;i++) {
380 free(mb->choices[i]);
381 }
382 free(mb->choices);
383 free(mb);
384}
385
386Widget_t *open_message_dialog(Widget_t *w, int style, const char *title,
387 const char *message, const char *choices) {
388
389 MessageDialog *mb = (MessageDialog*)malloc(sizeof(MessageDialog));
390 mb->response = 0;
391 mb->message_type = 0;
392 mb->lin = 0;
393 mb->width = 330;
394 mb->height = 200;
395 mb->message = NULL;
396 mb->sel = 0;
397 mb->choices = NULL;
398 check_for_message(mb, message);
399 check_for_choices(mb, choices);
400 check_for_style(mb, style);
401 Widget_t *wid = create_window(w->app, os_get_root_window(w->app, IS_WINDOW), 0, 0, mb->width, mb->height);
402 wid->label = message;
403 wid->flags |= HAS_MEM;
404 wid->scale.gravity = CENTER;
405 wid->parent_struct = mb;
406 wid->parent = w;
407 wid->func.mem_free_callback = mg_mem_free;
408 wid->func.expose_callback = draw_message_window;
409 check_for_hyperlinks(wid);
410 char *alternate_title = NULL;
411 char *button_title = (char*)_("OK");
412 Widget_t *no;
413 switch (style) {
414 case INFO_BOX:
415 widget_get_png(wid, LDVAR(info_png));
416 alternate_title = (char*)_("INFO");
419 break;
420 case WARNING_BOX:
421 widget_get_png(wid, LDVAR(warning_png));
422 alternate_title = (char*)_("WARNING");
425 break;
426 case ERROR_BOX:
427 widget_get_png(wid, LDVAR(error_png));
428 alternate_title = (char*)_("ERROR");
431 break;
432 case QUESTION_BOX:
433 widget_get_png(wid, LDVAR(question_png));
434 alternate_title = (char*)_("QUESTION");
435 no = add_button(wid, _("NO"), 10, mb->height-40, 60, 30);
436 no->scale.gravity = CENTER;
437 no->func.value_changed_callback = message_no_callback;
439 button_title = (char*)_("YES");
441 break;
442 case SELECTION_BOX:
443 widget_get_png(wid, LDVAR(choice_png));
444 alternate_title = (char*)_("SELECTION");
446 create_checkboxes(wid);
448 break;
449 case ENTRY_BOX:
450 widget_get_png(wid, LDVAR(message_png));
451 alternate_title = (char*)_("TEXT ENTRY");
453 create_entry_box(wid);
455 break;
456 }
457 widget_set_title(wid, (title)? title : alternate_title);
458
459 Widget_t *okay = add_button(wid, button_title, mb->width-70, mb->height-40, 60, 30);
460 okay->scale.gravity = CENTER;
461 okay->func.value_changed_callback = message_okay_callback;
462
463 widget_show_all(wid);
464 return wid;
465}
Widget_t ** childs
Definition xchildlist.h:51
xevfunc expose_callback
Definition xwidget.h:85
xevfunc leave_callback
Definition xwidget.h:88
xevfunc value_changed_callback
Definition xwidget.h:90
xevfunc mem_free_callback
Definition xwidget.h:92
xevfunc enter_callback
Definition xwidget.h:87
evfunc button_press_callback
Definition xwidget.h:100
unsigned int lin
unsigned int height
unsigned int sel
unsigned int width
Metrics_t - struct to receive window size, position & visibility Pass this struct to os_get_window_...
float ascale
Definition xwidget.h:369
Gravity gravity
Definition xwidget.h:347
Widget_t - struct to hold the basic Widget_t info.
Definition xwidget.h:457
Resize_t scale
Definition xwidget.h:525
Adjustment_t * adj_y
Definition xwidget.h:495
XColor_t * color_scheme
Definition xwidget.h:467
cairo_surface_t * image
Definition xwidget.h:491
Adjustment_t * adj
Definition xwidget.h:497
void * parent
Definition xwidget.h:471
Window widget
Definition xwidget.h:469
cairo_t * crb
Definition xwidget.h:489
Childlist_t * childlist
Definition xwidget.h:499
long long flags
Definition xwidget.h:461
char input_label[32]
Definition xwidget.h:459
const char * label
Definition xwidget.h:463
cairo_t * cr
Definition xwidget.h:485
void * parent_struct
Definition xwidget.h:473
Func_t func
Definition xwidget.h:481
Xputty * app
Definition xwidget.h:465
Colors normal
Definition xcolor.h:106
Colors selected
Definition xcolor.h:108
int button
int normal_font
Definition xputty.h:248
Display * dpy
Definition xputty.h:232
void adj_set_value(Adjustment_t *adj, float value)
adj_set_value - set the current value to the Adjustment_t
int asprintf(char *strp[], const char *fmt,...)
Definition xasprintf.c:36
Widget_t * add_button(Widget_t *parent, const char *label, int x, int y, int width, int height)
add_button - add a button to a Widget_t connect to func.value_changed_callback to implement your acti...
Definition xbutton.c:26
Widget_t * add_check_box(Widget_t *parent, const char *label, int x, int y, int width, int height)
add_check_box - add a check box to a Widget_t connect to func.value_changed_callback to implement you...
Definition xbutton.c:141
Color_state get_color_state(Widget_t *wid)
get_color_state - get the Color_state to use in relation to the Widget_t state
Definition xcolor.c:222
void use_text_color_scheme(Widget_t *w, Color_state st)
use_text_color_scheme - use text Colors to paint on Widget_t
Definition xcolor.c:266
@ BACKGROUND_
Definition xcolor.h:65
void use_fg_color_scheme(Widget_t *w, Color_state st)
use_fg_color_scheme - use forground Colors to paint on Widget_t
Definition xcolor.c:245
void set_pattern(Widget_t *w, Colors *from, Colors *to, Color_mod mod)
set_pattern - set pattern for the selected Colors
Definition xcolor.c:308
void use_base_color_scheme(Widget_t *w, Color_state st)
use_base_color_scheme - use base Colors to paint on Widget_t
Definition xcolor.c:259
@ NORMAL_
Definition xcolor.h:44
void hyperlink_pressed(void *w_, void *button_, void *user_data)
Widget_t * create_hyperlink(Widget_t *w, char *label, int x, int y, int width, int height)
Widget_t * open_message_dialog(Widget_t *w, int style, const char *title, const char *message, const char *choices)
open_message_dialog - open a non blocking dialog window, lines in message chould be separated by the ...
void draw_hyperlink(void *w_, void *user_data)
void radio_box_set_active(Widget_t *w)
@ QUESTION_BOX
@ WARNING_BOX
@ ENTRY_BOX
@ SELECTION_BOX
@ ERROR_BOX
@ INFO_BOX
void widget_get_png(Widget_t *w, const unsigned char *name)
widget_get_png - read png into Widget_t xlib surface
Definition xpngloader.c:75
void widget_set_icon_from_surface(Widget_t *w, cairo_surface_t *image)
widget_set_icon_from_surface - set icon image from cairo surface for Widget_t those icon will be used...
Definition xpngloader.c:119
void os_get_window_metrics(Widget_t *w, Metrics_t *metrics)
os_get_window_metrics - Get the Merics_t struct related to a Widget_t
Window os_get_root_window(Xputty *main, int flag)
os_get_root_window - get a pointer to the root window (desktop)
bool os_get_keyboard_input(Widget_t *w, XKeyEvent *key, char *buf, size_t bufsize)
os_ get_keyboard_input - Get the Keyboard input and convert it to utf8
void os_expose_widget(Widget_t *w)
os_expose_widget - Draw the the back buffer to the Widget_t surface
void os_get_surface_size(cairo_surface_t *surface, int *width, int *height)
os_get_surface_size - get the size of the cairo surface
void widget_set_title(Widget_t *w, const char *title)
widget_set_title - set window title for a Widget_t
Definition xwidget.c:359
void widget_set_scale(Widget_t *w)
widget_set_scale - set scaling mode to scale a image surface to the size of the Widget_t surface
Definition xwidget.c:159
Widget_t * create_widget(Xputty *app, Widget_t *win, int x, int y, int width, int height)
*create_widget - create a widget A Widget_t could only be created as child of a other Widget_t To...
Definition xwidget.c:265
int key_mapping(Display *dpy, XKeyEvent *xkey)
_key_mapping - modifier key's mapped to a integer value
Definition xwidget.c:37
Widget_t * create_window(Xputty *app, Window win, int x, int y, int width, int height)
*create_window - create a Window You need to create as least minimun one Window to get started....
Definition xwidget.c:163
@ CENTER
Definition xwidget.h:320
@ ASPECT
Definition xwidget.h:322
@ HAS_POINTER
Definition xwidget.h:402
@ HAS_MEM
Definition xwidget.h:406
@ IS_RADIO
Definition xwidget.h:394
@ HAS_FOCUS
Definition xwidget.h:400
@ IS_WINDOW
Definition xwidget.h:390
void widget_reset_scale(Widget_t *w)
widget_reset_scale - used to reset scaling mode after a image surface is drawn to the Widget_t surfac...
Definition xwidget.c:155
void widget_show_all(Widget_t *w)
widget_show_all - map/show Widget_t with all childs
Definition xwidget.c:386
void transparent_draw(void *wid, void *user_data)
transparent_draw - copy parent surface to child surface you usaualy didn't need to call this,...
Definition xwidget.c:449
void destroy_widget(Widget_t *w, Xputty *main)
destroy_widget - destroy a widget When a Widget_t receive a destroy_widget() call,...
Definition xwidget.c:86