1 /*******************************************************************************
2 * Copyright (c) 2013-2021, Andrés Martinelli <andmarti@gmail.com> *
3 * All rights reserved. *
4 * *
5 * This file is a part of SC-IM *
6 * *
7 * SC-IM is a spreadsheet program that is based on SC. The original authors *
8 * of SC are James Gosling and Mark Weiser, and mods were later added by *
9 * Chuck Martin. *
10 * *
11 * Redistribution and use in source and binary forms, with or without *
12 * modification, are permitted provided that the following conditions are met: *
13 * 1. Redistributions of source code must retain the above copyright *
14 * notice, this list of conditions and the following disclaimer. *
15 * 2. Redistributions in binary form must reproduce the above copyright *
16 * notice, this list of conditions and the following disclaimer in the *
17 * documentation and/or other materials provided with the distribution. *
18 * 3. All advertising materials mentioning features or use of this software *
19 * must display the following acknowledgement: *
20 * This product includes software developed by Andrés Martinelli *
21 * <andmarti@gmail.com>. *
22 * 4. Neither the name of the Andrés Martinelli nor the *
23 * names of other contributors may be used to endorse or promote products *
24 * derived from this software without specific prior written permission. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY ANDRES MARTINELLI ''AS IS'' AND ANY *
27 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *
29 * DISCLAIMED. IN NO EVENT SHALL ANDRES MARTINELLI BE LIABLE FOR ANY *
30 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;*
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
36 *******************************************************************************/
37
38 /**
39 * \file shift.c
40 * \author Andrés Martinelli <andmarti@gmail.com>
41 * \date 2017-07-18
42 * \brief TODO Write a tbrief file description.
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include "shift.h"
48 #include "sc.h"
49 #include "vmtbl.h" // for growtbl
50 #include "cmds.h"
51 #include "dep_graph.h"
52 #include "undo.h"
53 #include "marks.h"
54 #include "yank.h"
55 #include "conf.h"
56 #include "tui.h"
57
58 extern graphADT graph;
59 extern int cmd_multiplier;
60
61 /**
62 * @brief Shift function - handles undo
63 *
64 * Shift functin - handles unto. Should also be called form gram.y.
65 *
66 * \param[in] r
67 * \param[in] c
68 * \param[in] rf
69 * \param[in] cf
70 * \param[in] type
71 *
72 * \return none
73 */
74
shift(int r,int c,int rf,int cf,wchar_t type)75 void shift(int r, int c, int rf, int cf, wchar_t type) {
76 if ( any_locked_cells(r, c, rf, cf) && (type == L'h' || type == L'k') ) {
77 sc_error("Locked cells encountered. Nothing changed");
78 return;
79 }
80 #ifdef UNDO
81 create_undo_action();
82 #endif
83 int ic = cmd_multiplier + 1;
84
85 switch (type) {
86
87 case L'j':
88 fix_marks( (rf - r + 1) * cmd_multiplier, 0, r, maxrow, c, cf);
89 #ifdef UNDO
90 save_undo_range_shift(cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf);
91 #endif
92 while (ic--) shift_range(ic, 0, r, c, rf, cf);
93 break;
94
95 case L'k':
96 fix_marks( -(rf - r + 1) * cmd_multiplier, 0, r, maxrow, c, cf);
97 yank_area(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, 'a', cmd_multiplier); // keep ents in yanklist for sk
98 #ifdef UNDO
99 ents_that_depends_on_range(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf);
100 copy_to_undostruct(r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf, UNDO_DEL, HANDLE_DEPS, NULL);
101 save_undo_range_shift(-cmd_multiplier, 0, r, c, rf + (rf-r+1) * (cmd_multiplier - 1), cf);
102 #endif
103 while (ic--) shift_range(-ic, 0, r, c, rf, cf);
104 if (get_conf_int("autocalc") && ! loading) EvalAll();
105 #ifdef UNDO
106 copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL);
107 #endif
108 break;
109
110 case L'h':
111 fix_marks(0, -(cf - c + 1) * cmd_multiplier, r, rf, c, maxcol);
112 yank_area(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), 'a', cmd_multiplier); // keep ents in yanklist for sk
113 #ifdef UNDO
114 // here we save in undostruct, all the ents that depends on the deleted one (before change)
115 ents_that_depends_on_range(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1));
116 copy_to_undostruct(r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1), UNDO_DEL, HANDLE_DEPS, NULL);
117 save_undo_range_shift(0, -cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1));
118 #endif
119 while (ic--) shift_range(0, -ic, r, c, rf, cf);
120
121 if (get_conf_int("autocalc") && ! loading) EvalAll();
122 //update(TRUE); // this is used just to make debugging easier
123 #ifdef UNDO
124 copy_to_undostruct(0, 0, -1, -1, UNDO_ADD, HANDLE_DEPS, NULL);
125 #endif
126 break;
127
128 case L'l':
129 fix_marks(0, (cf - c + 1) * cmd_multiplier, r, rf, c, maxcol);
130 #ifdef UNDO
131 save_undo_range_shift(0, cmd_multiplier, r, c, rf, cf + (cf-c+1) * (cmd_multiplier - 1));
132 #endif
133 while (ic--) shift_range(0, ic, r, c, rf, cf);
134 break;
135 }
136 #ifdef UNDO
137 end_undo_action();
138 extern struct ent_ptr * deps;
139 if (deps != NULL) free(deps);
140 deps = NULL;
141 #endif
142 /* just for testing
143 sync_refs();
144 rebuild_graph();
145 sync_refs();
146 rebuild_graph(); */
147 cmd_multiplier = 0;
148 return;
149 }
150
151 /**
152 * \brief Shift a range to 'ENTS'
153 *
154 * \param[in] delta_rows
155 * \param[in] delta_cols
156 * \param[in] tlrow
157 * \param[in] tlcol
158 * \param[in] brrow
159 * \param[in] brcol
160 *
161 * \return none
162 */
163
shift_range(int delta_rows,int delta_cols,int tlrow,int tlcol,int brrow,int brcol)164 void shift_range(int delta_rows, int delta_cols, int tlrow, int tlcol, int brrow, int brcol) {
165 currow = tlrow;
166 curcol = tlcol;
167
168 if (delta_rows > 0) shift_cells_down (brrow - tlrow + 1, brcol - tlcol + 1);
169 else if (delta_rows < 0) shift_cells_up (brrow - tlrow + 1, brcol - tlcol + 1);
170
171 if (delta_cols > 0) shift_cells_right(brrow - tlrow + 1, brcol - tlcol + 1);
172 else if (delta_cols < 0) shift_cells_left (brrow - tlrow + 1, brcol - tlcol + 1);
173
174 return;
175 }
176
177 /**
178 * \brief Shift cells down
179 *
180 * \param[in] deltarows
181 * \param[in] deltacols
182 *
183 * \return none
184 */
185
shift_cells_down(int deltarows,int deltacols)186 void shift_cells_down(int deltarows, int deltacols) {
187 int r, c;
188 struct ent ** pp;
189 if (currow > maxrow) maxrow = currow;
190 maxrow += deltarows;
191 if ((maxrow >= maxrows) && !growtbl(GROWROW, maxrow, 0))
192 return;
193
194 for (r = maxrow; r > currow + deltarows - 1; r--) {
195 for (c = curcol; c < curcol + deltacols; c++) {
196 pp = ATBL(tbl, r, c);
197 pp[0] = *ATBL(tbl, r-deltarows, c);
198 if ( pp[0] ) pp[0]->row += deltarows;
199 }
200 }
201 // blank new ents
202 for (c = curcol; c < curcol + deltacols; c++)
203 for (r = currow; r < currow + deltarows; r++) {
204 pp = ATBL(tbl, r, c);
205 *pp = (struct ent *) 0;
206 }
207 return;
208 }
209
210 /**
211 * \brief Shift cells right
212 *
213 * \param[in] deltaros
214 * \param[in] deltacols
215 *
216 * \return none
217 */
218
shift_cells_right(int deltarows,int deltacols)219 void shift_cells_right(int deltarows, int deltacols) {
220 int r, c;
221 struct ent ** pp;
222
223 if (curcol + deltacols > maxcol)
224 maxcol = curcol + deltacols;
225 maxcol += deltacols;
226
227 if ((maxcol >= maxcols) && !growtbl(GROWCOL, 0, maxcol))
228 return;
229
230 int lim = maxcol - curcol - deltacols;
231 for (r=currow; r < currow + deltarows; r++) {
232 pp = ATBL(tbl, r, maxcol);
233 for (c = lim; c-- >= 0; pp--)
234 if ((pp[0] = pp[-deltacols])) pp[0]->col += deltacols;
235
236 pp = ATBL(tbl, r, curcol);
237 for (c = curcol; c < curcol + deltacols; c++, pp++)
238 *pp = (struct ent *) 0;
239 }
240 return;
241 }
242
243 /**
244 * \brief Shift cells up
245 *
246 * \param[in] deltarows
247 * \param[in] deltacols
248 *
249 * \return none
250 */
251
shift_cells_up(int deltarows,int deltacols)252 void shift_cells_up(int deltarows, int deltacols) {
253 int r, c;
254 struct ent ** pp;
255
256 for (r = currow; r <= maxrow; r++) {
257 for (c = curcol; c < curcol + deltacols; c++) {
258
259 if (r < currow + deltarows) {
260 pp = ATBL(tbl, r, c);
261
262 /* delete vertex in graph
263 unless vertex is referenced by other. Shall comment this? See NOTE1 above */
264 vertexT * v = getVertex(graph, *pp, 0);
265 if (v != NULL && v->back_edges == NULL ) destroy_vertex(*pp);
266
267 if (*pp) {
268 mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted
269 //clearent(*pp);
270 //free(*pp);
271 *pp = NULL;
272 }
273 }
274 if (r <= maxrow - deltarows) {
275 pp = ATBL(tbl, r, c);
276 pp[0] = *ATBL(tbl, r + deltarows, c);
277 if ( pp[0] ) pp[0]->row -= deltarows;
278 }
279 //blank bottom ents
280 if (r > maxrow - deltarows) {
281 pp = ATBL(tbl, r, c);
282 *pp = (struct ent *) 0;
283 }
284 }
285 }
286 return;
287 }
288
289 /**
290 * \brief Shift cells left
291 *
292 * \param[in] deltarows
293 * \param[in] deltacols
294 *
295 * \return none
296 */
297
shift_cells_left(int deltarows,int deltacols)298 void shift_cells_left(int deltarows, int deltacols) {
299 int r, c;
300 struct ent ** pp;
301
302 for (c = curcol; c <= maxcol; c++) {
303 for (r = currow; r < currow + deltarows; r++) {
304
305 if (c < curcol + deltacols) {
306 pp = ATBL(tbl, r, c);
307
308 /* delete vertex in graph
309 unless vertex is referenced by other */
310 vertexT * v = getVertex(graph, *pp, 0);
311 if (v != NULL && v->back_edges == NULL ) destroy_vertex(*pp);
312
313 if (*pp) {
314 mark_ent_as_deleted(*pp, TRUE); //important: this mark the ents as deleted
315 //clearent(*pp);
316 //free(*pp);
317 *pp = NULL;
318 }
319 }
320 if (c <= maxcol - deltacols) {
321 pp = ATBL(tbl, r, c);
322 pp[0] = *ATBL(tbl, r, c + deltacols);
323 if ( pp[0] ) pp[0]->col -= deltacols;
324 }
325 //blank bottom ents
326 if (c > maxcol - deltacols) {
327 pp = ATBL(tbl, r, c);
328 *pp = (struct ent *) 0;
329 }
330 }
331 }
332 return;
333 }
334