1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include "vt_edit_scroll.h"
4
5 #include <pobl/bl_util.h>
6
7 #include "vt_edit_util.h"
8
9 /* --- static functions --- */
10
11 /*
12 * src and dst may overlap
13 */
copy_lines(vt_edit_t * edit,int dst_row,int src_row,u_int size,int mark_changed)14 static int copy_lines(vt_edit_t *edit, int dst_row, int src_row, u_int size, int mark_changed) {
15 int count;
16 vt_line_t *src_line;
17 vt_line_t *dst_line;
18
19 if (size == 0 || dst_row == src_row) {
20 return 1;
21 }
22
23 if (src_row + size > edit->model.num_rows) {
24 #ifdef DEBUG
25 bl_warn_printf(BL_DEBUG_TAG " copying %d lines from %d row is over edit->model.num_rows(%d)",
26 size, src_row, edit->model.num_rows);
27 #endif
28
29 size = edit->model.num_rows - src_row;
30
31 #ifdef DEBUG
32 bl_msg_printf(" ... size modified -> %d.\n", size);
33 #endif
34 }
35
36 if (dst_row + size > edit->model.num_rows) {
37 #ifdef DEBUG
38 bl_warn_printf(BL_DEBUG_TAG " copying %d lines to %d row is over edit->model.num_rows(%d)",
39 size, dst_row, edit->model.num_rows);
40 #endif
41
42 size = edit->model.num_rows - dst_row;
43
44 #ifdef DEBUG
45 bl_msg_printf(" ... size modified -> %d.\n", size);
46 #endif
47 }
48
49 if (dst_row < src_row) {
50 for (count = 0; count < size; count++) {
51 dst_line = vt_model_get_line(&edit->model, dst_row + count);
52 src_line = vt_model_get_line(&edit->model, src_row + count);
53
54 vt_line_swap(dst_line, src_line);
55 if (mark_changed) {
56 vt_line_set_modified_all(dst_line);
57 }
58 }
59 } else {
60 for (count = size - 1; count >= 0; count--) {
61 dst_line = vt_model_get_line(&edit->model, dst_row + count);
62 src_line = vt_model_get_line(&edit->model, src_row + count);
63
64 vt_line_swap(dst_line, src_line);
65 if (mark_changed) {
66 vt_line_set_modified_all(dst_line);
67 }
68 }
69 }
70
71 return 1;
72 }
73
clear_lines_to_eol(vt_edit_t * edit,int beg_row,u_int size)74 static int clear_lines_to_eol(vt_edit_t *edit, int beg_row, u_int size) {
75 int count;
76
77 vt_edit_clear_lines(edit, beg_row, size);
78
79 for (count = 0; count < size; count++) {
80 vt_line_set_modified_all(vt_model_get_line(&edit->model, beg_row + count));
81 }
82
83 return 1;
84 }
85
scroll_upward_region(vt_edit_t * edit,int boundary_beg,int boundary_end,u_int size)86 static int scroll_upward_region(vt_edit_t *edit, int boundary_beg, int boundary_end, u_int size) {
87 int count;
88 int window_is_scrolled;
89
90 if (boundary_beg + size > boundary_end) {
91 /*
92 * all lines within boundary are scrolled out.
93 */
94
95 if (edit->is_logging) {
96 for (count = boundary_beg; count < boundary_end; count++) {
97 (*edit->scroll_listener->receive_scrolled_out_line)(edit->scroll_listener->self,
98 vt_model_get_line(&edit->model, count));
99 }
100 }
101
102 edit->cursor.row = boundary_beg;
103 edit->cursor.col = 0;
104 edit->cursor.char_index = 0;
105
106 (*edit->scroll_listener->scrolled_out_lines_finished)(edit->scroll_listener->self);
107
108 return clear_lines_to_eol(edit, boundary_beg, boundary_end - boundary_beg + 1);
109 }
110
111 /*
112 * scrolling up in window.
113 *
114 * !! Notice !!
115 * This should be done before vt_edit_t data structure is chanegd
116 * for the listener object to clear existing cache.
117 */
118 #if 0
119 bl_debug_printf(" SCROLL UP region %d %d size %d\n", boundary_beg, boundary_end, size);
120 #endif
121 window_is_scrolled = (*edit->scroll_listener->window_scroll_upward_region)(
122 edit->scroll_listener->self, boundary_beg, boundary_end, size);
123
124 /*
125 * handing over scrolled out lines , and calculating scrolling beg/end y
126 * positions.
127 */
128
129 if (edit->is_logging) {
130 for (count = boundary_beg; count < boundary_beg + size; count++) {
131 (*edit->scroll_listener->receive_scrolled_out_line)(edit->scroll_listener->self,
132 vt_model_get_line(&edit->model, count));
133 }
134 }
135
136 /*
137 * resetting cursor position.
138 */
139
140 if (boundary_beg <= edit->cursor.row && edit->cursor.row <= boundary_end) {
141 if (edit->cursor.row < boundary_beg + size) {
142 edit->cursor.row = boundary_beg;
143 edit->cursor.char_index = 0;
144 edit->cursor.col = 0;
145 } else {
146 edit->cursor.row -= size;
147 }
148 }
149
150 /*
151 * scrolling up in edit.
152 */
153
154 if (boundary_beg == 0 && boundary_end == vt_model_end_row(&edit->model)) {
155 vt_model_scroll_upward(&edit->model, size);
156 } else {
157 copy_lines(edit, boundary_beg, boundary_beg + size, boundary_end - (boundary_beg + size) + 1,
158 0);
159 }
160
161 if (!window_is_scrolled) {
162 int count;
163
164 vt_edit_clear_lines(edit, boundary_end - size + 1, size);
165
166 for (count = boundary_beg; count <= boundary_end; count++) {
167 vt_line_set_modified_all(vt_model_get_line(&edit->model, count));
168 }
169 } else {
170 clear_lines_to_eol(edit, boundary_end - size + 1, size);
171 }
172
173 /*
174 * This must be called after vt_model_scroll_upward() because
175 * scrolled_out_lines_finished()
176 * can change vt_model_t.
177 */
178 (*edit->scroll_listener->scrolled_out_lines_finished)(edit->scroll_listener->self);
179
180 return 1;
181 }
182
scroll_downward_region(vt_edit_t * edit,int boundary_beg,int boundary_end,u_int size)183 static int scroll_downward_region(vt_edit_t *edit, int boundary_beg, int boundary_end, u_int size) {
184 int window_is_scrolled;
185
186 if (boundary_beg + size > boundary_end) {
187 /*
188 * all lines within boundary are scrolled out.
189 */
190
191 edit->cursor.row = boundary_end;
192 edit->cursor.col = 0;
193 edit->cursor.char_index = 0;
194
195 return clear_lines_to_eol(edit, boundary_beg, boundary_end - boundary_beg + 1);
196 }
197
198 /*
199 * scrolling down in window.
200 *
201 * !! Notice !!
202 * This should be done before vt_edit_t data structure is chanegd
203 * for the listener object to clear existing cache.
204 */
205 #if 0
206 bl_debug_printf(" SCROLL DOWN region %d %d size %d\n", boundary_beg, boundary_end, size);
207 #endif
208 window_is_scrolled = (*edit->scroll_listener->window_scroll_downward_region)(
209 edit->scroll_listener->self, boundary_beg, boundary_end, size);
210
211 /*
212 * resetting cursor position.
213 */
214 if (boundary_beg <= edit->cursor.row && edit->cursor.row <= boundary_end) {
215 if (edit->cursor.row + size >= boundary_end + 1) {
216 edit->cursor.row = boundary_end;
217 edit->cursor.char_index = 0;
218 edit->cursor.col = 0;
219 } else {
220 edit->cursor.row += size;
221 }
222 }
223
224 /*
225 * scrolling down in edit.
226 */
227
228 if (boundary_beg == 0 && boundary_end == vt_model_end_row(&edit->model)) {
229 vt_model_scroll_downward(&edit->model, size);
230 } else {
231 copy_lines(edit, boundary_beg + size, boundary_beg, (boundary_end - size) - boundary_beg + 1,
232 0);
233 }
234
235 if (!window_is_scrolled) {
236 int count;
237
238 vt_edit_clear_lines(edit, boundary_beg, size);
239
240 for (count = boundary_beg; count <= boundary_end; count++) {
241 vt_line_set_modified_all(vt_model_get_line(&edit->model, count));
242 }
243 } else {
244 clear_lines_to_eol(edit, boundary_beg, size);
245 }
246
247 return 1;
248 }
249
250 /* --- global functions --- */
251
vt_edsl_scroll_upward(vt_edit_t * edit,u_int size)252 int vt_edsl_scroll_upward(vt_edit_t *edit, u_int size) {
253 #if 0
254 /*
255 * XXX
256 * Can this cause unexpected result ?
257 */
258 if (edit->vmargin_beg > edit->cursor.row || edit->cursor.row > edit->vmargin_end) {
259 return 0;
260 }
261 #endif
262
263 return scroll_upward_region(edit, edit->vmargin_beg, edit->vmargin_end, size);
264 }
265
vt_edsl_scroll_downward(vt_edit_t * edit,u_int size)266 int vt_edsl_scroll_downward(vt_edit_t *edit, u_int size) {
267 #if 0
268 /*
269 * XXX
270 * Can this cause unexpected result ?
271 */
272 if (edit->vmargin_beg > edit->cursor.row || edit->cursor.row > edit->vmargin_end) {
273 return 0;
274 }
275 #endif
276
277 return scroll_downward_region(edit, edit->vmargin_beg, edit->vmargin_end, size);
278 }
279
280 /*
281 * XXX
282 * not used for now.
283 */
284 #if 0
285 int vt_edsl_scroll_upward_in_all(vt_edit_t *edit, u_int size) {
286 return scroll_upward_region(edit, 0, edit->model.num_rows - 1, size);
287 }
288
289 int vt_edsl_scroll_downward_in_all(vt_edit_t *edit, u_int size) {
290 return scroll_downward_region(edit, 0, edit->model.num_rows - 1, size);
291 }
292 #endif
293
vt_is_scroll_upperlimit(vt_edit_t * edit,int row)294 int vt_is_scroll_upperlimit(vt_edit_t *edit, int row) { return (row == edit->vmargin_beg); }
295
vt_is_scroll_lowerlimit(vt_edit_t * edit,int row)296 int vt_is_scroll_lowerlimit(vt_edit_t *edit, int row) { return (row == edit->vmargin_end); }
297
vt_edsl_insert_new_line(vt_edit_t * edit)298 int vt_edsl_insert_new_line(vt_edit_t *edit) {
299 int start_row;
300 int start_col;
301 int end_row;
302
303 if (edit->cursor.row < edit->vmargin_beg || edit->vmargin_end < edit->cursor.row) {
304 return 0;
305 }
306
307 start_row = edit->cursor.row;
308 start_col = edit->cursor.col;
309 end_row = edit->vmargin_end;
310
311 scroll_downward_region(edit, start_row, end_row, 1);
312 vt_cursor_goto_by_col(&edit->cursor, start_col, start_row);
313 vt_edit_clear_line_to_right(edit);
314
315 return 1;
316 }
317
vt_edsl_delete_line(vt_edit_t * edit)318 int vt_edsl_delete_line(vt_edit_t *edit) {
319 int start_row;
320 int start_col;
321 int end_row;
322 int is_logging;
323
324 if (edit->cursor.row < edit->vmargin_beg || edit->vmargin_end < edit->cursor.row) {
325 return 0;
326 }
327
328 is_logging = edit->is_logging;
329 edit->is_logging = 0;
330
331 start_row = edit->cursor.row;
332 start_col = edit->cursor.col;
333 end_row = edit->vmargin_end;
334
335 scroll_upward_region(edit, start_row, end_row, 1);
336 vt_edit_clear_lines(edit, end_row, 1);
337 vt_cursor_goto_by_col(&edit->cursor, start_col, start_row);
338
339 edit->is_logging = is_logging;
340
341 return 1;
342 }
343