1 /*
2 * levels.cc
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * DIN Is Noise is released under GNU Public License 2.0
5 * For more information, please visit https://dinisnoise.org/
6 */
7 
8 
9 #include "main.h"
10 #include "levels.h"
11 #include "viewwin.h"
12 #include "input.h"
13 #include "console.h"
14 #include "utils.h"
15 #include "font.h"
16 #include "log.h"
17 
18 using namespace std;
19 
20 extern string user_data_dir;
21 extern int mousex, mousey, wheel, mouseyy, prev_mousey;
22 extern char BUFFER [];
23 extern int line_height;
24 
levels(const string & s)25 levels::levels (const string& s) {
26   name = s;
27 	editing = lmb_clicked = paint = nsel = 0;
28 	selection = 0;
29   chgl = 0;
30   shftl = 0;
31   paintl = 0;
32   load ();
33 
34   if (editable) {
35     const char* bt [] = {"Wrap", "Slide", "<<", ">>", "All", "None", "Invert", "+", "-", "x"};
36     button* b[] = {&cbwrap, &bslide, &blshift, &brshift, &ball, &bnone, &binvert, &plus, &minus, &cross};
37     click_listener* cl [] = {&cbwrap, &sll, &lsl, &rsl, &alll, &nonl, &invl, &pll, &mil, &crol};
38     for (int i = 0; i < 10; ++i) {
39       button* pbi = b[i];
40       click_listener* pcl = cl[i];
41       pbi->set_text (bt[i]);
42       pbi->set_listener (pcl);
43       pcl->data = this;
44       this->add_child (pbi);
45     }
46 
47     this->add_child (&szr);
48 
49     MOVE (szr);
50     szr.movlis = this;
51 
52     blshift.click_repeat = brshift.click_repeat = 1;
53 
54     bml.data = this;
55   }
56 }
57 
~levels()58 levels::~levels () {
59   save ();
60   removeallbookmarks ();
61 	if (selection) delete[] selection;
62 }
63 
load()64 void levels::load () {
65 
66   string ignore;
67   int left, bottom;
68 
69   ifstream file ((user_data_dir + name).c_str(), ios::in);
70   file >> ignore >> n;
71   last = n - 1;
72   file >> ignore >> left >> bottom;
73   file >> ignore >> elem;
74   file >> ignore >> height;
75   file >> ignore >> editable;
76   file >> ignore >> saveable;
77 
78   int w;
79   file >> ignore >> w;
80   cbwrap.set_state (w,0);
81 
82 	a = 0.7;
83   a0 = a / 4;
84   extents (left, bottom, left + n * elem, bottom + height);
85   set_pos (left, bottom);
86 
87   values.resize (n);
88   heights.resize (n);
89 
90 	selection = new bool [n];
91 	sel_sz = sizeof (bool) * n;
92 	memset (selection, 0, sel_sz);
93 
94   if (saveable) {
95     int savings;
96     file >> ignore >> savings;
97     for (int i = 0; i < savings; ++i) {
98       float h; file >> h >> selection[i];
99       heights[i] = h;
100       values[i] =  h * extents.height_1;
101     }
102 		file >> nsel;
103   }
104 
105   int nb;
106   file >> ignore >> nb;
107   if (nb) {
108     bmk.resize (nb);
109     for (int i = 0, y = minus.extents.bottom - state_button::SIZE2; i < nb; ++i) {
110       bookmark* b = new bookmark ();
111       b->set_pos (minus.extents.left, y);
112       y -= state_button::SIZE2;
113       b->set_listener (&bml);
114       this->add_child (b);
115       bmk[i] = b;
116       int nid;
117       file >> nid;
118       vector<int>& ids = b->ids;
119       ids.resize (nid);
120       for (int m = 0; m < nid; ++m) file >> ids[m];
121     }
122   }
123 
124   editing = 0;
125 
126 }
127 
save()128 void levels::save () {
129   ofstream file ((user_data_dir+name).c_str(), ios::out);
130   if (file) {
131     file << "num_levels " << n << endl;
132     file << "lower_corner " << extents.left << spc << extents.bottom << endl;
133     file << "element_width " << elem << endl;
134     file << "height " << height << endl;
135     file << "editable " << editable << endl;
136     file << "saveable " << saveable << endl;
137 		file << "wrap " << cbwrap.state << endl;
138     if (saveable) {
139       file << "savings " << n << spc;
140       for (int i = 0; i < n; ++i) file << heights[i] << spc << selection[i] << spc;
141 			file << nsel << endl;
142     } else {
143       file << "savings 0" << endl;
144     }
145 
146     int j = bmk.size ();
147     file << "bookmarks " << j << spc;
148     if (j) {
149       for (int i = 0; i < j; ++i) {
150         bookmark* bi = bmk[i];
151         vector<int>& ids = bi->ids;
152         int n = ids.size ();
153         file << n << spc;
154         for (int m = 0; m < n; ++m) file << ids[m] << spc;
155       }
156     }
157   } else dlog << "!!! couldnt save levels !!!" << endl;
158 }
159 
stop_editing()160 int levels::stop_editing () {
161 	if (editing == FINISH) {
162 		editing = 0;
163 		return 1;
164 	}
165 	return 0;
166 }
167 
handle_input()168 int levels::handle_input () {
169 
170 	prev_mousey = mousey;
171 
172   widget::handle_input ();
173 
174 	int hne = hover && !editing;
175 	if (hne) calc_lev ();
176 
177   if (keypressed (SDLK_f)) {
178     paint = !paint;
179     if (paintl) paintl->paint (*this);
180   }
181 
182 	if (editable) {
183 
184     for (int i = 0, j = children.size(); i < j; ++i) {
185       if (children[i]->handle_input ()) return 1;
186     }
187 
188 		if (lmb) {
189 			if (lmb_clicked == 0) {
190 				if (stop_editing () == 0) {
191 					if (hne) {
192 						if (SHIFT) {
193 							bool& k = selection [lev];
194 							k = !k;
195 							if (k) ++nsel; else --nsel;
196 						} else {
197 							editing = STARTED;
198 							widget::focus = this;
199 						}
200 					}
201 				}
202 			}
203 			lmb_clicked = 1;
204 		} else {
205 
206 			lmb_clicked = 0;
207 			if (editing) {
208 
209 				if (wheel) {
210 					mousey -= wheel;
211 					warp_mouse (mousex, mousey);
212 				}
213 
214 				if (paint) calc_lev ();
215 
216 				calc_hgt_val ();
217 
218 				int dh = set (lev, val, hgt);
219 				int uml = 0;
220 				if (selection[lev] && !SHIFT ) uml = update_mul_lev (dh);
221 				if (chgl && (dh || uml)) chgl->changed (*this);
222 
223 				editing = FINISH;
224 
225 			} else {
226 				if (widget::focus == this) widget::focus = 0;
227 			}
228 		}
229 	}
230 
231   return 1;
232 
233 }
234 
update_mul_lev(int dh)235 int levels::update_mul_lev (int dh) {
236 	float dv = dh * extents.height_1;
237 	int ret = 0;
238 	for (int i = 0; i < n; ++i) {
239 		if ((i != lev) && selection[i]) {
240 			int& hi = heights[i];
241 			float& vi = values[i];
242 			int hji = hi + dh;
243 			float vji = vi + dv;
244 
245 			if (hji < 0) hji = 0; else if (hji > extents.height) hji = extents.height;
246 			if (vji < 0.0f) vji = 0.0f; else if (vji > 1.0f) vji = 1.0f;
247 			hi = hji;
248 			vi = vji;
249 			ret = 1;
250 		}
251 	}
252 	return ret;
253 }
254 
calc_lev()255 void levels::calc_lev () {
256   lev =  (mousex - extents.left) / elem;
257   if (lev > last || lev < 0) lev = -1;
258 }
259 
calc_hgt_val()260 void levels::calc_hgt_val () {
261   hgt = mouseyy - extents.bottom;
262 	clamp<int> (0, hgt, extents.height);
263   val = hgt * extents.height_1;
264 }
265 
clear_hgt_val()266 void levels::clear_hgt_val () {
267   for (int i = 0; i < n; ++i) values[i] = heights[i] = 0;
268 }
269 
draw()270 void levels::draw () {
271 
272   glEnable (GL_BLEND);
273   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
274     int i = 0, x = extents.left, ds = elem - 2;
275     if (extents.left < 0) {
276       i = -extents.left / elem;
277       x = 0;
278     }
279     for (;i < n; ++i) {
280       int l = x + 1, r = x + ds;
281       glColor4f (clr.r, clr.g, clr.b, a0);
282         glRecti (l, extents.bottom, r, extents.top);
283 
284 			float dc = selection[i] * 0.4;
285       glColor4f (clr.r + dc * clr.r, clr.g + dc * clr.g, clr.b + dc * clr.b, a);
286         glRecti (l, extents.bottom, r, extents.bottom + heights[i]);
287       x += elem;
288       extern viewport view;
289       if (x > view.xmax) break;
290     }
291   glDisable (GL_BLEND);
292 
293   sprintf (BUFFER, "%d/%.3f", lev+1, lev > -1? values[lev]:-1);
294   draw_string (BUFFER, extents.left, extents.bottom - line_height, 0);
295 
296   if (editable) for (int i = 0, j = children.size(); i < j; ++i) children[i]->draw ();
297 
298 }
299 
change(int i,float dv)300 int levels::change (int i, float dv) {
301 	if (i > -1 && i < n) {
302 		float& vi = values[i];
303 		vi += dv;
304 		int result = clamp<float> (0, vi, 1);
305 		heights[i] = (int) (vi * extents.height + 0.5);
306 		return result;
307 	}
308 	return 0;
309 }
310 
set_only(int i,float v)311 void levels::set_only (int i, float v) {
312 	if (i > -1 && i < n) {
313 		clamp<float> (0, v, 1);
314 		values[i] = v;
315 		heights[i] = (int)(v * extents.height + 0.5);
316 	}
317 }
318 
set(int i,float v,int h)319 int levels::set (int i, float v, int h) { // from ui
320   if (i > -1 && i < n) {
321 		int& hi = heights[i];
322 		int dh = h - hi;
323 		hi = h;
324 		float& vi = values[i];
325 		if (vi != v) { // bcos from ui
326 			vi = v;
327 		}
328 		return dh;
329   }
330 	return 0;
331 }
332 
update()333 void levels::update () {
334 	if (chgl) chgl->changed (*this);
335 }
336 
chkpos()337 void levels::chkpos () {
338   extern viewport view;
339   if (!view.inside (extents.left, extents.bottom)) extents.lower_corner (0, 0);
340 }
341 
reheight()342 void levels::reheight () {
343 	for (int i = 0; i < n; ++i) {
344 		float v = values[i];
345 		int h = v * height + 0.5;
346 		heights[i] = h;
347 	}
348 }
349 
lshift()350 int levels::lshift () {
351 
352 	float v0 = values[0];
353 	int h0 = heights[0];
354 
355   int wrap = cbwrap.state;
356 
357 	if (wrap == 0) {
358 		if (h0) return 0;
359 	}
360 
361 	for (int i = 0, j = 1; i < last; ++i, ++j) {
362 		values[i] = values[j];
363 		heights[i] = heights[j];
364 	}
365 
366   float& vl = values[last];
367   int& hl = heights[last];
368 	if (wrap) {
369 		vl = v0;
370 		hl = h0;
371 	} else {
372     vl = 0;
373     hl = 0;
374 	}
375 
376   if (shftl) shftl->shifted (*this);
377 
378 	return 1;
379 
380 }
381 
rshift()382 int levels::rshift () {
383 	float vl = values[last];
384 	int hl = heights[last];
385 
386   int wrap = cbwrap.state;
387 	if (wrap == 0) {
388 		if (hl) return 0;
389 	}
390 
391 	for (int j = last, i = last - 1; j > 0; --j, --i) {
392 		values[j]=values[i];
393 		heights[j]=heights[i];
394 	}
395 
396   float& v0 = values[0];
397   int& h0 = heights[0];
398 
399 	if (wrap) {
400 		v0 = vl;
401 		h0 = hl;
402 	} else {
403 		v0 = 0;
404     h0 = 0;
405 	}
406 
407   if (shftl) shftl->shifted (*this);
408 
409 	return 1;
410 
411 }
412 
selall()413 void levels::selall () {
414   nsel = 0;
415 	for (int i = 0; i < n; ++i) {
416 		if (heights[i]) {
417       selection[i] = 1;
418       ++nsel;
419     }
420 	}
421 	clearbookmarks ();
422 }
423 
selnon()424 void levels::selnon () {
425 	for (int i = 0; i < n; ++i) selection[i] = 0;
426 	nsel = 0;
427 	clearbookmarks ();
428 }
429 
invsel()430 void levels::invsel () {
431 	for (int i = 0; i < n; ++i) {
432 		bool& si = selection[i];
433 		if (si) {
434 			si = 0;
435 			--nsel;
436 		}
437 		else if (heights[i]) {
438 			si = 1;
439 			++nsel;
440 		}
441 	}
442 	clearbookmarks ();
443 }
444 
CLICKED_BUTTON(levels,alllis)445 CLICKED_BUTTON (levels, alllis) {
446   levels* l = (levels*) data;
447   l->selall();
448 }
449 
CLICKED_BUTTON(levels,nonlis)450 CLICKED_BUTTON (levels, nonlis) {
451   levels* l = (levels*) data;
452   l->selnon();
453 }
454 
455 
CLICKED_BUTTON(levels,invlis)456 CLICKED_BUTTON (levels, invlis) {
457   levels* l = (levels*) data;
458   l->invsel();
459 }
460 
CLICKED_BUTTON(levels,lshiftlis)461 CLICKED_BUTTON (levels, lshiftlis) {
462   levels* l = (levels*) data;
463   l->lshift ();
464 }
465 
CLICKED_BUTTON(levels,rshiftlis)466 CLICKED_BUTTON (levels, rshiftlis) {
467   levels* l = (levels*) data;
468   l->rshift ();
469 }
470 
CLICKED_BUTTON(levels,pluslis)471 CLICKED_BUTTON (levels, pluslis) {
472   levels* l = (levels*) data;
473   l->addbookmark ();
474 }
475 
clicked(button & b)476 void levels::slide::clicked (button& b) {
477   if (!mouse_slider0.active) {
478     mouse_slider0.add (this);
479     activate_mouse_slider ();
480   }
481 }
482 
moused(int dir,double scl)483 void levels::slide::moused (int dir, double scl) {
484   levels* l = (levels*) data;
485   if (dir > 0) l->rshift (); else l->lshift ();
486 }
487 
set_pos(int x,int y)488 void levels::set_pos (int x, int y) {
489   widget::set_pos (x, y);
490   extern int line_height;
491   int bx = extents.right + 3, by = extents.top - line_height;
492   blshift.set_pos (bx, by);
493   brshift.set_pos (bx + 28, by);
494   by -= line_height;
495   {
496     button* b[] = {&cbwrap, &bslide, &ball, &bnone, &binvert};
497     for (int i = 0; i < 5; ++i) {
498       button& bi = *b[i];
499       bi.set_pos (bx, by);
500       by -= line_height;
501     }
502   }
503   {
504     button* b[] = {&plus, &minus, &cross};
505     for (int i = 0; i < 3; ++i) {
506       b[i]->set_pos (bx, by);
507       bx += 20;
508     }
509   }
510   szr.set_pos (extents.right + elem, extents.bottom);
511 }
512 
addbookmark()513 void levels::addbookmark () {
514 
515 	if (nsel) {
516 		bookmark* bm = new bookmark ();
517 		int bs = bmk.size ();
518 		if (bs) {
519 			int lb = bs - 1;
520 			bookmark* plb = bmk [lb];
521 			bm->set_pos (minus.extents.left, plb->extents.bottom - state_button::SIZE2);
522 		} else {
523 			bm->set_pos (minus.extents.left, minus.extents.bottom - state_button::SIZE2);
524 		}
525 
526 		for (int i = 0; i < n; ++i) if (selection[i]) bm->ids.push_back (i);
527 
528 		clearbookmarks ();
529 
530 		bm->set_state (1, 0);
531 		bm->set_listener (&bml);
532 
533 		bmk.push_back (bm);
534     this->add_child (bm);
535 
536     cons << GREEN << "Bookmarked " << nsel << spc << name << eol;
537 
538 	} else {
539 		cons << RED << "No " << name << " selected to bookmark. SHIFT+click " << name << " to select." << eol;
540 	}
541 
542 }
543 
removebookmark()544 void levels::removebookmark () {
545 	for (vector<bookmark*>::iterator i = bmk.begin (), j = bmk.end (); i != j; ) {
546 		bookmark* b = *i;
547 		if (b->state) {
548 			i = bmk.erase (i);
549 			j = bmk.end ();
550       this->remove_child (b);
551       delete b;
552 		} else {
553 			++i;
554 		}
555 	}
556 }
557 
removeallbookmarks()558 void levels::removeallbookmarks () {
559 	for (int i = 0, j = bmk.size (); i < j; ++i) {
560 		bookmark* pbi = bmk[i];
561 		this->remove_child (pbi);
562     delete pbi;
563 	}
564 	bmk.clear ();
565 }
566 
clearbookmarks()567 void levels::clearbookmarks () {
568 	for (int i = 0, j = bmk.size (); i < j; ++i) bmk[i]->set_state (0,0);
569 }
570 
CLICKED_CHECKBUTTON(levels,bmlis)571 CLICKED_CHECKBUTTON (levels, bmlis) {
572 	bookmark& b = dynamic_cast<bookmark&>(cb);
573 	int s = b.state;
574   levels& l = *( (levels*) data);
575 	if (SHIFT)
576 		;
577 	else {
578 		l.selnon ();
579 		if (s == 0) s = 1;
580 		b.set_state (s, 0);
581 	}
582 
583   int sl [] = {-1, 1};
584 	for (int i = 0, j = l.bmk.size (); i < j; ++i) {
585 		if (&b == l.bmk[i]) {
586 			vector<int>& ids = b.ids;
587 			int n = ids.size ();
588 			for (int m = 0; m < n; ++m) l.selection[ids[m]] = s;
589 			l.nsel += (n * sl[s]);
590 		}
591 	}
592 }
593 
CLICKED_BUTTON(levels,minuslis)594 CLICKED_BUTTON (levels, minuslis) {
595   ((levels*) data)->removebookmark ();
596 }
597 
CLICKED_BUTTON(levels,crosslis)598 CLICKED_BUTTON (levels, crosslis) {
599   ((levels*) data)->removeallbookmarks ();
600 }
601 
602 /*MOVED (levels,szrlis) {
603   levels* pl = (levels *) data;
604   l->sized ();
605 }*/
606 
moved()607 void levels::moved () {
608 	if (extents.top > szr.extents.bottom) {
609 		height = extents.height = extents.top - szr.extents.bottom;
610 		set_pos (posx, szr.posy);
611 		reheight ();
612 	}
613 }
614