Rev 2297 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* levels.cc
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/
#include "main.h"
#include "levels.h"
#include "viewwin.h"
#include "input.h"
#include "console.h"
#include "utils.h"
#include "font.h"
#include "log.h"
using namespace std;
extern string user_data_dir;
extern int mousex, mousey, wheel, mouseyy, prev_mousey;
extern char BUFFER [];
extern int line_height;
levels::levels (const string& s) {
name = s;
editing = lmb_clicked = paint = nsel = 0;
selection = 0;
chgl = 0;
shftl = 0;
paintl = 0;
load ();
if (editable) {
const char* bt [] = {"Wrap", "Slide", "<<", ">>", "All", "None", "Invert", "+", "-", "x"};
button* b[] = {&cbwrap, &bslide, &blshift, &brshift, &ball, &bnone, &binvert, &plus, &minus, &cross};
click_listener* cl [] = {&cbwrap, &sll, &lsl, &rsl, &alll, &nonl, &invl, &pll, &mil, &crol};
for (int i = 0; i < 10; ++i) {
button* pbi = b[i];
click_listener* pcl = cl[i];
pbi->set_text (bt[i]);
pbi->set_listener (pcl);
pcl->data = this;
this->add_child (pbi);
}
this->add_child (&szr);
MOVE (szr);
szr.movlis = this;
blshift.click_repeat = brshift.click_repeat = 1;
bml.data = this;
}
}
levels::~levels () {
save ();
removeallbookmarks ();
if (selection) delete[] selection;
}
void levels::load () {
string ignore;
int left, bottom;
ifstream file ((user_data_dir + name).c_str(), ios::in);
file >> ignore >> n;
last = n - 1;
file >> ignore >> left >> bottom;
file >> ignore >> elem;
file >> ignore >> height;
file >> ignore >> editable;
file >> ignore >> saveable;
int w;
file >> ignore >> w;
cbwrap.set_state (w,0);
a = 0.7;
a0 = a / 4;
extents (left, bottom, left + n * elem, bottom + height);
set_pos (left, bottom);
values.resize (n);
heights.resize (n);
selection = new bool [n];
sel_sz = sizeof (bool) * n;
memset (selection, 0, sel_sz);
if (saveable) {
int savings;
file >> ignore >> savings;
for (int i = 0; i < savings; ++i) {
float h; file >> h >> selection[i];
heights[i] = h;
values[i] = h * extents.height_1;
}
file >> nsel;
}
int nb;
file >> ignore >> nb;
if (nb) {
bmk.resize (nb);
for (int i = 0, y = minus.extents.bottom - state_button::SIZE2; i < nb; ++i) {
bookmark* b = new bookmark ();
b->set_pos (minus.extents.left, y);
y -= state_button::SIZE2;
b->set_listener (&bml);
this->add_child (b);
bmk[i] = b;
int nid;
file >> nid;
vector<int>& ids = b->ids;
ids.resize (nid);
for (int m = 0; m < nid; ++m) file >> ids[m];
}
}
editing = 0;
}
void levels::save () {
ofstream file ((user_data_dir+name).c_str(), ios::out);
if (file) {
file << "num_levels " << n << endl;
file << "lower_corner " << extents.left << spc << extents.bottom << endl;
file << "element_width " << elem << endl;
file << "height " << height << endl;
file << "editable " << editable << endl;
file << "saveable " << saveable << endl;
file << "wrap " << cbwrap.state << endl;
if (saveable) {
file << "savings " << n << spc;
for (int i = 0; i < n; ++i) file << heights[i] << spc << selection[i] << spc;
file << nsel << endl;
} else {
file << "savings 0" << endl;
}
int j = bmk.size ();
file << "bookmarks " << j << spc;
if (j) {
for (int i = 0; i < j; ++i) {
bookmark* bi = bmk[i];
vector<int>& ids = bi->ids;
int n = ids.size ();
file << n << spc;
for (int m = 0; m < n; ++m) file << ids[m] << spc;
}
}
} else dlog << "!!! couldnt save levels !!!" << endl;
}
int levels::stop_editing () {
if (editing == FINISH) {
editing = 0;
return 1;
}
return 0;
}
int levels::handle_input () {
prev_mousey = mousey;
widget::handle_input ();
int hne = hover && !editing;
if (hne) calc_lev ();
if (editable) {
if (keypressed (SDLK_f)) {
paint = !paint;
if (paintl) paintl->paint (*this);
} else if (keypressedd (SDLK_LEFT)) {
lshift ();
} else if (keypressedd (SDLK_RIGHT)) {
rshift ();
}
for (int i = 0, j = children.size(); i < j; ++i) {
if (children[i]->handle_input ()) return 1;
}
if (lmb) {
if (lmb_clicked == 0) {
if (stop_editing () == 0) {
if (hne) {
if (SHIFT) {
bool& k = selection [lev];
k = !k;
if (k) ++nsel; else --nsel;
} else {
editing = STARTED;
widget::focus = this;
}
}
}
}
lmb_clicked = 1;
} else {
lmb_clicked = 0;
if (editing) {
if (wheel) {
mousey -= wheel;
warp_mouse (mousex, mousey);
}
if (paint) calc_lev ();
calc_hgt_val ();
int dh = set (lev, val, hgt);
int uml = 0;
if (selection[lev] && !SHIFT ) uml = update_mul_lev (dh);
if (chgl && (dh || uml)) chgl->changed (*this);
editing = FINISH;
} else {
if (widget::focus == this) widget::focus = 0;
}
}
}
return 1;
}
int levels::update_mul_lev (int dh) {
float dv = dh * extents.height_1;
int ret = 0;
for (int i = 0; i < n; ++i) {
if ((i != lev) && selection[i]) {
int& hi = heights[i];
float& vi = values[i];
int hji = hi + dh;
float vji = vi + dv;
if (hji < 0) hji = 0; else if (hji > extents.height) hji = extents.height;
if (vji < 0.0f) vji = 0.0f; else if (vji > 1.0f) vji = 1.0f;
hi = hji;
vi = vji;
ret = 1;
}
}
return ret;
}
void levels::calc_lev () {
lev = (mousex - extents.left) / elem;
if (lev > last || lev < 0) lev = -1;
}
void levels::calc_hgt_val () {
hgt = mouseyy - extents.bottom;
clamp<int> (0, hgt, extents.height);
val = hgt * extents.height_1;
}
void levels::clear_hgt_val () {
for (int i = 0; i < n; ++i) values[i] = heights[i] = 0;
}
void levels::draw () {
if (editing) {
glColor3f (.5f, .5f, .5f);
int ybh = extents.bottom + hgt;
glBegin (GL_LINES);
glVertex2i (extents.left, ybh);
glVertex2i (extents.right, ybh);
glEnd ();
}
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int i = 0, x = extents.left, ds = elem - 2;
if (extents.left < 0) {
i = -extents.left / elem;
x = 0;
}
for (;i < n; ++i) {
int l = x + 1, r = x + ds;
glColor4f (clr.r, clr.g, clr.b, a0);
glRecti (l, extents.bottom, r, extents.top);
float dc = selection[i] * 0.4;
glColor4f (clr.r + dc * clr.r, clr.g + dc * clr.g, clr.b + dc * clr.b, a);
glRecti (l, extents.bottom, r, extents.bottom + heights[i]);
x += elem;
extern viewport view;
if (x > view.xmax) break;
}
glDisable (GL_BLEND);
sprintf (BUFFER, "%d/%.3f", lev+1, lev > -1? values[lev]:-1);
draw_string (BUFFER, extents.left, extents.bottom - line_height, 0);
if (editable) for (int i = 0, j = children.size(); i < j; ++i) children[i]->draw ();
}
int levels::change (int i, float dv) {
if (i > -1 && i < n) {
float& vi = values[i];
vi += dv;
int result = clamp<float> (0, vi, 1);
heights[i] = (int) (vi * extents.height + 0.5);
return result;
}
return 0;
}
void levels::set_only (int i, float v) {
if (i > -1 && i < n) {
clamp<float> (0, v, 1);
values[i] = v;
heights[i] = (int)(v * extents.height + 0.5);
}
}
int levels::set (int i, float v, int h) { // from ui
if (i > -1 && i < n) {
int& hi = heights[i];
int dh = h - hi;
hi = h;
float& vi = values[i];
if (vi != v) { // bcos from ui
vi = v;
}
return dh;
}
return 0;
}
void levels::update () {
if (chgl) chgl->changed (*this);
}
void levels::chkpos () {
extern viewport view;
if (!view.inside (extents.left, extents.bottom)) extents.lower_corner (0, 0);
}
void levels::reheight () {
for (int i = 0; i < n; ++i) {
float v = values[i];
int h = v * height + 0.5;
heights[i] = h;
}
}
int levels::lshift () {
float v0 = values[0];
int h0 = heights[0];
int wrap = cbwrap.state;
if (wrap == 0) {
if (h0) return 0;
}
for (int i = 0, j = 1; i < last; ++i, ++j) {
values[i] = values[j];
heights[i] = heights[j];
}
float& vl = values[last];
int& hl = heights[last];
if (wrap) {
vl = v0;
hl = h0;
} else {
vl = 0;
hl = 0;
}
if (shftl) shftl->shifted (*this);
return 1;
}
int levels::rshift () {
float vl = values[last];
int hl = heights[last];
int wrap = cbwrap.state;
if (wrap == 0) {
if (hl) return 0;
}
for (int j = last, i = last - 1; j > 0; --j, --i) {
values[j]=values[i];
heights[j]=heights[i];
}
float& v0 = values[0];
int& h0 = heights[0];
if (wrap) {
v0 = vl;
h0 = hl;
} else {
v0 = 0;
h0 = 0;
}
if (shftl) shftl->shifted (*this);
return 1;
}
void levels::selall () {
nsel = 0;
for (int i = 0; i < n; ++i) {
if (heights[i]) {
selection[i] = 1;
++nsel;
}
}
clearbookmarks ();
}
void levels::selnon () {
for (int i = 0; i < n; ++i) selection[i] = 0;
nsel = 0;
clearbookmarks ();
}
void levels::invsel () {
for (int i = 0; i < n; ++i) {
bool& si = selection[i];
if (si) {
si = 0;
--nsel;
}
else if (heights[i]) {
si = 1;
++nsel;
}
}
clearbookmarks ();
}
CLICKED_BUTTON (levels, alllis) {
levels* l = (levels*) data;
l->selall();
}
CLICKED_BUTTON (levels, nonlis) {
levels* l = (levels*) data;
l->selnon();
}
CLICKED_BUTTON (levels, invlis) {
levels* l = (levels*) data;
l->invsel();
}
CLICKED_BUTTON (levels, lshiftlis) {
levels* l = (levels*) data;
l->lshift ();
}
CLICKED_BUTTON (levels, rshiftlis) {
levels* l = (levels*) data;
l->rshift ();
}
CLICKED_BUTTON (levels, pluslis) {
levels* l = (levels*) data;
l->addbookmark ();
}
void levels::slide::clicked (button& b) {
if (!mouse_slider0.active) {
mouse_slider0.add (this);
activate_mouse_slider ();
}
}
void levels::slide::moused (int dir, double scl) {
levels* l = (levels*) data;
if (dir > 0) l->rshift (); else l->lshift ();
}
void levels::set_pos (int x, int y) {
widget::set_pos (x, y);
extern int line_height;
int bx = extents.right + 3, by = extents.top - line_height;
blshift.set_pos (bx, by);
brshift.set_pos (bx + 28, by);
by -= line_height;
{
button* b[] = {&cbwrap, &bslide, &ball, &bnone, &binvert};
for (int i = 0; i < 5; ++i) {
button& bi = *b[i];
bi.set_pos (bx, by);
by -= line_height;
}
}
{
button* b[] = {&plus, &minus, &cross};
for (int i = 0; i < 3; ++i) {
b[i]->set_pos (bx, by);
bx += 20;
}
}
szr.set_pos (extents.right + elem, extents.bottom);
}
void levels::addbookmark () {
if (nsel) {
bookmark* bm = new bookmark ();
int bs = bmk.size ();
if (bs) {
int lb = bs - 1;
bookmark* plb = bmk [lb];
bm->set_pos (minus.extents.left, plb->extents.bottom - state_button::SIZE2);
} else {
bm->set_pos (minus.extents.left, minus.extents.bottom - state_button::SIZE2);
}
for (int i = 0; i < n; ++i) if (selection[i]) bm->ids.push_back (i);
clearbookmarks ();
bm->set_state (1, 0);
bm->set_listener (&bml);
bmk.push_back (bm);
this->add_child (bm);
cons << GREEN << "Bookmarked " << nsel << spc << name << eol;
} else {
cons << RED << "No " << name << " selected to bookmark. SHIFT+click " << name << " to select." << eol;
}
}
void levels::removebookmark () {
for (vector<bookmark*>::iterator i = bmk.begin (), j = bmk.end (); i != j; ) {
bookmark* b = *i;
if (b->state) {
i = bmk.erase (i);
j = bmk.end ();
this->remove_child (b);
delete b;
} else {
++i;
}
}
}
void levels::removeallbookmarks () {
for (int i = 0, j = bmk.size (); i < j; ++i) {
bookmark* pbi = bmk[i];
this->remove_child (pbi);
delete pbi;
}
bmk.clear ();
}
void levels::clearbookmarks () {
for (int i = 0, j = bmk.size (); i < j; ++i) bmk[i]->set_state (0,0);
}
CLICKED_CHECKBUTTON (levels, bmlis) {
bookmark& b = dynamic_cast<bookmark&>(cb);
int s = b.state;
levels& l = *( (levels*) data);
if (SHIFT)
;
else {
l.selnon ();
if (s == 0) s = 1;
b.set_state (s, 0);
}
int sl [] = {-1, 1};
for (int i = 0, j = l.bmk.size (); i < j; ++i) {
if (&b == l.bmk[i]) {
vector<int>& ids = b.ids;
int n = ids.size ();
for (int m = 0; m < n; ++m) l.selection[ids[m]] = s;
l.nsel += (n * sl[s]);
}
}
}
CLICKED_BUTTON (levels, minuslis) {
((levels*) data)->removebookmark ();
}
CLICKED_BUTTON (levels, crosslis) {
((levels*) data)->removeallbookmarks ();
}
/*MOVED (levels,szrlis) {
levels* pl = (levels *) data;
l->sized ();
}*/
void levels::moved () {
if (extents.top > szr.extents.bottom) {
height = extents.height = extents.top - szr.extents.bottom;
set_pos (posx, szr.posy);
reheight ();
}
}