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 
22 #include "xlistview_private.h"
23 #include "xtooltip.h"
24 #include <sys/stat.h>
25 
26 
_draw_listview(void * w_,void * user_data)27 void _draw_listview(void *w_, void* user_data) {
28     Widget_t *w = (Widget_t*)w_;
29     if (!w) return;
30     set_pattern(w,&w->app->color_scheme->normal,&w->app->color_scheme->active,BACKGROUND_);
31     cairo_paint (w->cr);
32 }
33 
_draw_list(void * w_,void * user_data)34 void _draw_list(void *w_, void* user_data) {
35     Widget_t *w = (Widget_t*)w_;
36     XWindowAttributes attrs;
37     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
38     if (attrs.map_state != IsViewable) return;
39     int width = attrs.width;
40     int height = attrs.height;
41     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
42 
43     use_base_color_scheme(w, NORMAL_);
44     cairo_rectangle(w->crb, 0, 0, width, height);
45     cairo_fill (w->crb);
46     cairo_set_font_size (w->crb, min(w->app->big_font ,w->app->normal_font/w->scale.ascale));
47     cairo_text_extents_t extents;
48     cairo_text_extents(w->crb,"Ay", &extents);
49     double h = extents.height;
50 
51     int i = (int)max(0,adj_get_value(w->adj));
52     int a = 0;
53     int j = filelist->list_size<filelist->show_items+i+1 ?
54       filelist->list_size : filelist->show_items+i+1;
55     for(;i<j;i++) {
56         if(i == filelist->prelight_item && i == filelist->active_item)
57             use_base_color_scheme(w, ACTIVE_);
58         else if(i == filelist->prelight_item)
59             use_base_color_scheme(w, PRELIGHT_);
60         else if (i == filelist->active_item)
61             use_base_color_scheme(w, SELECTED_);
62         else
63             use_base_color_scheme(w,NORMAL_ );
64         cairo_rectangle(w->crb, 0, a*25, width, 25);
65         cairo_fill_preserve(w->crb);
66         cairo_set_line_width(w->crb, 1.0);
67         use_frame_color_scheme(w, PRELIGHT_);
68         cairo_stroke(w->crb);
69 
70         /** show label **/
71         if(i == filelist->prelight_item && i == filelist->active_item)
72             use_text_color_scheme(w, ACTIVE_);
73         else if(i == filelist->prelight_item)
74             use_text_color_scheme(w, PRELIGHT_);
75         else if (i == filelist->active_item)
76             use_text_color_scheme(w, SELECTED_);
77         else
78             use_text_color_scheme(w,NORMAL_ );
79 
80         if (filelist->check_dir) {
81             struct stat sb;
82             if (stat(filelist->list_names[i], &sb) == 0 && S_ISDIR(sb.st_mode)) {
83                 cairo_scale(w->crb,0.08, 0.08);
84                 cairo_set_source_surface (w->crb, filelist->folder,1.0*12.5,((double)a+0.1)*25.0*12.5);
85                 cairo_paint (w->crb);
86                 cairo_scale(w->crb,12.5, 12.5);
87                 use_text_color_scheme(w, INSENSITIVE_);
88             } else {
89                 cairo_scale(w->crb,0.08, 0.08);
90                 cairo_set_source_surface (w->crb, filelist->file,1.0*12.5,((double)a+0.1)*25.0*12.5);
91                 cairo_paint (w->crb);
92                 cairo_scale(w->crb,12.5, 12.5);
93                 use_text_color_scheme(w,NORMAL_ );
94             }
95         }
96         cairo_text_extents(w->crb,filelist->list_names[i] , &extents);
97 
98         cairo_move_to (w->crb, 20, (25.0*((double)a+1.0))+3.0 - (h*max(0.71,w->scale.ascale)));
99         cairo_show_text(w->crb, filelist->list_names[i]);
100         cairo_new_path (w->crb);
101         if (i == filelist->prelight_item && extents.width > (float)width-20) {
102             tooltip_set_text(w,filelist->list_names[i]);
103             w->flags |= HAS_TOOLTIP;
104             show_tooltip(w);
105         } else if (i == filelist->prelight_item && extents.width < (float)width-20){
106             w->flags &= ~HAS_TOOLTIP;
107             hide_tooltip(w);
108         }
109         a++;
110     }
111 }
112 
_update_list_view(void * w_)113 void _update_list_view(void *w_) {
114     Widget_t *w = (Widget_t*)w_;
115     XWindowAttributes attrs;
116     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
117     if (attrs.map_state != IsViewable) return;
118     int width = attrs.width;
119     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
120 
121     cairo_push_group (w->crb);
122     use_base_color_scheme(w, NORMAL_);
123     cairo_set_font_size (w->crb, min(w->app->big_font ,w->app->normal_font/w->scale.ascale));
124     cairo_text_extents_t extents;
125     cairo_text_extents(w->crb,"Ay", &extents);
126     double h = extents.height;
127 
128     int i = (int)max(0,adj_get_value(w->adj));
129     int a = 0;
130     int j = filelist->list_size<filelist->show_items+i+1 ?
131       filelist->list_size : filelist->show_items+i+1;
132     for(;i<j;i++) {
133         if (i != filelist->prelight_item && i != filelist->prev_prelight_item) {
134             if (i<j-1) {
135                 a++;
136             }
137             continue;
138         }
139         if(i == filelist->prelight_item && i == filelist->active_item)
140             use_base_color_scheme(w, ACTIVE_);
141         else if(i == filelist->prelight_item)
142             use_base_color_scheme(w, PRELIGHT_);
143         else if (i == filelist->active_item)
144             use_base_color_scheme(w, SELECTED_);
145         else
146             use_base_color_scheme(w,NORMAL_ );
147         cairo_rectangle(w->crb, 0, a*25, width, 25);
148         cairo_fill_preserve(w->crb);
149         cairo_set_line_width(w->crb, 1.0);
150         use_frame_color_scheme(w, PRELIGHT_);
151         cairo_stroke(w->crb);
152 
153         /** show label **/
154         if(i == filelist->prelight_item && i == filelist->active_item)
155             use_text_color_scheme(w, ACTIVE_);
156         else if(i == filelist->prelight_item)
157             use_text_color_scheme(w, PRELIGHT_);
158         else if (i == filelist->active_item)
159             use_text_color_scheme(w, SELECTED_);
160         else
161             use_text_color_scheme(w,NORMAL_ );
162 
163         if (filelist->check_dir) {
164             struct stat sb;
165             if (stat(filelist->list_names[i], &sb) == 0 && S_ISDIR(sb.st_mode)) {
166                 cairo_scale(w->crb,0.08, 0.08);
167                 cairo_set_source_surface (w->crb, filelist->folder,1.0*12.5,((double)a+0.1)*25.0*12.5);
168                 cairo_paint (w->crb);
169                 cairo_scale(w->crb,12.5, 12.5);
170                 use_text_color_scheme(w, INSENSITIVE_);
171             } else {
172                 cairo_scale(w->crb,0.08, 0.08);
173                 cairo_set_source_surface (w->crb, filelist->file,1.0*12.5,((double)a+0.1)*25.0*12.5);
174                 cairo_paint (w->crb);
175                 cairo_scale(w->crb,12.5, 12.5);
176                 use_text_color_scheme(w,NORMAL_ );
177             }
178         }
179         cairo_text_extents(w->crb,filelist->list_names[i] , &extents);
180 
181         cairo_move_to (w->crb, 20, (25.0*((double)a+1.0))+3.0 - (h*max(0.71,w->scale.ascale)));
182         cairo_show_text(w->crb, filelist->list_names[i]);
183         cairo_new_path (w->crb);
184         if (i == filelist->prelight_item && extents.width > (float)width-20) {
185             tooltip_set_text(w,filelist->list_names[i]);
186             w->flags |= HAS_TOOLTIP;
187             show_tooltip(w);
188         } else if (i == filelist->prelight_item && extents.width < (float)width-20){
189             w->flags &= ~HAS_TOOLTIP;
190             hide_tooltip(w);
191         }
192         a++;
193     }
194     cairo_pop_group_to_source (w->crb);
195     cairo_paint (w->crb);
196     cairo_push_group (w->cr);
197     cairo_set_source_surface (w->cr, w->buffer,0,0);
198     cairo_paint (w->cr);
199 
200     cairo_pop_group_to_source (w->cr);
201     cairo_paint (w->cr);
202 }
203 
_list_motion(void * w_,void * xmotion_,void * user_data)204 void _list_motion(void *w_, void* xmotion_, void* user_data) {
205     Widget_t *w = (Widget_t*)w_;
206     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
207     XMotionEvent *xmotion = (XMotionEvent*)xmotion_;
208     XWindowAttributes attrs;
209     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
210     int height = attrs.height;
211     int _items = height/(height/25);
212     int prelight_item = (xmotion->y/_items)  + (int)max(0,adj_get_value(w->adj));
213     if(prelight_item != filelist->prelight_item) {
214         filelist->prev_prelight_item = filelist->prelight_item;
215         filelist->prelight_item = prelight_item;
216         hide_tooltip(w);
217         _update_list_view(w);
218     }
219 }
220 
_list_key_pressed(void * w_,void * xkey_,void * user_data)221 void _list_key_pressed(void *w_, void* xkey_, void* user_data) {
222     Widget_t *w = (Widget_t*)w_;
223     Widget_t* listview = (Widget_t*) w->parent;
224     XKeyEvent *xkey = (XKeyEvent*)xkey_;
225     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
226     XWindowAttributes attrs;
227     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
228     int height = attrs.height;
229     int _items = height/(height/25);
230     filelist->prelight_item = xkey->y/_items  + (int)max(0,adj_get_value(w->adj));
231     int nk = key_mapping(w->app->dpy, xkey);
232     if (nk) {
233         switch (nk) {
234             case 3:
235             case 4:
236             case 5:
237             case 6: filelist->prelight_item = xkey->y/_items  + (int)max(0,adj_get_value(w->adj));
238             break;
239             default:
240             break;
241         }
242     }
243     listview->func.key_press_callback(listview, xkey_, user_data);
244 }
245 
_list_entry_released(void * w_,void * button_,void * user_data)246 void _list_entry_released(void *w_, void* button_, void* user_data) {
247     Widget_t *w = (Widget_t*)w_;
248     if (w->flags & HAS_POINTER) {
249         ViewList_t *filelist = (ViewList_t*)w->parent_struct;
250         XButtonEvent *xbutton = (XButtonEvent*)button_;
251         XWindowAttributes attrs;
252         XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
253         int height = attrs.height;
254         int _items = height/(height/25);
255         int prelight_item = xbutton->y/_items  + (int)max(0,adj_get_value(w->adj));
256         if (prelight_item > filelist->list_size-1) return;
257         if(xbutton->button == Button4) {
258             if(prelight_item != filelist->prelight_item) {
259                 filelist->prelight_item = prelight_item;
260             }
261         } else if (xbutton->button == Button5) {
262             if(prelight_item != filelist->prelight_item) {
263                 filelist->prelight_item = prelight_item;
264             }
265         } else if(xbutton->button == Button1) {
266             Widget_t* listview = (Widget_t*) w->parent;
267             filelist->active_item = filelist->prelight_item;
268             adj_set_value(listview->adj,filelist->active_item);
269             listview->func.button_release_callback(listview,xbutton,user_data);
270         }
271     }
272 }
273 
_list_entry_double_clicked(void * w_,void * button_,void * user_data)274 void _list_entry_double_clicked(void *w_, void* button_, void* user_data) {
275     Widget_t *w = (Widget_t*)w_;
276     Widget_t* listview = (Widget_t*) w->parent;
277     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
278     XButtonEvent *xbutton = (XButtonEvent*)button_;
279     XWindowAttributes attrs;
280     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
281     int height = attrs.height;
282     int _items = height/(height/25);
283     int prelight_item = xbutton->y/_items  + (int)max(0,adj_get_value(w->adj));
284     if (prelight_item > filelist->list_size-1) return;
285     listview->func.double_click_callback(listview,button_,NULL);
286 }
287 
_leave_list(void * w_,void * user_data)288 void _leave_list(void *w_, void* user_data) {
289     Widget_t *w = (Widget_t*)w_;
290     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
291     filelist->prelight_item = -1;
292     expose_widget(w);
293 }
294 
_reconfigure_listview_viewport(void * w_,void * user_data)295 void _reconfigure_listview_viewport(void *w_, void* user_data) {
296     Widget_t *w = (Widget_t*)w_;
297     float st = adj_get_state(w->adj);
298     Widget_t* listview = (Widget_t*) w->parent;
299     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
300     XWindowAttributes attrs;
301     XGetWindowAttributes(listview->app->dpy, (Window)listview->widget, &attrs);
302     int height = attrs.height;
303     filelist->show_items = height/25;
304     w->adj->max_value = filelist->list_size-filelist->show_items;
305     adj_set_state(w->adj,st);
306 }
307 
_configure_listview(void * w_,void * user_data)308 void _configure_listview(void *w_, void* user_data) {
309     Widget_t *w = (Widget_t*)w_;
310     Widget_t* listview = (Widget_t*) w->parent;
311     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
312     XWindowAttributes attrs;
313     XGetWindowAttributes(listview->app->dpy, (Window)listview->widget, &attrs);
314     int width = attrs.width;
315     int height = attrs.height;
316     filelist->show_items = height/25;
317     filelist->slider->adj->step = max(0.0,1.0/(filelist->list_size-filelist->show_items));
318     adj_set_scale(filelist->slider->adj, ((float)filelist->list_size/(float)filelist->show_items)/25.0);
319     XResizeWindow (w->app->dpy, w->widget, width, height);
320 }
321 
_set_listview_viewpoint(void * w_,void * user_data)322 void _set_listview_viewpoint(void *w_, void* user_data) {
323     Widget_t *w = (Widget_t*)w_;
324     ViewList_t *filelist = (ViewList_t*)w->parent_struct;
325     adj_set_state(filelist->slider->adj,adj_get_state(w->adj));
326     expose_widget(w);
327 }
328 
_draw_listviewslider(void * w_,void * user_data)329 void _draw_listviewslider(void *w_, void* user_data) {
330     Widget_t *w = (Widget_t*)w_;
331     Widget_t* view_port = (Widget_t*)w->parent_struct;
332     ViewList_t *filelist = (ViewList_t*)view_port->parent_struct;
333     int v = (int)w->adj->max_value;
334     if (!v) return;
335     XWindowAttributes attrs;
336     XGetWindowAttributes(w->app->dpy, (Window)w->widget, &attrs);
337     if (attrs.map_state != IsViewable) return;
338     int width = attrs.width;
339     int height = attrs.height;
340     int show_items = height/25;
341     float slidersize = 1.0;
342     if (filelist->list_size > show_items)
343         slidersize = (float)((float)show_items/(float)filelist->list_size);
344     float sliderstate = adj_get_state(w->adj);
345     use_bg_color_scheme(w, get_color_state(w));
346     cairo_rectangle(w->crb, 0,0,width,height);
347     cairo_fill_preserve(w->crb);
348     use_shadow_color_scheme(w, NORMAL_);
349     cairo_fill(w->crb);
350     use_bg_color_scheme(w, NORMAL_);
351     cairo_rectangle(w->crb, 0,((float)height-
352         ((float)height*slidersize))*sliderstate,width,((float)height*slidersize));
353     cairo_fill(w->crb);
354 }
355 
_set_listviewport(void * w_,void * user_data)356 void _set_listviewport(void *w_, void* user_data) {
357     Widget_t *w = (Widget_t*)w_;
358     Widget_t *viewport = (Widget_t*)w->parent_struct;
359     adj_set_state(viewport->adj, adj_get_state(w->adj));
360     expose_widget(w);
361 }
362