diff options
author | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:56:41 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:59:33 -0800 |
commit | d577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch) | |
tree | 590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/srccontrols/iup_dial.c |
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/srccontrols/iup_dial.c')
-rwxr-xr-x | iup/srccontrols/iup_dial.c | 864 |
1 files changed, 864 insertions, 0 deletions
diff --git a/iup/srccontrols/iup_dial.c b/iup/srccontrols/iup_dial.c new file mode 100755 index 0000000..1dd2d0f --- /dev/null +++ b/iup/srccontrols/iup_dial.c @@ -0,0 +1,864 @@ +/** \file + * \brief Dial Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include <cd.h> +#include <cdiup.h> +#include <cddbuf.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_controls.h" +#include "iup_cdutil.h" + + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define IDIAL_SPACE 3 +#define IDIAL_NCOLORS 10 +#define IDIAL_DEFAULT_DENSITY 0.2 +#define IDIAL_DEFAULT_DENSITY_STR "0.2" +#define IDIAL_DEFAULT_FGCOLOR "64 64 64" +#define IDIAL_DEFAULT_FGCOLOR_COMP 64 + +enum{IDIAL_VERTICAL, IDIAL_HORIZONTAL, IDIAL_CIRCULAR}; + +#define dialmin(a,b) ((a)<(b)?(a):(b)) + + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + /* attributes */ + double angle; + int type; + double unit; + double density; + + /* mouse interaction control */ + int px; + int py; + int pressing; + + /* visual appearance control */ + void (*Draw)(Ihandle* ih); + int w, h; + int has_focus; + int num_div; /* number of sections in the dial wheel */ + double radius; /* radius size of the dial wheel */ + long fgcolor[IDIAL_NCOLORS+1]; + long bgcolor, + light_shadow, + mid_shadow, + dark_shadow; + + /* drawing canvas */ + cdCanvas *cddbuffer; + cdCanvas *cdcanvas; +}; + + +static long int iDialGetFgColor(Ihandle* ih, double a, double amin) +{ + double nu = fabs(a - 0.5 * M_PI); + double de = fabs(0.5 * M_PI - amin); + double fr = nu / de; + int i = (int)(IDIAL_NCOLORS * fr); + return ih->data->fgcolor[IDIAL_NCOLORS - i]; +} + +static void iDialDrawVerticalBackground(Ihandle* ih, double amin, double amax, int *ymin, int *ymax) +{ + double delta = (0.5 * M_PI - amin) / IDIAL_NCOLORS; + double a, yc = ih->data->h / 2.0; + *ymin = *ymax = ih->data->h / 2; + for (a = amin; a < 0.5 * M_PI; a += delta) /* shading */ + { + int y0 = (int)(yc - ih->data->radius * cos(a)); + int y1 = (int)(yc - ih->data->radius * cos(a+delta)); + cdCanvasForeground(ih->data->cddbuffer, iDialGetFgColor(ih, a, amin)); + cdCanvasBox(ih->data->cddbuffer, IDIAL_SPACE+1, ih->data->w-1-IDIAL_SPACE-2, y0, y1); + + if (y0 < *ymin) *ymin = y0; + + if (abs(y1-y0) < 2) + continue; + } + for (a = 0.5 * M_PI; a < amax; a += delta) + { + int y0 = (int)(yc + ih->data->radius * fabs(cos(a))); + int y1 = (int)(yc + ih->data->radius * fabs(cos(a+delta))); + cdCanvasForeground(ih->data->cddbuffer, iDialGetFgColor(ih, a, amin)); + cdCanvasBox(ih->data->cddbuffer, IDIAL_SPACE+1, ih->data->w-1-IDIAL_SPACE-2, y0, y1); + + if (y1 > *ymax) *ymax = y1; + + if (abs(y1-y0) < 2) + continue; + } +} + +static void iDialDrawVertical(Ihandle* ih) +{ + double delta = 2 * M_PI / ih->data->num_div; + double a, amin, amax; + int ymin, ymax; + + ih->data->radius = (ih->data->h - 2 * IDIAL_SPACE - 2) / 2.0; + + amin = 0.0; + amax = M_PI; + if(ih->data->angle < amin) + { + for (a = ih->data->angle; a < amin; a += delta) + ; + } + else + { + for (a = ih->data->angle; a > amin; a -= delta) + ; + a += delta; + } + + iDialDrawVerticalBackground(ih, amin, amax, &ymin, &ymax); + + cdIupDrawRaisenRect(ih->data->cddbuffer, IDIAL_SPACE, ymin, ih->data->w-1-IDIAL_SPACE, ymax, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + for ( ; a < amax; a += delta) /* graduation */ + { + int y; + if (a < 0.5 * M_PI) y = (int)(ih->data->h / 2.0 - ih->data->radius * cos(a)); + else y = (int)(ih->data->h / 2.0 + ih->data->radius * fabs(cos(a))); + + if (abs(y-ymin) < 3 || abs(ymax-y) < 3) + continue; + + cdIupDrawHorizSunkenMark(ih->data->cddbuffer, IDIAL_SPACE+1, ih->data->w-1-IDIAL_SPACE-2, y, ih->data->light_shadow, ih->data->dark_shadow); + } +} + +static void iDialDrawHorizontalBackground(Ihandle* ih,double amin,double amax, int *xmin, int *xmax) +{ + double delta = (0.5 * M_PI - amin) / IDIAL_NCOLORS; + double a, xc = ih->data->w / 2.0; + *xmin = *xmax = ih->data->w / 2; + for (a = amin; a < 0.5 * M_PI; a += delta) + { + int x0=(int)(xc - ih->data->radius * cos(a)); + int x1=(int)(xc - ih->data->radius * cos(a + delta)); + cdCanvasForeground(ih->data->cddbuffer,iDialGetFgColor(ih, a, amin)); + cdCanvasBox(ih->data->cddbuffer, x0, x1, IDIAL_SPACE+2, ih->data->h-1-IDIAL_SPACE-1); + + if (x0 < *xmin) *xmin = x0; + + if (abs(x1 - x0) < 2) + continue; + } + for (a = 0.5 * M_PI; a < amax; a += delta) + { + int x0 =(int)(xc + ih->data->radius * fabs(cos(a))); + int x1 =(int)(xc + ih->data->radius * fabs(cos(a + delta))); + cdCanvasForeground(ih->data->cddbuffer, iDialGetFgColor(ih, a, amin)); + cdCanvasBox(ih->data->cddbuffer, x0, x1, IDIAL_SPACE+2, ih->data->h-1-IDIAL_SPACE-1); + + if (x1 > *xmax) *xmax = x1; + + if (abs(x1-x0) < 2) + continue; + } +} + +static void iDialDrawHorizontal(Ihandle* ih) +{ + double delta = 2 * M_PI / ih->data->num_div; + int x; + double a, amin, amax; + int xmin, xmax; + ih->data->radius = (ih->data->w - 2 * IDIAL_SPACE - 2) / 2.0; + amin = 0.0; + amax = M_PI; + if(ih->data->angle < amin) + { + for (a = ih->data->angle; a < amin; a += delta) ; + } + else + { + for (a = ih->data->angle; a > amin; a-= delta) ; + a += delta; + } + + iDialDrawHorizontalBackground(ih, amin, amax, &xmin, &xmax); + + cdIupDrawRaisenRect(ih->data->cddbuffer, xmin, IDIAL_SPACE, xmax, ih->data->h-1-IDIAL_SPACE, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + for ( ; a < amax; a += delta) + { + if (a < 0.5 * M_PI) x = (int)(ih->data->w / 2.0 - ih->data->radius * cos(a)); + else x = (int)(ih->data->w / 2.0 + ih->data->radius * fabs(cos(a))); + + if (abs(x - xmin) < 3 || abs(xmax - x) < 3) + continue; + + cdIupDrawVertSunkenMark(ih->data->cddbuffer, x, IDIAL_SPACE+2, ih->data->h-1-IDIAL_SPACE-1, ih->data->light_shadow, ih->data->dark_shadow); + } +} + +static void iDialDrawCircularMark(Ihandle* ih, int x1, int y1) +{ + cdCanvasForeground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasBox(ih->data->cddbuffer,x1, x1+4, y1, y1+4); + + cdCanvasForeground(ih->data->cddbuffer, ih->data->light_shadow); + cdCanvasLine(ih->data->cddbuffer, x1, y1+1, x1, y1+3); + cdCanvasLine(ih->data->cddbuffer, x1+1, y1+4, x1+3, y1+4); + + cdCanvasForeground(ih->data->cddbuffer, ih->data->mid_shadow); + cdCanvasLine(ih->data->cddbuffer, x1+1, y1, x1+4, y1); + cdCanvasLine(ih->data->cddbuffer, x1+4, y1, x1+4, y1+3); + + cdCanvasForeground(ih->data->cddbuffer, ih->data->dark_shadow); + cdCanvasLine(ih->data->cddbuffer, x1+2, y1, x1+3, y1); + cdCanvasLine(ih->data->cddbuffer, x1+4, y1+1, x1+4, y1+2); +} + +static void iDialDrawCircular(Ihandle* ih) +{ + double delta = 2 * M_PI / ih->data->num_div, a = ih->data->angle; + int i, xc = ih->data->w / 2, yc = ih->data->h / 2, wide; + ih->data->radius = dialmin(ih->data->w, ih->data->h) / 2 - 2 * IDIAL_SPACE; + + wide = (int)(2 * ih->data->radius); + cdCanvasForeground(ih->data->cddbuffer, ih->data->mid_shadow); + cdCanvasLineWidth(ih->data->cddbuffer, 2); + cdCanvasArc(ih->data->cddbuffer, xc, yc, wide-1, wide-1, -135, 45.0); + cdCanvasLineWidth(ih->data->cddbuffer, 1); + cdCanvasForeground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasSector(ih->data->cddbuffer, xc, yc, wide-2, wide-2, 0.0, 360.0); + cdCanvasForeground(ih->data->cddbuffer, ih->data->light_shadow); + cdCanvasArc(ih->data->cddbuffer, xc, yc, wide, wide, 45, 225); + cdCanvasForeground(ih->data->cddbuffer, ih->data->dark_shadow); + cdCanvasArc(ih->data->cddbuffer, xc, yc, wide, wide, -135, 45); + + for (i = 0; i < ih->data->num_div; ++i) + { + int x2 = (int)(xc + (ih->data->radius - 6) * cos(a)); + int y2 = (int)(yc + (ih->data->radius - 6) * sin(a)); + + if (i == 0) + { + cdCanvasForeground(ih->data->cddbuffer, CD_BLACK); + cdCanvasLine(ih->data->cddbuffer, xc, yc, x2, y2); + } + + iDialDrawCircularMark(ih, x2-2, y2-2); + a += delta; + } + + iDialDrawCircularMark(ih, xc-2, yc-2); +} + +static void iDialRepaint(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return; + + /* update render */ + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + ih->data->Draw(ih); + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + cdIupDrawFocusRect(ih, ih->data->cdcanvas, 0, 0, ih->data->w-1, ih->data->h-1); +} + +static void iDialUpdateFgColors(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b) +{ + int i, max, deltar, deltag, deltab; + + /* this function is also called before mapping */ + max = (ih->handle && iupdrvIsActive(ih))? 255 : 192; + deltar = (max-r) / IDIAL_NCOLORS; + deltag = (max-g) / IDIAL_NCOLORS; + deltab = (max-b) / IDIAL_NCOLORS; + + for (i=0; i<=IDIAL_NCOLORS; i++) + { + ih->data->fgcolor[i] = cdEncodeColor(r, g, b); + r = (unsigned char)(r + deltar); + g = (unsigned char)(g + deltag); + b = (unsigned char)(b + deltab); + } +} + +static int iDialButtonPress(Ihandle* ih, int button, int x, int y) +{ + IFn cb; + + if (button!=IUP_BUTTON1) + return IUP_DEFAULT; + + y = cdIupInvertYAxis(y, ih->data->h); + ih->data->px = x; + ih->data->py = y; + + if (ih->data->type != IDIAL_CIRCULAR) + ih->data->angle=0; + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB"); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_DEFAULT; +} + +static int iDialButtonRelease(Ihandle* ih, int button) +{ + IFn cb; + + if (button!=IUP_BUTTON1) + return IUP_DEFAULT; + + iDialRepaint(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB"); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_DEFAULT; +} + + +/******************************************************************/ + + +static int iDialMotionVertical_CB(Ihandle* ih, int x, int y, char *status) +{ + IFn cb; + (void)x; /* not used */ + + if (!iup_isbutton1(status)) + return IUP_DEFAULT; + + y = cdIupInvertYAxis(y, ih->data->h); + ih->data->angle += (double)(y-ih->data->py) / ih->data->radius; + ih->data->py = y; + + iDialRepaint(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_DEFAULT; +} + +static int iDialMotionHorizontal_CB(Ihandle* ih, int x, int y, char *status) +{ + IFn cb; + + if (!iup_isbutton1(status)) + return IUP_DEFAULT; + + y = cdIupInvertYAxis(y, ih->data->h); + ih->data->angle += (double)(x-ih->data->px) / ih->data->radius; + ih->data->px = x; + + iDialRepaint(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_DEFAULT; +} + +static int iDialMotionCircular_CB(Ihandle* ih, int x, int y, char *status) +{ + int cx = ih->data->w / 2; + int cy = ih->data->h / 2; + double vet, xa, ya, xb, yb, ma, mb, ab; + IFn cb; + + if (!iup_isbutton1(status)) + return IUP_DEFAULT; + + y = cdIupInvertYAxis(y, ih->data->h); + + xa = ih->data->px-cx; + ya = ih->data->py-cy; + ma = sqrt(xa * xa + ya * ya); + + xb = x - cx; + yb = y - cy; + mb = sqrt(xb * xb + yb * yb); + + ab = xa * xb + ya * yb; + vet = xa * yb - xb * ya; + + ab = ab / (ma * mb); + + /* if the mouse is in the center of the dial, ignore it */ + if (ma == 0 || mb == 0 || ab < -1 || ab > 1) + return IUP_DEFAULT; + + if (vet>0) ih->data->angle += acos(ab); + else ih->data->angle -= acos(ab); + + iDialRepaint(ih); + ih->data->px = x; + ih->data->py = y; + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_DEFAULT; +} + +static int iDialButton_CB(Ihandle* ih, int button, int pressed, int x, int y) +{ + if (pressed) + return iDialButtonPress(ih, button, x, y); + else + return iDialButtonRelease(ih, button); +} + +static int iDialResize_CB(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + { + /* update canvas size */ + cdCanvasActivate(ih->data->cdcanvas); + + /* this can fail if canvas size is zero */ + ih->data->cddbuffer = cdCreateCanvas(CD_DBUFFER, ih->data->cdcanvas); + } + + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + /* update size */ + cdCanvasActivate(ih->data->cddbuffer); + cdCanvasGetSize(ih->data->cddbuffer, &ih->data->w, &ih->data->h, NULL, NULL); + + /* update number of divisions */ + switch(ih->data->type) + { + case IDIAL_VERTICAL: + ih->data->num_div = (int)((ih->data->h-2 * IDIAL_SPACE-2) * ih->data->density); + break; + + case IDIAL_HORIZONTAL: + ih->data->num_div = (int)((ih->data->w-2 * IDIAL_SPACE-2) * ih->data->density); + break; + + case IDIAL_CIRCULAR: + ih->data->num_div = (int)((dialmin(ih->data->w, ih->data->h)-2 * IDIAL_SPACE-2) * ih->data->density); + break; + } + + /* update render */ + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + ih->data->Draw(ih); + + return IUP_DEFAULT; +} + +static int iDialRedraw_CB(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + cdIupDrawFocusRect(ih, ih->data->cdcanvas, 0, 0, ih->data->w-1, ih->data->h-1); + + return IUP_DEFAULT; +} + +static int iDialFocus_CB(Ihandle* ih, int focus) +{ + ih->data->has_focus = focus; + iDialRepaint(ih); + return IUP_DEFAULT; +} + +static int iDialKeyPress_CB(Ihandle* ih, int c, int press) +{ + IFn cb; + char* cb_name; + + if (c != K_LEFT && c != K_UP && + c != K_sLEFT && c != K_sUP && + c != K_RIGHT && c != K_DOWN && + c != K_sRIGHT && c != K_sDOWN && + c != K_HOME) + return IUP_DEFAULT; + + if (press && ih->data->pressing) + { + switch(c) + { + case K_sLEFT: + case K_sDOWN: + ih->data->angle -= M_PI / 100.0; + break; + case K_LEFT: + case K_DOWN: + ih->data->angle -= M_PI / 10.0; + break; + case K_sRIGHT: + case K_sUP: + ih->data->angle += M_PI / 100.0; + break; + case K_RIGHT: + case K_UP: + ih->data->angle += M_PI / 10.0; + break; + } + } + + if (c == K_HOME) + ih->data->angle = 0; + + if (press) + { + if (ih->data->pressing) + { + cb_name = "MOUSEMOVE_CB"; + } + else + { + ih->data->pressing = 1; + if (ih->data->type != IDIAL_CIRCULAR) + ih->data->angle = 0; + cb_name = "BUTTON_PRESS_CB"; + } + } + else + { + ih->data->pressing = 0; + cb_name = "RELEASE_CB"; + } + + iDialRepaint(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, cb_name); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ +} + +static int iDialWheel_CB(Ihandle* ih, float delta) +{ + IFn cb; + + ih->data->angle += ((double)delta) * (M_PI / 10.0); + + if (fabs(ih->data->angle) < M_PI / 10.1) + ih->data->angle = 0; + + iDialRepaint(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + cb(ih); + else + { + IFnd cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + if (cb_old) + cb_old(ih, ih->data->angle * ih->data->unit); + } + + return IUP_DEFAULT; +} + + +/*********************************************************************************/ + + +static char* iDialGetValueAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->angle); + return str; +} + +static int iDialSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) /* reset to default */ + ih->data->angle = 0; + else + ih->data->angle = atof(value); + + iDialRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static int iDialSetDensityAttrib(Ihandle* ih, const char* value) +{ + ih->data->density = atof(value); + iDialRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iDialGetDensityAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->density); + return str; +} + +static int iDialSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (!value) + value = iupControlBaseGetParentBgColor(ih); + + ih->data->bgcolor = cdIupConvertColor(value); + + cdIupCalcShadows(ih->data->bgcolor, &ih->data->light_shadow, &ih->data->mid_shadow, &ih->data->dark_shadow); + if (!iupdrvIsActive(ih)) + ih->data->light_shadow = ih->data->mid_shadow; + + iDialRepaint(ih); + return 1; +} + +static int iDialSetFgColorAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + iDialUpdateFgColors(ih, r, g, b); + + iDialRepaint(ih); + return 1; +} + +static int iDialSetActiveAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + + iupBaseSetActiveAttrib(ih, value); + + value = iupAttribGetStr(ih, "FGCOLOR"); + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + iDialUpdateFgColors(ih, r, g, b); + + cdIupCalcShadows(ih->data->bgcolor, &ih->data->light_shadow, &ih->data->mid_shadow, &ih->data->dark_shadow); + if (!iupdrvIsActive(ih)) + ih->data->light_shadow = ih->data->mid_shadow; + + iDialRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static int iDialSetUnitAttrib(Ihandle* ih, const char* value) +{ + ih->data->unit = iupStrEqualNoCase(value, "DEGREES")? CD_RAD2DEG : 1.0; + return 1; +} + +static int iDialSetTypeAttrib(Ihandle* ih, const char* value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrEqualNoCase(value, "VERTICAL")) + { + ih->data->Draw = iDialDrawVertical; + ih->data->type = IDIAL_VERTICAL; + IupSetCallback(ih, "MOTION_CB", (Icallback)iDialMotionVertical_CB); + IupSetAttribute(ih, "SIZE", "16x80"); + } + else if (iupStrEqualNoCase(value, "CIRCULAR")) + { + ih->data->Draw = iDialDrawCircular; + ih->data->type = IDIAL_CIRCULAR; + IupSetCallback(ih, "MOTION_CB", (Icallback)iDialMotionCircular_CB); + IupSetAttribute(ih, "SIZE", "40x36"); + } + else /* "HORIZONTAL" */ + { + ih->data->Draw = iDialDrawHorizontal; + ih->data->type = IDIAL_HORIZONTAL; + IupSetCallback(ih, "MOTION_CB", (Icallback)iDialMotionHorizontal_CB); + IupSetAttribute(ih, "SIZE", "80x16"); + } + return 0; /* do not store value in hash table */ +} + +static char* iDialGetTypeAttrib(Ihandle* ih) +{ + if (ih->data->type == IDIAL_HORIZONTAL) + return "HORIZONTAL"; + else if (ih->data->type == IDIAL_VERTICAL) + return "VERTICAL"; + else /* (ih->data->type == IDIAL_CIRCULAR) */ + return "CIRCULAR"; +} + + +/****************************************************************************/ + + +static int iDialMapMethod(Ihandle* ih) +{ + ih->data->cdcanvas = cdCreateCanvas(CD_IUP, ih); + if (!ih->data->cdcanvas) + return IUP_ERROR; + + /* this can fail if canvas size is zero */ + ih->data->cddbuffer = cdCreateCanvas(CD_DBUFFER, ih->data->cdcanvas); + + return IUP_NOERROR; +} + +static void iDialUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static int iDialCreateMethod(Ihandle* ih, void **params) +{ + char* type = "HORIZONTAL"; + if (params && params[0]) + type = params[0]; + + /* free the data allocated by IupCanvas */ + if (ih->data) free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* change the IupCanvas default values */ + iupAttribSetStr(ih, "BORDER", "NO"); + ih->expand = IUP_EXPAND_NONE; + + /* default values */ + iDialSetTypeAttrib(ih, type); + ih->data->density = IDIAL_DEFAULT_DENSITY; + ih->data->unit = 1.0; /* RADIANS */ + iDialUpdateFgColors(ih, IDIAL_DEFAULT_FGCOLOR_COMP, IDIAL_DEFAULT_FGCOLOR_COMP, IDIAL_DEFAULT_FGCOLOR_COMP); + + /* IupCanvas callbacks */ + IupSetCallback(ih, "ACTION", (Icallback)iDialRedraw_CB); + IupSetCallback(ih, "RESIZE_CB", (Icallback)iDialResize_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iDialButton_CB); + IupSetCallback(ih, "FOCUS_CB", (Icallback)iDialFocus_CB); + IupSetCallback(ih, "KEYPRESS_CB", (Icallback)iDialKeyPress_CB); + IupSetCallback(ih, "WHEEL_CB", (Icallback)iDialWheel_CB); + + return IUP_NOERROR; +} + +Iclass* iupDialGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "dial"; + ic->format = "S"; /* one optional string */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iDialCreateMethod; + ic->Map = iDialMapMethod; + ic->UnMap = iDialUnMapMethod; + + /* Do not need to set base attributes because they are inherited from IupCanvas */ + + /* IupDial Callbacks */ + iupClassRegisterCallback(ic, "MOUSEMOVE_CB", "d"); + iupClassRegisterCallback(ic, "BUTTON_PRESS_CB", "d"); + iupClassRegisterCallback(ic, "BUTTON_RELEASE_CB", "d"); + iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); + + /* IupDial only */ + iupClassRegisterAttribute(ic, "VALUE", iDialGetValueAttrib, iDialSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TYPE", iDialGetTypeAttrib, iDialSetTypeAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DENSITY", iDialGetDensityAttrib, iDialSetDensityAttrib, IDIAL_DEFAULT_DENSITY_STR, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iDialSetFgColorAttrib, IDIAL_DEFAULT_FGCOLOR, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "UNIT", NULL, iDialSetUnitAttrib, IUPAF_SAMEASSYSTEM, "RADIANS", IUPAF_NOT_MAPPED); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iDialSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iDialSetBgColorAttrib, NULL, "255 255 255", IUPAF_NO_INHERIT); /* overwrite canvas implementation, set a system default to force a new default */ + + return ic; +} + +Ihandle* IupDial(const char* type) +{ + void *params[2]; + params[0] = (void*)type; + params[1] = NULL; + return IupCreatev("dial", params); +} |