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