1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "ui_selection.h"
4 
5 #include <string.h> /* memset */
6 #include <pobl/bl_mem.h>
7 #include <pobl/bl_debug.h>
8 #include <vt_str_parser.h>
9 
10 #if 0
11 #define __DEBUG
12 #endif
13 
14 /* --- static functions --- */
15 
update_sel_region(ui_selection_t * sel,int col,int row)16 static int update_sel_region(ui_selection_t *sel, int col, int row) {
17   int rv_beg_col;
18   int rv_beg_row;
19   int rv_end_col;
20   int rv_end_row;
21   int do_reverse;
22 
23   int rs_beg_col;
24   int rs_beg_row;
25   int rs_end_col;
26   int rs_end_row;
27   int do_restore;
28 
29   if (sel->is_rect) {
30     int conved;
31     int conved_col;
32 
33     (*sel->sel_listener->restore_color)(sel->sel_listener->self, sel->beg_col, sel->beg_row,
34                                         sel->end_col, sel->end_row, 1);
35 
36     if ((col < 0 && sel->base_col_r >= 0) || (col >= 0 && sel->base_col_r < 0)) {
37       conved_col = -col;
38       conved = 1;
39     } else {
40       conved_col = col;
41       conved = 0;
42     }
43 
44     if (conved_col < sel->base_col_r) {
45       if (row <= sel->base_row_r) {
46         sel->beg_col = col;
47         sel->beg_row = row;
48         sel->end_col = sel->base_col_l;
49         sel->end_row = sel->base_row_l;
50       } else {
51         sel->beg_col = conved_col;
52         sel->beg_row = sel->base_row_l;
53         if (conved) {
54           sel->end_col = -sel->base_col_l;
55         } else {
56           sel->end_col = sel->base_col_l;
57         }
58         sel->end_row = row;
59       }
60     } else {
61       if (row <= sel->base_row_r) {
62         if (conved) {
63           sel->beg_col = -sel->base_col_r;
64         } else {
65           sel->beg_col = sel->base_col_r;
66         }
67         sel->beg_row = row;
68         sel->end_col = conved_col;
69         sel->end_row = sel->base_row_r;
70       } else {
71         sel->beg_col = sel->base_col_r;
72         sel->beg_row = sel->base_row_r;
73         sel->end_col = col;
74         sel->end_row = row;
75       }
76     }
77 
78     (*sel->sel_listener->reverse_color)(sel->sel_listener->self, sel->beg_col, sel->beg_row,
79                                         sel->end_col, sel->end_row, 1);
80 
81     return 1;
82   }
83 
84   do_reverse = 0;
85   do_restore = 0;
86 
87   if (sel->beg_row > row || (sel->beg_row == row && sel->beg_col > col)) {
88     rv_beg_col = col;
89     rv_beg_row = row;
90     rv_end_col = sel->beg_col;
91     rv_end_row = sel->beg_row;
92     do_reverse = 1;
93 
94     sel->beg_col = col;
95     sel->beg_row = row;
96 
97     if (sel->end_row > sel->base_row_r ||
98         (sel->end_row == sel->base_row_r && sel->end_col >= sel->base_col_r)) {
99       rs_beg_col = sel->base_col_r;
100       rs_beg_row = sel->base_row_r;
101       rs_end_col = sel->end_col;
102       rs_end_row = sel->end_row;
103       do_restore = 1;
104 
105       sel->end_col = sel->base_col_l;
106       sel->end_row = sel->base_row_l;
107     }
108   } else if ((sel->beg_row < row || (sel->beg_row == row && sel->beg_col <= col)) &&
109              (sel->end_row > row || (sel->end_row == row && sel->end_col >= col))) {
110     if (row > sel->base_row_r || (row == sel->base_row_r && col >= sel->base_col_r)) {
111       rs_beg_col = col + 1; /* don't restore col itself */
112       rs_beg_row = row;
113       rs_end_col = sel->end_col;
114       rs_end_row = sel->end_row;
115       do_restore = 1;
116 
117       sel->end_col = col;
118       sel->end_row = row;
119     } else if (row < sel->base_row_l || (row == sel->base_row_l && col <= sel->base_col_l)) {
120       rs_beg_col = sel->beg_col;
121       rs_beg_row = sel->beg_row;
122       rs_end_col = col - 1; /* don't restore col itself */
123       rs_end_row = row;
124       do_restore = 1;
125 
126       sel->beg_col = col;
127       sel->beg_row = row;
128     }
129   } else if (sel->end_row < row || (sel->end_row == row && sel->end_col < col)) {
130     rv_beg_col = sel->end_col;
131     rv_beg_row = sel->end_row;
132     rv_end_col = col;
133     rv_end_row = row;
134     do_reverse = 1;
135 
136     sel->end_col = col;
137     sel->end_row = row;
138 
139     if (sel->beg_row < sel->base_row_l ||
140         (sel->beg_row == sel->base_row_l && sel->beg_col <= sel->base_col_l)) {
141       rs_beg_col = sel->beg_col;
142       rs_beg_row = sel->beg_row;
143       rs_end_col = sel->base_col_l;
144       rs_end_row = sel->base_row_l;
145       do_restore = 1;
146 
147       sel->beg_col = sel->base_col_r;
148       sel->beg_row = sel->base_row_r;
149     }
150   }
151 
152   if (do_reverse) {
153     (*sel->sel_listener->reverse_color)(sel->sel_listener->self, rv_beg_col, rv_beg_row, rv_end_col,
154                                         rv_end_row, 0);
155 
156 #ifdef __DEBUG
157     bl_debug_printf(BL_DEBUG_TAG " reversing %d %d %d %d\n", rv_beg_col, rv_beg_row, rv_end_col,
158                     rv_end_row);
159 #endif
160   }
161 
162   if (do_restore) {
163     (*sel->sel_listener->restore_color)(sel->sel_listener->self, rs_beg_col, rs_beg_row, rs_end_col,
164                                         rs_end_row, 0);
165 
166 #ifdef __DEBUG
167     bl_debug_printf(BL_DEBUG_TAG " restoring %d %d %d %d\n", rs_beg_col, rs_beg_row, rs_end_col,
168                     rs_end_row);
169 #endif
170 
171     if (sel->is_locked == 1) {
172       if ((sel->end_row < sel->lock_row ||
173            (sel->end_row == sel->lock_row && sel->end_col < sel->lock_col))) {
174         (*sel->sel_listener->reverse_color)(sel->sel_listener->self, rs_beg_col, rs_beg_row,
175                                             (sel->end_col = sel->lock_col),
176                                             (sel->end_row = sel->lock_row), 0);
177       }
178     } else if (sel->is_locked == -1) {
179       if ((sel->beg_row > sel->lock_row ||
180            (sel->beg_row == sel->lock_row && sel->beg_col > sel->lock_col))) {
181         (*sel->sel_listener->reverse_color)(sel->sel_listener->self, (sel->beg_col = sel->lock_col),
182                                             (sel->beg_row = sel->lock_row), rs_end_col, rs_end_row,
183                                             0);
184       }
185     }
186   }
187 
188 #ifdef __DEBUG
189   bl_debug_printf(BL_DEBUG_TAG " current region %d %d %d %d\n", sel->beg_col, sel->beg_row,
190                   sel->end_col, sel->end_row);
191 #endif
192 
193   return (do_reverse | do_restore);
194 }
195 
196 /* --- global functions --- */
197 
ui_sel_init(ui_selection_t * sel,ui_sel_event_listener_t * sel_listener)198 void ui_sel_init(ui_selection_t *sel, ui_sel_event_listener_t *sel_listener) {
199   memset(sel, 0, sizeof(ui_selection_t));
200 
201   sel->sel_listener = sel_listener;
202 }
203 
ui_sel_final(ui_selection_t * sel)204 void ui_sel_final(ui_selection_t *sel) {
205   if (sel->sel_str) {
206     vt_str_destroy(sel->sel_str, sel->sel_len);
207   }
208 }
209 
ui_start_selection(ui_selection_t * sel,int col_l,int row_l,int col_r,int row_r,ui_sel_type_t type,int is_rect)210 void ui_start_selection(ui_selection_t *sel, int col_l, int row_l, int col_r, int row_r,
211                         ui_sel_type_t type, int is_rect) {
212   sel->is_reversed = 1;
213   sel->is_selecting = type;
214   sel->is_rect = is_rect;
215 
216   sel->base_col_r = sel->beg_col = sel->end_col = sel->prev_col = col_r;
217   sel->base_row_r = sel->beg_row = sel->end_row = sel->prev_row = row_r;
218   sel->base_col_l = col_l;
219   sel->base_row_l = row_l;
220 
221   (*sel->sel_listener->reverse_color)(sel->sel_listener->self, sel->beg_col, sel->beg_row,
222                                       sel->end_col, sel->end_row, sel->is_rect);
223 
224 #ifdef __DEBUG
225   bl_debug_printf(BL_DEBUG_TAG " selection started => %d %d\n", sel->beg_col, sel->beg_row);
226 #endif
227 }
228 
ui_selecting(ui_selection_t * sel,int col,int row)229 int ui_selecting(ui_selection_t *sel, int col, int row) {
230   if (!sel->is_selecting) {
231     return 0;
232   }
233 
234   sel->prev_col = col;
235   sel->prev_row = row;
236 
237 #ifdef __DEBUG
238   {
239     int ret = update_sel_region(sel, col, row);
240 
241     bl_debug_printf(BL_DEBUG_TAG " selecting %d %d => %d %d - %d %d.\n", col, row, sel->beg_col,
242                     sel->beg_row, sel->end_col, sel->end_row);
243 
244     return ret;
245   }
246 #else
247   return update_sel_region(sel, col, row);
248 #endif
249 }
250 
ui_stop_selecting(ui_selection_t * sel)251 int ui_stop_selecting(ui_selection_t *sel) {
252 #ifdef __DEBUG
253   bl_debug_printf(BL_DEBUG_TAG " selection stops => %d %d - %d %d.\n", sel->beg_col, sel->beg_row,
254                   sel->end_col, sel->end_row);
255 #endif
256 
257   if (!sel->is_selecting) {
258     return 0;
259   }
260 
261   sel->is_selecting = 0;
262   sel->is_locked = 0;
263 
264   if (sel->sel_str) {
265     vt_str_destroy(sel->sel_str, sel->sel_len);
266   }
267 
268   if (!(*sel->sel_listener->select_in_window)(sel->sel_listener->self, &sel->sel_str, &sel->sel_len,
269                                               sel->beg_col, sel->beg_row, sel->end_col,
270                                               sel->end_row, sel->is_rect)) {
271 #ifdef __DEBUG
272     bl_debug_printf(BL_DEBUG_TAG " select_in_window() failed.\n");
273 #endif
274 
275     sel->sel_str = NULL;
276     sel->sel_len = 0;
277 
278     return 0;
279   }
280 
281   return 1;
282 }
283 
ui_sel_clear(ui_selection_t * sel)284 int ui_sel_clear(ui_selection_t *sel) {
285 #ifdef __DEBUG
286   bl_debug_printf(BL_DEBUG_TAG " selection is cleared.\n");
287 #endif
288 
289   if (sel->is_selecting) {
290     if (sel->sel_str) {
291       vt_str_destroy(sel->sel_str, sel->sel_len);
292       sel->sel_str = NULL;
293       sel->sel_len = 0;
294     }
295 
296     sel->is_selecting = 0;
297     sel->is_locked = 0;
298   }
299 
300   return ui_restore_selected_region_color(sel);
301 }
302 
ui_restore_selected_region_color_except_logs(ui_selection_t * sel)303 int ui_restore_selected_region_color_except_logs(ui_selection_t *sel) {
304   int beg_row;
305   int beg_col;
306 
307   if (!sel->is_reversed) {
308     return 0;
309   }
310 
311   if (sel->end_row < 0) {
312     return 0;
313   }
314 
315   if ((beg_row = sel->beg_row) < 0) {
316     beg_row = 0;
317     beg_col = 0;
318   } else {
319     beg_col = sel->beg_col;
320   }
321 
322   (*sel->sel_listener->restore_color)(sel->sel_listener->self, beg_col, beg_row, sel->end_col,
323                                       sel->end_row, sel->is_rect);
324 
325   return 1;
326 }
327 
ui_reverse_selected_region_color_except_logs(ui_selection_t * sel)328 int ui_reverse_selected_region_color_except_logs(ui_selection_t *sel) {
329   int beg_row;
330   int beg_col;
331 
332   if (!sel->is_reversed) {
333     return 0;
334   }
335 
336   if (sel->end_row < 0) {
337     return 0;
338   }
339 
340   if ((beg_row = sel->beg_row) < 0) {
341     beg_row = 0;
342     beg_col = 0;
343   } else {
344     beg_col = sel->beg_col;
345   }
346 
347   (*sel->sel_listener->reverse_color)(sel->sel_listener->self, beg_col, beg_row, sel->end_col,
348                                       sel->end_row, sel->is_rect);
349 
350   return 1;
351 }
352 
ui_restore_selected_region_color(ui_selection_t * sel)353 int ui_restore_selected_region_color(ui_selection_t *sel) {
354   if (!sel->is_reversed) {
355     return 0;
356   }
357 
358 #ifdef __DEBUG
359   bl_debug_printf(BL_DEBUG_TAG " restore selected region color => %d %d - %d %d.\n", sel->beg_col,
360                   sel->beg_row, sel->end_col, sel->end_row);
361 #endif
362 
363   (*sel->sel_listener->restore_color)(sel->sel_listener->self, sel->beg_col, sel->beg_row,
364                                       sel->end_col, sel->end_row, sel->is_rect);
365 
366   sel->is_reversed = 0;
367 
368   return 1;
369 }
370 
371 /*
372  * Not used for now.
373  */
374 #if 0
375 int ui_reverse_selected_region_color(ui_selection_t *sel) {
376   if (sel->is_reversed) {
377     return 0;
378   }
379 
380 #ifdef __DEBUG
381   bl_debug_printf(BL_DEBUG_TAG " reverse selected region color => %d %d - %d %d.\n", sel->beg_col,
382                   sel->beg_row, sel->end_col, sel->end_row);
383 #endif
384 
385   (*sel->sel_listener->reverse_color)(sel->sel_listener->self, sel->beg_col, sel->beg_row,
386                                       sel->end_col, sel->end_row, sel->is_rect);
387 
388   sel->is_reversed = 1;
389 
390   return 1;
391 }
392 #endif
393 
ui_sel_line_scrolled_out(ui_selection_t * sel,int min_row)394 void ui_sel_line_scrolled_out(ui_selection_t *sel, int min_row) {
395   if (!sel->is_selecting) {
396     return;
397   }
398 
399   if (sel->base_row_l > min_row) {
400     sel->base_row_l--;
401   } else {
402     sel->base_col_l = -1;
403   }
404 
405   if (sel->base_row_r > min_row) {
406     sel->base_row_r--;
407   } else {
408     sel->base_col_r = 0;
409   }
410 
411   if (sel->is_locked) {
412     if (sel->lock_row > min_row) {
413       sel->lock_row--;
414     } else {
415       sel->lock_col = 0;
416     }
417   }
418 
419   if (sel->beg_row > min_row) {
420     sel->beg_row--;
421   } else {
422     sel->beg_col = 0;
423   }
424 
425   if (sel->end_row > min_row) {
426     sel->end_row--;
427   } else {
428     sel->end_col = 0;
429   }
430 
431   if (sel->prev_row > min_row) {
432     sel->prev_row--;
433   } else {
434     sel->prev_col = 0;
435   }
436 }
437 
ui_selected_region_is_changed(ui_selection_t * sel,int col,int row,u_int base)438 int ui_selected_region_is_changed(ui_selection_t *sel, int col, int row, u_int base) {
439   if (abs(sel->prev_col - col) >= base || abs(sel->prev_row - row) >= base) {
440     return 1;
441   } else {
442     return 0;
443   }
444 }
445 
ui_is_after_sel_right_base_pos(ui_selection_t * sel,int col,int row)446 int ui_is_after_sel_right_base_pos(ui_selection_t *sel, int col, int row) {
447   if (sel->is_rect) {
448     return sel->base_col_r < col;
449   } else {
450     if (sel->base_row_r < row || (sel->base_row_r == row && sel->base_col_r < col)) {
451       return 1;
452     } else {
453       return 0;
454     }
455   }
456 }
457 
ui_is_before_sel_left_base_pos(ui_selection_t * sel,int col,int row)458 int ui_is_before_sel_left_base_pos(ui_selection_t *sel, int col, int row) {
459   if (sel->is_rect) {
460     return sel->base_col_l > col;
461   } else {
462     if (sel->base_row_l > row || (sel->base_row_l == row && sel->base_col_l > col)) {
463       return 1;
464     } else {
465       return 0;
466     }
467   }
468 }
469 
ui_sel_lock(ui_selection_t * sel)470 void ui_sel_lock(ui_selection_t *sel) {
471   if (sel->beg_row < sel->base_row_l ||
472       (sel->beg_row == sel->base_row_l && sel->beg_col <= sel->base_col_l)) {
473     /*
474      * (Text surrounded by '*' is selected region. '|' is the base position.)
475      * aaa*bbb*|ccc
476      *     ^
477      *     +---- lock position ("bbb" is always selected.)
478      *
479      * This lock position is usually used in RTL lines.
480      */
481 
482     sel->lock_col = sel->beg_col;
483     sel->lock_row = sel->beg_row;
484 
485     sel->is_locked = -1;
486   } else {
487     /*
488      * (Text surrounded by '*' is selected region. '|' is the base position.)
489      * aaa|*bbb*ccc
490      *        ^
491      *        +---- lock position ("bbb" is always selected.)
492      *
493      * This lock position is usually used in LTR lines.
494      */
495 
496     sel->lock_col = sel->end_col;
497     sel->lock_row = sel->end_row;
498 
499     sel->is_locked = 1;
500   }
501 }
502