Rev 2199 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* slider.h
* DIN Is Noise is copyright (c) 2006-2025 Jagannathan Sampath
* For more information, please visit http://dinisnoise.org/
*/
#ifndef __slider
#define __slider
#include "widget.h"
#include "viewwin.h"
#include "utils.h"
#include "filled_button.h"
#include "input.h"
#include <algorithm>
#include <vector>
extern int mousex;
extern viewport view;
extern int lmb;
template <typename S> struct after_slide_lis {
virtual void slided (S& s) = 0;
};
template <typename S> struct start_slide_lis {
virtual void start_slide (S& s) = 0;
};
template <typename T> struct values {
T low, high, delta, val;
float amount;
values (T l = 0, T h = 1, T v = 0) {
set_limits (l, h);
*this = v;
}
operator T() {
return ((T) val);
}
void set_limits (T l, T h) {
low = l;
high = h;
delta = high - low;
}
void get_limits (T& l, T& h) {
l = low;
h = high;
}
T operator() () const { return val; }
values& operator= (const T& v) {
val = v;
clamp<T> (low, val, high);
if (delta) amount = (val - low) * 1.0f / delta; else amount = 0;
return *this;
}
void set_amount (float a) {
amount = a;
clamp<float> (0.0f, amount, 1.0f);
val = (T) (low + delta * amount);
}
float get_amount () const { return amount; }
};
template <typename T> struct slider : widget, move_listener {
values<T> vx;
int dx;
std::vector<int> dxa;
int sliding;
int lmb_clicked;
change_listener<slider> *chgl;
after_slide_lis<slider> *asl;
start_slide_lis<slider> *ssl;
filled_button sizer;
static const int spc = 10;
slider (int sv = 0, int w = 64, int h = 16) : widget (0, 0, w, h), vx (0, 0, 0), sliding(0), lmb_clicked(0) {
chgl = 0;
asl = 0;
set_sizer_visible (sv);
}
void set_sizer_visible (int sv) {
sizer.visible = sv;
if (sizer.visible) {
sizer.set_moveable (1);
sizer.movlis = this;
} else {
sizer.set_moveable (0);
sizer.movlis = 0;
}
}
void set_pos (int x, int y) {
widget::set_pos (x, y);
sizer.set_pos (extents.right + spc, extents.bottom);
}
void set_right (int r) {
set_extents (extents.left, extents.bottom, r, extents.top);
dx = vx.get_amount () * extents.width;
}
void set_size (int w) {
set_extents (extents.left, extents.bottom, extents.left + w, extents.top);
dx = vx.get_amount () * extents.width;
}
void moved () {
int mpx = mousex - movr.prevx;
if (mpx) {
sizer.set_pos (mousex, extents.bottom);
int msx = mousex - spc;
if (msx > extents.left) set_right (msx);
}
}
int handle_input () {
widget::handle_input ();
if (sizer.visible && sizer.handle_input ()) return 1;
int ret = 0;
if (lmb) {
if (lmb_clicked == 0) {
if (sliding) {
sliding = 0;
if (asl) asl->slided (*this);
defocus (this);
ret = 1;
} else {
if (hover) {
sliding = 1;
if (ssl) ssl->start_slide (*this);
widget::focus = this;
ret = 1;
}
}
lmb_clicked = 1;
}
} else {
if (sliding) {
int nu_dx = mousex - extents.left;
clamp (0, nu_dx, extents.width);
if (nu_dx != dx) {
dx = nu_dx;
vx.set_amount (dx * extents.width_1);
if (chgl) chgl->changed (*this);
}
if (keypressed(SDLK_f)) dxa.push_back (dx);
if (keypressed(SDLK_BACKSPACE)) dxa.clear ();
} else
ret = 0;
lmb_clicked = 0;
}
return ret;
}
void draw () {
widget::draw ();
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
const color& c = clr;
glColor4f (c.r, c.g, c.b, (GLfloat) 0.25);
const box<int>& e = extents;
glRecti (e.left, e.bottom, e.right, e.top);
glColor4f (c.r, c.g, c.b, GLfloat (1));
glRecti (e.left, e.bottom, e.left + dx, e.top);
glDisable (GL_BLEND);
glColor3f (1, 1, 1);
for (int i = 0, j = dxa.size (); i < j; ++i) {
int dxi = extents.left + dxa[i];
glBegin (GL_LINES);
glVertex2i (dxi, extents.top + spc);
glVertex2i (dxi, extents.bottom - spc);
glEnd ();
}
if (sizer.visible) sizer.draw ();
}
void update () {
float amount = vx.get_amount ();
const box<int>& e = extents;
dx = (int) (amount * e.width);
}
void set_listener (change_listener<slider>* _chgl, start_slide_lis<slider>* _ssl = 0, after_slide_lis<slider>* _asl = 0) {
chgl = _chgl;
ssl = _ssl;
asl = _asl;
}
T operator() () const {return vx (); }
void set_val (const T& t) {
vx = t;
update ();
}
void set_limits (T l, T h) {
vx = values<T> (l, h, vx());
update ();
}
void get_limits (T& l, T& h) {
vx.get_limits (l, h);
}
};
#define MAKE_SLIDER_LISTENER(name,var) struct name : change_listener< slider<float> > { void changed (slider<float>& s); }; name var;
#define SLIDER_CHANGED(scope,name) void scope::name::changed (slider<float>& s)
#define MAKE_AFTER_SLIDE_LISTENER(name,type,var) struct name : after_slide_lis< type > { void slided (type& s); }; name var;
#define SLIDED(scope,name,type) void scope::name::slided (type& s)
#define MAKE_START_SLIDE_LISTENER(name,type,var) struct name : start_slide_lis< type > { void start_slide (type& s); }; name var;
#define START_SLIDE(scope,name,type) void scope::name::start_slide (type& s)
#endif