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 |
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/srccontrols')
48 files changed, 16279 insertions, 0 deletions
diff --git a/iup/srccontrols/Makefile b/iup/srccontrols/Makefile new file mode 100755 index 0000000..d02bbc3 --- /dev/null +++ b/iup/srccontrols/Makefile @@ -0,0 +1,6 @@ + +.PHONY: do_all iupcontrols +do_all: iupcontrols + +iupcontrols: + @$(MAKE) --no-print-directory -f ../tecmake_compact.mak diff --git a/iup/srccontrols/color/iup_colorbrowser.c b/iup/srccontrols/color/iup_colorbrowser.c new file mode 100755 index 0000000..82b4a88 --- /dev/null +++ b/iup/srccontrols/color/iup_colorbrowser.c @@ -0,0 +1,849 @@ +/** \file +* \brief ColorBrowser 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 <cdirgb.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" + +#include "iup_colorhsi.h" + + +#ifndef min +#define min(a, b) ( (a < b) ? (a) : (b) ) +#endif + +#define ICB_DEG2RAD 0.01745329252f /* degrees to radians (rad = ICB_DEG2RAD * deg) */ +#define ICB_DEFAULTSIZE 181 /* default size */ +#define ICB_SPACE 4 /* size of the spacing */ +#define ICB_HUEWIDTH 18 /* width of the hue ring */ +#define ICB_MARKSIZE 6 /* size of the cursor mark */ +enum {ICB_INSIDE_NONE, ICB_INSIDE_HUE, ICB_INSIDE_SI}; + + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + /* mouse interaction state */ + int h_down, + si_down; + + /* cursor positioning */ + int h_x, h_y, + si_x, si_y; + + /* HSI-XY coordinate convertion */ + int xc, yc, /* center */ + R, /* maximum radius available inside the size of the control */ + Ix, /* x coordinate where S is 0 */ + Iy1, /* y coordinate where I is 0 */ + Iy2, /* y coordinate where I is 1 */ + SxMax; /* x coordinate where S is 1 and I = 0.5 */ + + /* visual appearance control */ + int w, h; + int has_focus; + long bgcolor; + + /* attributes */ + float hue, /* 0<=H<=359 */ + saturation, /* 0<=S<=1 */ + intensity; /* 0<=I<=1 */ + unsigned char red, green, blue; /* 0<=x<=255 */ + + cdCanvas *cddbuffer; + cdCanvas *cdcanvas; +}; + + +static float iColorBrowserSXmax(Ihandle* ih, int y) +{ + if (y == ih->data->yc) + return (float)(ih->data->SxMax - ih->data->Ix); + else if (y < ih->data->yc) + { + float D2 = (ih->data->Iy2 - ih->data->Iy1)/2.0f; + return ((float)(ih->data->SxMax - ih->data->Ix)*(y-ih->data->yc + D2))/D2; + } + else + { + float D2 = (ih->data->Iy2 - ih->data->Iy1)/2.0f; + return -((float)(ih->data->SxMax - ih->data->Ix)*(y-ih->data->yc - D2))/D2; + } +} + +static float iColorBrowserCalcIntensity(Ihandle* ih, int y) +{ + return (float)(y - ih->data->Iy1)/(float)(ih->data->Iy2 - ih->data->Iy1); +} + +static float iColorBrowserCalcSaturation(Ihandle* ih, int x, float sx_max) +{ + if (sx_max == 0) + return 0; + else + return (float)(x - ih->data->Ix)/sx_max; +} + +/* Rotate points of 60 degrees */ +static void iColorBrowserRotatePoints(float *x1, float *y1, float *x2, float *y2, int xc, int yc) +{ + float xt, yt; + float nxt, nyt; + static const float s60 = 0.8660254f; + static const float c60 = 0.5f; + + xt = *x1 - xc; + yt = *y1 - yc; + nxt = xt * c60 - yt * s60; + nyt = xt * s60 + yt * c60; + *x1 = nxt + xc; + *y1 = nyt + yc; + + xt = *x2 - xc; + yt = *y2 - yc; + nxt = xt * c60 - yt * s60; + nyt = xt * s60 + yt * c60; + *x2 = nxt + xc; + *y2 = nyt + yc; +} + +static void iColorBrowserRenderImageHue(Ihandle* ih) +{ + int x, y, active = 1; + unsigned char *red, *green, *blue; + unsigned char bg_red, bg_green, bg_blue; + if (!ih->data->cddbuffer) + return; + + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + + if (!iupdrvIsActive(ih)) + active = 0; + + if (ih->data->has_focus) + cdDrawFocusRect(ih->data->cddbuffer, 0, 0, ih->data->w-1, ih->data->h-1); + + red = cdRedImage(ih->data->cddbuffer); + green = cdGreenImage(ih->data->cddbuffer); + blue = cdBlueImage(ih->data->cddbuffer); + + cdDecodeColor(ih->data->bgcolor, &bg_red, &bg_green, &bg_blue); + + for (y = 0; y < ih->data->h; y++) + { + float sx_max = iColorBrowserSXmax(ih, y); + + for (x = 0; x < ih->data->w; x++) + { + int xl, yl; + float radius, diff1, diff2; + + if (y > ih->data->Iy1 && + y < ih->data->Iy2 && + x > ih->data->Ix && + x < ih->data->Ix+(int)sx_max) + continue; + + xl = x - ih->data->xc; + yl = y - ih->data->yc; + radius = sqrtf(xl*xl + yl*yl); + + diff1 = radius - (ih->data->R-ICB_SPACE-ICB_HUEWIDTH); + diff2 = (ih->data->R-ICB_SPACE) - radius; + + if (diff1>0 && diff2>0) + { + float h, s, i; + int offset = y*ih->data->w + x; + unsigned char* r = red + offset; + unsigned char* g = green + offset; + unsigned char* b = blue + offset; + + h = atan2f(yl, xl); + h = (float)(h * CD_RAD2DEG); + s = 1.0f; /* maximum saturation */ + i = 0.5f; /* choose I where S is maximum */ + + iupColorHSI2RGB(h, s, i, r, g, b); + + if (diff1<1 || diff2<1) /* anti-aliasing */ + { + float diff = (float)(diff1<1? diff1: diff2); + *r = (unsigned char)((*r)*diff + bg_red*(1.0f-diff)); + *g = (unsigned char)((*g)*diff + bg_green*(1.0f-diff)); + *b = (unsigned char)((*b)*diff + bg_blue*(1.0f-diff)); + } + + if (!active) + { + *r = cdIupLIGTHER(*r); + *g = cdIupLIGTHER(*g); + *b = cdIupLIGTHER(*b); + } + } + } + } + + if (active) + { + float x1, x2, y1, y2; + unsigned char shade_lr, shade_lg, shade_lb, + shade_dr, shade_dg, shade_db; + shade_dr = (unsigned char)((2 * bg_red) / 3); + shade_dg = (unsigned char)((2 * bg_green) / 3); + shade_db = (unsigned char)((2 * bg_blue) / 3); + shade_lr = (unsigned char)((255 + bg_red) / 2); + shade_lg = (unsigned char)((255 + bg_green) / 2); + shade_lb = (unsigned char)((255 + bg_blue) / 2); + cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(shade_dr, shade_dg, shade_db)); + x1 = (float)(ih->data->xc-ih->data->R+ICB_SPACE); y1 = (float)ih->data->yc; x2 = (float)(x1+ICB_HUEWIDTH/2); y2 = (float)ih->data->yc; + cdCanvasLine(ih->data->cddbuffer, (int) x1, (int) y1, (int) x2, (int) y2); + iColorBrowserRotatePoints(&x1, &y1, &x2, &y2, ih->data->xc, ih->data->yc); + cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(shade_lr, shade_lg, shade_lb)); + cdCanvasLine(ih->data->cddbuffer, (int) x1, (int) y1, (int) x2, (int) y2); + iColorBrowserRotatePoints(&x1, &y1, &x2, &y2, ih->data->xc, ih->data->yc); + cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(shade_dr, shade_dg, shade_db)); + cdCanvasLine(ih->data->cddbuffer, (int) x1, (int) y1, (int) x2, (int) y2); + iColorBrowserRotatePoints(&x1, &y1, &x2, &y2, ih->data->xc, ih->data->yc); + cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(shade_lr, shade_lg, shade_lb)); + cdCanvasLine(ih->data->cddbuffer, (int) x1, (int) y1, (int) x2, (int) y2); + iColorBrowserRotatePoints(&x1, &y1, &x2, &y2, ih->data->xc, ih->data->yc); + cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(shade_dr, shade_dg, shade_db)); + cdCanvasLine(ih->data->cddbuffer, (int) x1, (int) y1, (int) x2, (int) y2); + iColorBrowserRotatePoints(&x1, &y1, &x2, &y2, ih->data->xc, ih->data->yc); + cdCanvasLine(ih->data->cddbuffer, (int) x1, (int) y1, (int) x2, (int) y2); + } +} + +static void iColorBrowserRenderImageSI(Ihandle* ih) +{ + int x, y, active = 1; + unsigned char *red, *green, *blue; + unsigned char bg_red, bg_green, bg_blue; + float angle, cos_angle, sin_angle; + if (!ih->data->cddbuffer) + return; + + if (!iupdrvIsActive(ih)) + active = 0; + + red = cdRedImage(ih->data->cddbuffer); + green = cdGreenImage(ih->data->cddbuffer); + blue = cdBlueImage(ih->data->cddbuffer); + + cdDecodeColor(ih->data->bgcolor, &bg_red, &bg_green, &bg_blue); + + angle = ih->data->hue * ICB_DEG2RAD; + cos_angle = cosf(angle); + sin_angle = sinf(angle); + + for (y = 0; y < ih->data->h; y++) + { + float sx_max, i; + + if (y < ih->data->Iy1) + continue; + else if (y > ih->data->Iy2) + continue; + + sx_max = iColorBrowserSXmax(ih, y); + i = iColorBrowserCalcIntensity(ih, y); + + for (x = 0; x < ih->data->w; x++) + { + if (x < ih->data->Ix) + continue; + else if (x > ih->data->Ix+(int)sx_max) + continue; + + { + int offset = y*ih->data->w + x; + unsigned char* r = red + offset; + unsigned char* g = green + offset; + unsigned char* b = blue + offset; + float s, diff; + + s = iColorBrowserCalcSaturation(ih, x, sx_max); + + iupColorHSI2RGB(ih->data->hue, s, i, r, g, b); + + diff = sx_max - (float)(x - ih->data->Ix); + if (diff<1.0f) /* anti-aliasing */ + { + *r = (unsigned char)((*r)*diff + bg_red*(1.0f-diff)); + *g = (unsigned char)((*g)*diff + bg_green*(1.0f-diff)); + *b = (unsigned char)((*b)*diff + bg_blue*(1.0f-diff)); + } + + if (!active) + { + *r = cdIupLIGTHER(*r); + *g = cdIupLIGTHER(*g); + *b = cdIupLIGTHER(*b); + } + } + } + } +} + +static void iColorBrowserUpdateCursorSI(Ihandle* ih) +{ + int x; + int y = (int)(ih->data->intensity*(ih->data->Iy2 - ih->data->Iy1)) + ih->data->Iy1; + ih->data->si_y = iupROUND(y); + x = (int)(ih->data->saturation*iColorBrowserSXmax(ih, ih->data->si_y)) + ih->data->Ix; + ih->data->si_x = iupROUND(x); +} + +static void iColorBrowserSetCursorSI(Ihandle* ih, int x, int y) +{ + float sx_max; + + if (y < ih->data->Iy1) + ih->data->si_y = ih->data->Iy1; + else if (y > ih->data->Iy2) + ih->data->si_y = ih->data->Iy2; + else + ih->data->si_y = y; + + sx_max = iColorBrowserSXmax(ih, ih->data->si_y); + + if (x < ih->data->Ix) + ih->data->si_x = ih->data->Ix; + else if (x > ih->data->Ix+sx_max) + ih->data->si_x = ih->data->Ix+(int)sx_max; + else + ih->data->si_x = x; + + ih->data->intensity = iColorBrowserCalcIntensity(ih, ih->data->si_y); + ih->data->saturation = iColorBrowserCalcSaturation(ih, ih->data->si_x, sx_max); + + if (ih->data->saturation == -0.0f) + ih->data->saturation = 0; + if (ih->data->intensity == -0.0f) + ih->data->intensity = 0; +} + +static void iColorBrowserUpdateCursorHue(Ihandle* ih) +{ + int rc = ih->data->R-ICB_SPACE-ICB_HUEWIDTH/2; + float angle = ih->data->hue * ICB_DEG2RAD; + float cos_angle = cosf(angle); + float sin_angle = sinf(angle); + float x = rc*cos_angle + ih->data->xc; + float y = rc*sin_angle + ih->data->yc; + ih->data->h_x = iupROUND(x); + ih->data->h_y = iupROUND(y); +} + +static void iColorBrowserSetCursorHue(Ihandle* ih, int x, int y) +{ + int xl = x - ih->data->xc; + int yl = y - ih->data->yc; + ih->data->hue = (float)(atan2f(yl, xl) * CD_RAD2DEG); + ih->data->hue = fmodf(ih->data->hue, 360.0f); + if (ih->data->hue < 0.0f) + ih->data->hue += 360.0f; + + iColorBrowserUpdateCursorHue(ih); +} + +static int iColorBrowserCheckInside(Ihandle* ih, int x, int y) +{ + int xl = x - ih->data->xc; + int yl = y - ih->data->yc; + float radius = sqrtf(xl*xl + yl*yl); + + if (radius < ih->data->R-ICB_SPACE-ICB_HUEWIDTH-ICB_SPACE) + return ICB_INSIDE_SI; + + if (radius > ih->data->R-ICB_SPACE-ICB_HUEWIDTH && + radius < ih->data->R-ICB_SPACE) + return ICB_INSIDE_HUE; + + return ICB_INSIDE_NONE; +} + +static void iColorBrowserHSI2RGB(Ihandle* ih) +{ + iupColorHSI2RGB(ih->data->hue, ih->data->saturation, ih->data->intensity, + &(ih->data->red), &(ih->data->green), &(ih->data->blue)); +} + +static void iColorBrowserRGB2HSI(Ihandle* ih) +{ + iupColorRGB2HSI(ih->data->red, ih->data->green, ih->data->blue, + &(ih->data->hue), &(ih->data->saturation), &(ih->data->intensity)); +} + +static void iColorBrowserUpdateDisplay(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return; + + cdCanvasFlush(ih->data->cddbuffer); /* swap the RGB to the display canvas */ + + if (iupdrvIsActive(ih)) + { + cdCanvasForeground(ih->data->cdcanvas, CD_GRAY); + cdCanvasArc(ih->data->cdcanvas, ih->data->h_x+1, ih->data->h_y, ICB_MARKSIZE, ICB_MARKSIZE, 0, 360); + cdCanvasArc(ih->data->cdcanvas, ih->data->si_x+1, ih->data->si_y, ICB_MARKSIZE, ICB_MARKSIZE, 0, 360); + cdCanvasForeground(ih->data->cdcanvas, CD_WHITE); + cdCanvasArc(ih->data->cdcanvas, ih->data->h_x, ih->data->h_y, ICB_MARKSIZE, ICB_MARKSIZE, 0, 360); + cdCanvasArc(ih->data->cdcanvas, ih->data->si_x, ih->data->si_y, ICB_MARKSIZE, ICB_MARKSIZE, 0, 360); + } + else + { + cdCanvasForeground(ih->data->cdcanvas, CD_DARK_GRAY); + cdCanvasSector(ih->data->cdcanvas, ih->data->h_x, ih->data->h_y, ICB_MARKSIZE+1, ICB_MARKSIZE+1, 0, 360); + cdCanvasSector(ih->data->cdcanvas, ih->data->si_x, ih->data->si_y, ICB_MARKSIZE+1, ICB_MARKSIZE+1, 0, 360); + } +} + +static void iColorBrowserCallChangeCb(Ihandle* ih) +{ + IFnccc change_cb = (IFnccc) IupGetCallback(ih, "CHANGE_CB"); + if (change_cb) + change_cb(ih, ih->data->red, ih->data->green, ih->data->blue); + + iupBaseCallValueChangedCb(ih); +} + +static void iColorBrowserCallDragCb(Ihandle* ih) +{ + IFnccc drag_cb = (IFnccc) IupGetCallback(ih, "DRAG_CB"); + if (drag_cb) + drag_cb(ih, ih->data->red, ih->data->green, ih->data->blue); + + iupBaseCallValueChangedCb(ih); +} + +static int iColorBrowserHmouse(Ihandle* ih, int x, int y, int drag) +{ + iColorBrowserSetCursorHue(ih, x, y); + iColorBrowserHSI2RGB(ih); + /* must update the Si area */ + iColorBrowserRenderImageSI(ih); + iColorBrowserUpdateDisplay(ih); + + if (drag) + iColorBrowserCallDragCb(ih); + else + iColorBrowserCallChangeCb(ih); + + return IUP_DEFAULT; +} + +static int iColorBrowserSImouse(Ihandle* ih, int x, int y, int drag) +{ + iColorBrowserSetCursorSI(ih, x, y); + iColorBrowserHSI2RGB(ih); + iColorBrowserUpdateDisplay(ih); + + if (drag) + iColorBrowserCallDragCb(ih); + else + iColorBrowserCallChangeCb(ih); + + return IUP_DEFAULT; +} + + +/******************************************************************/ + + +static int iColorBrowserButton_CB(Ihandle* ih, int b, int press, int x, int y) +{ + if (b != IUP_BUTTON1) + return IUP_DEFAULT; + + cdCanvasUpdateYAxis(ih->data->cdcanvas, &y); + + if (press) + { + int inside = iColorBrowserCheckInside(ih, x, y); + + if (!ih->data->h_down && inside==ICB_INSIDE_HUE) + { + iColorBrowserHmouse(ih, x, y, 1); + ih->data->h_down = 1; + } + + if (!ih->data->si_down && inside==ICB_INSIDE_SI) + { + iColorBrowserSImouse(ih, x, y, 1); + ih->data->si_down = 1; + } + } + else + { + if (ih->data->h_down) + { + iColorBrowserHmouse(ih, x, y, 0); + ih->data->h_down = 0; + } + + if (ih->data->si_down) + { + iColorBrowserSImouse(ih, x, y, 0); + ih->data->si_down = 0; + } + } + + return IUP_DEFAULT; +} + +/* Callback for the mouse motion in the canvas */ +static int iColorBrowserMotion_CB(Ihandle* ih, int x, int y, char *status) +{ + if (!iup_isbutton1(status)) + { + ih->data->h_down = 0; + ih->data->si_down = 0; + return IUP_DEFAULT; + } + + if (ih->data->h_down) + { + cdCanvasUpdateYAxis(ih->data->cdcanvas, &y); + iColorBrowserHmouse(ih, x, y, 1); + } + else if (ih->data->si_down) + { + cdCanvasUpdateYAxis(ih->data->cdcanvas, &y); + iColorBrowserSImouse(ih, x, y, 1); + } + + return IUP_DEFAULT; +} + +static int iColorBrowserFocus_CB(Ihandle* ih, int focus) +{ + ih->data->has_focus = focus; + iColorBrowserRenderImageHue(ih); + iColorBrowserRenderImageSI(ih); + iColorBrowserUpdateDisplay(ih); + return IUP_DEFAULT; +} + +static void iColorBrowserUpdateSize(Ihandle* ih) +{ + int T, D; + + /* update canvas size */ + cdCanvasActivate(ih->data->cddbuffer); + cdCanvasGetSize(ih->data->cddbuffer, &ih->data->w, &ih->data->h, NULL, NULL); + + ih->data->R = min(ih->data->w, ih->data->h)/2; + ih->data->xc = ih->data->w/2; + ih->data->yc = ih->data->h/2; + T = ih->data->R-ICB_SPACE-ICB_HUEWIDTH-ICB_SPACE; + ih->data->Ix = ih->data->xc - T/2; /* cos(60)=0.5 */ + D = (int)(2*T*0.866); /* sin(60)=0.866 */ + ih->data->Iy1 = ih->data->yc - D/2; + ih->data->Iy2 = ih->data->Iy1 + D; + ih->data->SxMax = ih->data->xc + T; +} + +static int iColorBrowserResize_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_DBUFFERRGB, ih->data->cdcanvas); + } + + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + /* update size */ + iColorBrowserUpdateSize(ih); + + iColorBrowserUpdateCursorHue(ih); + iColorBrowserUpdateCursorSI(ih); + + /* update render */ + iColorBrowserRenderImageHue(ih); + iColorBrowserRenderImageSI(ih); + + return IUP_DEFAULT; +} + +static int iColorBrowserRedraw_CB(Ihandle* ih) +{ + iColorBrowserUpdateDisplay(ih); + return IUP_DEFAULT; +} + +static int iColorBrowserWheel_CB(Ihandle* ih, float delta) +{ + ih->data->hue += delta; + + iColorBrowserUpdateCursorHue(ih); + iColorBrowserHSI2RGB(ih); + /* must update the Si area */ + iColorBrowserRenderImageSI(ih); + iColorBrowserUpdateDisplay(ih); + iColorBrowserCallChangeCb(ih); + + return IUP_DEFAULT; +} + +static int iColorBrowserKeypress_CB(Ihandle* ih, int c, int press) +{ + int x, y, changing_hue = 0; + + if (!press) + return IUP_DEFAULT; + + x = ih->data->si_x; + y = ih->data->si_y; + + switch (c) + { + case K_UP: + y++; + break; + case K_DOWN: + y--; + break; + case K_RIGHT: + x++; + break; + case K_LEFT: + x--; + break; + case K_PGUP: + ih->data->hue += 1.0f; + changing_hue = 1; + break; + case K_PGDN: + ih->data->hue -= 1.0f; + changing_hue = 1; break; + case K_HOME: + ih->data->hue = 0.0f; + changing_hue = 1; + break; + case K_END: + ih->data->hue = 180.0f; + changing_hue = 1; + break; + default: + return IUP_DEFAULT; + } + + if (changing_hue) + { + iColorBrowserUpdateCursorHue(ih); + /* must update the Si area */ + iColorBrowserRenderImageSI(ih); + } + else + iColorBrowserSetCursorSI(ih, x, y); + + iColorBrowserHSI2RGB(ih); + + iColorBrowserUpdateDisplay(ih); + iColorBrowserCallChangeCb(ih); + + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ +} + + +/*********************************************************************************/ + + +static char* iColorBrowserGetHSIAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%f %f %f", (double)ih->data->hue, (double)ih->data->saturation, (double)ih->data->intensity); + return buffer; +} + +static int iColorBrowserSetHSIAttrib(Ihandle* ih, const char* value) +{ + float old_hue = ih->data->hue, + old_saturation = ih->data->saturation, + old_intensity = ih->data->intensity; + + if (!iupStrToHSI(value, &ih->data->hue, &ih->data->saturation, &ih->data->intensity)) + return 0; + + if (ih->data->cddbuffer) + { + if (old_hue != ih->data->hue) + iColorBrowserUpdateCursorHue(ih); + if (old_saturation != ih->data->saturation || old_intensity != ih->data->intensity) + iColorBrowserUpdateCursorSI(ih); + iColorBrowserHSI2RGB(ih); + iColorBrowserRenderImageSI(ih); + iColorBrowserUpdateDisplay(ih); + } + + return 0; +} + +static char* iColorBrowserGetRGBAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(20); + sprintf(buffer, "%d %d %d", (int) ih->data->red, (int) ih->data->green, (int) ih->data->blue); + return buffer; +} + +static int iColorBrowserSetRGBAttrib(Ihandle* ih, const char* value) +{ + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + ih->data->red = r; + ih->data->green = g; + ih->data->blue = b; + iColorBrowserRGB2HSI(ih); + + if (ih->data->cddbuffer) + { + iColorBrowserUpdateCursorHue(ih); + iColorBrowserUpdateCursorSI(ih); + iColorBrowserRenderImageSI(ih); + iColorBrowserUpdateDisplay(ih); + } + + return 0; +} + +static int iColorBrowserSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (!value) + value = iupControlBaseGetParentBgColor(ih); + ih->data->bgcolor = cdIupConvertColor(value); + + if (ih->data->cddbuffer) + { + iColorBrowserRenderImageHue(ih); + iColorBrowserRenderImageSI(ih); + iColorBrowserUpdateDisplay(ih); + } + return 1; +} + +static int iColorBrowserSetActiveAttrib(Ihandle* ih, const char* value) +{ + iupBaseSetActiveAttrib(ih, value); + iColorBrowserUpdateDisplay(ih); + return 0; /* do not store value in hash table */ +} + + +/****************************************************************************/ + + +static int iColorBrowserMapMethod(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_DBUFFERRGB, ih->data->cdcanvas); + + if (ih->data->cddbuffer) + iColorBrowserUpdateSize(ih); + + return IUP_NOERROR; +} + +static void iColorBrowserUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static int iColorBrowserCreateMethod(Ihandle* ih, void **params) +{ + (void)params; + + /* free the data allocated by IupCanvas */ + if (ih->data) free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* change the IupCanvas default values */ + IupSetfAttribute(ih, "RASTERSIZE", "%dx%d", ICB_DEFAULTSIZE, ICB_DEFAULTSIZE); + iupAttribSetStr(ih, "BORDER", "NO"); + ih->expand = IUP_EXPAND_NONE; + + /* IupCanvas callbacks */ + IupSetCallback(ih, "ACTION", (Icallback)iColorBrowserRedraw_CB); + IupSetCallback(ih, "RESIZE_CB", (Icallback)iColorBrowserResize_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iColorBrowserButton_CB); + IupSetCallback(ih, "MOTION_CB", (Icallback)iColorBrowserMotion_CB); + IupSetCallback(ih, "FOCUS_CB", (Icallback)iColorBrowserFocus_CB); + IupSetCallback(ih, "KEYPRESS_CB", (Icallback)iColorBrowserKeypress_CB); + IupSetCallback(ih, "WHEEL_CB", (Icallback)iColorBrowserWheel_CB); + + return IUP_NOERROR; +} + +Iclass* iupColorBrowserGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "colorbrowser"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iColorBrowserCreateMethod; + ic->Map = iColorBrowserMapMethod; + ic->UnMap = iColorBrowserUnMapMethod; + + /* IupColorBrowser Callbacks */ + iupClassRegisterCallback(ic, "DRAG_CB", "ccc"); + iupClassRegisterCallback(ic, "CHANGE_CB", "ccc"); + iupClassRegisterCallback(ic, "VALUECHANGED_CB", ""); + + /* IupColorBrowser only */ + iupClassRegisterAttribute(ic, "RGB", iColorBrowserGetRGBAttrib, iColorBrowserSetRGBAttrib, "255 0 0", NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "HSI", iColorBrowserGetHSIAttrib, iColorBrowserSetHSIAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iColorBrowserSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iColorBrowserSetBgColorAttrib, NULL, "255 255 255", IUPAF_NO_INHERIT); /* overwrite canvas implementation, set a system default to force a new default */ + + return ic; +} + +Ihandle *IupColorBrowser(void) +{ + return IupCreate("colorbrowser"); +} diff --git a/iup/srccontrols/color/iup_colorbrowserdlg.c b/iup/srccontrols/color/iup_colorbrowserdlg.c new file mode 100755 index 0000000..65e4d37 --- /dev/null +++ b/iup/srccontrols/color/iup_colorbrowserdlg.c @@ -0,0 +1,1120 @@ +/** \file + * \brief IupColorDlg pre-defined dialog control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" +#include "iupcontrols.h" + +#include <cd.h> +#include <cdiup.h> +#include <cddbuf.h> +#include <cdirgb.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_strmessage.h" +#include "iup_drv.h" +#include "iup_stdcontrols.h" +#include "iup_controls.h" +#include "iup_cdutil.h" +#include "iup_register.h" +#include "iup_register.h" +#include "iup_image.h" +#include "iup_colorhsi.h" +#include "iup_childtree.h" + + +const char* default_colortable_cells[20] = +{ + "0 0 0", "64 64 64", "128 128 128", "144 144 144", "0 128 128", "128 0 128", "128 128 0", "128 0 0", "0 128 0", "0 0 128", + "255 255 255", "240 240 240", "224 224 224", "192 192 192", "0 255 255", "255 0 255", "255 255 0", "255 0 0", "0 255 0", "0 0 255" +}; + +typedef struct _IcolorDlgData +{ + int status; + + long previous_color, color; + + float hue, saturation, intensity; + unsigned char red, green, blue, alpha; + + Ihandle *red_txt, *green_txt, *blue_txt, *alpha_txt; + Ihandle *hue_txt, *intensity_txt, *saturation_txt; + Ihandle *color_browser, *color_cnv, *colorhex_txt; + Ihandle *colortable_cbar, *alpha_val; + Ihandle *help_bt; + + cdCanvas* color_cdcanvas, *color_cddbuffer; +} IcolorDlgData; + + +static void iColorBrowserDlgColorCnvRepaint(IcolorDlgData* colordlg_data) +{ + int x, y, w, h, width, height, box_size = 10; + + if (!colordlg_data->color_cddbuffer) + return; + + cdCanvasGetSize(colordlg_data->color_cddbuffer, &width, &height, NULL, NULL); + + cdCanvasBackground(colordlg_data->color_cddbuffer, CD_WHITE); + cdCanvasClear(colordlg_data->color_cddbuffer); + + w = (width+box_size-1)/box_size; + h = (height+box_size-1)/box_size; + + cdCanvasForeground(colordlg_data->color_cddbuffer, CD_GRAY); + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + if (((x%2) && (y%2)) || (((x+1)%2) && ((y+1)%2))) + { + int xmin, xmax, ymin, ymax; + + xmin = x*box_size; + xmax = xmin+box_size; + ymin = y*box_size; + ymax = ymin+box_size; + + cdCanvasBox(colordlg_data->color_cddbuffer, xmin, xmax, ymin, ymax); + } + } + } + + cdCanvasForeground(colordlg_data->color_cddbuffer, colordlg_data->previous_color); + cdCanvasBox(colordlg_data->color_cddbuffer, 0, width/2, 0, height); + + cdCanvasForeground(colordlg_data->color_cddbuffer, colordlg_data->color); + cdCanvasBox(colordlg_data->color_cddbuffer, width/2+1, width, 0, height); + + cdCanvasFlush(colordlg_data->color_cddbuffer); +} + +static void iColorBrowserDlgHSI2RGB(IcolorDlgData* colordlg_data) +{ + iupColorHSI2RGB(colordlg_data->hue, colordlg_data->saturation, colordlg_data->intensity, + &colordlg_data->red, &colordlg_data->green, &colordlg_data->blue); +} + +static void iColorBrowserDlgRGB2HSI(IcolorDlgData* colordlg_data) +{ + iupColorRGB2HSI(colordlg_data->red, colordlg_data->green, colordlg_data->blue, + &(colordlg_data->hue), &(colordlg_data->saturation), &(colordlg_data->intensity)); +} + +static void iColorBrowserDlgHex_TXT_Update(IcolorDlgData* colordlg_data) +{ + IupSetfAttribute(colordlg_data->colorhex_txt, "VALUE", "#%02X%02X%02X", (int)colordlg_data->red, (int)colordlg_data->green, (int)colordlg_data->blue); +} + +static int iupStrHexToRGB(const char *str, unsigned char *r, unsigned char *g, unsigned char *b) +{ + unsigned int ri = 0, gi = 0, bi = 0; + if (!str) return 0; + if (sscanf(str, "#%2X%2X%2X", &ri, &gi, &bi) != 3) return 0; + if (ri > 255 || gi > 255 || bi > 255) return 0; + *r = (unsigned char)ri; + *g = (unsigned char)gi; + *b = (unsigned char)bi; + return 1; +} + +/*************************************************\ +* Updates text fields with the current HSI values * +\*************************************************/ +static void iColorBrowserDlgHSI_TXT_Update(IcolorDlgData* colordlg_data) +{ + IupSetfAttribute(colordlg_data->hue_txt, "VALUE", "%d", iupROUND(colordlg_data->hue)); + IupSetfAttribute(colordlg_data->saturation_txt, "VALUE", "%d", iupROUND(colordlg_data->saturation * 100)); + IupSetfAttribute(colordlg_data->intensity_txt, "VALUE", "%d", iupROUND(colordlg_data->intensity * 100)); +} + +/*************************************************\ +* Updates text fields with the current RGB values * +\*************************************************/ +static void iColorBrowserDlgRGB_TXT_Update(IcolorDlgData* colordlg_data) +{ + IupSetfAttribute(colordlg_data->red_txt, "VALUE", "%d", (int) colordlg_data->red); + IupSetfAttribute(colordlg_data->green_txt, "VALUE", "%d", (int) colordlg_data->green); + IupSetfAttribute(colordlg_data->blue_txt, "VALUE", "%d", (int) colordlg_data->blue); +} + +static void iColorBrowserDlgBrowserRGB_Update(IcolorDlgData* colordlg_data) +{ + IupSetfAttribute(colordlg_data->color_browser, "RGB", "%d %d %d", colordlg_data->red, colordlg_data->green, colordlg_data->blue); +} + +static void iColorBrowserDlgBrowserHSI_Update(IcolorDlgData* colordlg_data) +{ + IupSetfAttribute(colordlg_data->color_browser, "HSI", "%f %f %f", (double)colordlg_data->hue, (double)colordlg_data->saturation, (double)colordlg_data->intensity); +} + +/*****************************************\ +* Sets the RGB color in the Color Canvas * +\*****************************************/ +static void iColorBrowserDlgColor_Update(IcolorDlgData* colordlg_data) +{ + colordlg_data->color = cdEncodeColor(colordlg_data->red, colordlg_data->green, colordlg_data->blue); + colordlg_data->color = cdEncodeAlpha(colordlg_data->color, colordlg_data->alpha); + iColorBrowserDlgColorCnvRepaint(colordlg_data); +} + +static void iColorBrowserDlgHSIChanged(IcolorDlgData* colordlg_data) +{ + iColorBrowserDlgHSI2RGB(colordlg_data); + iColorBrowserDlgBrowserHSI_Update(colordlg_data); + iColorBrowserDlgHex_TXT_Update(colordlg_data); + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + iColorBrowserDlgColor_Update(colordlg_data); +} + +static void iColorBrowserDlgRGBChanged(IcolorDlgData* colordlg_data) +{ + iColorBrowserDlgRGB2HSI(colordlg_data); + iColorBrowserDlgBrowserRGB_Update(colordlg_data); + iColorBrowserDlgHex_TXT_Update(colordlg_data); + iColorBrowserDlgHSI_TXT_Update(colordlg_data); + iColorBrowserDlgColor_Update(colordlg_data); +} + +/***********************************************\ +* Initializes the default values to the element * +\***********************************************/ +static void iColorBrowserDlgInit_Defaults(IcolorDlgData* colordlg_data) +{ + char* str = iupStrGetMemory(100); + Ihandle* box; + int i; + + IupSetAttribute(colordlg_data->color_browser, "RGB", "0 0 0"); + + IupSetAttribute(colordlg_data->red_txt, "VALUE", "0"); + IupSetAttribute(colordlg_data->green_txt, "VALUE", "0"); + IupSetAttribute(colordlg_data->blue_txt, "VALUE", "0"); + + IupSetAttribute(colordlg_data->hue_txt, "VALUE", "0"); + IupSetAttribute(colordlg_data->saturation_txt, "VALUE", "0"); + IupSetAttribute(colordlg_data->intensity_txt, "VALUE", "0"); + + IupSetAttribute(colordlg_data->colorhex_txt, "VALUE", "#000000"); + + colordlg_data->alpha = 255; + IupSetAttribute(colordlg_data->alpha_val, "VALUE", "255"); + IupSetAttribute(colordlg_data->alpha_txt, "VALUE", "255"); + + box = IupGetParent(colordlg_data->alpha_val); + IupSetAttribute(box, "FLOATING", "YES"); + IupSetAttribute(box, "VISIBLE", "NO"); + + box = IupGetParent(colordlg_data->colortable_cbar); + IupSetAttribute(box, "FLOATING", "YES"); + IupSetAttribute(box, "VISIBLE", "NO"); + + box = IupGetParent(colordlg_data->colorhex_txt); + IupSetAttribute(box, "FLOATING", "YES"); + IupSetAttribute(box, "VISIBLE", "NO"); + + for(i = 0; i < 20; i++) + { + sprintf(str, "CELL%d", i); + IupSetAttribute(colordlg_data->colortable_cbar, str, default_colortable_cells[i]); + } +} + + +/**************************************************************************************************************/ +/* Internal Callbacks */ +/**************************************************************************************************************/ + + +static int iColorBrowserDlgButtonOK_CB(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + colordlg_data->status = 1; + return IUP_CLOSE; +} + +static int iColorBrowserDlgButtonCancel_CB(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + colordlg_data->status = 0; + return IUP_CLOSE; +} + +static int iColorBrowserDlgButtonHelp_CB(Ihandle* ih) +{ + Icallback cb = IupGetCallback(IupGetDialog(ih), "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + { + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + colordlg_data->status = 0; + return IUP_CLOSE; + } + return IUP_DEFAULT; +} + +static int iColorBrowserDlgColorCnvRedraw_CB(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + if (!colordlg_data->color_cddbuffer) + return IUP_DEFAULT; + + cdCanvasActivate(colordlg_data->color_cddbuffer); + + iColorBrowserDlgColorCnvRepaint(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgRedAction_CB(Ihandle* ih, int c, char *value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->red = (unsigned char)vi; + iColorBrowserDlgRGBChanged(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgRedSpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->red = (unsigned char)vi; + iColorBrowserDlgRGBChanged(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgGreenAction_CB(Ihandle* ih, int c, char *value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->green = (unsigned char)vi; + iColorBrowserDlgRGBChanged(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgGreenSpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->green = (unsigned char)vi; + iColorBrowserDlgRGBChanged(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgBlueAction_CB(Ihandle* ih, int c, char *value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->blue = (unsigned char)vi; + iColorBrowserDlgRGBChanged(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgBlueSpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->blue = (unsigned char)vi; + iColorBrowserDlgRGBChanged(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgHueAction_CB(Ihandle* ih, int c, char *value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->hue = (float)vi; + iColorBrowserDlgHSIChanged(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgHueSpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->hue = (float)vi; + iColorBrowserDlgHSIChanged(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgSaturationAction_CB(Ihandle* ih, int c, char *value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->saturation = (float)vi/100.0f; + iColorBrowserDlgHSIChanged(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgSaturationSpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->saturation = (float)vi/100.0f; + iColorBrowserDlgHSIChanged(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgIntensityAction_CB(Ihandle* ih, int c, char *value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->intensity = (float)vi/100.0f; + iColorBrowserDlgHSIChanged(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgIntensitySpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->intensity = (float)vi/100.0f; + iColorBrowserDlgHSIChanged(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgHexAction_CB(Ihandle* ih, int c, char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + if (iupStrHexToRGB(value, &colordlg_data->red, &colordlg_data->green, &colordlg_data->blue)) + { + iColorBrowserDlgRGB2HSI(colordlg_data); + iColorBrowserDlgBrowserRGB_Update(colordlg_data); + iColorBrowserDlgHSI_TXT_Update(colordlg_data); + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + iColorBrowserDlgColor_Update(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgColorSelDrag_CB(Ihandle* ih, unsigned char r, unsigned char g, unsigned char b) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->red = r; + colordlg_data->green = g; + colordlg_data->blue = b; + + iColorBrowserDlgRGB2HSI(colordlg_data); + iColorBrowserDlgHex_TXT_Update(colordlg_data); + iColorBrowserDlgHSI_TXT_Update(colordlg_data); + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + + colordlg_data->color = cdEncodeColor(colordlg_data->red,colordlg_data->green,colordlg_data->blue); + colordlg_data->color = cdEncodeAlpha(colordlg_data->color, colordlg_data->alpha); + iColorBrowserDlgColorCnvRepaint(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgAlphaVal_CB(Ihandle* ih, double val) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->alpha = (unsigned char)val; + IupSetfAttribute(colordlg_data->alpha_txt, "VALUE", "%d", (int)colordlg_data->alpha); + + colordlg_data->color = cdEncodeAlpha(colordlg_data->color, colordlg_data->alpha); + iColorBrowserDlgColorCnvRepaint(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgAlphaAction_CB(Ihandle* ih, int c, char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int vi; + + if (iupStrToInt(value, &vi)) + { + colordlg_data->alpha = (unsigned char)vi; + IupSetfAttribute(colordlg_data->alpha_val, "VALUE", "%d", (int)colordlg_data->alpha); + + colordlg_data->color = cdEncodeAlpha(colordlg_data->color, colordlg_data->alpha); + iColorBrowserDlgColorCnvRepaint(colordlg_data); + } + + (void)c; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgAlphaSpin_CB(Ihandle* ih, int vi) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + colordlg_data->alpha = (unsigned char)vi; + IupSetfAttribute(colordlg_data->alpha_val, "VALUE", "%d", (int)colordlg_data->alpha); + + colordlg_data->color = cdEncodeAlpha(colordlg_data->color, colordlg_data->alpha); + iColorBrowserDlgColorCnvRepaint(colordlg_data); + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgColorTableSelect_CB(Ihandle* ih, int cell, int type) +{ + char* str = iupStrGetMemory(30); + + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + sprintf(str, "CELL%d", cell); + iupStrToRGB(IupGetAttribute(ih, str), &colordlg_data->red, &colordlg_data->green, &colordlg_data->blue); + + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + iColorBrowserDlgRGBChanged(colordlg_data); + + (void)type; + return IUP_DEFAULT; +} + +static int iColorBrowserDlgColorCnvButton_CB(Ihandle* ih, int b, int press, int x, int y) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int width; + (void)y; + + if (b != IUP_BUTTON1 || !press || !colordlg_data->color_cddbuffer) + return IUP_DEFAULT; + + cdCanvasGetSize(colordlg_data->color_cddbuffer, &width, NULL, NULL, NULL); + + if (x < width/2) + { + /* reset color to previous */ + colordlg_data->red = cdRed(colordlg_data->previous_color); + colordlg_data->green = cdGreen(colordlg_data->previous_color); + colordlg_data->blue = cdBlue(colordlg_data->previous_color); + colordlg_data->alpha = cdAlpha(colordlg_data->previous_color); + + IupSetfAttribute(colordlg_data->alpha_txt, "VALUE", "%d", (int)colordlg_data->alpha); + IupSetfAttribute(colordlg_data->alpha_val, "VALUE", "%d", (int)colordlg_data->alpha); + + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + iColorBrowserDlgRGBChanged(colordlg_data); + } + + return IUP_DEFAULT; +} + +static int iColorBrowserDlgColorCnvMap_CB(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + /* Create Canvas */ + colordlg_data->color_cdcanvas = cdCreateCanvas(CD_IUP, colordlg_data->color_cnv); + + if (!colordlg_data->color_cdcanvas) + return IUP_DEFAULT; + + /* this can fail if canvas size is zero */ + colordlg_data->color_cddbuffer = cdCreateCanvas(CD_DBUFFERRGB, colordlg_data->color_cdcanvas); + return IUP_DEFAULT; +} + +static int iColorBrowserDlgColorCnvUnMap_CB(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + if (colordlg_data->color_cddbuffer) + cdKillCanvas(colordlg_data->color_cddbuffer); + + if (colordlg_data->color_cdcanvas) + cdKillCanvas(colordlg_data->color_cdcanvas); + + return IUP_DEFAULT; +} + + +/**************************************************************************************************************/ +/* Attributes */ +/**************************************************************************************************************/ + + +static char* iColorBrowserDlgGetStatusAttrib(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + if (colordlg_data->status) + return "1"; + else + return NULL; +} + +static int iColorBrowserDlgSetShowHelpAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + IupSetAttribute(colordlg_data->help_bt, "VISIBLE", iupStrBoolean(value)? "YES": "NO"); + return 1; +} + +static int iColorBrowserDlgSetShowHexAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + /* valid only before map */ + if (ih->handle) + return 1; + + if (iupStrBoolean(value)) + { + Ihandle* box = IupGetParent(colordlg_data->colorhex_txt); + IupSetAttribute(box, "FLOATING", NULL); + IupSetAttribute(box, "VISIBLE", "YES"); + } + + return 1; +} + +static int iColorBrowserDlgSetShowColorTableAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + /* valid only before map */ + if (ih->handle) + return 1; + + if (iupStrBoolean(value)) + { + Ihandle* box = IupGetParent(colordlg_data->colortable_cbar); + IupSetAttribute(box, "FLOATING", NULL); + IupSetAttribute(box, "VISIBLE", "YES"); + } + + return 1; +} + +static int iColorBrowserDlgSetShowAlphaAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + /* valid only before map */ + if (ih->handle) + return 1; + + if (iupStrBoolean(value)) + { + Ihandle* box = IupGetParent(colordlg_data->alpha_val); + IupSetAttribute(box, "FLOATING", NULL); + IupSetAttribute(box, "VISIBLE", "YES"); + } + + return 1; +} + +static int iColorBrowserDlgSetAlphaAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int alpha; + if (iupStrToInt(value, &alpha)) + { + colordlg_data->alpha = (unsigned char)alpha; + IupSetfAttribute(colordlg_data->alpha_txt, "VALUE", "%d", (int)colordlg_data->alpha); + IupSetfAttribute(colordlg_data->alpha_val, "VALUE", "%d", (int)colordlg_data->alpha); + + colordlg_data->color = cdEncodeAlpha(colordlg_data->color, colordlg_data->alpha); + colordlg_data->previous_color = cdEncodeAlpha(colordlg_data->previous_color, colordlg_data->alpha); + iColorBrowserDlgColorCnvRepaint(colordlg_data); + + if (!ih->handle) /* do it only before map */ + IupSetAttribute(ih, "SHOWALPHA", "YES"); + } + + return 1; +} + +static char* iColorBrowserDlgGetAlphaAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + sprintf(buffer, "%d", (int)colordlg_data->alpha); + return buffer; +} + +static int iColorBrowserDlgSetValueAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int ret = iupStrToRGBA(value, &colordlg_data->red, &colordlg_data->green, &colordlg_data->blue, &colordlg_data->alpha); + if (!ret) + return 0; + + colordlg_data->previous_color = cdEncodeColor(colordlg_data->red, colordlg_data->green, colordlg_data->blue); + colordlg_data->previous_color = cdEncodeAlpha(colordlg_data->previous_color, colordlg_data->alpha); + + if (ret == 4) + { + IupSetfAttribute(colordlg_data->alpha_txt, "VALUE", "%d", (int)colordlg_data->alpha); + IupSetfAttribute(colordlg_data->alpha_val, "VALUE", "%d", (int)colordlg_data->alpha); + + if (!ih->handle) /* do it only before map */ + IupSetAttribute(ih, "SHOWALPHA", "YES"); + } + + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + iColorBrowserDlgRGBChanged(colordlg_data); + + return 0; +} + +static char* iColorBrowserDlgGetValueAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + if (iupAttribGetBoolean(ih, "SHOWALPHA")) + sprintf(buffer, "%d %d %d %d", (int)colordlg_data->red, (int)colordlg_data->green, (int)colordlg_data->blue, (int)colordlg_data->alpha); + else + sprintf(buffer, "%d %d %d", (int)colordlg_data->red, (int)colordlg_data->green, (int)colordlg_data->blue); + return buffer; +} + +static int iupStrToHSI_Int(const char *str, int *h, int *s, int *i) +{ + int fh, fs, fi; + if (!str) return 0; + if (sscanf(str, "%d %d %d", &fh, &fs, &fi) != 3) return 0; + if (fh > 359 || fs > 100 || fi > 100) return 0; + if (fh < 0 || fs < 0 || fi < 0) return 0; + *h = fh; + *s = fs; + *i = fi; + return 1; +} + +static int iColorBrowserDlgSetValueHSIAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + int hue, saturation, intensity; + + if (!iupStrToHSI_Int(value, &hue, &saturation, &intensity)) + return 0; + + colordlg_data->hue = (float)hue; + colordlg_data->saturation = (float)saturation/100.0f; + colordlg_data->intensity = (float)intensity/100.0f; + + iColorBrowserDlgHSI2RGB(colordlg_data); + colordlg_data->previous_color = cdEncodeColor(colordlg_data->red, colordlg_data->green, colordlg_data->blue); + colordlg_data->previous_color = cdEncodeAlpha(colordlg_data->previous_color, colordlg_data->alpha); + + iColorBrowserDlgHSIChanged(colordlg_data); + return 0; +} + +static char* iColorBrowserDlgGetValueHSIAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + sprintf(buffer, "%d %d %d", (int)colordlg_data->hue, (int)(colordlg_data->saturation*100), (int)(colordlg_data->intensity*100)); + return buffer; +} + +static int iColorBrowserDlgSetValueHexAttrib(Ihandle* ih, const char* value) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + if (!iupStrHexToRGB(value, &colordlg_data->red, &colordlg_data->green, &colordlg_data->blue)) + return 0; + + colordlg_data->previous_color = cdEncodeColor(colordlg_data->red, colordlg_data->green, colordlg_data->blue); + colordlg_data->previous_color = cdEncodeAlpha(colordlg_data->previous_color, colordlg_data->alpha); + + iColorBrowserDlgRGB2HSI(colordlg_data); + iColorBrowserDlgBrowserRGB_Update(colordlg_data); + iColorBrowserDlgHSI_TXT_Update(colordlg_data); + iColorBrowserDlgRGB_TXT_Update(colordlg_data); + iColorBrowserDlgColor_Update(colordlg_data); + return 0; +} + +static char* iColorBrowserDlgGetValueHexAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + sprintf(buffer, "#%02X%02X%02X", (int)colordlg_data->red, (int)colordlg_data->green, (int)colordlg_data->blue); + return buffer; +} + +static char* iColorBrowserDlgGetColorTableAttrib(Ihandle* ih) +{ + int i, inc, off = 0; + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + char* color_str, attrib_str[30]; + char* str = iupStrGetMemory(300); + for (i=0; i < 20; i++) + { + sprintf(attrib_str, "CELL%d", i); + color_str = IupGetAttribute(colordlg_data->colortable_cbar, attrib_str); + inc = strlen(color_str); + memcpy(str+off, color_str, inc); + memcpy(str+off+inc, ";", 1); + off += inc+1; + } + str[off-1] = 0; /* remove last separator */ + return str; +} + +static int iColorBrowserDlgSetColorTableAttrib(Ihandle* ih, const char* value) +{ + int i = 0; + unsigned char r, g, b; + char str[30]; + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + + if (!ih->handle) /* do it only before map */ + iColorBrowserDlgSetShowColorTableAttrib(ih, "YES"); + + while (value && *value && i < 20) + { + if (iupStrToRGB(value, &r, &g, &b)) + { + sprintf(str, "CELL%d", i); + IupSetfAttribute(colordlg_data->colortable_cbar, str, "%d %d %d", (int)r, (int)g, (int)b); + } + + value = strchr(value, ';'); + if (value) value++; + i++; + } + + return 1; +} + + +/**************************************************************************************************************/ +/* Methods */ +/**************************************************************************************************************/ + +static int iColorBrowserDlgMapMethod(Ihandle* ih) +{ + if (!IupGetCallback(ih, "HELP_CB")) + { + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + IupSetAttribute(colordlg_data->help_bt, "VISIBLE", "NO"); + } + + return IUP_NOERROR; +} + +static void iColorBrowserDlgDestroyMethod(Ihandle* ih) +{ + IcolorDlgData* colordlg_data = (IcolorDlgData*)iupAttribGetInherit(ih, "_IUP_GC_DATA"); + free(colordlg_data); +} + +static int iColorBrowserDlgCreateMethod(Ihandle* ih, void** params) +{ + Ihandle *ok_bt, *cancel_bt; + Ihandle *rgb_vb, *hsi_vb, *clr_vb; + Ihandle *lin1, *lin2, *col1, *col2; + + IcolorDlgData* colordlg_data = (IcolorDlgData*)malloc(sizeof(IcolorDlgData)); + memset(colordlg_data, 0, sizeof(IcolorDlgData)); + iupAttribSetStr(ih, "_IUP_GC_DATA", (char*)colordlg_data); + + /* ======================================================================= */ + /* BUTTONS ============================================================= */ + /* ======================================================================= */ + ok_bt = IupButton("OK", NULL); /* Ok Button */ + IupSetAttribute(ok_bt, "PADDING", "20x0"); + IupSetCallback (ok_bt, "ACTION", (Icallback)iColorBrowserDlgButtonOK_CB); + IupSetAttributeHandle(ih, "DEFAULTENTER", ok_bt); + + cancel_bt = IupButton(iupStrMessageGet("IUP_CANCEL"), NULL); /* Cancel Button */ + IupSetAttribute(cancel_bt, "PADDING", "20x0"); + IupSetCallback (cancel_bt, "ACTION", (Icallback)iColorBrowserDlgButtonCancel_CB); + IupSetAttributeHandle(ih, "DEFAULTESC", cancel_bt); + + colordlg_data->help_bt = IupButton(iupStrMessageGet("IUP_HELP"), NULL); /* Help Button */ + IupSetAttribute(colordlg_data->help_bt, "PADDING", "20x0"); + IupSetCallback (colordlg_data->help_bt, "ACTION", (Icallback)iColorBrowserDlgButtonHelp_CB); + + /* ======================================================================= */ + /* COLOR =============================================================== */ + /* ======================================================================= */ + colordlg_data->color_browser = IupColorBrowser(); + IupSetAttribute(colordlg_data->color_browser, "EXPAND", "YES"); + IupSetCallback(colordlg_data->color_browser, "DRAG_CB", (Icallback)iColorBrowserDlgColorSelDrag_CB); + IupSetCallback(colordlg_data->color_browser, "CHANGE_CB", (Icallback)iColorBrowserDlgColorSelDrag_CB); + + colordlg_data->color_cnv = IupCanvas(NULL); /* Canvas of the color */ + IupSetAttribute(colordlg_data->color_cnv, "SIZE", "x12"); + IupSetAttribute(colordlg_data->color_cnv, "CANFOCUS", "NO"); + IupSetAttribute(colordlg_data->color_cnv, "EXPAND", "HORIZONTAL"); + IupSetCallback (colordlg_data->color_cnv, "ACTION", (Icallback)iColorBrowserDlgColorCnvRedraw_CB); + IupSetCallback (colordlg_data->color_cnv, "MAP_CB", (Icallback)iColorBrowserDlgColorCnvMap_CB); + IupSetCallback (colordlg_data->color_cnv, "UNMAP_CB", (Icallback)iColorBrowserDlgColorCnvUnMap_CB); + IupSetCallback (colordlg_data->color_cnv, "BUTTON_CB", (Icallback)iColorBrowserDlgColorCnvButton_CB); + + colordlg_data->colorhex_txt = IupText(NULL); /* Hex of the color */ + IupSetAttribute(colordlg_data->colorhex_txt, "VISIBLECOLUMNS", "7"); + IupSetCallback (colordlg_data->colorhex_txt, "ACTION", (Icallback)iColorBrowserDlgHexAction_CB); + IupSetAttribute(colordlg_data->colorhex_txt, "MASK", "#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]"); + + /* ======================================================================= */ + /* ALPHA TRANSPARENCY ================================================== */ + /* ======================================================================= */ + colordlg_data->alpha_val = IupVal("HORIZONTAL"); + IupSetAttribute(colordlg_data->alpha_val, "EXPAND", "HORIZONTAL"); + IupSetAttribute(colordlg_data->alpha_val, "MIN", "0"); + IupSetAttribute(colordlg_data->alpha_val, "MAX", "255"); + IupSetAttribute(colordlg_data->alpha_val, "VALUE", "255"); + IupSetAttribute(colordlg_data->alpha_val, "SIZE", "80x12"); + IupSetCallback (colordlg_data->alpha_val, "MOUSEMOVE_CB", (Icallback)iColorBrowserDlgAlphaVal_CB); + IupSetCallback (colordlg_data->alpha_val, "BUTTON_PRESS_CB", (Icallback)iColorBrowserDlgAlphaVal_CB); + IupSetCallback (colordlg_data->alpha_val, "BUTTON_RELEASE_CB", (Icallback)iColorBrowserDlgAlphaVal_CB); + + colordlg_data->alpha_txt = IupText(NULL); /* Alpha value */ + IupSetAttribute(colordlg_data->alpha_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->alpha_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->alpha_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->alpha_txt, "SPINMAX", "255"); + IupSetAttribute(colordlg_data->alpha_txt, "SPININC", "1"); + IupSetCallback (colordlg_data->alpha_txt, "ACTION", (Icallback)iColorBrowserDlgAlphaAction_CB); + IupSetCallback (colordlg_data->alpha_txt, "SPIN_CB", (Icallback)iColorBrowserDlgAlphaSpin_CB); + IupSetAttribute(colordlg_data->alpha_txt, "MASKINT", "0:255"); + + /* ======================================================================= */ + /* COLOR TABLE ========================================================= */ + /* ======================================================================= */ + colordlg_data->colortable_cbar = IupColorbar(); + IupSetAttribute(colordlg_data->colortable_cbar, "ORIENTATION", "HORIZONTAL"); + IupSetAttribute(colordlg_data->colortable_cbar, "NUM_PARTS", "2"); + IupSetAttribute(colordlg_data->colortable_cbar, "NUM_CELLS", "20"); + IupSetAttribute(colordlg_data->colortable_cbar, "SHOW_PREVIEW", "NO"); + IupSetAttribute(colordlg_data->colortable_cbar, "SIZE", "138x22"); + IupSetAttribute(colordlg_data->colortable_cbar, "SQUARED", "NO"); + IupSetCallback (colordlg_data->colortable_cbar, "SELECT_CB", (Icallback)iColorBrowserDlgColorTableSelect_CB); + + /* ======================================================================= */ + /* RGB TEXT FIELDS ===================================================== */ + /* ======================================================================= */ + colordlg_data->red_txt = IupText(NULL); /* Red value */ + IupSetAttribute(colordlg_data->red_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->red_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->red_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->red_txt, "SPINMAX", "255"); + IupSetAttribute(colordlg_data->red_txt, "SPININC", "1"); + IupSetCallback (colordlg_data->red_txt, "ACTION", (Icallback)iColorBrowserDlgRedAction_CB); + IupSetCallback (colordlg_data->red_txt, "SPIN_CB", (Icallback)iColorBrowserDlgRedSpin_CB); + IupSetAttribute(colordlg_data->red_txt, "MASKINT", "0:255"); + + colordlg_data->green_txt = IupText(NULL); /* Green value */ + IupSetAttribute(colordlg_data->green_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->green_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->green_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->green_txt, "SPINMAX", "255"); + IupSetAttribute(colordlg_data->green_txt, "SPININC", "1"); + IupSetCallback (colordlg_data->green_txt, "ACTION", (Icallback)iColorBrowserDlgGreenAction_CB); + IupSetCallback (colordlg_data->green_txt, "SPIN_CB", (Icallback)iColorBrowserDlgGreenSpin_CB); + IupSetAttribute(colordlg_data->green_txt, "MASKINT", "0:255"); + + colordlg_data->blue_txt = IupText(NULL); /* Blue value */ + IupSetAttribute(colordlg_data->blue_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->blue_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->blue_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->blue_txt, "SPINMAX", "255"); + IupSetAttribute(colordlg_data->blue_txt, "SPININC", "1"); + IupSetCallback (colordlg_data->blue_txt, "ACTION", (Icallback)iColorBrowserDlgBlueAction_CB); + IupSetCallback (colordlg_data->blue_txt, "SPIN_CB", (Icallback)iColorBrowserDlgBlueSpin_CB); + IupSetAttribute(colordlg_data->blue_txt, "MASKINT", "0:255"); + + /* ======================================================================= */ + /* HSI TEXT FIELDS ===================================================== */ + /* ======================================================================= */ + colordlg_data->hue_txt = IupText(NULL); /* Hue value */ + IupSetAttribute(colordlg_data->hue_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->hue_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->hue_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->hue_txt, "SPINMAX", "359"); + IupSetAttribute(colordlg_data->hue_txt, "SPINWRAP", "YES"); + IupSetAttribute(colordlg_data->hue_txt, "SPININC", "1"); + IupSetCallback(colordlg_data->hue_txt, "ACTION", (Icallback)iColorBrowserDlgHueAction_CB); + IupSetCallback(colordlg_data->hue_txt, "SPIN_CB", (Icallback)iColorBrowserDlgHueSpin_CB); + IupSetAttribute(colordlg_data->hue_txt, "MASKINT", "0:359"); + + colordlg_data->saturation_txt = IupText(NULL); /* Saturation value */ + IupSetAttribute(colordlg_data->saturation_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->saturation_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->saturation_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->saturation_txt, "SPINMAX", "100"); + IupSetAttribute(colordlg_data->saturation_txt, "SPININC", "1"); + IupSetCallback(colordlg_data->saturation_txt, "ACTION", (Icallback)iColorBrowserDlgSaturationAction_CB); + IupSetCallback(colordlg_data->saturation_txt, "SPIN_CB", (Icallback)iColorBrowserDlgSaturationSpin_CB); + IupSetAttribute(colordlg_data->saturation_txt, "MASKINT", "0:100"); + + colordlg_data->intensity_txt = IupText(NULL); /* Intensity value */ + IupSetAttribute(colordlg_data->intensity_txt, "VISIBLECOLUMNS", "3"); + IupSetAttribute(colordlg_data->intensity_txt, "SPIN", "YES"); + IupSetAttribute(colordlg_data->intensity_txt, "SPINMIN", "0"); + IupSetAttribute(colordlg_data->intensity_txt, "SPINMAX", "100"); + IupSetAttribute(colordlg_data->intensity_txt, "SPININC", "1"); + IupSetCallback(colordlg_data->intensity_txt, "ACTION", (Icallback)iColorBrowserDlgIntensityAction_CB); + IupSetCallback(colordlg_data->intensity_txt, "SPIN_CB", (Icallback)iColorBrowserDlgIntensitySpin_CB); + IupSetAttribute(colordlg_data->intensity_txt, "MASKINT", "0:100"); + + /* =================== */ + /* 1st line = Controls */ + /* =================== */ + + col1 = IupVbox(colordlg_data->color_browser, IupSetAttributes(IupHbox(colordlg_data->color_cnv, NULL), "MARGIN=30x0"),NULL); + + hsi_vb = IupVbox(IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_HUE")), + colordlg_data->hue_txt, + NULL), "ALIGNMENT=ACENTER"), + IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_SATURATION")), + colordlg_data->saturation_txt, + NULL), "ALIGNMENT=ACENTER"), + IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_INTENSITY")), + colordlg_data->intensity_txt, + NULL), "ALIGNMENT=ACENTER"), + NULL); + IupSetAttribute(hsi_vb, "GAP", "5"); + + rgb_vb = IupVbox(IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_RED")), + colordlg_data->red_txt, + NULL), "ALIGNMENT=ACENTER"), + IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_GREEN")), + colordlg_data->green_txt, + NULL), "ALIGNMENT=ACENTER"), + IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_BLUE")), + colordlg_data->blue_txt, + NULL), "ALIGNMENT=ACENTER"), + NULL); + IupSetAttribute(rgb_vb, "GAP", "5"); + + clr_vb = IupVbox(IupSetAttributes(IupHbox(IupLabel(iupStrMessageGet("IUP_OPACITY")), + colordlg_data->alpha_txt, colordlg_data->alpha_val, + NULL), "ALIGNMENT=ACENTER"), + IupSetAttributes(IupHbox(IupLabel("He&xa:"), + colordlg_data->colorhex_txt, + NULL), "ALIGNMENT=ACENTER"), + IupSetAttributes(IupVbox(IupLabel(iupStrMessageGet("IUP_PALETTE")), + colordlg_data->colortable_cbar, + NULL), "GAP=3"), + NULL); + IupSetAttribute(clr_vb, "GAP", "5"); + IupSetAttribute(clr_vb, "EXPAND", "YES"); + + IupDestroy(IupSetAttributes(IupNormalizer(IupGetChild(IupGetChild(hsi_vb, 0), 0), /* Hue Label */ + IupGetChild(IupGetChild(hsi_vb, 1), 0), /* Saturation Label */ + IupGetChild(IupGetChild(hsi_vb, 2), 0), /* Intensity Label */ + IupGetChild(IupGetChild(clr_vb, 0), 0), /* Opacity Label */ + IupGetChild(IupGetChild(clr_vb, 1), 0), /* Hexa Label */ + NULL), "NORMALIZE=HORIZONTAL")); + + IupDestroy(IupSetAttributes(IupNormalizer(IupGetChild(IupGetChild(rgb_vb, 0), 0), /* Red Label */ + IupGetChild(IupGetChild(rgb_vb, 1), 0), /* Green Label */ + IupGetChild(IupGetChild(rgb_vb, 2), 0), /* Blue Label */ + NULL), "NORMALIZE=HORIZONTAL")); + + col2 = IupVbox(IupSetAttributes(IupHbox(hsi_vb, IupFill(), rgb_vb, NULL), "EXPAND=YES"), + IupSetAttributes(IupLabel(NULL), "SEPARATOR=HORIZONTAL"), + clr_vb, + NULL); + IupSetAttributes(col2, "EXPAND=NO, GAP=10"); + + lin1 = IupHbox(col1, col2, NULL); + IupSetAttribute(lin1, "GAP", "10"); + IupSetAttribute(lin1, "MARGIN", "0x0"); + + /* ================== */ + /* 2nd line = Buttons */ + /* ================== */ + + lin2 = IupHbox(IupFill(), ok_bt, cancel_bt, colordlg_data->help_bt, NULL); + IupSetAttribute(lin2, "GAP", "5"); + IupSetAttribute(lin2, "MARGIN", "0x0"); + IupSetAttribute(lin2, "NORMALIZESIZE", "HORIZONTAL"); + + /* Do not use IupAppend because we set childtype=IUP_CHILDNONE */ + iupChildTreeAppend(ih, IupSetAttributes(IupVbox(lin1, IupSetAttributes(IupLabel(NULL), "SEPARATOR=HORIZONTAL"), lin2, NULL), "MARGIN=10x10, GAP=10")); + + iColorBrowserDlgInit_Defaults(colordlg_data); + + (void)params; + return IUP_NOERROR; +} + +Iclass* iupColorBrowserDlgGetClass(void) +{ + Iclass* ic = iupClassNew(iupDialogGetClass()); + + ic->Create = iColorBrowserDlgCreateMethod; + ic->Destroy = iColorBrowserDlgDestroyMethod; + ic->Map = iColorBrowserDlgMapMethod; + + ic->name = "colordlg"; /* this will hide the GTK and Windows implementations */ + ic->nativetype = IUP_TYPEDIALOG; + ic->is_interactive = 1; + ic->childtype = IUP_CHILDNONE; + + iupClassRegisterAttribute(ic, "COLORTABLE", iColorBrowserDlgGetColorTableAttrib, iColorBrowserDlgSetColorTableAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "STATUS", iColorBrowserDlgGetStatusAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", iColorBrowserDlgGetValueAttrib, iColorBrowserDlgSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ALPHA", iColorBrowserDlgGetAlphaAttrib, iColorBrowserDlgSetAlphaAttrib, IUPAF_SAMEASSYSTEM, "255", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUEHSI", iColorBrowserDlgGetValueHSIAttrib, iColorBrowserDlgSetValueHSIAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUEHEX", iColorBrowserDlgGetValueHexAttrib, iColorBrowserDlgSetValueHexAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWALPHA", NULL, iColorBrowserDlgSetShowAlphaAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWCOLORTABLE", NULL, iColorBrowserDlgSetShowColorTableAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWHEX", NULL, iColorBrowserDlgSetShowHexAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWHELP", NULL, iColorBrowserDlgSetShowHelpAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/srccontrols/color/iup_colorhsi.c b/iup/srccontrols/color/iup_colorhsi.c new file mode 100755 index 0000000..ce5e71f --- /dev/null +++ b/iup/srccontrols/color/iup_colorhsi.c @@ -0,0 +1,358 @@ +/** \file + * \brief HSI Color Manipulation + * Copied and adapted from IM + * + * See Copyright Notice in "iup.h" + */ + + +#include <math.h> +#include <stdio.h> +#include "iup_colorhsi.h" + +static const float rad60 = 1.0471975f; +static const float rad120 = 2.0943951f; +static const float rad180 = 3.1415926f; +static const float rad240 = 4.1887902f; +static const float rad300 = 5.2359877f; +static const float rad360 = 6.2831853f; +static const float sqrt3 = 1.7320508f; +static const float rad2deg = 57.2957795131f; + +static float costab[361]; +static float sintab[361]; +static int init_tab = 0; + +static void iColorBuildTables(void) +{ + int theta; + for (theta=0; theta<=360; theta++) + { + float th = ((float)theta)/rad2deg; + costab[theta] = cosf(th); + sintab[theta] = sinf(th); + } + init_tab = 1; +} + +static void iColorSinCos(float H, float *sinH, float *cosH) +{ + int theta; + + H *= rad2deg; + theta = (int)(H + 0.5f); /* Round */ + + if (!init_tab) + iColorBuildTables(); + + if (theta<0) theta = 0; + if (theta>360) theta = 360; + + *cosH = costab[theta]; + *sinH = sintab[theta]; +} + +static float iColorNormHue(float H) +{ + while (H < 0.0f) + H += rad360; + + if (H > rad360) + H = fmodf(H, rad360); + + return H; +} + +static unsigned char iColorQuantize(float value) +{ + if (value >= 1.0f) return 255; + if (value <= 0.0f) return 0; + return (unsigned char)(value*256); +} + +static float iColorReconstruct(unsigned char value) +{ + if (value <= 0) return 0.0f; + if (value >= 255) return 1.0f; + return (((float)value + 0.5f)/256.0f); +} + +static void iColorSmax01(float h, float hr, float hb, float hg, float *h0, float *h1) +{ + if (h < rad60) + { + *h0 = hb; + *h1 = hr; + } + else if (h < rad120) + { + *h0 = hb; + *h1 = hg; + } + else if (h < rad180) + { + *h0 = hr; + *h1 = hg; + } + else if (h < rad240) + { + *h0 = hr; + *h1 = hb; + } + else if (h < rad300) + { + *h0 = hg; + *h1 = hb; + } + else + { + *h0 = hg; + *h1 = hr; + } +} + +/* Given H and I, returns S max, but s is in u,v space. */ +static float iColorHSI_Smax(float h, float cosH, float sinH, float i) +{ + float hr, hb, hg, imax, h0, h1; + + /* i here is normalized between 0-1 */ + + if (i == 0.0f || i == 1.0f) + return 0.0f; + + /* Making r=0, g=0, b=0, r=1, g=1 or b=1 in the parametric equations and + writting s in function of H and I. */ + + /* at bottom */ + if (i <= 1.0f/3.0f) + { + /* face B=0 */ + if (h < rad120) + { + hb = (cosH + sinH*sqrt3)/3.0f; + return i/hb; + } + + /* face R=0 */ + if (h < rad240) + { + hr = -cosH/1.5f; + return i/hr; + } + + /* face G=0 (h < rad360) */ + { + hg = (cosH - sinH*sqrt3)/3.0f; + return i/hg; + } + } + + /* at top */ + if (i >= 2.0f/3.0f) + { + /* face R=1 */ + if (h < rad60 || h > rad300) + { + hr = cosH/1.5f; + return (1.0f-i)/hr; + } + + /* face G=1 */ + if (h < rad180) + { + hg = (-cosH + sinH*sqrt3)/3.0f; + return (1.0f-i)/hg; + } + + /* face B=1 (h > rad180 && h < rad300) */ + { + hb = (-cosH - sinH*sqrt3)/3.0f; + return (1.0f-i)/hb; + } + } + + /* in the middle */ + hr = cosH/1.5f; + hg = (-cosH + sinH*sqrt3)/3.0f; + hb = (-cosH - sinH*sqrt3)/3.0f; + + iColorSmax01(h, hr, hb, hg, &h0, &h1); + + if (h == 0.0f || h == rad120 || h == rad240) + imax = 1.0f/3.0f; + else if (h == rad60 || h == rad180 || h == rad300) + imax = 2.0f/3.0f; + else + imax = h0/(h0 - h1); + + if (i < imax) + return -i/h0; + else + return (1.0f-i)/h1; +} + +/* Given H, returns I where S is max, + BUT the maximum S here is 1 at the corners of the cube. */ +static float iColorHSI_ImaxS(float h, float cosH, float sinH) +{ + float i, h0, h1; + float hr, hb, hg; + + /* i here is normalized between 0-1 */ + + if (h == 0.0f || h == rad120 || h == rad240) + return 1.0f/3.0f; + + if (h == rad60 || h == rad180 || h == rad300) + return 2.0f/3.0f; + + hr = cosH/1.5f; + hg = (-cosH + sinH*sqrt3)/3.0f; + hb = (-cosH - sinH*sqrt3)/3.0f; + + iColorSmax01(h, hr, hb, hg, &h0, &h1); + + i = h0/(h0 - h1); + + return i; +} + +static void iColorRGB2HSI(float r, float g, float b, float *h, float *s, float *i) +{ + float v, u, ImaxS; + + /* Parametric equations */ + v = r - (g + b)/2.0f; + u = (g - b) * (sqrt3/2.0f); + + *i = (r + g + b)/3; /* already normalized to 0-1 */ + + *s = sqrtf(v*v + u*u); /* s is between 0-1, BUT it is linear in the cube and it is in u,v space. */ + + if (*s == 0.0f) + { + /* *h = <any> (left unchanged) */ + ImaxS = 1.0f/3.0f; + } + else + { + float Smax; + float H, cosH, sinH; + + H = atan2f(u, v); + H = iColorNormHue(H); + *h = H * rad2deg; + + iColorSinCos(H, &sinH, &cosH); + + /* must scale S from 0-Smax to 0-1 */ + Smax = iColorHSI_Smax(H, cosH, sinH, *i); + if (Smax == 0.0f) + *s = 0.0f; + else + { + if (*s > Smax) /* because of round problems when calculating s and Smax */ + *s = Smax; + *s /= Smax; + } + + ImaxS = iColorHSI_ImaxS((float)H, cosH, sinH); + } + + /* must convert I from linear scale to non-linear scale. USED ONLY FOR THE COLORBROWSER */ + if (*i < 0.5f) /* half I is I=ImaxS, not I=0.5 */ + *i = ((*i)*0.5f)/ImaxS; + else + *i = (((*i) - ImaxS)*0.5f)/(1.0f - ImaxS) + 0.5f; +} + +static void iColorHSI2RGB(float h, float s, float i, float *r, float *g, float *b) +{ + float cosH, sinH, H, v, u; + float Smax, ImaxS; + + if (i < 0) i = 0; + else if (i > 1) i = 1; + + if (s < 0) s = 0; + else if (s > 1) s = 1; + + if (s == 0.0f || i == 1.0f || i == 0.0f || (int)h == 360) + { + *r = i; + *g = i; + *b = i; + return; + } + + H = h/rad2deg; + H = iColorNormHue(H); + + iColorSinCos(H, &sinH, &cosH); + + /* must convert I from non-linear scale to linear scale. USED ONLY FOR THE COLORBROWSER */ + ImaxS = iColorHSI_ImaxS(H, cosH, sinH); + if (i < 0.5f) /* half I is I=ImaxS, not I=0.5 */ + i = ImaxS * (i / 0.5f); + else + i = (1.0f - ImaxS) * (i - 0.5f)/0.5f + ImaxS; + + /* must scale S from 0-1 to 0-Smax */ + Smax = iColorHSI_Smax(H, cosH, sinH, i); + s *= Smax; + if (s > 1.0f) /* because of round problems when calculating s and Smax */ + s = 1.0f; + + v = s * cosH; + u = s * sinH; + + /* Inverse of the Parametric equations, using i normalized to 0-1 */ + *r = i + v/1.5f; + *g = i - (v - u*sqrt3)/3.0f; + *b = i - (v + u*sqrt3)/3.0f; + + /* fix round errors */ + if (*r < 0.0f) *r = 0; + if (*g < 0.0f) *g = 0; + if (*b < 0.0f) *b = 0; + + if (*r > 1.0f) *r = 1.0f; + if (*g > 1.0f) *g = 1.0f; + if (*b > 1.0f) *b = 1.0f; +} + +/*********************************************************************************************/ + +void iupColorRGB2HSI(unsigned char r, unsigned char g, unsigned char b, float *h, float *s, float *i) +{ + float fr = iColorReconstruct(r); + float fg = iColorReconstruct(g); + float fb = iColorReconstruct(b); + + iColorRGB2HSI(fr, fg, fb, h, s, i); +} + +void iupColorHSI2RGB(float h, float s, float i, unsigned char *r, unsigned char *g, unsigned char *b) +{ + float fr, fg, fb; + + iColorHSI2RGB(h, s, i, &fr, &fg, &fb); + + *r = iColorQuantize(fr); + *g = iColorQuantize(fg); + *b = iColorQuantize(fb); +} + +int iupStrToHSI(const char *str, float *h, float *s, float *i) +{ + float fh, fs, fi; + if (!str) return 0; + if (sscanf(str, "%f %f %f", &fh, &fs, &fi) != 3) return 0; + if (fh > 359 || fs > 1 || fi > 1) return 0; + if (fh < 0 || fs < 0 || fi < 0) return 0; + *h = fh; + *s = fs; + *i = fi; + return 1; +} diff --git a/iup/srccontrols/color/iup_colorhsi.h b/iup/srccontrols/color/iup_colorhsi.h new file mode 100755 index 0000000..b29ea48 --- /dev/null +++ b/iup/srccontrols/color/iup_colorhsi.h @@ -0,0 +1,44 @@ +/** \file + * \brief HSI Color Manipulation + * Copied and adapted from IM + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_COLORHSI_H +#define __IUP_COLORHSI_H + +#if defined(__cplusplus) +extern "C" { +#endif + +/* 0<=H<=359 */ +/* 0<=S<=1 */ +/* 0<=I<=1 */ + + +/* Converts from RGB to HSI. + */ +void iupColorRGB2HSI(unsigned char r, unsigned char g, unsigned char b, float *h, float *s, float *i); + +/* Converts from HSI to RGB. + */ +void iupColorHSI2RGB(float h, float s, float i, unsigned char *r, unsigned char *g, unsigned char *b); + +int iupStrToHSI(const char *str, float *h, float *s, float *i); + +#ifdef IUP_DEFMATHFLOAT +#define atan2f(_X, _Y) ((float)atan2((double)_X, (double)_Y)) +#define cosf(_X) ((float)cos((double)_X)) +#define fmodf(_X, _Y) ((float)fmod((double)_X, (double)_Y)) +#define sinf(_X) ((float)sin((double)_X)) +#define sqrtf(_X) ((float)sqrt((double)_X)) +#endif + + + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/iup/srccontrols/config.mak b/iup/srccontrols/config.mak new file mode 100755 index 0000000..394d607 --- /dev/null +++ b/iup/srccontrols/config.mak @@ -0,0 +1,48 @@ +PROJNAME = iup +LIBNAME = iupcontrols +OPT = YES + +INCLUDES = ../include ../src . + +SRCCOLOR = iup_colorbrowser.c iup_colorhsi.c iup_colorbrowserdlg.c +SRCCOLOR := $(addprefix color/, $(SRCCOLOR)) + +SRCMATRIX = iupmat_key.c iupmat_mark.c iupmat_aux.c iupmat_mem.c iupmat_mouse.c iupmat_numlc.c \ + iupmat_colres.c iupmat_draw.c iupmat_focus.c iupmat_getset.c iupmatrix.c \ + iupmat_scroll.c iupmat_edit.c +SRCMATRIX := $(addprefix matrix/, $(SRCMATRIX)) + +SRC = iup_cdutil.c iup_gauge.c iup_cells.c iup_colorbar.c iup_controls.c \ + iup_dial.c iup_oldtabs.c iup_oldval.c iup_oldmask.c \ + $(SRCCOLOR) $(SRCMATRIX) + +LIBS = iup iupcd +LDIR = ../lib/$(TEC_UNAME) +USE_CD = Yes + +# force the definition of math functions using float +# Some compilers do not define them +ifeq ($(TEC_UNAME), dll) + DEFINES += IUP_DEFMATHFLOAT +endif +ifeq ($(TEC_UNAME), vc6) + DEFINES += IUP_DEFMATHFLOAT +endif +ifeq ($(TEC_UNAME), dll7) + DEFINES += IUP_DEFMATHFLOAT +endif +ifeq ($(TEC_UNAME), vc7) + DEFINES += IUP_DEFMATHFLOAT +endif +ifneq ($(findstring ow, $(TEC_UNAME)), ) + DEFINES += IUP_DEFMATHFLOAT +endif +ifneq ($(findstring bc, $(TEC_UNAME)), ) + DEFINES += IUP_DEFMATHFLOAT +endif +ifneq ($(findstring AIX, $(TEC_UNAME)), ) + DEFINES += IUP_DEFMATHFLOAT +endif +ifneq ($(findstring SunOS, $(TEC_UNAME)), ) + DEFINES += IUP_DEFMATHFLOAT +endif diff --git a/iup/srccontrols/iup_cdutil.c b/iup/srccontrols/iup_cdutil.c new file mode 100755 index 0000000..3ffb15b --- /dev/null +++ b/iup/srccontrols/iup_cdutil.c @@ -0,0 +1,153 @@ +/** \file + * \brief cdiuputil. CD and IUP utilities for the IupControls + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdlib.h> +#include <stdarg.h> + +#include <cd.h> + +#include "iup.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_cdutil.h" + + +long cdIupConvertColor(const char *color) +{ + unsigned char r, g, b; + if (iupStrToRGB(color, &r, &g, &b)) + return cdEncodeColor(r, g, b); + else + return 0; +} + +void cdIupCalcShadows(long bgcolor, long *light_shadow, long *mid_shadow, long *dark_shadow) +{ + int r, bg_r = cdRed(bgcolor); + int g, bg_g = cdGreen(bgcolor); + int b, bg_b = cdBlue(bgcolor); + + /* light_shadow */ + + int max = bg_r; + if (bg_g > max) max = bg_g; + if (bg_b > max) max = bg_b; + + if (255-max < 64) + { + r = 255; + g = 255; + b = 255; + } + else + { + /* preserve some color information */ + if (bg_r == max) r = 255; + else r = bg_r + (255-max); + if (bg_g == max) g = 255; + else g = bg_g + (255-max); + if (bg_b == max) b = 255; + else b = bg_b + (255-max); + } + + if (light_shadow) *light_shadow = cdEncodeColor((unsigned char)r, (unsigned char)g, (unsigned char)b); + + /* dark_shadow */ + r = bg_r - 128; + g = bg_g - 128; + b = bg_b - 128; + if (r < 0) r = 0; + if (g < 0) g = 0; + if (b < 0) b = 0; + + if (dark_shadow) *dark_shadow = cdEncodeColor((unsigned char)r, (unsigned char)g, (unsigned char)b); + + /* mid_shadow = (dark_shadow+bgcolor)/2 */ + if (mid_shadow) *mid_shadow = cdEncodeColor((unsigned char)((bg_r+r)/2), (unsigned char)((bg_g+g)/2), (unsigned char)((bg_b+b)/2)); +} + +void cdIupDrawSunkenRect(cdCanvas *canvas, int x1, int y1, int x2, int y2, long light_shadow, long mid_shadow, long dark_shadow) +{ + cdCanvasForeground(canvas, mid_shadow); + cdCanvasLine(canvas, x1, y1+1, x1, y2); + cdCanvasLine(canvas, x1, y2, x2-1, y2); + + cdCanvasForeground(canvas, dark_shadow); + cdCanvasLine(canvas, x1+1, y1+2, x1+1, y2-1); + cdCanvasLine(canvas, x1+1, y2-1, x2-2, y2-1); + + cdCanvasForeground(canvas, light_shadow); + cdCanvasLine(canvas, x1, y1, x2, y1); + cdCanvasLine(canvas, x2, y1, x2, y2); +} + +void cdIupDrawRaisenRect(cdCanvas *canvas, int x1, int y1, int x2, int y2, long light_shadow, long mid_shadow, long dark_shadow) +{ + cdCanvasForeground(canvas, light_shadow); + cdCanvasLine(canvas, x1, y1+1, x1, y2); + cdCanvasLine(canvas, x1, y2, x2-1, y2); + + cdCanvasForeground(canvas, dark_shadow); + cdCanvasLine(canvas, x1, y1, x2, y1); + cdCanvasLine(canvas, x2, y1, x2, y2); + + cdCanvasForeground(canvas, mid_shadow); + cdCanvasLine(canvas, x1+1, y1+1, x2-1, y1+1); + cdCanvasLine(canvas, x2-1, y1+2, x2-1, y2-1); +} + +void cdIupDrawVertSunkenMark(cdCanvas *canvas, int x, int y1, int y2, long light_shadow, long dark_shadow) +{ + cdCanvasForeground(canvas, dark_shadow); + cdCanvasLine(canvas, x-1, y1, x-1, y2); + cdCanvasForeground(canvas, light_shadow); + cdCanvasLine(canvas, x, y1, x, y2); +} + +void cdIupDrawHorizSunkenMark(cdCanvas *canvas, int x1, int x2, int y, long light_shadow, long dark_shadow) +{ + cdCanvasForeground(canvas, dark_shadow); + cdCanvasLine(canvas, x1, y+1, x2, y+1); + cdCanvasForeground(canvas, light_shadow); + cdCanvasLine(canvas, x1, y, x2, y); +} + +void cdIupDrawFocusRect(Ihandle* ih, cdCanvas *canvas, int x1, int y1, int x2, int y2) +{ + int y, x, w, h; +#ifdef WIN32 + void* gc = cdCanvasGetAttribute(canvas, "HDC"); +#else + void* gc = cdCanvasGetAttribute(canvas, "GC"); +#endif + + cdCanvasUpdateYAxis(canvas, &y1); + cdCanvasUpdateYAxis(canvas, &y2); + y = y1; + if (y2<y1) y = y2; + x = x1; + if (x2<x1) x = x2; + + w = abs(x2-x1)+1; + h = abs(y2-y1)+1; + + iupdrvDrawFocusRect(ih, gc, x, y, w, h); +} + +void cdDrawFocusRect(cdCanvas *canvas, int x1, int y1, int x2, int y2) +{ + int old_linestyle = cdCanvasLineStyle(canvas, CD_DOTTED); + int old_foreground = cdCanvasForeground(canvas, CD_WHITE); + int old_writemode = cdCanvasWriteMode(canvas, CD_XOR); + + cdCanvasRect(canvas, x1, x2, y1, y2); + + cdCanvasWriteMode(canvas, old_writemode); + cdCanvasForeground(canvas, old_foreground); + cdCanvasLineStyle(canvas, old_linestyle); +} diff --git a/iup/srccontrols/iup_cdutil.h b/iup/srccontrols/iup_cdutil.h new file mode 100755 index 0000000..73ad3b4 --- /dev/null +++ b/iup/srccontrols/iup_cdutil.h @@ -0,0 +1,35 @@ +/** \file + * \brief cdiuputil. CD and IUP utilities for the IupControls + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_CDUTIL_H +#define __IUP_CDUTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +void cdIupCalcShadows(long bgcolor, long *light_shadow, long *mid_shadow, long *dark_shadow); +long cdIupConvertColor(const char *color); +void cdIupDrawSunkenRect(cdCanvas *canvas, int x1, int y1, int x2, int y2, + long light_shadow, long mid_shadow, long dark_shadow); +void cdIupDrawRaisenRect(cdCanvas *canvas, int x1, int y1, int x2, int y2, + long light_shadow, long mid_shadow, long dark_shadow); +void cdIupDrawVertSunkenMark(cdCanvas *canvas, int x, int y1, int y2, long light_shadow, long dark_shadow); +void cdIupDrawHorizSunkenMark(cdCanvas *canvas, int x1, int x2, int y, long light_shadow, long dark_shadow); +void cdIupDrawFocusRect(Ihandle* ih, cdCanvas *canvas, int x1, int y1, int x2, int y2); + +void cdDrawFocusRect(cdCanvas *canvas, int x1, int y1, int x2, int y2); + +#define cdIupInvertYAxis(_y, _h) ((_h) - (_y) - 1); + +#define cdIupLIGTHER(_x) ((unsigned char)(((_x)+ 192)/2)) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/iup_cells.c b/iup/srccontrols/iup_cells.c new file mode 100755 index 0000000..d9a7fe4 --- /dev/null +++ b/iup/srccontrols/iup_cells.c @@ -0,0 +1,974 @@ +/** \file + * \brief Cells Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#undef CD_NO_OLD_INTERFACE + +#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" + + +#define ICELLS_OUT -999 + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + cdCanvas* cdcanvas; /* cd canvas for drawing */ + cdCanvas* cddbuffer; /* image canvas for double buffering */ + int w; /* control width (pixels) */ + int h; /* control height (pixels) */ + int clipped; /* cells bounding box clipping activated */ + int boxed; /* draw cells bounding box activated */ + int bufferize; /* bufferize on */ + int non_scrollable_lins; /* number of non-scrollable lines */ + int non_scrollable_cols; /* number of non-scrollable columns */ + long int bgcolor; /* Empty area color and bgcolor */ +}; + + +/* Function to inquire application cell data (line height) */ +static int iCellsGetHeight(Ihandle* ih, int i) +{ + int size; + + IFni cb = (IFni)IupGetCallback(ih, "HEIGHT_CB"); + if (!cb) + return 30; /* default value */ + + size = cb(ih, i); + if (size < 0) + size = 0; + + return size; +} + +/* Function to inquire application cell data (column width) */ +static int iCellsGetWidth(Ihandle* ih, int j) +{ + int size; + + IFni cb = (IFni)IupGetCallback(ih, "WIDTH_CB"); + if (!cb) + return 60; /* default value */ + + size = cb(ih, j); + if (size < 0) + size = 0; + + return size; +} + +/* Function used to calculate a cell limits */ +static int iCellsGetLimits(Ihandle* ih, int i, int j, int* xmin, int* xmax, int* ymin, int* ymax) +{ + int result = 1; + int xmin_sum = 0; + int ymin_sum = 0; + int w = ih->data->w; + int h = ih->data->h; + int _xmin, _xmax, _ymin, _ymax; + + /* Adjusting the inital position according to the cell's type. If it + * is non-scrollable, the origin is always zero, otherwise the origin + * is the scrollbar position */ + int posx = (j <= ih->data->non_scrollable_cols)? 0: IupGetInt(ih, "POSX"); + int posy = (i <= ih->data->non_scrollable_lins)? 0: IupGetInt(ih, "POSY"); + int idx; + + /* Adding to the origin, the cells' width and height */ + for (idx = 1; idx < j; idx++) + xmin_sum += iCellsGetWidth(ih, idx); + + for (idx = 1; idx < i; idx++) + ymin_sum += iCellsGetHeight(ih, idx); + + /* Finding the cell origin */ + _xmin = xmin_sum - posx; + _ymax = h - (ymin_sum - posy) - 1; + + /* Computing the cell limit, based on its origin and size */ + _xmax = _xmin + iCellsGetWidth(ih, j); + _ymin = _ymax - iCellsGetHeight(ih, i); + + /* Checking if the cell is visible */ + if (_xmax < 0 || _xmin > w || _ymin > h || _ymax < 0) + result = 0; + + if (xmin != NULL) + *xmin = _xmin; + + if (xmax != NULL) + *xmax = _xmax; + + if (ymin != NULL) + *ymin = _ymin; + + if (ymax != NULL) + *ymax = _ymax; + + return result; +} + +/* Function to inquire application cell data (vertical span) */ +static int iCellsGetVspan(Ihandle* ih, int i, int j) +{ + int result = 1; /* default value */ + + IFnii cb = (IFnii)IupGetCallback(ih, "VSPAN_CB"); + if (cb) + result = cb(ih, i, j); + + if (result < 0) + result = 1; + + return result; +} + +/* Function to inquire application cell data (horizontal span) */ +static int iCellsGetHspan(Ihandle* ih, int i, int j) +{ + int result = 1; /* default value */ + + IFnii cb = (IFnii)IupGetCallback(ih, "HSPAN_CB"); + if (cb) + result = cb(ih, i, j); + + if (result < 0) + result = 1; + + return result; +} + +/* Function to inquire application cell data (#columns) */ +static int iCellsGetNCols(Ihandle* ih) +{ + int result = 10; /* default value */ + + Icallback cb = IupGetCallback(ih, "NCOLS_CB"); + if (cb) + result = cb(ih); + + if (result < 0) + result = 0; + + return result; +} + +/* Function to inquire application cell data (# lines) */ +static int iCellsGetNLines(Ihandle* ih) +{ + int result = 10; /* default value */ + + Icallback cb = IupGetCallback(ih, "NLINES_CB"); + if (cb) + result = cb(ih); + + if (result < 0) + result = 0; + + return result; +} + +/* Recalculation of first visible line */ +static int iCellsGetFirstLine(Ihandle* ih) +{ + int i, j; + int nlines = iCellsGetNLines(ih); + int ncols = iCellsGetNCols(ih); + + if (ih->data->non_scrollable_lins >= nlines) + return 1; + + /* Looping the lines until a visible one is found */ + for (i = 1; i <= nlines; i++) { + for (j = 1; j <= ncols; j++) { + if (iCellsGetLimits(ih, i, j, NULL, NULL, NULL, NULL)) + return i; + } + } + return ICELLS_OUT; +} + +/* Recalculation of first visible column */ +static int iCellsGetFirstCol(Ihandle* ih) +{ + int i, j; + int ncols = iCellsGetNCols(ih); + int nlines = iCellsGetNLines(ih); + + if (ih->data->non_scrollable_cols >= ncols) + return 1; + + /* Looping the columns until a visible one is found */ + for (j = 1; j <= ncols; j++) { + for (i = 1; i <= nlines; i++) { + if (iCellsGetLimits(ih, i, j, NULL, NULL, NULL, NULL)) + return j; + } + } + return ICELLS_OUT; +} + +/* Function used to get the cells groups virtual size */ +static void iCellsGetVirtualSize(Ihandle* ih, int* wi, int* he) +{ + int i, j; + *wi = 0; *he = 0; + + /* Looping through all lines and columns, adding its width and heights + * to the return values. So, the cells virtual size is computed */ + for (i = 1; i <= iCellsGetNLines(ih); i++) + *he = *he + iCellsGetHeight(ih, i); + for (j = 1; j <= iCellsGetNCols(ih); j++) + *wi = *wi + iCellsGetWidth(ih, j); +} + +/* Function used to calculate a group of columns height */ +static int iCellsGetRangedHeight(Ihandle* ih, int from, int to) +{ + int i; + int result = 0; + + /* Looping through a column adding the line height */ + for (i = from; i <= to; i++) + result += iCellsGetHeight(ih, i); + + return result; +} + +/* Function used to calculate a group of lines width */ +static int iCellsGetRangedWidth(Ihandle* ih, int from, int to) +{ + int j; + int result = 0; + + /* Looping through a column adding the column width */ + for (j = from; j <= to; j++) + result += iCellsGetWidth(ih, j); + + return result; +} + +/* Function used to turn a cell visible */ +static void iCellsSetFullVisible(Ihandle* ih, int i, int j) +{ + int xmin, xmax, ymin, ymax; + int posx = IupGetInt(ih, "POSX"); + int posy = IupGetInt(ih, "POSY"); + int dx = 0; + int dy = 0; + + /* Getting the frontiers positions for the visible cell */ + int min_x = iCellsGetRangedWidth(ih, 1, ih->data->non_scrollable_cols); + int max_y = ih->data->h - iCellsGetRangedHeight(ih, 1, ih->data->non_scrollable_lins); + + /* Getting the cell's area limit */ + iCellsGetLimits(ih, i, j, &xmin, &xmax, &ymin, &ymax); + + /* Adjusting the diference of the scrollbars' position (horizontal) */ + if (xmax > ih->data->w) + dx = xmax - ih->data->w; + + /* Giving priority to xmin position. This can be seen by the usage + * of dx at the left part of the expression (using the last dx). + * This is the case wher the cell cannot be fitted. */ + if (xmin - dx < min_x) + dx = - (min_x - xmin); + + /* Adjusting the diference of the scrollbars' position (horizontal) */ + if (ymax > max_y) + dy = - (ymax - max_y); + if (ymin < 0) + dy = -ymin; + + /* Adding the diference to scrollbars' position */ + posx += dx; + posy += dy; + + /* Setting iup scrollbars' attributes */ + IupSetfAttribute(ih, "POSX", "%d", posx); + IupSetfAttribute(ih, "POSY", "%d", posy); +} + +/* Function used to make a cell the first visible one */ +static void iCellsAdjustOrigin(Ihandle* ih, int lin, int col) +{ + int xmin_sum, ymin_sum; + + /* If the origin line is a non-scrollable one, the scrollbar position is + * set to zero. Otherwise, the sum of the previous widths will be + * set to the scrollbar position. This algorithm is applied to both + * scrollbars */ + if (lin <= ih->data->non_scrollable_lins) + { + IupSetAttribute(ih, "POSY", "0"); + } + else if (lin <= iCellsGetNLines(ih)) + { + ymin_sum = iCellsGetRangedHeight(ih, ih->data->non_scrollable_lins+1, lin-1); + IupSetfAttribute(ih, "POSY", "%d", ymin_sum); + } + + /* As said before... */ + if (col <= ih->data->non_scrollable_cols) + { + IupSetAttribute(ih, "POSX", "0"); + } + else if (col <= iCellsGetNCols(ih)) + { + xmin_sum = iCellsGetRangedWidth(ih, ih->data->non_scrollable_cols+1, col-1); + IupSetfAttribute(ih, "POSX", "%d", xmin_sum); + } +} + +/* Function used for the scrollbar's update; usually needed when the + * object has modified its size or the cells sizes has changed. */ +static void iCellsAdjustScrolls(Ihandle* ih) +{ + int virtual_height, virtual_width; + + /* Getting the virtual size */ + iCellsGetVirtualSize(ih, &virtual_width, &virtual_height); + + IupSetfAttribute(ih, "YMAX", "%d", virtual_height-1); + IupSetfAttribute(ih, "XMAX", "%d", virtual_width-1); + + /* Setting the object scrollbar position */ + IupSetfAttribute(ih, "DY", "%d", ih->data->h); + IupSetfAttribute(ih, "DX", "%d", ih->data->w); +} + +/* Function used to call the client; is used when a cell must be repainted. */ +static void iCellsCallDrawCb(Ihandle* ih, int xmin, int xmax, int ymin, int ymax, int i, int j) +{ + int cxmin, cxmax, cymin, cymax; + int oldxmin, oldxmax, oldymin, oldymax, oldclip; + int w = ih->data->w; + int h = ih->data->h; + IFniiiiii draw_cb; + cdCanvas* old_cnv = cdActiveCanvas(); + + /* Getting clipping area for post restore */ + oldclip = cdCanvasClip(ih->data->cddbuffer, CD_QUERY); + cdCanvasGetClipArea(ih->data->cddbuffer, &oldxmin, &oldxmax, &oldymin, &oldymax); + + if (ih->data->clipped) /* Clipping the cell area */ + { + cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); + cxmin = xmin < 0 ? 0 : xmin; + cymin = ymin < 0 ? 0 : ymin; + cxmax = xmax > w ? w : xmax; + cymax = ymax > h ? h : ymax; + cdCanvasClipArea(ih->data->cddbuffer, xmin, xmax, ymin, ymax); + } + + draw_cb = (IFniiiiii)IupGetCallback(ih, "DRAW_CB"); + if (draw_cb) + { + if (old_cnv != ih->data->cddbuffer) /* backward compatibility code */ + cdActivate(ih->data->cddbuffer); + + draw_cb(ih, i, j, xmin, xmax, ymin, ymax); + + if (old_cnv && old_cnv != ih->data->cddbuffer) + { + cdActivate(old_cnv); + cdCanvasActivate(ih->data->cddbuffer); + } + } + + cdCanvasClip(ih->data->cddbuffer, oldclip); + cdCanvasClipArea(ih->data->cddbuffer, oldxmin, oldxmax, oldymin, oldymax); +} + +/* Render function for one cell in a given coordinate. */ +static void iCellsRenderCellIn(Ihandle* ih, int i, int j, int xmin, int xmax, int ymin, int ymax) +{ + int k; + int w = ih->data->w; + int h = ih->data->h; + int hspan = 1; + int vspan = 1; + + /* Checking if the cells is out of range. (no span will affect it!) */ + if (xmin > w || ymax < 0) + return; + + /* Calculating cell spans */ + hspan = iCellsGetHspan(ih, i, j); + vspan = iCellsGetVspan(ih, i, j); + + /* if any span is set to zero, then another cell invaded its space and + * the cell does not need to draw itself */ + if (hspan == 0 || vspan == 0) + return; + + /* Increasing cell's width and height according to its spans */ + for(k = 1; k < hspan; k++) + xmax += iCellsGetWidth(ih, j+k); + for(k = 1; k < vspan; k++) + ymin -= iCellsGetHeight(ih, i+k); + + /* Checking if the cell expanded enough to appear inside the canvas */ + if (xmax < 0 || ymin > h) + return; + + /* Calling application's draw callback */ + iCellsCallDrawCb(ih, xmin, xmax, ymin, ymax, i, j); + + /* Drawing a box in cell's area */ + if (ih->data->boxed) + { + cdCanvasForeground(ih->data->cddbuffer, CD_BLACK); + cdCanvasRect(ih->data->cddbuffer, xmin, xmax, ymin, ymax); + } +} + +/* Repaint function for all cells in a given range */ +static void iCellsRenderRangedCells(Ihandle* ih, int linfrom, int linto, int colfrom, int colto) +{ + int i, j; + int xmin, xmax, ymin, ymax; + int refxmin, refxmax; + + /* Getting first cell limits: this function is slow to be called everytime */ + iCellsGetLimits(ih, linfrom, colfrom, &xmin, &xmax, &ymin, &ymax); + + /* Initializing current reference position */ + refxmin = xmin; + refxmax = xmax; + + /* Looping through the cells adding next cell width and height */ + for (i = linfrom; i <= linto; i++) + { + xmin = refxmin; + xmax = refxmax; + for (j = colfrom; j <= colto; j++) + { + iCellsRenderCellIn(ih, i, j, xmin, xmax, ymin, ymax); + xmin = xmax; + xmax = xmin + (j == colto ? 0 : iCellsGetWidth(ih, j+1)); + } + ymax = ymin; + ymin = ymax - (i == linto ? 0 : iCellsGetHeight(ih, i+1)); + } +} + +/* Repaint function for all cells */ +static void iCellsRenderCells(Ihandle* ih) +{ + int sline = ih->data->non_scrollable_lins; + int scol = ih->data->non_scrollable_cols; + int nlines = iCellsGetNLines(ih); + int ncols = iCellsGetNCols(ih); + + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + + /* Repainting the four parts of the cells: common cells, non-scrollable + * columns, non-scrollable lines, and non-scrollable margin + * (line and column) */ + iCellsRenderRangedCells(ih, sline+1, nlines, scol+1, ncols); + iCellsRenderRangedCells(ih, sline+1, nlines, 1, scol); + iCellsRenderRangedCells(ih, 1, sline, scol+1, ncols); + iCellsRenderRangedCells(ih, 1, sline, 1, scol); +} + +static void iCellsRepaint(Ihandle* ih) +{ + if (ih->data->cddbuffer == NULL) + return; + + /* If object is buffering, it will not be drawn */ + if (ih->data->bufferize == 1) + return; + + /* update render */ + iCellsRenderCells(ih); + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); +} + +static int iCellsRedraw_CB(Ihandle* ih) +{ + if (ih->data->cddbuffer == NULL) + return IUP_DEFAULT; + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + return IUP_DEFAULT; +} + +/* Function used to calculate the cell coordinates limited by a hint */ +static int iCellsGetRangedCoord(Ihandle* ih, int x, int y, int* lin, int* col, int linfrom, int linto, int colfrom, int colto) +{ + int i, j, k; + int hspan, vspan; + int rxmax, rymin; + int xmin, xmax, ymin, ymax; + int refxmin, refxmax; + int w = ih->data->w; + + /* Getting the first cell's limit -- based on the range */ + iCellsGetLimits(ih, linfrom, colfrom, &xmin, &xmax, &ymin, &ymax); + + /* Initializing reference position */ + refxmin = xmin; + refxmax = xmax; + + /* Looping through the cells adding next cell width and height */ + for (i = linfrom; i <= linto; i++) + { + xmin = refxmin; + xmax = refxmax; + if (!(ymax < 0)) + { + for (j = colfrom; j <= colto; j++) + { + hspan = 1; + vspan = 1; + if (!(xmin > w)) + { + hspan = iCellsGetHspan(ih, i, j); + vspan = iCellsGetVspan(ih, i, j); + if (hspan != 0 && vspan != 0) + { + rxmax = xmax; + rymin = ymin; + for(k = 1; k < hspan; k++) + rxmax += iCellsGetWidth(ih, j+k); + for(k = 1; k < vspan; k++) + rymin -= iCellsGetHeight(ih, i+k); + + /* A cell was found */ + if (x >= xmin && x <= rxmax && y >= rymin && y <= ymax) + { + *lin = i; + *col = j; + return 1; + } + } + xmin = xmax; + xmax = xmin + (j == colto ? 0 : iCellsGetWidth(ih, j+1)); + } + } + } + ymax = ymin; + ymin = ymax - (i == linto ? 0 : iCellsGetHeight(ih, i+1)); + } + + /* No cell selected... */ + *lin = ICELLS_OUT; + *col = ICELLS_OUT; + return 0; +} + +/* Function used to calculate the cell coordinates */ +static int iCellsGetCoord(Ihandle* ih, int x, int y, int* lin, int* col) +{ + int pck = 0; + int sline = ih->data->non_scrollable_lins; + int scol = ih->data->non_scrollable_cols; + int nlines = iCellsGetNLines(ih); + int ncols = iCellsGetNCols(ih); + + /* Trying to pick a cell (raster coordinates) at the four + * parts of the cells (reverse order of the repainting): + * non-scrollable margin (line and column), non-scrollable + * columns, non-scrollable lines, and common cells. */ + pck = iCellsGetRangedCoord(ih, x, y, lin, col, 1, sline, 1, scol); + if (pck) + return 1; + + pck = iCellsGetRangedCoord(ih, x, y, lin, col, 1, sline, scol+1, ncols); + if (pck) + return 1; + + pck = iCellsGetRangedCoord(ih, x, y, lin, col, sline+1, nlines, 1, scol); + if (pck) + return 1; + + pck = iCellsGetRangedCoord(ih, x, y, lin, col, 1, nlines, 1, ncols); + return pck; +} + +static int iCellsScroll_CB(Ihandle* ih) +{ + IFnii cb; + int ret = IUP_DEFAULT; + int fline = -999; + int fcol = -999; + + fline = iCellsGetFirstLine(ih); + fcol = iCellsGetFirstCol(ih); + + /* Checking the existence of a scroll bar callback. If the application + * has set one, it will be called now. If the application returns + * IUP_DEFAULT, the cells will be repainted. */ + cb = (IFnii)IupGetCallback(ih, "SCROLLING_CB"); + if (cb) + ret = cb(ih, fline, fcol); + + if (ret == IUP_DEFAULT) + iCellsRepaint(ih); + + return IUP_DEFAULT; +} + +static int iCellsMotion_CB(Ihandle* ih, int x, int y, char* r) +{ + int i, j; + + /* Checking the existence of a motion bar callback. If the application + * has set one, it will be called now. However, before calling the + * callback, we need to find out which cell is under the mouse + * position. */ + IFniiiis cb = (IFniiiis)IupGetCallback(ih, "MOUSEMOTION_CB"); + if (!cb) + return IUP_DEFAULT; + + iCellsGetCoord(ih, x, y, &i, &j); + return cb(ih, i, j, x, y, r); +} + +static int iCellsResize_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 canvas size */ + cdCanvasActivate(ih->data->cddbuffer); + cdCanvasGetSize(ih->data->cddbuffer, &ih->data->w, &ih->data->h, NULL, NULL); + + /* recalculate scrollbars positions and size */ + iCellsAdjustScrolls(ih); + + /* update render */ + iCellsRenderCells(ih); + + return IUP_DEFAULT; +} + +static int iCellsButton_CB(Ihandle* ih, int b, int m, int x, int y, char* r) +{ + int i, j; + IFniiiiiis cb; + + y = cdIupInvertYAxis(y, ih->data->h); + + /* Treating the button event. The application will receive + * a button press callback. */ + cb = (IFniiiiiis)IupGetCallback(ih, "MOUSECLICK_CB"); + if (!cb) + return IUP_DEFAULT; + + iCellsGetCoord(ih, x, y, &i, &j); + return cb(ih, b, m, i, j, x, y, r); +} + +static char* iCellsGetImageCanvasAttrib(Ihandle* ih) +{ + return (char*)ih->data->cddbuffer; +} + +static char* iCellsGetCanvasAttrib(Ihandle* ih) +{ + return (char*)ih->data->cdcanvas; +} + +static char* iCellsGetFirstLineAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(80); + sprintf( buffer, "%d", iCellsGetFirstLine(ih) ); + return buffer; +} + +static char* iCellsGetFirstColAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(80); + sprintf(buffer, "%d", iCellsGetFirstCol(ih) ); + return buffer; +} + +static char* iCellsGetLimitsAttrib(Ihandle* ih, const char* name_id) +{ + char* buffer = iupStrGetMemory(80); + int xmin, xmax, ymin, ymax; + int i, j; + + if (iupStrToIntInt(name_id, &i, &j, ':') != 2) + return NULL; + + iCellsGetLimits(ih, i, j, &xmin, &xmax, &ymin, &ymax); + sprintf(buffer, "%d:%d:%d:%d", xmin, xmax, ymin, ymax); + return buffer; +} + +static int iCellsSetBufferizeAttrib(Ihandle* ih, const char* value) +{ + if (value == NULL || iupStrEqualNoCase(value, "NO")) + { + ih->data->bufferize = 0; + iCellsAdjustScrolls(ih); + iCellsRepaint(ih); + } + else + ih->data->bufferize = 1; + + return 0; +} + +static char* iCellsGetBufferizeAttrib(Ihandle* ih) +{ + if (ih->data->bufferize) + return "YES"; + else + return "NO"; +} + +static int iCellsSetRepaintAttrib(Ihandle* ih, const char* value) +{ + (void)value; /* not used */ + ih->data->bufferize = 0; + iCellsAdjustScrolls(ih); + iCellsRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static int iCellsSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (!value) + value = iupControlBaseGetParentBgColor(ih); + + ih->data->bgcolor = cdIupConvertColor(value); + + iCellsRepaint(ih); + return 1; +} + +static int iCellsSetOriginAttrib(Ihandle* ih, const char* value) +{ + int lin = -9; + int col = -9; + iupStrToIntInt(value, &lin, &col, ':'); + iCellsAdjustOrigin(ih, lin, col); + iCellsRepaint(ih); + return 1; +} + +static int iCellsSetNonScrollableColsAttrib(Ihandle* ih, const char* value) +{ + if (iupStrToInt(value, &ih->data->non_scrollable_cols)) + iCellsRepaint(ih); + return 0; +} + +static char* iCellsGetNonScrollableColsAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(80); + sprintf(buffer, "%d", ih->data->non_scrollable_cols); + return buffer; +} + +static int iCellsSetNonScrollableLinesAttrib(Ihandle* ih, const char* value) +{ + if (iupStrToInt(value, &ih->data->non_scrollable_lins)) + iCellsRepaint(ih); + return 0; +} + +static char* iCellsGetNonScrollableLinesAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(80); + sprintf(buffer, "%d", ih->data->non_scrollable_lins); + return buffer; +} + +static int iCellsSetBoxedAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + ih->data->boxed = 0; + else + ih->data->boxed = 1; + + iCellsRepaint(ih); + return 0; +} + +static char* iCellsGetBoxedAttrib(Ihandle* ih) +{ + if (ih->data->boxed) + return "YES"; + else + return "NO"; +} + +static int iCellsSetClippedAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + ih->data->clipped = 0; + else + ih->data->clipped = 1; + + iCellsRepaint(ih); + return 0; +} + +static char* iCellsGetClippedAttrib(Ihandle* ih) +{ + if (ih->data->clipped) + return "YES"; + else + return "NO"; +} + +static int iCellsSetFullVisibleAttrib(Ihandle* ih, const char* value) +{ + int i, j; + if (iupStrToIntInt(value, &i, &j, ':') != 2) + return 0; + + iCellsSetFullVisible(ih, i, j); + iCellsRepaint(ih); + return 0; /* do not store value in hash table */ +} + + +/****************************************************************************/ + + +static int iCellsMapMethod(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 iCellsUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static int iCellsCreateMethod(Ihandle* ih, void **params) +{ + (void)params; + + /* free the data allocated by IupCanvas */ + if (ih->data) free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* change the IupCanvas default values */ + iupAttribSetStr(ih, "SCROLLBAR", "YES"); + iupAttribSetStr(ih, "BORDER", "NO"); + + /* default values */ + ih->data->boxed = 1; + ih->data->clipped = 1; + + /* IupCanvas callbacks */ + IupSetCallback(ih, "RESIZE_CB", (Icallback)iCellsResize_CB); + IupSetCallback(ih, "ACTION", (Icallback)iCellsRedraw_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iCellsButton_CB); + IupSetCallback(ih, "MOTION_CB", (Icallback)iCellsMotion_CB); + IupSetCallback(ih, "SCROLL_CB", (Icallback)iCellsScroll_CB); + + return IUP_NOERROR; +} + +Iclass* iupCellsGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "cells"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */ + + /* Class functions */ + ic->Create = iCellsCreateMethod; + ic->Map = iCellsMapMethod; + ic->UnMap = iCellsUnMapMethod; + + /* Do not need to set base attributes because they are inherited from IupCanvas */ + + /* IupCells Callbacks */ + iupClassRegisterCallback(ic, "SCROLLING_CB", "ii"); + iupClassRegisterCallback(ic, "MOUSEMOTION_CB", "iiiis"); + iupClassRegisterCallback(ic, "MOUSECLICK_CB", "iiiiiis"); + iupClassRegisterCallback(ic, "DRAW_CB", "iiiiiiv"); + iupClassRegisterCallback(ic, "VSPAN_CB", "ii"); + iupClassRegisterCallback(ic, "HSPAN_CB", "ii"); + iupClassRegisterCallback(ic, "NCOLS_CB", ""); + iupClassRegisterCallback(ic, "NLINES_CB", ""); + iupClassRegisterCallback(ic, "HEIGHT_CB", "i"); + iupClassRegisterCallback(ic, "WIDTH_CB", "i"); + + /* IupCells only */ + iupClassRegisterAttribute(ic, "BOXED", iCellsGetBoxedAttrib, iCellsSetBoxedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPPED", iCellsGetClippedAttrib, iCellsSetClippedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "NON_SCROLLABLE_LINES", iCellsGetNonScrollableLinesAttrib, iCellsSetNonScrollableLinesAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "NON_SCROLLABLE_COLS", iCellsGetNonScrollableColsAttrib, iCellsSetNonScrollableColsAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "NO_COLOR", iupControlBaseGetBgColorAttrib, iCellsSetBgColorAttrib, NULL, NULL, IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "BUFFERIZE", iCellsGetBufferizeAttrib, iCellsSetBufferizeAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ORIGIN", NULL, iCellsSetOriginAttrib, NULL, NULL, IUPAF_DEFAULT); + + iupClassRegisterAttribute(ic, "FULL_VISIBLE", NULL, iCellsSetFullVisibleAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REPAINT", NULL, iCellsSetRepaintAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "LIMITS", iCellsGetLimitsAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FIRST_COL", iCellsGetFirstColAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FIRST_LINE", iCellsGetFirstLineAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE_CANVAS", iCellsGetImageCanvasAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CANVAS", iCellsGetCanvasAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iCellsSetBgColorAttrib, NULL, "255 255 255", IUPAF_NO_INHERIT); /* overwrite canvas implementation, set a system default to force a new default */ + + return ic; +} + +Ihandle* IupCells(void) +{ + return IupCreate("cells"); +} diff --git a/iup/srccontrols/iup_colorbar.c b/iup/srccontrols/iup_colorbar.c new file mode 100755 index 0000000..72e717c --- /dev/null +++ b/iup/srccontrols/iup_colorbar.c @@ -0,0 +1,1082 @@ +/** \file + * \brief Colorbar Control. + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "iup.h" +#include "iupcontrols.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_image.h" +#include "iup_cdutil.h" + + +#define ICOLORBAR_DEFAULT_NUM_CELLS 16 /* default number of cells */ +#define ICOLORBAR_NO_COLOR 0xff000000 /* no color */ +#define ICOLORBAR_DELTA 5 /* preview margin */ +#define ICOLORBAR_RENDER_ALL -1 +#define ICOLORBAR_RENDER_NONE -2 + + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + int w; /* size of the canvas - width */ + int h; /* size of the canvas - height */ + cdCanvas* cdcanvas; /* cd canvas for drawing */ + cdCanvas* cddbuffer; /* image canvas for double buffering */ + long int colors[256]; /* CD color vector */ + int num_cells; /* number of cells at the widgets */ + int num_parts; /* number of sections used to split the colors cells area */ + int vertical; /* vertical orientation flag */ + int squared; /* square cells attribute flag */ + int shadowed; /* 3D shadowed attribute flag */ + long bgcolor; /* control background color */ + long light_shadow; /* } */ + long mid_shadow; /* } 3D shadowed color */ + long dark_shadow; /* } */ + int bufferize; /* bufferation flag */ + long int transparency; /* transparency color */ + int show_secondary; /* secondary color selction flag */ + int preview_size; /* preview size (pixels) 0=disabled, -1=automatic */ + int fgcolor_idx; /* current primary index selected */ + int bgcolor_idx; /* current secondary index selected */ + int focus_cell; /* cell with focus */ + int has_focus; /* 1 if the control has the focus, else 0 */ +}; + +/* Default colors used for a widget */ +static struct { + unsigned int r; + unsigned int g; + unsigned int b; +} default_colors[ICOLORBAR_DEFAULT_NUM_CELLS] = { + { 0, 0, 0 }, { 128, 0, 0 }, { 0, 128, 0 }, { 128, 128, 0 }, + { 0, 0, 128 }, { 128, 0, 128 }, { 0, 128, 128 }, { 192, 192, 192 }, + { 128, 128, 128 }, { 255, 0, 0 }, { 0, 255, 0 }, { 255, 255, 0 }, + { 0, 0, 255 }, { 255, 0, 255 }, { 0, 255, 255 }, { 255, 255, 255 } +}; + + +/* This function draw the 3D cell effect. */ +static void iColorbarDrawSunken(Ihandle* ih, int xmin, int xmax, int ymin, int ymax) +{ + if (!ih->data->shadowed) return; + cdIupDrawSunkenRect(ih->data->cddbuffer, xmin, ymin, xmax, ymax, ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); +} + +/* This function is used to draw a box for a cell. */ +static void iColorbarDrawBox(Ihandle* ih, int xmin, int xmax, int ymin, int ymax, int idx) +{ + long int color = ih->data->colors[idx]; + cdCanvasInteriorStyle(ih->data->cddbuffer, CD_SOLID); + + if (color == ih->data->transparency) + { + int xm = (xmin+xmax)/2; + int ym = (ymin+ymax)/2; + cdCanvasForeground(ih->data->cddbuffer,0xeeeeee); + cdCanvasBox(ih->data->cddbuffer,xmin, xm, ymin, ym); + cdCanvasBox(ih->data->cddbuffer,xm, xmax, ym, ymax); + cdCanvasForeground(ih->data->cddbuffer,0xcccccc); + cdCanvasBox(ih->data->cddbuffer,xmin, xm, ym, ymax); + cdCanvasBox(ih->data->cddbuffer,xm, xmax, ymin, ym); + } + else + { + if (!iupdrvIsActive(ih)) + { + unsigned char r, g, b, bg_r, bg_g, bg_b; + cdDecodeColor(color, &r, &g, &b); + cdDecodeColor(ih->data->bgcolor, &bg_r, &bg_g, &bg_b); + iupImageColorMakeInactive(&r, &g, &b, bg_r, bg_g, bg_b); + color = cdEncodeColor(r, g, b); + } + cdCanvasForeground(ih->data->cddbuffer,color); + cdCanvasBegin(ih->data->cddbuffer,CD_FILL); + cdCanvasVertex(ih->data->cddbuffer,xmin, ymin); cdCanvasVertex(ih->data->cddbuffer,xmin, ymax); + cdCanvasVertex(ih->data->cddbuffer,xmax, ymax); cdCanvasVertex(ih->data->cddbuffer,xmax, ymin); + cdCanvasEnd(ih->data->cddbuffer); + } + + cdCanvasForeground(ih->data->cddbuffer,CD_BLACK); + cdCanvasBegin(ih->data->cddbuffer,CD_CLOSED_LINES); + cdCanvasVertex(ih->data->cddbuffer,xmin, ymin); cdCanvasVertex(ih->data->cddbuffer,xmin, ymax); + cdCanvasVertex(ih->data->cddbuffer,xmax, ymax); cdCanvasVertex(ih->data->cddbuffer,xmax, ymin); + cdCanvasEnd(ih->data->cddbuffer); +} + +/* This function is used to get the largest square of a cell bounding box. */ +static void iColorbarFitSquare(int* xmin, int* xmax, int* ymin, int* ymax) +{ + int mx = (*xmax + *xmin) / 2; + int my = (*ymax + *ymin) / 2; + int dx = (*xmax - *xmin) / 2; + int dy = (*ymax - *ymin) / 2; + + if (dx < dy) + { + *ymin = my - dx; + *ymax = my + dx; + } + else + { + *xmin = mx - dy; + *xmax = mx + dy; + } +} + +/* This function is used to get the preview area bounding box. */ +static void iColorbarGetPreviewLimit(Ihandle* ih, int* xmin, int* xmax, int* ymin, int* ymax) +{ + int num_itens = ih->data->num_cells / ih->data->num_parts + 1; /* include space for preview area */ + + *xmin = 0; *ymin = 0; + if (ih->data->vertical) + { + *xmax = ih->data->w; + if (ih->data->preview_size > 0) + *ymax = *ymin + ih->data->preview_size; + else + *ymax = ih->data->h / num_itens; + } + else + { + *ymax = ih->data->h; + if (ih->data->preview_size > 0) + *xmax = *xmin + ih->data->preview_size; + else + *xmax = ih->data->w / num_itens; + } + if (ih->data->squared) + iColorbarFitSquare(xmin, xmax, ymin, ymax); +} + +/* This function is used to get a cell bounding box. */ +static void iColorbarGetCellLimit(Ihandle* ih, int idx, int* xmin, int* xmax, int* ymin, int* ymax) +{ + int delta, dummy; + int wcell, hcell; + int px = 0, py = 0; + int posx, posy; + int num_itens = ih->data->num_cells / ih->data->num_parts; + + if (ih->data->preview_size != 0) + iColorbarGetPreviewLimit(ih, &dummy, &px, &dummy, &py); + + if (ih->data->vertical) /* Vertical orientation */ + { + wcell = ih->data->w / ih->data->num_parts; + hcell = (ih->data->h - py) / num_itens; + posx = idx / num_itens; + posy = idx % num_itens; + if (ih->data->squared) + { + wcell = wcell < hcell ? wcell : hcell; + hcell = wcell; + } + delta = (ih->data->w - (ih->data->num_parts*wcell)) / 2; + *xmin = delta + (posx+0)*wcell; + *xmax = delta + (posx+1)*wcell; + *ymin = py + (posy+0)*hcell; + *ymax = py + (posy+1)*hcell; + } + else /* Horizontal orientation */ + { + hcell = ih->data->h / ih->data->num_parts; + wcell = (ih->data->w - px) / num_itens; + posx = idx % num_itens; + posy = idx / num_itens; + if (ih->data->squared) + { + wcell = wcell < hcell ? wcell : hcell; + hcell = wcell; + } + delta = (ih->data->h - (ih->data->num_parts * hcell)) / 2; + *xmin = px + (posx + 0) * wcell; + *xmax = px + (posx + 1) * wcell; + *ymin = delta + (posy + 0) * hcell; + *ymax = delta + (posy + 1) * hcell; + } +} + +/* This function is used to get the index color of a canvas coordinate. */ +static int iColorbarGetIndexColor(Ihandle* ih, int x, int y) +{ + int i; + int xmin, ymin; + int xmax, ymax; + int result = -9; + + for (i = 0; i < ih->data->num_cells; i++) + { + iColorbarGetCellLimit(ih, i, &xmin, &xmax, &ymin, &ymax); + if (x > xmin && x < xmax && y > ymin && y < ymax) + { + result = i; + break; + } + } + return result; +} + +/* This function is used to repaint the preview area. */ +static void iColorbarRenderPreview(Ihandle* ih) +{ + int delta = ICOLORBAR_DELTA; + int xmin, ymin; + int xmax, ymax; + int xhalf, yhalf; + int bg = ih->data->bgcolor_idx; + int fg = ih->data->fgcolor_idx; + + if (ih->data->preview_size == 0) + return; + + iColorbarGetPreviewLimit(ih, &xmin, &xmax, &ymin, &ymax); + + if (xmax-xmin < delta || ymax-ymin < delta) + delta = 0; + + if (ih->data->show_secondary) + { + xhalf = 2 * (xmax - xmin - 2 * delta) / 3 + delta; + yhalf = 2 * (ymax - ymin - 2 * delta) / 3 + delta; + + iColorbarDrawBox(ih, xmax - xhalf, xmax - delta, ymin + delta, ymin + yhalf, bg); + iColorbarDrawBox(ih, xmin + delta, xmin + xhalf, ymax - yhalf, ymax - delta, fg); + } + else + { + iColorbarDrawBox(ih, xmin + delta, xmax - delta, ymin + delta, ymax - delta, fg); + } +} + +static void iColorbarDrawFocusCell(Ihandle* ih) +{ + int delta = 4; + int xmin, ymin; + int xmax, ymax; + + iColorbarGetCellLimit(ih, ih->data->focus_cell, &xmin, &xmax, &ymin, &ymax); + xmin += delta; + xmax -= delta; + ymin += delta; + ymax -= delta; + + cdIupDrawFocusRect(ih, ih->data->cdcanvas, xmin, ymin, xmax, ymax); +} + +/* This function is used to repaint a cell. */ +static void iColorbarRenderCell(Ihandle* ih, int idx) +{ + int delta = 2; + int xmin, ymin; + int xmax, ymax; + + iColorbarGetCellLimit(ih, idx, &xmin, &xmax, &ymin, &ymax); + xmin += delta; + xmax -= delta; + ymin += delta; + ymax -= delta; + + iColorbarDrawBox(ih, xmin, xmax, ymin, ymax, idx); + iColorbarDrawSunken(ih, xmin, xmax, ymin, ymax); +} + +/* This function loops all cells, repainting them. */ +static void iColorbarRenderCells(Ihandle* ih) +{ + int i; + for (i = 0; i < ih->data->num_cells; i++) + iColorbarRenderCell(ih, i); +} + +static void iColorbarRepaint(Ihandle* ih) +{ + /* Checking errors or not initialized conditions */ + if (ih->data->cddbuffer == NULL) + return; + + /* If object is buffering, it will be not drawn */ + if (ih->data->bufferize == 1) + return; + + /* update render */ + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + iColorbarRenderPreview(ih); + iColorbarRenderCells(ih); + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + iColorbarDrawFocusCell(ih); +} + +static int iColorbarCheckPreview(Ihandle* ih, int x, int y) +{ + int xmin, ymin; + int xmax, ymax; + int xhalf, yhalf; + int delta = ICOLORBAR_DELTA; + + iColorbarGetPreviewLimit(ih, &xmin, &xmax, &ymin, &ymax); + + if (ih->data->show_secondary) + { + xhalf = 2 * (xmax - xmin - 2 * delta) / 3 + delta; + yhalf = 2 * (ymax - ymin - 2 * delta) / 3 + delta; + + if (x > xmin+delta && x < xmin+xhalf && y > ymax-yhalf && y < ymax-delta) + return IUP_PRIMARY; + if (x > xmax-xhalf && x < xmax-delta && y > ymin+delta && y < ymin+yhalf) + return IUP_SECONDARY; + if (x > xmin && x < xmax && y > ymin && y < ymax) + return 1; /* switch */ + } + else + { + if (x > xmin+delta && x < xmax-delta && y > ymin+delta && y < ymax-delta) + return IUP_PRIMARY; + } + + return 0; +} + +static int iColorbarSetNumPartsAttrib(Ihandle* ih, const char* value) +{ + if (iupStrToInt(value, &ih->data->num_parts)) + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetNumPartsAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%d", ih->data->num_parts); + return buffer; +} + +static int iColorbarSetPrimaryCellAttrib(Ihandle* ih, const char* value) +{ + int new_val; + if (iupStrToInt(value, &new_val)) + { + if (new_val > 0 && new_val < ih->data->num_cells) + { + ih->data->fgcolor_idx = new_val; + iColorbarRepaint(ih); + } + } + return 0; +} + +static char* iColorbarGetPrimaryCellAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%d", ih->data->fgcolor_idx); + return buffer; +} + +static int iColorbarSetSecondaryCellAttrib(Ihandle* ih, const char* value) +{ + int new_val; + if (iupStrToInt(value, &new_val)) + { + if (new_val > 0 && new_val < ih->data->num_cells) + { + ih->data->bgcolor_idx = new_val; + iColorbarRepaint(ih); + } + } + + return 0; +} + +static char* iColorbarGetSecondaryCellAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%d", ih->data->bgcolor_idx); + return buffer; +} + +static int iColorbarSetBufferizeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + { + ih->data->bufferize = 0; + iColorbarRepaint(ih); + } + else + ih->data->bufferize = 1; + + return 0; +} + +static char* iColorbarGetBufferizeAttrib(Ihandle* ih) +{ + if (ih->data->bufferize) + return "YES"; + else + return "NO"; +} + +static int iColorbarSetNumCellsAttrib(Ihandle* ih, const char* value) +{ + int new_val; + if (iupStrToInt(value, &new_val)) + { + if (new_val > 0 && new_val <= 256) + { + ih->data->num_cells = new_val; + + if (ih->data->fgcolor_idx >= ih->data->num_cells) + ih->data->fgcolor_idx = ih->data->num_cells - 1; + + if (ih->data->bgcolor_idx >= ih->data->num_cells) + ih->data->bgcolor_idx = ih->data->num_cells - 1; + + iColorbarRepaint(ih); + } + } + return 0; +} + +static char* iColorbarGetNumCellsAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%d", ih->data->num_cells); + return buffer; +} + +static int iColorbarSetOrientationAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "HORIZONTAL")) + ih->data->vertical = 0; + else + ih->data->vertical = 1; + + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetOrientationAttrib(Ihandle* ih) +{ + if (ih->data->vertical) + return "VERTICAL"; + else + return "HORIZONTAL"; +} + +static int iColorbarSetSquaredAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + ih->data->squared = 0; + else + ih->data->squared = 1; + + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetSquaredAttrib(Ihandle* ih) +{ + if (ih->data->squared) + return "YES"; + else + return "NO"; +} + +static int iColorbarSetShadowedAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + ih->data->shadowed = 0; + else + ih->data->shadowed = 1; + + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetShadowedAttrib(Ihandle* ih) +{ + if (ih->data->shadowed) + return "YES"; + else + return "NO"; +} + +static int iColorbarSetShowSecondaryAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + ih->data->show_secondary = 0; + else + ih->data->show_secondary = 1; + + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetShowSecondaryAttrib(Ihandle* ih) +{ + if (ih->data->show_secondary) + return "YES"; + else + return "NO"; +} + +static int iColorbarSetShowPreviewAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NO")) + ih->data->preview_size = 0; + else + ih->data->preview_size = -1; /* reset to automatic */ + + iColorbarRepaint(ih); + return 1; +} + +static int iColorbarSetPreviewSizeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrToInt(value, &ih->data->preview_size)) + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetPreviewSizeAttrib(Ihandle* ih) +{ + if (ih->data->preview_size == -1) /* automatic */ + return NULL; + else + { + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%d", ih->data->preview_size); + return buffer; + } +} + +static int iColorbarSetCellAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int idx = -1; + iupStrToInt(name_id, &idx); + if (idx >= 0 || idx < ih->data->num_cells) + { + ih->data->colors[idx] = cdIupConvertColor(value); + iColorbarRepaint(ih); + } + + return 0; +} + +static char* iColorbarGetCellAttrib(Ihandle* ih, const char* name_id) +{ + char* buffer = iupStrGetMemory(100); + int idx = -1; + long color; + + iupStrToInt(name_id, &idx); + if (idx < 0 || idx >= ih->data->num_cells) + return NULL; + + color = ih->data->colors[idx]; + sprintf(buffer, "%d %d %d", cdRed(color), cdGreen(color), cdBlue(color)); + return buffer; +} + +static int iColorbarSetTransparencyAttrib(Ihandle* ih, const char* value) +{ + if (value == NULL) + ih->data->transparency = ICOLORBAR_NO_COLOR; + else + ih->data->transparency = cdIupConvertColor(value); + + iColorbarRepaint(ih); + return 0; +} + +static char* iColorbarGetTransparencyAttrib(Ihandle* ih) +{ + if (ih->data->transparency == ICOLORBAR_NO_COLOR) + return NULL; + else + { + char* buffer = iupStrGetMemory(100); + sprintf(buffer, "%d %d %d", cdRed(ih->data->transparency), cdGreen(ih->data->transparency), cdBlue(ih->data->transparency)); + return buffer; + } +} + +static int iColorbarSetBgColorAttrib(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; + + iColorbarRepaint(ih); + return 1; +} + +static int iColorbarSetActiveAttrib(Ihandle* ih, const char* value) +{ + iupBaseSetActiveAttrib(ih, 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; + + iColorbarRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static int iColorbarRedraw_CB(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + iColorbarDrawFocusCell(ih); + + return IUP_DEFAULT; +} + +static int iColorbarResize_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 render */ + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + iColorbarRenderPreview(ih); + iColorbarRenderCells(ih); + + return IUP_DEFAULT; +} + +static void iColorbarRenderPartsRepaint(Ihandle* ih, int preview, int idx) +{ + /* update render */ + if (preview) + iColorbarRenderPreview(ih); + + if (idx != ICOLORBAR_RENDER_NONE) + { + if (idx == ICOLORBAR_RENDER_ALL) + iColorbarRenderCells(ih); + else + iColorbarRenderCell(ih, idx); + } + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + iColorbarDrawFocusCell(ih); +} + +static int iColorbarFocus_CB(Ihandle* ih, int focus) +{ + ih->data->has_focus = focus; + + if (ih->data->cddbuffer) + { + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + iColorbarDrawFocusCell(ih); + } + + return IUP_DEFAULT; +} + +static void iColorbarCallExtentedCb(Ihandle* ih, int idx) +{ + IFni extended_cb = (IFni)IupGetCallback(ih, "EXTENDED_CB"); + if (!extended_cb) + return; + + if (extended_cb(ih, idx) == IUP_IGNORE) + return; + + iColorbarRenderPartsRepaint(ih, 1, ICOLORBAR_RENDER_ALL); /* the preview and all the cells are rendered */ +} + +static void iColorbarCallSelectCb(Ihandle* ih, int idx, int type) +{ + IFnii select_cb; + + if (type == IUP_SECONDARY && !ih->data->show_secondary) + return; + + select_cb = (IFnii)IupGetCallback(ih, "SELECT_CB"); + if (!select_cb) + return; + + if (select_cb(ih, idx, type) == IUP_IGNORE) + return; + + if (type == IUP_PRIMARY) + ih->data->fgcolor_idx = idx; + else + ih->data->bgcolor_idx = idx; + + iColorbarRenderPartsRepaint(ih, 1, ICOLORBAR_RENDER_NONE); /* only the preview area is rendered */ +} + +static void iColorbarCallCellCb(Ihandle* ih, int idx) +{ + char* returned; + sIFni cell_cb = (sIFni)IupGetCallback(ih, "CELL_CB"); + if (!cell_cb) + return; + + returned = cell_cb(ih, idx); /* the application can change the color */ + if (returned) + { + int preview = 0; + /* check if the preview area should be rendered */ + if (idx == ih->data->fgcolor_idx || idx == ih->data->bgcolor_idx) + preview = 1; + + ih->data->colors[idx] = cdIupConvertColor(returned); + iColorbarRenderPartsRepaint(ih, preview, idx); /* the preview and the cell are rendered */ + } +} + +static int iColorbarKeyPress_CB(Ihandle* ih, int c, int press) +{ + if (c != K_LEFT && c != K_UP && c != K_RIGHT && c != K_DOWN && + c != K_HOME && c != K_END && + c != K_SP && c != K_sCR && c != K_sSP && c != K_cSP) + return IUP_DEFAULT; + + if (!press || !ih->data->has_focus) + return IUP_DEFAULT; + + switch(c) + { + case K_LEFT: + if (ih->data->vertical) + { + int cells_per_line = ih->data->num_cells / ih->data->num_parts; + if (ih->data->focus_cell > cells_per_line) + ih->data->focus_cell -= cells_per_line; + } + else + { + if (ih->data->focus_cell > 0) + ih->data->focus_cell--; + } + break; + case K_DOWN: + if (ih->data->vertical) + { + if (ih->data->focus_cell > 0) + ih->data->focus_cell--; + } + else + { + int cells_per_line = ih->data->num_cells / ih->data->num_parts; + if (ih->data->focus_cell > cells_per_line) + ih->data->focus_cell -= cells_per_line; + } + break; + case K_RIGHT: + if (ih->data->vertical) + { + int cells_per_line = ih->data->num_cells / ih->data->num_parts; + if (ih->data->focus_cell+cells_per_line < ih->data->num_cells-1) + ih->data->focus_cell += cells_per_line; + } + else + { + if (ih->data->focus_cell < ih->data->num_cells-1) + ih->data->focus_cell++; + } + break; + case K_UP: + if (ih->data->vertical) + { + if (ih->data->focus_cell < ih->data->num_cells-1) + ih->data->focus_cell++; + } + else + { + int cells_per_line = ih->data->num_cells / ih->data->num_parts; + if (ih->data->focus_cell+cells_per_line < ih->data->num_cells-1) + ih->data->focus_cell += cells_per_line; + } + break; + case K_HOME: + ih->data->focus_cell = 0; + break; + case K_END: + ih->data->focus_cell = ih->data->num_cells-1; + break; + case K_sCR: + iColorbarCallCellCb(ih, ih->data->focus_cell); + return IUP_DEFAULT; + case K_SP: + iColorbarCallSelectCb(ih, ih->data->focus_cell, IUP_PRIMARY); + return IUP_DEFAULT; + case K_cSP: + iColorbarCallSelectCb(ih, ih->data->focus_cell, IUP_SECONDARY); + return IUP_DEFAULT; + case K_sSP: + iColorbarCallExtentedCb(ih, ih->data->focus_cell); + return IUP_DEFAULT; + } + + if (ih->data->cddbuffer) + { + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + iColorbarDrawFocusCell(ih); + } + + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ +} + +static int iColorbarButton_CB(Ihandle* ih, int b, int m, int x, int y, char* r) +{ + int idx; + + if (m == 0) + return IUP_DEFAULT; + + y = cdIupInvertYAxis(y, ih->data->h); + + if (b == IUP_BUTTON1 && iup_isdouble(r)) + { + idx = iColorbarGetIndexColor(ih, x, y); + if (idx < 0 || idx >= ih->data->num_cells) + { + int ret = iColorbarCheckPreview(ih, x, y); + if (ret) + { + if (ret == 1) + { + IFnii switch_cb = (IFnii)IupGetCallback(ih, "SWITCH_CB"); + + if (!ih->data->show_secondary) + return IUP_DEFAULT; + + if (switch_cb && switch_cb(ih, ih->data->fgcolor_idx, ih->data->bgcolor_idx) == IUP_IGNORE) + return IUP_DEFAULT; + + /* the application allow to switch the indices */ + idx = ih->data->fgcolor_idx; + ih->data->fgcolor_idx = ih->data->bgcolor_idx; + ih->data->bgcolor_idx = idx; + + iColorbarRenderPartsRepaint(ih, 1, ICOLORBAR_RENDER_NONE); /* only the preview area is rendered */ + } + else + { + if (ret == IUP_PRIMARY) + idx = ih->data->fgcolor_idx; + else + idx = ih->data->bgcolor_idx; + + iColorbarCallCellCb(ih, idx); + } + } + + return IUP_DEFAULT; + } + + ih->data->focus_cell = idx; + + iColorbarCallCellCb(ih, idx); + } + else if (b == IUP_BUTTON1) + { + idx = iColorbarGetIndexColor(ih, x, y); + if (idx < 0 || idx >= ih->data->num_cells) + return IUP_DEFAULT; + + ih->data->focus_cell = idx; + + iColorbarCallSelectCb(ih, idx, IUP_PRIMARY); + } + else if (b == IUP_BUTTON3 && iup_isshift(r)) + { + idx = iColorbarGetIndexColor(ih, x, y); + if (idx < 0 || idx >= ih->data->num_cells) + return IUP_DEFAULT; + + ih->data->focus_cell = idx; + + iColorbarCallExtentedCb(ih, idx); + } + else if (b == IUP_BUTTON3) + { + idx = iColorbarGetIndexColor(ih, x, y); + if (idx < 0 || idx >= ih->data->num_cells) + return IUP_DEFAULT; + + ih->data->focus_cell = idx; + + iColorbarCallSelectCb(ih, idx, IUP_SECONDARY); + } + + return IUP_DEFAULT; +} + + +/****************************************************************************/ + + +static int iColorbarMapMethod(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 iColorbarUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static int iColorbarCreateMethod(Ihandle* ih, void **params) +{ + int i; + (void)params; + + /* free the data allocated by IupCanvas */ + if (ih->data) free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* change the IupCanvas default values */ + iupAttribSetStr(ih, "BORDER", "NO"); + + /* default values */ + ih->data->num_cells = 16; + ih->data->num_parts = 1; + ih->data->vertical = 1; + ih->data->squared = 1; + ih->data->shadowed = 1; + ih->data->focus_cell = 0; + ih->data->preview_size = -1; /* automatic */ + ih->data->fgcolor_idx = 0; /* black */ + ih->data->bgcolor_idx = 15; /* white */ + ih->data->transparency = ICOLORBAR_NO_COLOR; + ih->data->light_shadow = CD_WHITE; + ih->data->mid_shadow = CD_GRAY; + ih->data->dark_shadow = CD_DARK_GRAY; + + /* Initialization of the color vector */ + for (i = 0; i < ICOLORBAR_DEFAULT_NUM_CELLS; i++) + { + ih->data->colors[i] = cdEncodeColor((unsigned char)default_colors[i].r, + (unsigned char)default_colors[i].g, + (unsigned char)default_colors[i].b); + } + + /* IupCanvas callbacks */ + IupSetCallback(ih, "RESIZE_CB", (Icallback)iColorbarResize_CB); + IupSetCallback(ih, "ACTION", (Icallback)iColorbarRedraw_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iColorbarButton_CB); + IupSetCallback(ih, "FOCUS_CB", (Icallback)iColorbarFocus_CB); + IupSetCallback(ih, "KEYPRESS_CB", (Icallback)iColorbarKeyPress_CB); + + return IUP_NOERROR; +} + +Iclass* iupColorbarGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "colorbar"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */ + + /* Class functions */ + ic->Create = iColorbarCreateMethod; + ic->Map = iColorbarMapMethod; + ic->UnMap = iColorbarUnMapMethod; + + /* Do not need to set base attributes because they are inherited from IupCanvas */ + + /* IupColorbar Callbacks */ + iupClassRegisterCallback(ic, "CELL_CB", "i=s"); + iupClassRegisterCallback(ic, "SWITCH_CB", "ii"); + iupClassRegisterCallback(ic, "SELECT_CB", "ii"); + iupClassRegisterCallback(ic, "EXTENDED_CB", "i"); + + /* IupColorbar only */ + iupClassRegisterAttributeId(ic, "CELL", iColorbarGetCellAttrib, iColorbarSetCellAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUM_CELLS", iColorbarGetNumCellsAttrib, iColorbarSetNumCellsAttrib, IUPAF_SAMEASSYSTEM, "16", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUM_PARTS", iColorbarGetNumPartsAttrib, iColorbarSetNumPartsAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PREVIEW_SIZE", iColorbarGetPreviewSizeAttrib, iColorbarSetPreviewSizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PRIMARY_CELL", iColorbarGetPrimaryCellAttrib, iColorbarSetPrimaryCellAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SECONDARY_CELL", iColorbarGetSecondaryCellAttrib, iColorbarSetSecondaryCellAttrib, IUPAF_SAMEASSYSTEM, "15", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "BUFFERIZE", iColorbarGetBufferizeAttrib, iColorbarSetBufferizeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "ORIENTATION", iColorbarGetOrientationAttrib, iColorbarSetOrientationAttrib, IUPAF_SAMEASSYSTEM, "VERTICAL", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TRANSPARENCY", iColorbarGetTransparencyAttrib, iColorbarSetTransparencyAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SHOW_PREVIEW", NULL, iColorbarSetShowPreviewAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SHOW_SECONDARY", iColorbarGetShowSecondaryAttrib, iColorbarSetShowSecondaryAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SQUARED", iColorbarGetSquaredAttrib, iColorbarSetSquaredAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SHADOWED", iColorbarGetShadowedAttrib, iColorbarSetShadowedAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iColorbarSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iColorbarSetBgColorAttrib, NULL, "255 255 255", IUPAF_NO_INHERIT); /* overwrite canvas implementation, set a system default to force a new default */ + + return ic; +} + +Ihandle *IupColorbar(void) +{ + return IupCreate("colorbar"); +} diff --git a/iup/srccontrols/iup_controls.c b/iup/srccontrols/iup_controls.c new file mode 100755 index 0000000..e60bd91 --- /dev/null +++ b/iup/srccontrols/iup_controls.c @@ -0,0 +1,56 @@ +/** \file + * \brief initializes the additional controls. + * + * See Copyright Notice in "iup.h" + */ + + +#include "iup.h" +#include "iupcontrols.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_register.h" +#include "iup_controls.h" +#include "iup_attrib.h" + + +int IupControlsOpen(void) +{ + if (IupGetGlobal("_IUP_CONTROLS_OPEN")) + return IUP_OPENED; + + iupRegisterClass(iupDialGetClass()); + iupRegisterClass(iupCellsGetClass()); + iupRegisterClass(iupColorbarGetClass()); + iupRegisterClass(iupColorBrowserGetClass()); + iupRegisterClass(iupMatrixGetClass()); + iupRegisterClass(iupGaugeGetClass()); + iupRegisterClass(iupColorBrowserDlgGetClass()); + + IupSetGlobal("_IUP_CONTROLS_OPEN", "1"); + + return IUP_NOERROR; +} + +void IupControlsClose(void) /* for backward compatibility */ +{ +} + +char *iupControlBaseGetParentBgColor(Ihandle* ih) +{ + return IupGetAttribute(iupChildTreeGetNativeParent(ih), "BGCOLOR"); +} + +char *iupControlBaseGetBgColorAttrib(Ihandle* ih) +{ + /* check the hash table */ + char *color = iupAttribGet(ih, "BGCOLOR"); + + /* If not defined check native definition from parent */ + if (!color) + color = iupControlBaseGetParentBgColor(ih); + + return color; +} + diff --git a/iup/srccontrols/iup_controls.h b/iup/srccontrols/iup_controls.h new file mode 100755 index 0000000..bb26963 --- /dev/null +++ b/iup/srccontrols/iup_controls.h @@ -0,0 +1,33 @@ +/** \file + * \brief Additional Controls Class Initialization functions. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUP_CONTROLS_H +#define __IUP_CONTROLS_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +Iclass* iupDialGetClass(void); +Iclass* iupCellsGetClass(void); +Iclass* iupColorbarGetClass(void); +Iclass* iupColorBrowserGetClass(void); +Iclass* iupMatrixGetClass(void); +Iclass* iupGaugeGetClass(void); +Iclass* iupTabsGetClass(void); +Iclass* iupColorBrowserDlgGetClass(void); + +char *iupControlBaseGetParentBgColor (Ihandle* ih); +char *iupControlBaseGetBgColorAttrib(Ihandle* ih); + + +#ifdef __cplusplus +} +#endif + +#endif 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); +} diff --git a/iup/srccontrols/iup_gauge.c b/iup/srccontrols/iup_gauge.c new file mode 100755 index 0000000..8732eee --- /dev/null +++ b/iup/srccontrols/iup_gauge.c @@ -0,0 +1,435 @@ +/** \file + * \brief Gauge 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" + +#define IGAUGE_DEFAULTCOLOR "64 96 192" +#define IGAUGE_DEFAULTSIZE "120x14" + +#define IGAUGE_GAP 3 +#define IGAUGE_BLOCKS 20 + +#define gaugeround(_) ((int)((_)+.5)) + + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + int w; + int h; + + int show_text; + int dashed; + int horiz_padding, vert_padding; /* internal margin */ + + long bgcolor; + long fgcolor; + long light_shadow; + long mid_shadow; + long dark_shadow; + + double value; /* min<=value<max */ + double vmin; + double vmax; + + char* text; + + cdCanvas *cddbuffer; + cdCanvas *cdcanvas; +}; + + +static void iGaugeDrawText(Ihandle* ih, int xmid) +{ + int x, y, xmin, xmax, ymin, ymax; + char* text = ih->data->text; + + cdCanvasNativeFont(ih->data->cddbuffer, IupGetAttribute(ih, "FONT")); + cdCanvasTextAlignment(ih->data->cddbuffer, CD_CENTER); + cdCanvasBackOpacity(ih->data->cddbuffer, CD_TRANSPARENT); + + x = (int)(0.5 * ih->data->w); + y = (int)(0.5 * ih->data->h); + + if(text == NULL) + { + char* m = iupStrGetMemory(30); + sprintf(m, "%.1f%%", 100 * (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)); + text = m; + } + + cdCanvasGetTextBox(ih->data->cddbuffer, x, y, text, &xmin, &xmax, &ymin, &ymax); + + if(xmid < xmin) + { + cdCanvasForeground(ih->data->cddbuffer, ih->data->fgcolor); + cdCanvasText(ih->data->cddbuffer, x, y, text); + } + else if(xmid > xmax) + { + cdCanvasForeground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasText(ih->data->cddbuffer, x, y, text); + } + else + { + cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); + cdCanvasClipArea(ih->data->cddbuffer, xmin, xmid, ymin, ymax); + cdCanvasForeground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasText(ih->data->cddbuffer, x, y, text); + + cdCanvasClipArea(ih->data->cddbuffer, xmid, xmax, ymin, ymax); + cdCanvasForeground(ih->data->cddbuffer, ih->data->fgcolor); + cdCanvasText(ih->data->cddbuffer, x, y, text); + cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); + } +} + +static void iGaugeDrawGauge(Ihandle* ih) +{ + int border = 3; /* includes the pixel used to draw the 3D border */ + int xstart = ih->data->horiz_padding+border; + int ystart = ih->data->vert_padding+border; + int xend = ih->data->w-1 - (ih->data->horiz_padding+border); + int yend = ih->data->h-1 - (ih->data->vert_padding+border); + + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + + cdIupDrawSunkenRect(ih->data->cddbuffer, 0, 0, ih->data->w-1, ih->data->h-1, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + cdCanvasForeground(ih->data->cddbuffer, ih->data->fgcolor); + + if (ih->data->dashed) + { + float step = (xend - xstart + 1) / (float)IGAUGE_BLOCKS; + float boxw = step - IGAUGE_GAP; + float vx = (float)((xend-xstart + 1) * (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)); + int intvx = (int)(100 * vx); + float i = 0; + + if(ih->data->value == ih->data->vmin) + return; + + while(gaugeround(100*(i + boxw)) <= intvx) + { + cdCanvasBox(ih->data->cddbuffer, xstart + gaugeround(i), + xstart + gaugeround(i + boxw) - 1, ystart, yend); + i += step; + } + } + else + { + int xmid = xstart + gaugeround((xend-xstart + 1) * (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)); + + if(ih->data->value != ih->data->vmin) + cdCanvasBox(ih->data->cddbuffer, xstart, xmid, ystart, yend ); + + if(ih->data->show_text) + iGaugeDrawText(ih, xmid); + } +} + +static int iGaugeResize_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 render */ + iGaugeDrawGauge(ih); + + return IUP_DEFAULT; +} + +static void iGaugeRepaint(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return; + + /* update render */ + iGaugeDrawGauge(ih); + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); +} + +static int iGaugeRedraw_CB(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + /* update display */ + cdCanvasFlush(ih->data->cddbuffer); + return IUP_DEFAULT; +} + +static void iGaugeCropValue(Ihandle* ih) +{ + if(ih->data->value>ih->data->vmax) + ih->data->value = ih->data->vmax; + else if(ih->data->value<ih->data->vmin) + ih->data->value = ih->data->vmin; +} + +static int iGaugeSetFgColorAttrib(Ihandle* ih, const char* value) +{ + ih->data->fgcolor = cdIupConvertColor(value); + iGaugeRepaint(ih); + return 1; +} + +static int iGaugeSetBgColorAttrib(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); + + iGaugeRepaint(ih); + return 1; +} + +static int iGaugeSetValueAttrib(Ihandle* ih, const char* value) +{ + if(value == NULL) + ih->data->value = 0; + else + ih->data->value = atof(value); + iGaugeCropValue(ih); + + iGaugeRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iGaugeGetValueAttrib(Ihandle* ih) +{ + char* value = iupStrGetMemory(30); + sprintf(value, "%g", ih->data->value); + return value; +} + +static int iGaugeSetMinAttrib(Ihandle* ih, const char* value) +{ + ih->data->vmin = atof(value); + iGaugeCropValue(ih); + + iGaugeRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iGaugeGetMinAttrib(Ihandle* ih) +{ + char* value = iupStrGetMemory(30); + sprintf(value, "%g", ih->data->vmin); + return value; +} + +static int iGaugeSetMaxAttrib(Ihandle* ih, const char* value) +{ + ih->data->vmax = atof(value); + iGaugeCropValue(ih); + iGaugeRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iGaugeGetMaxAttrib(Ihandle* ih) +{ + char* value = iupStrGetMemory(30); + sprintf(value, "%g", ih->data->vmax); + return value; +} + +static int iGaugeSetShowTextAttrib(Ihandle* ih, const char* value) +{ + if(iupStrEqualNoCase(value, "YES")) + ih->data->show_text = 1; + else if(iupStrEqualNoCase(value, "NO")) + ih->data->show_text = 0; + + iGaugeRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iGaugeGetShowTextAttrib(Ihandle* ih) +{ + if(ih->data->show_text) + return "YES"; + else + return "NO"; +} + +static int iGaugeSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + iGaugeRepaint(ih); + return 0; +} + +static char* iGaugeGetPaddingAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%dx%d", ih->data->horiz_padding, ih->data->vert_padding); + return str; +} + +static int iGaugeSetDashedAttrib(Ihandle* ih, const char* value) +{ + if(iupStrEqualNoCase(value, "YES")) + ih->data->dashed = 1; + else if(iupStrEqualNoCase(value, "NO")) + ih->data->dashed = 0; + + iGaugeRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iGaugeGetDashedAttrib(Ihandle* ih) +{ + if(ih->data->dashed) + return "YES"; + else + return "NO"; +} + +static int iGaugeSetTextAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->text) + free(ih->data->text); + + ih->data->text = iupStrDup(value); + + iGaugeRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iGaugeGetTextAttrib(Ihandle* ih) +{ + return ih->data->text; +} + +static void iGaugeUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static int iGaugeMapMethod(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 int iGaugeCreateMethod(Ihandle* ih, void **params) +{ + (void)params; + + /* free the data allocated by IupCanvas */ + if (ih->data) + free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* change the IupCanvas default values */ + iupAttribSetStr(ih, "BORDER", "NO"); + IupSetAttribute(ih, "SIZE", IGAUGE_DEFAULTSIZE); + ih->expand = IUP_EXPAND_NONE; + + /* default values */ + iupAttribSetStr(ih, "FGCOLOR", IGAUGE_DEFAULTCOLOR); + ih->data->fgcolor = cdIupConvertColor(IGAUGE_DEFAULTCOLOR); + ih->data->vmax = 1; + ih->data->bgcolor = CD_GRAY; + ih->data->light_shadow = CD_WHITE; + ih->data->mid_shadow = CD_GRAY; + ih->data->dark_shadow = CD_DARK_GRAY; + ih->data->show_text = 1; + + /* IupCanvas callbacks */ + IupSetCallback(ih, "RESIZE_CB", (Icallback)iGaugeResize_CB); + IupSetCallback(ih, "ACTION", (Icallback)iGaugeRedraw_CB); + + return IUP_NOERROR; +} + +Iclass* iupGaugeGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "gauge"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Class functions */ + ic->Create = iGaugeCreateMethod; + ic->Map = iGaugeMapMethod; + ic->UnMap = iGaugeUnMapMethod; + + /* Do not need to set base attributes because they are inherited from IupCanvas */ + + /* IupGauge only */ + iupClassRegisterAttribute(ic, "MIN", iGaugeGetMinAttrib, iGaugeSetMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAX", iGaugeGetMaxAttrib, iGaugeSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", iGaugeGetValueAttrib, iGaugeSetValueAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DASHED", iGaugeGetDashedAttrib, iGaugeSetDashedAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "PADDING", iGaugeGetPaddingAttrib, iGaugeSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TEXT", iGaugeGetTextAttrib, iGaugeSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOW_TEXT", iGaugeGetShowTextAttrib, iGaugeSetShowTextAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iGaugeSetFgColorAttrib, IGAUGE_DEFAULTCOLOR, NULL, IUPAF_NOT_MAPPED); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iGaugeSetBgColorAttrib, NULL, "255 255 255", IUPAF_NO_INHERIT); /* overwrite canvas implementation, set a system default to force a new default */ + + return ic; +} + +Ihandle *IupGauge(void) +{ + return IupCreate("gauge"); +} diff --git a/iup/srccontrols/iup_oldmask.c b/iup/srccontrols/iup_oldmask.c new file mode 100755 index 0000000..fec10f3 --- /dev/null +++ b/iup/srccontrols/iup_oldmask.c @@ -0,0 +1,208 @@ +/** \file + * \brief OLD mask pattern matching + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> + +#include "iup.h" +#include "iupcontrols.h" +#include "iupmask.h" + +#include "iup_mask.h" +#include "iup_str.h" + + +void iupmaskRemove(Ihandle *ih) +{ + IupSetAttribute(ih,"MASK", NULL); +} + +void iupmaskMatRemove(Ihandle *ih, int lin, int col) +{ + IupMatSetAttribute(ih,"MASK", lin, col, NULL); +} + +int iupmaskSetInt(Ihandle *ih, int autofill, int min, int max) +{ + (void)autofill; + IupSetfAttribute(ih,"MASKINT", "%d:%d", min, max); + return 1; +} + +int iupmaskMatSetInt(Ihandle *ih, int autofill, int min, int max, int lin, int col) +{ + (void)autofill; + IupMatSetfAttribute(ih,"MASKINT", lin, col, "%d:%d", min, max); + return 1; +} + +int iupmaskSetFloat(Ihandle* ih, int autofill, float min, float max) +{ + (void)autofill; + IupSetfAttribute(ih,"MASKFLOAT", "%f:%f", min, max); + return 1; +} + +int iupmaskMatSetFloat(Ihandle* ih, int autofill, float min, float max, int lin, int col) +{ + (void)autofill; + IupMatSetfAttribute(ih,"MASKFLOAT", lin, col, "%f:%f", min, max); + return 0; +} + +int iupmaskSet(Ihandle* ih, const char* mask_str, int autofill, int casei) +{ + (void)autofill; + IupSetAttribute(ih,"MASKCASEI", casei?"YES":"NO"); + IupStoreAttribute(ih,"MASK", mask_str); + if (iupStrEqual(mask_str, IupGetAttribute(ih,"MASK"))) + return 1; + else + return 0; +} + +int iupmaskMatSet(Ihandle* ih, const char* mask_str, int autofill, int casei, int lin, int col) +{ + (void)autofill; + IupMatSetAttribute(ih,"MASKCASEI", lin, col, casei?"YES":"NO"); + IupMatSetAttribute(ih,"MASK", lin, col, (char*)mask_str); + if (iupStrEqual(mask_str, IupMatGetAttribute(ih,"MASK", lin, col))) + return 1; + else + return 0; +} + +int iupmaskCheck(Ihandle* ih) +{ + char *val = IupGetAttribute(ih,"VALUE"); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + return iupMaskCheck(mask,val)==1; +} + +int iupmaskMatCheck(Ihandle *ih, int lin, int col) +{ + char *val = IupMatGetAttribute(ih,"",lin,col); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + return iupMaskCheck(mask,val)==1; +} + +int iupmaskGet(Ihandle *ih, char **sval) +{ + char *val = IupGetAttribute(ih,"VALUE"); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if (iupMaskCheck(mask,val)==1) + { + *sval = val; + return 1; + } + else + return 0; +} + +int iupmaskMatGet(Ihandle *ih, char **sval, int lin, int col) +{ + char *val = IupMatGetAttribute(ih,"",lin,col); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if (iupMaskCheck(mask,val)==1) + { + *sval = val; + return 1; + } + else + return 0; +} + +int iupmaskGetDouble(Ihandle *ih, double *dval) +{ + char *val = IupGetAttribute(ih,"VALUE"); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if(iupMaskCheck(mask,val)==1) + { + *dval = 0.0; + sscanf(val,"%lf",dval); + return 1; + } + else + return 0; +} + +int iupmaskMatGetDouble(Ihandle *ih, double *dval, int lin, int col) +{ + char *val = IupMatGetAttribute(ih,"",lin,col); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if(iupMaskCheck(mask,val)==1) + { + *dval = 0.0; + sscanf(val,"%lf",dval); + return 1; + } + else + return 0; +} + +int iupmaskGetFloat(Ihandle *ih, float *fval) +{ + char *val = IupGetAttribute(ih,"VALUE"); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if(iupMaskCheck(mask,val)==1) + { + *fval = 0.0F; + sscanf(val,"%f",fval); + return 1; + } + else + return 0; +} + +int iupmaskMatGetFloat(Ihandle *ih, float *fval, int lin, int col) +{ + char *val = IupMatGetAttribute(ih,"",lin,col); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if (iupMaskCheck(mask,val)==1) + { + *fval = 0.0F; + sscanf(val,"%f",fval); + return 1; + } + else + return 0; +} + +int iupmaskGetInt(Ihandle *ih, int *ival) +{ + char *val = IupGetAttribute(ih,"VALUE"); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if (iupMaskCheck(mask,val)==1) + { + *ival = 0; + sscanf(val,"%d",ival); + return 1; + } + else + return 0; +} + +int iupmaskMatGetInt(Ihandle *ih, int *ival, int lin, int col) +{ + char *val = IupMatGetAttribute(ih,"",lin,col); + Imask* mask = (Imask*)IupGetAttribute(ih,"OLD_MASK_DATA"); + + if(iupMaskCheck(mask,val)==1) + { + *ival = 0; + sscanf(val,"%d",ival); + return 1; + } + else + return 0; +} diff --git a/iup/srccontrols/iup_oldtabs.c b/iup/srccontrols/iup_oldtabs.c new file mode 100755 index 0000000..43b0c57 --- /dev/null +++ b/iup/srccontrols/iup_oldtabs.c @@ -0,0 +1,2616 @@ +/** \file + * \brief iuptabs control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.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_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_register.h" +#include "iup_layout.h" +#include "iup_controls.h" +#include "iup_cdutil.h" + + +/* Constants */ +static const int ITABS_BORDER = 1; +static const int ITABS_MARGIN = 10; +static const int ITABS_SPACING = 2; +static const int ITABS_SCROLL_LENGTH = 51; /* the length of the scroll control in any direction */ +static const int ITABS_SCROLL_THICK = 17; +static const int ITABS_SCROLL_SPACING = 7; +static const int ITABS_BROKEN_TAB = 8; +static const int ITABS_CURRENT_EXTRA_PIXELS = 1; + +/* Enum's */ +typedef enum +{ + ITABS_TOP, ITABS_BOTTOM, ITABS_LEFT, ITABS_RIGHT +} ItabsType; + +typedef enum +{ + ITABS_FALSE, ITABS_TRUE +} ItabsBool; + +typedef enum +{ + ITABS_BROKEN_NONE, + ITABS_BROKEN_START, + ITABS_BROKEN_END, + ITABS_BROKEN_CENTER +} ItabsBrokenType; + +typedef enum +{ + ITABS_HORIZONTAL, ITABS_VERTICAL +} ItabsOrientation; + +typedef enum +{ + ITABS_BUTTON_NONE, + ITABS_BUTTONPRESS_FORWARD, ITABS_BUTTONPRESS_MENU, ITABS_BUTTONPRESS_BACKWARD, /* can not change order because of "+= 3" */ + ITABS_BUTTONRELEASE_FORWARD, ITABS_BUTTONRELEASE_MENU, ITABS_BUTTONRELEASE_BACKWARD +} ItabsButtonState; + +typedef enum +{ + ITABS_RENDER_PLANE_ALIGN, ITABS_RENDER_PLANE_NORMAL +} ItabsTextRender; + +/* Info about how to draw each tab */ +typedef struct _tagTabsDrawInfo +{ + Ihandle* ihandle; /* child handle */ + int text_w, /* width of the text of this Tab */ + tab_len; /* len */ +} ItabsDrawInfo; + +typedef struct _tagTabsLine +{ + /* Visible tabs (start and end interval) */ + int start_tab, end_tab; + + /* Shows if any button is pressed */ + ItabsButtonState button; + + /* Info about how to draw each tab */ + ItabsDrawInfo* tabs_info; + + /* Shows if all the tabs are visible */ + ItabsBool scroll_visible, + broken_start_visible, + broken_end_visible; + + /* Shows if the current tab is visible, when + there are other tabs to the left or right */ + ItabsBool broken_center_visible; + + /* Available space to the broken tabs */ + int broken_tab_space, + broken_space_start, + broken_space_end; + + /* Tabs line size */ + int line_thick, + line_length; + + /* Point to thick and length according to render */ + int* line_w; + int* line_h; + + /* Tabs scroll size */ + int scroll_len, /* the scroll space in the tabs line length direction */ + scroll_thick, + scroll_x, + scroll_y, + scroll_w, + scroll_h; + + int text_h; /* height of the text (all texts have the same height) */ +} ItabsLine; + +/* Control context */ +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + /* tabs type */ + ItabsType tabs_type; + ItabsOrientation tabs_orientation; + ItabsTextRender tabs_render; /* tabs line render (depends on + tabs type and orientation) */ + + cdCanvas* cdcanvas; /* CD canvas for drawing */ + cdCanvas* cddbuffer; /* image canvas for double buffering */ + Ihandle* zbox; /* Handle "zbox" is a child of Tabs */ + + int number_of_tabs; /* number of tabs */ + int current_tab; /* current tab */ + ItabsLine tabs_line; /* data from a queue of tabs */ + + /* data from width and weight */ + int w, h; + int* max_line_length; /* pointer to w or h */ + + /* Used colors */ + long bgcolor; + long fgcolor; + long light_shadow; + long mid_shadow; + long dark_shadow; + + int has_focus, + focus_x1, + focus_x2, + focus_y1, + focus_y2; + + char* font_active; + char* font_inactive; +}; + +static void iTabsUpdateRender(Ihandle* ih) +{ + if (ih->data->tabs_orientation == ITABS_VERTICAL) + { + if (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT) + ih->data->tabs_render = ITABS_RENDER_PLANE_ALIGN; + else + ih->data->tabs_render = ITABS_RENDER_PLANE_NORMAL; + } + else + { + if (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT) + ih->data->tabs_render = ITABS_RENDER_PLANE_NORMAL; + else + ih->data->tabs_render = ITABS_RENDER_PLANE_ALIGN; + } + + if (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT) + { + ih->data->tabs_line.line_w = &ih->data->tabs_line.line_thick; + ih->data->tabs_line.line_h = &ih->data->tabs_line.line_length; + ih->data->max_line_length = &ih->data->h; + } + else + { + ih->data->tabs_line.line_w = &ih->data->tabs_line.line_length; + ih->data->tabs_line.line_h = &ih->data->tabs_line.line_thick; + ih->data->max_line_length = &ih->data->w; + } + + if (ih->data->tabs_render == ITABS_RENDER_PLANE_NORMAL) + { + ih->data->tabs_line.scroll_len = ITABS_SCROLL_THICK; + ih->data->tabs_line.scroll_thick = ITABS_SCROLL_LENGTH; + } + else + { + ih->data->tabs_line.scroll_len = ITABS_SCROLL_LENGTH; + ih->data->tabs_line.scroll_thick = ITABS_SCROLL_THICK; + } + + if (ih->data->tabs_orientation == ITABS_HORIZONTAL) + { + ih->data->tabs_line.scroll_w = ITABS_SCROLL_LENGTH; + ih->data->tabs_line.scroll_h = ITABS_SCROLL_THICK; + } + else + { + ih->data->tabs_line.scroll_w = ITABS_SCROLL_THICK; + ih->data->tabs_line.scroll_h = ITABS_SCROLL_LENGTH; + } +} + +static void iTabsSetCDFont(Ihandle* ih, char* tab_font, int bold) +{ + if (tab_font) + cdCanvasNativeFont(ih->data->cddbuffer, tab_font); + else + cdCanvasNativeFont(ih->data->cddbuffer, IupGetAttribute(ih, "FONT")); + + if (bold) + cdCanvasFont(ih->data->cddbuffer, NULL, CD_BOLD, 0); +} + +/* Gets the associated name of the tab */ +static Ihandle* iTabsGetTabIhandle(Ihandle* ih, int number) +{ + return ih->data->tabs_line.tabs_info[number].ihandle; +} + +/* ========================================================================= */ +/* Drawing functions */ +/* ========================================================================= */ + +/* Fills the draw area */ +static void iTabsFillArea(cdCanvas* canvas, int x1, int y1, int x2, int y2, + int x3, int y3, int x4, int y4) +{ + cdCanvasBegin(canvas, CD_FILL); + cdCanvasVertex(canvas, x1, y1); + cdCanvasVertex(canvas, x2, y2); + cdCanvasVertex(canvas, x3, y3); + cdCanvasVertex(canvas, x4, y4); + cdCanvasEnd(canvas); + + cdCanvasBegin(canvas, CD_CLOSED_LINES); + cdCanvasVertex(canvas, x1, y1); + cdCanvasVertex(canvas, x2, y2); + cdCanvasVertex(canvas, x3, y3); + cdCanvasVertex(canvas, x4, y4); + cdCanvasEnd(canvas); +} + +/* Draws the broken borders */ +static void iTabsDrawBrokenBorder(Ihandle* ih, ItabsType type, int x1, int y1, int x2, int y2) +{ + cdCanvas* canvas = ih->data->cddbuffer; + double step_x = (x2 - x1) / 5; + double step_y = (y2 - y1) / 5; + int old_color = cdCanvasForeground(canvas, CD_QUERY); + + switch(type) + { + case ITABS_TOP: + cdCanvasForeground(canvas, ih->data->mid_shadow); + cdCanvasLine(canvas, (int)(x1 + step_x * 3.), y1, (int)(x1 + 4. * step_x), y2); + cdCanvasLine(canvas, (int)(x1 + step_x), y1, (int)(x1 + 2. * step_x), y2); + + cdCanvasForeground(canvas, ih->data->dark_shadow); + cdCanvasLine(canvas, x1, y1, (int)(x1 + step_x), y2); + cdCanvasLine(canvas, (int)(x1 + step_x), y1 - 1, (int)(x1 + 2. * step_x), y2 - 1); + cdCanvasLine(canvas, (int)(x1 + step_x * 2.), y1, (int)(x1 + 3. * step_x), y2); + cdCanvasLine(canvas, (int)(x1 + step_x * 3.), y1 + 1, (int)(x1 + 4. * step_x), y2 + 1); + cdCanvasLine(canvas, (int)(x1 + step_x * 4.), y1, x2, y2); + break; + + case ITABS_BOTTOM: + cdCanvasForeground(canvas, ih->data->mid_shadow); + cdCanvasLine(canvas, (int)(x1 + step_x * 3.), y1, (int)(x1 + 4. * step_x), y2); + cdCanvasLine(canvas, (int)(x1 + step_x), y1, (int)(x1 + 2. * step_x), y2); + + cdCanvasForeground(canvas, ih->data->dark_shadow); + cdCanvasLine(canvas, x1, y1, (int)(x1 + step_x), y2); + cdCanvasLine(canvas, (int)(x1 + step_x), y1 - 1, (int)(x1 + 2. * step_x), y2 - 1); + cdCanvasLine(canvas, (int)(x1 + step_x * 2.), y1, (int)(x1 + 3. * step_x), y2); + cdCanvasLine(canvas, (int)(x1 + step_x * 3.), y1 + 1, (int)(x1 + 4. * step_x), y2 + 1); + cdCanvasLine (canvas, (int)(x1 + step_x * 4.), y1, x2, y2); + break; + + case ITABS_LEFT: + cdCanvasForeground(canvas, ih->data->mid_shadow); + cdCanvasLine(canvas, x1, (int)(y1 + 3. * step_y), x2, (int)(y1 + step_y * 4.)); + cdCanvasLine(canvas, x1, (int)(y1 + step_y), x2, (int)(y1 + step_y * 2.)); + + cdCanvasForeground(canvas, ih->data->dark_shadow); + cdCanvasLine(canvas, x1, y1, x2, (int)(y1 + step_y)); + cdCanvasLine(canvas, x1 - 1, (int)(y1 + step_y), x2 - 1, (int)(y1 + step_y * 2.)); + cdCanvasLine(canvas, x1, (int)(y1 + step_y * 2.), x2, (int)(y1 + step_y * 3.)); + cdCanvasLine(canvas, x1 + 1, (int)(y1 + 3. * step_y), x2 + 1, (int)(y1 + step_y * 4.)); + cdCanvasLine(canvas, x1, (int)(y1 + 4. * step_y), x2, y2); + break; + + case ITABS_RIGHT: + cdCanvasForeground(canvas, ih->data->mid_shadow); + cdCanvasLine(canvas, x1, (int)(y1 + 3. * step_y), x2, (int)(y1 + step_y * 4.)); + cdCanvasLine(canvas, x1, (int)(y1 + step_y), x2, (int)(y1 + step_y * 2.)); + + cdCanvasForeground(canvas, ih->data->dark_shadow); + cdCanvasLine(canvas, x1, y1, x2, (int)(y1 + step_y)); + cdCanvasLine(canvas, x1 - 1, (int)(y1 + step_y), x2 - 1, (int)(y1 + step_y * 2.)); + cdCanvasLine(canvas, x1, (int)(y1 + step_y * 2.), x2, (int)(y1 + step_y * 3.)); + cdCanvasLine(canvas, x1 + 1, (int)(y1 + 3. * step_y), x2 + 1, (int)(y1 + step_y * 4.)); + cdCanvasLine(canvas, x1, (int)(y1 + 4. * step_y), x2, y2); + break; + } + + cdCanvasForeground (canvas, old_color); +} + +/* Draws the borders */ +static void iTabsDrawBorder(Ihandle* ih, ItabsType type, int x1, int y1, int x2, int y2) +{ + cdCanvas* canvas = ih->data->cddbuffer; + + switch(type) + { + case ITABS_TOP: + cdCanvasForeground(canvas, ih->data->light_shadow); + cdCanvasLine(canvas, x1, y1, x2, y2); + break; + + case ITABS_LEFT: + cdCanvasForeground(canvas, ih->data->light_shadow); + cdCanvasLine(canvas, x1, y1, x2, y2); + break; + + case ITABS_BOTTOM: + cdCanvasForeground(canvas, ih->data->dark_shadow); + cdCanvasLine(canvas, x1, y1, x2, y2); + cdCanvasForeground(canvas, ih->data->mid_shadow); + if (x1 > x2) + cdCanvasLine(canvas, x2+1, y1+1, x1-1, y2+1); + else + cdCanvasLine(canvas, x1+1, y1+1, x2-1, y2+1); + break; + + case ITABS_RIGHT: + cdCanvasForeground(canvas, ih->data->dark_shadow); + cdCanvasLine(canvas, x1, y1, x2, y2); + cdCanvasForeground(canvas, ih->data->mid_shadow); + if (y1 > y2) + cdCanvasLine(canvas, x1-1, y2+1, x2-1, y1-1); + else + cdCanvasLine(canvas, x1-1, y1+1, x2-1, y2-1); + break; + } +} + +/* Draws a tab corner */ +static void iTabsDrawCorner(Ihandle* ih, int color, int x1, int y1, int x2, int y2) +{ + cdCanvas* canvas = ih->data->cddbuffer; + + cdCanvasForeground(canvas, ih->data->bgcolor); + cdCanvasLine(canvas, x1, y1, x2, y1); + cdCanvasLine(canvas, x1, y1, x1, y2); + cdCanvasForeground(canvas,color); + cdCanvasLine(canvas, x1, y2, x2, y1); +} + +/* Draws a tab */ +static void iTabsDrawTab(Ihandle* ih, int tab_index, int offset) +{ + cdCanvas* canvas = ih->data->cddbuffer; + int x1, y1, x2, y2, x3, y3, x4, y4, x1a, y1a, x4a, y4a; + int tab_w, tab_h; + int x_text = 0, y_text = 0; + int line_thick, tab_len, full_tab_len; + ItabsType types[3]; + ItabsBool beforeCurrent, afterCurrent; + int extraHeight = (tab_index == ih->data->current_tab) ? 0 : 1; + ItabsBrokenType type; + + /* there is an error in visible tabs that happen when you change the tab configuration dynamically */ + if (tab_index < 0 || tab_index > ih->data->number_of_tabs-1) + return; + + /* Defines what type of tab that will be drawn and sets the length */ + full_tab_len = ih->data->tabs_line.tabs_info[tab_index].tab_len; + + if (tab_index == (ih->data->tabs_line.end_tab + 1)) + { + type = ITABS_BROKEN_END; + tab_len = ih->data->tabs_line.broken_space_end; + } + else if (tab_index == (ih->data->tabs_line.start_tab - 1)) + { + type = ITABS_BROKEN_START; + tab_len = ih->data->tabs_line.broken_space_start; + } + else if (ih->data->tabs_line.broken_center_visible == ITABS_TRUE) + { + type = ITABS_BROKEN_CENTER; + tab_len = ih->data->tabs_line.broken_tab_space; + } + else + { + type = ITABS_BROKEN_NONE; + tab_len = full_tab_len; + } + + if (tab_len > full_tab_len) + tab_len = full_tab_len; + + /* If the selected tab is not the first, and this tab is visible, + * subtracts one pixel from him and advances the tab on one pixel, + * to prevent the side of tab is confused with the border control. */ + if (ih->data->current_tab != 0 && + ((ih->data->tabs_line.start_tab == 0 && tab_index == 0) || + (ih->data->tabs_line.start_tab > 0 && tab_index == (ih->data->tabs_line.start_tab - 1)))) + { + offset += 1; + tab_len--; + full_tab_len--; + } + + line_thick = ih->data->tabs_line.line_thick; + + if (tab_index != ih->data->current_tab) + line_thick -= ITABS_CURRENT_EXTRA_PIXELS; + + if (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT) + { + tab_w = line_thick; + tab_h = tab_len; + } + else + { + tab_w = tab_len; + tab_h = line_thick; + } + + /* Calculates the border of tabs, text position and the sides will be drawn */ + switch(ih->data->tabs_type) + { + case ITABS_TOP: + x1 = x1a = offset; + y1 = ih->data->h - *(ih->data->tabs_line.line_h) - 1; + y1a = y1 + extraHeight; + x2 = x1; + y2 = y1 + tab_h - 1; + x3 = x2 + tab_w - 1; + y3 = y2; + x4 = x3; + y4 = y1; + x4a = x3; + y4a = y1; + + /* defines the order to draw */ + types[0] = ITABS_LEFT; + types[1] = ITABS_TOP; + types[2] = ITABS_RIGHT; + + break; + + case ITABS_BOTTOM: + x1 = x1a = offset; + y1 = *(ih->data->tabs_line.line_h) - 1; + y1a = y1 - extraHeight; + x2 = x1; + y2 = y1 - tab_h + 1; + x3 = x2 + tab_w - 1; + y3 = y2; + x4 = x3; + y4 = y1; + x4a = x3; + y4a = y1; + + types[0] = ITABS_LEFT; + types[1] = ITABS_BOTTOM; + types[2] = ITABS_RIGHT; + + break; + + case ITABS_LEFT: + x1 = *(ih->data->tabs_line.line_w) - 1; + x1a = x1 - extraHeight; + y1 = y1a = ih->data->h - offset - 1; + x2 = x1 - tab_w + 1; + y2 = y1; + x3 = x2; + y3 = y1 - tab_h + 1; + x4 = x1; + y4 = y3; + x4a = x1a; + y4a = y3; + + types[0] = ITABS_TOP; + types[1] = ITABS_LEFT; + types[2] = ITABS_BOTTOM; + + break; + + case ITABS_RIGHT: + x1 = ih->data->w - ih->data->tabs_line.line_thick - 1; + x1a = x1 + extraHeight; + y1 = y1a = ih->data->h - offset - 1; + x2 = x1 + tab_w - 1; + y2 = y1; + x3 = x2; + y3 = y1 - tab_h + 1; + x4 = x1; + y4 = y3; + x4a = x1a; + y4a = y3; + + types[0] = ITABS_TOP; + types[1] = ITABS_RIGHT; + types[2] = ITABS_BOTTOM; + + break; + + default: + return; + } + + if (tab_index == (ih->data->current_tab - 1)) + { + beforeCurrent = ITABS_TRUE; + afterCurrent = ITABS_FALSE; + } + else if (tab_index == (ih->data->current_tab + 1)) + { + beforeCurrent = ITABS_FALSE; + afterCurrent = ITABS_TRUE; + } + else + { + beforeCurrent = ITABS_FALSE; + afterCurrent = ITABS_FALSE; + } + + /* Draws the square of tab*/ + cdCanvasForeground(canvas, ih->data->bgcolor); + + /* Fills the square of tab */ + iTabsFillArea(canvas, x1, y1, x2, y2, x3, y3, x4, y4); + + /* Draws the border on the top */ + iTabsDrawBorder(ih, types[1], x2, y2, x3, y3); + + switch(type) + { + case ITABS_BROKEN_END: + switch(ih->data->tabs_type) + { + case ITABS_TOP: + cdCanvasClipArea(canvas, x1, x3 - ITABS_BORDER - 1, y1, y3); + break; + case ITABS_BOTTOM: + cdCanvasClipArea(canvas, x2, x4 - ITABS_BORDER - 1, y2, y4); + break; + case ITABS_LEFT: + cdCanvasClipArea(canvas, x3, x1, y3 + ITABS_BORDER + 1, y1); + break; + case ITABS_RIGHT: + cdCanvasClipArea(canvas, x4, x2, y4 + ITABS_BORDER + 1, y2); + break; + } + + if (beforeCurrent == ITABS_TRUE) + iTabsDrawBrokenBorder(ih, types[0], x1a, y1a, x2, y2); + else if (afterCurrent == ITABS_TRUE) + iTabsDrawBrokenBorder(ih, types[2], x3, y3, x4a, y4a); + else + { + iTabsDrawBorder(ih, types[0], x1a, y1a, x2, y2); + iTabsDrawBrokenBorder(ih, types[2], x3, y3, x4a, y4a); + } + + if (types[1] == ITABS_TOP) + iTabsDrawCorner(ih, ih->data->light_shadow, x1 + ITABS_BORDER - 1, y3 + ITABS_BORDER - 1, + x1 + ITABS_BORDER + 1, y3 + ITABS_BORDER - 3); + + if (types[1] == ITABS_BOTTOM) + iTabsDrawCorner(ih, ih->data->dark_shadow, x2 + ITABS_BORDER - 1, y2 + ITABS_BORDER - 1, + x2 + ITABS_BORDER + 1, y2 + ITABS_BORDER + 1); + break; + + case ITABS_BROKEN_START: + switch(ih->data->tabs_type) + { + case ITABS_TOP: + cdCanvasClipArea(canvas, x1 + ITABS_BORDER + 1, x3, y1, y3); + break; + case ITABS_BOTTOM: + cdCanvasClipArea(canvas, x2 + ITABS_BORDER + 1, x4, y2, y4); + break; + case ITABS_LEFT: + cdCanvasClipArea(canvas, x3, x1, y3, y1 - ITABS_BORDER - 1); + break; + case ITABS_RIGHT: + cdCanvasClipArea(canvas, x4, x2, y4, y2 - ITABS_BORDER - 1); + break; + } + + if (beforeCurrent == ITABS_TRUE) + iTabsDrawBrokenBorder(ih, types[0], x1a, y1a, x2, y2); + else if (afterCurrent == ITABS_TRUE) + iTabsDrawBrokenBorder(ih, types[2], x3, y3, x4a, y4a); + else + { + iTabsDrawBrokenBorder(ih, types[0], x1a, y1a, x2, y2); + iTabsDrawBorder(ih, types[2], x3, y3, x4a, y4a); + } + + if (types[1] == ITABS_TOP) + iTabsDrawCorner(ih, ih->data->dark_shadow, x3 + ITABS_BORDER - 1, y3 + ITABS_BORDER - 1, + x3 + ITABS_BORDER - 3, y3 + ITABS_BORDER - 3); + + if (types[1] == ITABS_BOTTOM) + iTabsDrawCorner(ih, ih->data->dark_shadow, x4 + ITABS_BORDER - 1, y2 + ITABS_BORDER - 1, + x4 + ITABS_BORDER - 3, y2 + ITABS_BORDER + 1); + break; + + case ITABS_BROKEN_CENTER: + switch(ih->data->tabs_type) + { + case ITABS_TOP: + cdCanvasClipArea (canvas, x1 + ITABS_BORDER + 1, x3 - ITABS_BORDER - 1, + y1 + ITABS_BORDER + 1, y3 - ITABS_BORDER - 1); + break; + case ITABS_BOTTOM: + cdCanvasClipArea (canvas, x2 + ITABS_BORDER + 1, x4 - ITABS_BORDER - 1, + y2 + ITABS_BORDER + 1, y4 - ITABS_BORDER - 1); + break; + case ITABS_LEFT: + cdCanvasClipArea (canvas, x3 + ITABS_BORDER + 1, x1 - ITABS_BORDER - 1, + y3 + ITABS_BORDER + 1, y1 - ITABS_BORDER - 1); + break; + case ITABS_RIGHT: + cdCanvasClipArea (canvas, x4 + ITABS_BORDER + 1, x2 - ITABS_BORDER - 1, + y4 + ITABS_BORDER + 1, y2 - ITABS_BORDER - 1); + break; + } + + iTabsDrawBrokenBorder(ih, types[0], x1, y1, x2, y2); + iTabsDrawBrokenBorder(ih, types[2], x3, y3, x4, y4); + break; + + case ITABS_BROKEN_NONE: + switch(ih->data->tabs_type) + { + case ITABS_TOP: + cdCanvasClipArea (canvas, x1 + ITABS_BORDER + 1, x3 - ITABS_BORDER - 1, + y1 + ITABS_BORDER + 1, y3 - ITABS_BORDER - 1); + break; + case ITABS_BOTTOM: + cdCanvasClipArea (canvas, x2 + ITABS_BORDER + 1, x4 - ITABS_BORDER - 1, + y2 + ITABS_BORDER + 1, y4 - ITABS_BORDER - 1); + break; + case ITABS_LEFT: + cdCanvasClipArea (canvas, x3 + ITABS_BORDER + 1, x1 - ITABS_BORDER - 1, + y3 + ITABS_BORDER + 1, y1 - ITABS_BORDER - 1); + break; + case ITABS_RIGHT: + cdCanvasClipArea (canvas, x4 + ITABS_BORDER + 1, x2 - ITABS_BORDER - 1, + y4 + ITABS_BORDER + 1, y2 - ITABS_BORDER - 1); + break; + } + + if (beforeCurrent == ITABS_TRUE) + iTabsDrawBorder(ih, types[0], x1a, y1a, x2, y2); + else if (afterCurrent == ITABS_TRUE) + iTabsDrawBorder(ih, types[2], x3, y3, x4a, y4a); + else + { + iTabsDrawBorder(ih, types[0], x1a, y1a, x2, y2); + iTabsDrawBorder(ih, types[2], x3, y3, x4a, y4a); + } + + if (types[1] == ITABS_TOP) + { + iTabsDrawCorner(ih, ih->data->light_shadow, x1 + ITABS_BORDER - 1, y3 + ITABS_BORDER - 1, + x1 + ITABS_BORDER + 1, y3 + ITABS_BORDER - 3); + + iTabsDrawCorner(ih, ih->data->dark_shadow, x3 + ITABS_BORDER - 1, y3 + ITABS_BORDER - 1, + x3 + ITABS_BORDER - 3, y3 + ITABS_BORDER - 3); + } + + if (types[1] == ITABS_BOTTOM) + { + iTabsDrawCorner(ih, ih->data->dark_shadow, x2 + ITABS_BORDER - 1, y2 + ITABS_BORDER - 1, + x2 + ITABS_BORDER + 1, y2 + ITABS_BORDER + 1); + + iTabsDrawCorner(ih, ih->data->dark_shadow, x4 + ITABS_BORDER - 1, y2 + ITABS_BORDER - 1, + x4 + ITABS_BORDER - 3, y2 + ITABS_BORDER + 1); + } + + if (types[1] == ITABS_LEFT) + { + iTabsDrawCorner(ih, ih->data->light_shadow, x3 + ITABS_BORDER - 1, y1 + ITABS_BORDER - 1, + x3 + ITABS_BORDER + 1, y1 + ITABS_BORDER - 3); + + iTabsDrawCorner(ih, ih->data->dark_shadow, x3 + ITABS_BORDER - 1, y3 + ITABS_BORDER - 1, + x3 + ITABS_BORDER + 1, y3 + ITABS_BORDER + 1); + } + + if (types[1] == ITABS_RIGHT) + { + iTabsDrawCorner(ih, ih->data->dark_shadow, x2 + ITABS_BORDER - 1, y2 + ITABS_BORDER - 1, + x2 + ITABS_BORDER - 3, y2 + ITABS_BORDER - 3); + + iTabsDrawCorner(ih, ih->data->dark_shadow, x2 + ITABS_BORDER - 1, y4 + ITABS_BORDER - 1, + x2 + ITABS_BORDER - 3, y4 + ITABS_BORDER + 1); + } + + break; + } + + if (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT) + tab_h = full_tab_len; + else + tab_w = full_tab_len; + + switch(ih->data->tabs_type) + { + case ITABS_TOP: + x_text = x1 + tab_w / 2; + y_text = y1 + tab_h / 2; + break; + case ITABS_BOTTOM: + x_text = x2 + tab_w / 2; + y_text = y2 + tab_h / 2; + break; + case ITABS_LEFT: + x_text = x1 - tab_w / 2; + y_text = y1 - tab_h / 2; + break; + case ITABS_RIGHT: + x_text = x2 - tab_w / 2; + y_text = y2 - tab_h / 2; + break; + } + cdCanvasTextAlignment (canvas, CD_CENTER); + + /* Draws the text */ + cdCanvasForeground (canvas, ih->data->fgcolor); + + if (ih->data->tabs_orientation == ITABS_VERTICAL) + cdCanvasTextOrientation(canvas, 90); + else + cdCanvasTextOrientation(canvas, 0); + + { + char* tab_font = NULL; + int bold = 0; + + if (iupdrvIsActive(ih) && IupGetInt(ih->data->tabs_line.tabs_info[tab_index].ihandle, "ACTIVE")) + { + if (tab_index == ih->data->current_tab) + { + tab_font = ih->data->font_active; + bold = 1; + } + } + else + { + cdCanvasForeground(canvas, CD_DARK_GRAY); + tab_font = ih->data->font_inactive; + } + + iTabsSetCDFont(ih, tab_font, bold); + } + + cdCanvasClip(canvas, CD_CLIPAREA); + + { + char* text = iupAttribGet(ih->data->tabs_line.tabs_info[tab_index].ihandle, "TABTITLE"); + if (!text) text = " "; + + if (ih->data->has_focus && (tab_index == ih->data->current_tab)) + { + int x1, y1, x2, y2; + cdCanvasGetTextBox(canvas, x_text, y_text, text, &x1, &x2, &y1, &y2); + if (ih->data->tabs_orientation == ITABS_VERTICAL) + {y1-=2; y2+=2;} + else + {x1-=2; x2+=2;} + ih->data->focus_x1 = x1; + ih->data->focus_x2 = x2; + ih->data->focus_y1 = y1; + ih->data->focus_y2 = y2; + } + + cdCanvasText(canvas, x_text, y_text, text); + } + + cdCanvasClip (canvas, CD_CLIPOFF); +} + +/* Draws the lower border of the tab labels */ +static void iTabsDrawLabelLowerBorder(Ihandle* ih, int start, int end) +{ + switch(ih->data->tabs_type) + { + case ITABS_TOP: + iTabsDrawBorder(ih, ITABS_TOP, start, ih->data->h - *(ih->data->tabs_line.line_h) - 1 - 1, + end, ih->data->h - *(ih->data->tabs_line.line_h) - 1 - 1); + break; + + case ITABS_LEFT: + if (!start) + iTabsDrawBorder(ih, ITABS_LEFT, *(ih->data->tabs_line.line_w) - 1 + 1, ih->data->h - 1 - start, + *(ih->data->tabs_line.line_w) - 1 + 1, ih->data->h - 1 - end); + else + iTabsDrawBorder(ih, ITABS_LEFT, *(ih->data->tabs_line.line_w) - 1 + 1, ih->data->h - 1 - start, + *(ih->data->tabs_line.line_w) - 1 + 1, 0); + break; + + case ITABS_BOTTOM: + iTabsDrawBorder(ih, ITABS_BOTTOM, start, *(ih->data->tabs_line.line_h) - 1 + 1, + end, *(ih->data->tabs_line.line_h) - 1 + 1); + break; + + case ITABS_RIGHT: + if (!start) + iTabsDrawBorder(ih, ITABS_RIGHT, ih->data->w - *(ih->data->tabs_line.line_w) - 1 - 1, ih->data->h - 1 - start, + ih->data->w - *(ih->data->tabs_line.line_w) - 1 - 1, ih->data->h - 1 - end); + else + iTabsDrawBorder(ih, ITABS_RIGHT, ih->data->w - *(ih->data->tabs_line.line_w) - 1 - 1, ih->data->h - 1 - start, + ih->data->w - *(ih->data->tabs_line.line_w) - 1 - 1, 0); + break; + } +} + +/* Draws a normal button */ +static void iTabsDrawButton(Ihandle* ih, int x, int y, int width, int height) +{ + cdCanvas* canvas = ih->data->cddbuffer; + int old_color = cdCanvasForeground(canvas, ih->data->bgcolor); + + cdCanvasBegin(canvas, CD_FILL); + cdCanvasVertex(canvas, x, y); + cdCanvasVertex(canvas, x + width - 1, y); + cdCanvasVertex(canvas, x + width - 1, y + height - 1); + cdCanvasVertex(canvas, x, y + height - 1); + cdCanvasEnd(canvas); + + cdCanvasForeground (canvas, old_color); + + iTabsDrawBorder(ih, ITABS_TOP, x + width - 1, y + height - 1, x, y + height - 1); + iTabsDrawBorder(ih, ITABS_LEFT, x, y + height - 1, x, y); + iTabsDrawBorder(ih, ITABS_BOTTOM, x, y, x + width - 1, y); + iTabsDrawBorder(ih, ITABS_RIGHT, x + width - 1, y, x + width - 1, y + height - 1); +} + +/* Draws arrows +* +* x, y ..........: lower border of the bounding box +* width, height .: dimensions of the bounding box +* type ..........: ITABS_LEFT, ITABS_RIGHT, ITABS_TOP, ITABS_BOTTOM +*/ +static void iTabsDrawArrow(Ihandle* ih, int x, int y, int width, int height, int type) +{ + cdCanvas* canvas = ih->data->cddbuffer; + long old_color; + + if (iupdrvIsActive(ih)) + old_color = cdCanvasForeground(canvas, CD_BLACK); + else + old_color = cdCanvasForeground(canvas, CD_DARK_GRAY); + + cdCanvasBegin(canvas, CD_CLOSED_LINES); + switch(type) + { + case ITABS_LEFT: + cdCanvasVertex(canvas, x + 4, y + height / 2); + cdCanvasVertex(canvas, x + width - 1 - 4, y + height - 1 - 4); + cdCanvasVertex(canvas, x + width - 1 - 4, y + 4); + break; + + case ITABS_RIGHT: + cdCanvasVertex(canvas, x + width - 1 - 4, y + height / 2); + cdCanvasVertex(canvas, x + 4, y + height - 1 - 4); + cdCanvasVertex(canvas, x + 4, y + 4); + break; + + case ITABS_TOP: + cdCanvasVertex(canvas, x + 4, y + 4); + cdCanvasVertex(canvas, x + width / 2, y + height - 1 - 4); + cdCanvasVertex(canvas, x + width - 1 - 4, y + 4); + break; + + case ITABS_BOTTOM: + cdCanvasVertex(canvas, x + 4, y + height - 1 - 4); + cdCanvasVertex(canvas, x + width / 2, y + 4); + cdCanvasVertex(canvas, x + width - 1 - 4, y + height - 1 - 4); + break; + } + cdCanvasEnd(canvas); + + cdCanvasBegin(canvas, CD_FILL); + switch(type) + { + case ITABS_LEFT: + cdCanvasVertex(canvas, x + 4, y + height / 2); + cdCanvasVertex(canvas, x + width - 1 - 4, y + height - 1 - 4); + cdCanvasVertex(canvas, x + width - 1 - 4, y + 4); + break; + + case ITABS_RIGHT: + cdCanvasVertex(canvas, x + width - 1 - 4, y + height / 2); + cdCanvasVertex(canvas, x + 4, y + height - 1 - 4); + cdCanvasVertex(canvas, x + 4, y + 4); + break; + + case ITABS_TOP: + cdCanvasVertex(canvas, x + 4, y + 4); + cdCanvasVertex(canvas, x + width / 2, y + height - 1 - 4); + cdCanvasVertex(canvas, x + width - 1 - 4, y + 4); + break; + + case ITABS_BOTTOM: + cdCanvasVertex(canvas, x + 4, y + height - 1 - 4); + cdCanvasVertex(canvas, x + width / 2, y + 4); + cdCanvasVertex(canvas, x + width - 1 - 4, y + height - 1 - 4); + break; + } + cdCanvasEnd(canvas); + + cdCanvasForeground(canvas, old_color); +} + +/* Draws dots "..." */ +static void iTabsDrawDots(Ihandle* ih, int x, int y, int width, int height) +{ + x -= 1; + y += height / 3 - 1; + cdCanvasRect(ih->data->cddbuffer, x + 3, x + 4, y + 3, y + 4); + cdCanvasRect(ih->data->cddbuffer, x + width / 2, x+ width / 2 + 1 , y + 3, y + 4); + cdCanvasRect(ih->data->cddbuffer, x + width - 1 - 3, x + width - 1 - 2, y + 3, y + 4); +} + +/* Draws the scroll_visible with the dots button "..." */ +static void iTabsDrawScroll(Ihandle* ih) +{ + int x = ih->data->tabs_line.scroll_x, + y = ih->data->tabs_line.scroll_y, + w = ih->data->tabs_line.scroll_w, + h = ih->data->tabs_line.scroll_h; + int scroll_updown; + + if (ih->data->tabs_type == ITABS_TOP || + ih->data->tabs_type == ITABS_BOTTOM) + scroll_updown = 0; + else + scroll_updown = 1; + + if (ih->data->tabs_orientation == ITABS_HORIZONTAL) + { + int x3 = w / 3; + + iTabsDrawButton(ih, x, y, x3, h); + iTabsDrawArrow (ih, x, y, x3, h, scroll_updown ? ITABS_TOP : ITABS_LEFT); + + iTabsDrawButton(ih, x + x3, y, x3, h); + iTabsDrawDots (ih, x + x3, y, x3, h); + + iTabsDrawButton(ih, x + 2 * x3, y, x3, h ); + iTabsDrawArrow (ih, x + 2 * x3, y, x3, h, scroll_updown ? ITABS_BOTTOM : ITABS_RIGHT); + } + else + { + int y3 = h / 3; + + iTabsDrawButton(ih, x, y, w, y3); + iTabsDrawArrow (ih, x, y, w, y3, scroll_updown ? ITABS_BOTTOM : ITABS_RIGHT); + + iTabsDrawButton(ih, x, y + y3, w, y3); + iTabsDrawDots (ih, x, y + y3, w, y3); + + iTabsDrawButton(ih, x, y + 2 * y3, w, y3); + iTabsDrawArrow (ih, x, y + 2 * y3, w, y3, scroll_updown ? ITABS_TOP : ITABS_LEFT); + } + + iTabsDrawCorner(ih, ih->data->dark_shadow, x + w - 1, y + h - 1, x + w - 3, y + h - 3); + iTabsDrawCorner(ih, ih->data->dark_shadow, x + w - 1, y, x + w - 3, y + 2); + iTabsDrawCorner(ih, ih->data->light_shadow, x, y + h - 1, x + 2, y + h - 3); + iTabsDrawCorner(ih, ih->data->dark_shadow, x, y, x + 2, y + 2); +} + +/* Clear tab background */ +static void iTabsDrawBackground(Ihandle* ih) +{ + int x1, y1, x2, y2, x3, y3, x4, y4; + cdCanvas* canvas = ih->data->cddbuffer; + + cdCanvasBackground(canvas, cdIupConvertColor(iupControlBaseGetParentBgColor(ih))); + cdCanvasClear(canvas); + + switch(ih->data->tabs_type) + { + case ITABS_TOP: + x1 = 0; + y1 = ih->data->h - *(ih->data->tabs_line.line_h) - 1 - 1; + x2 = x1; + y2 = 0; + x3 = ih->data->w - 1; + y3 = y2; + x4 = x3; + y4 = y1; + break; + + case ITABS_BOTTOM: + x1 = 0; + y1 = *(ih->data->tabs_line.line_h) - 1 + 1; + x2 = x1; + y2 = ih->data->h - 1; + x3 = ih->data->w - 1; + y3 = y2; + x4 = x3; + y4 = y1; + break; + + case ITABS_LEFT: + x1 = *(ih->data->tabs_line.line_w) - 1 + 1; + y1 = ih->data->h - 1; + x2 = ih->data->w - 1; + y2 = y1; + x3 = x2; + y3 = 0; + x4 = x1; + y4 = y3; + break; + + case ITABS_RIGHT: + x1 = ih->data->w - *(ih->data->tabs_line.line_w) - 1 - 1; + y1 = ih->data->h - 1; + x2 = 0; + y2 = y1; + x3 = x2; + y3 = 0; + x4 = x1; + y4 = y3; + break; + + default: + return; + } + + /* Foreground color */ + cdCanvasForeground(canvas, ih->data->bgcolor); + + cdCanvasBegin(canvas, CD_FILL); + cdCanvasVertex(canvas, x1, y1); + cdCanvasVertex(canvas, x2, y2); + cdCanvasVertex(canvas, x3, y3); + cdCanvasVertex(canvas, x4, y4); + cdCanvasEnd(canvas); + + cdCanvasBegin(canvas, CD_CLOSED_LINES); + cdCanvasVertex(canvas, x1, y1); + cdCanvasVertex(canvas, x2, y2); + cdCanvasVertex(canvas, x3, y3); + cdCanvasVertex(canvas, x4, y4); + cdCanvasEnd(canvas); +} + +/* Draws tab borders */ +static void iTabsDrawTabsBorders(Ihandle* ih) +{ + int x1, y1, x2, y2, x3, y3, x4, y4; + ItabsType types[3]; + + switch(ih->data->tabs_type) + { + case ITABS_TOP: + x1 = 0; + y1 = ih->data->h - *(ih->data->tabs_line.line_h) - 1 - 1; + x2 = x1; + y2 = 0; + x3 = ih->data->w - 1; + y3 = y2; + x4 = x3; + y4 = y1; + + /* defines the order to draw */ + types[0] = ITABS_LEFT; + types[1] = ITABS_BOTTOM; + types[2] = ITABS_RIGHT; + break; + + case ITABS_BOTTOM: + x1 = 0; + y1 = *(ih->data->tabs_line.line_h) - 1 + 1; + x2 = x1; + y2 = ih->data->h - 1; + x3 = ih->data->w - 1; + y3 = y2; + x4 = x3; + y4 = y1; + + /* defines the order to draw */ + types[0] = ITABS_LEFT; + types[1] = ITABS_TOP; + types[2] = ITABS_RIGHT; + break; + + case ITABS_LEFT: + x1 = *(ih->data->tabs_line.line_w) - 1 + 1; + y1 = ih->data->h - 1; + x2 = ih->data->w - 1; + y2 = y1; + x3 = x2; + y3 = 0; + x4 = x1; + y4 = y3; + + /* defines the order to draw */ + types[0] = ITABS_TOP; + types[1] = ITABS_RIGHT; + types[2] = ITABS_BOTTOM; + break; + + case ITABS_RIGHT: + x1 = ih->data->w - *(ih->data->tabs_line.line_w) - 1 - 1; + y1 = ih->data->h - 1; + x2 = 0; + y2 = y1; + x3 = x2; + y3 = 0; + x4 = x1; + y4 = y3; + + /* defines the order to draw */ + types[0] = ITABS_TOP; + types[1] = ITABS_LEFT; + types[2] = ITABS_BOTTOM; + break; + + default: + return; + } + + iTabsDrawBorder(ih, types[0], x1, y1, x2, y2); + iTabsDrawBorder(ih, types[1], x2, y2, x3, y3); + iTabsDrawBorder(ih, types[2], x3, y3, x4, y4); +} + +/* Draws all the tabs and the scroll_visible, if it exists */ +static void iTabsDrawLineOfTabs(Ihandle* ih) +{ + int offset = 0; + int c = 0; + + /* draws decorations, when necessary */ + if (ih->data->tabs_line.broken_start_visible == ITABS_TRUE) + { + iTabsDrawTab(ih, ih->data->tabs_line.start_tab - 1, offset); + offset += ih->data->tabs_line.broken_space_start; + } + + if (ih->data->tabs_line.broken_center_visible == ITABS_FALSE) + { + for(c = ih->data->tabs_line.start_tab; c <= ih->data->tabs_line.end_tab; c++) + { + if (c != ih->data->current_tab) + { + iTabsDrawTab(ih, c, offset); + offset += ih->data->tabs_line.tabs_info[c].tab_len; + } + else + { + if (ih->data->current_tab != 0) + iTabsDrawLabelLowerBorder(ih, 0, offset); + + iTabsDrawTab(ih, c, offset); + offset += ih->data->tabs_line.tabs_info[c].tab_len; + iTabsDrawLabelLowerBorder(ih, offset - 1, ih->data->w); + } + } + } + else + { + if (ih->data->current_tab != 0) + iTabsDrawLabelLowerBorder(ih, 0, offset); + + iTabsDrawTab(ih, ih->data->current_tab, offset); + offset += ih->data->tabs_line.broken_tab_space; + iTabsDrawLabelLowerBorder(ih, offset, ih->data->w); + } + + if (ih->data->tabs_line.broken_end_visible) + { + iTabsDrawTab(ih, ih->data->tabs_line.end_tab + 1, offset); + offset += ih->data->tabs_line.broken_space_end; + } + + if (ih->data->tabs_line.scroll_visible == ITABS_TRUE) + iTabsDrawScroll(ih); +} + +/* Calls the user callback to change of tab */ +static int iTabsCallTabChangeCb(Ihandle* ih, Ihandle* new_tab, Ihandle* old_tab) +{ + IFnnn cb = NULL; + + if (!IupGetInt(new_tab, "ACTIVE")) + return IUP_IGNORE; + + cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + if (!cb) + return IUP_DEFAULT; + + return cb(ih, new_tab, old_tab); +} + +/* ========================================================================= */ +/* Functions to calculate the tab sizes and the tab visibilities */ +/* ========================================================================= */ + +/* Calculates the box size that involves the text of the tabs */ +static void iTabsCalcTextSize(Ihandle* ih) +{ + char* title; + int t, text_w, size, tabsize; + int text_width, text_height; + + iupdrvFontGetCharSize(ih, NULL, &text_height); + ih->data->tabs_line.text_h = text_height; + + /* Get the global size of tab */ + size = iupAttribGetInt(ih, "TABSIZE"); + + for(t = 0; t < ih->data->number_of_tabs; t++) + { + Ihandle* tab_child = ih->data->tabs_line.tabs_info[t].ihandle; + + title = iupAttribGet(tab_child, "TABTITLE"); + if (!title) title = " "; + + /* Get the size of an specific tab */ + tabsize = iupAttribGetInt(tab_child, "TABSIZE"); + text_width = iupdrvFontGetStringWidth(ih, title); + + /* Uses the specific size if the value is larger than the minimum size */ + if (tabsize > text_width) + text_w = tabsize; + else + { + /* Else, uses the tab size if the value is larger than the minimum size */ + if (size > text_width) + text_w = size; + else /* otherwise, uses the minimum size */ + text_w = text_width; + } + + ih->data->tabs_line.tabs_info[t].text_w = text_w; + } +} + +static void iTabsCalcTabSize(Ihandle* ih) +{ + int t, tab_len, tab_thick; + + iTabsCalcTextSize(ih); + + ih->data->tabs_line.line_thick = 0; + ih->data->tabs_line.line_length = 0; + + for(t = 0; t < ih->data->number_of_tabs; t++) + { + /* initialize with the text size */ + if (ih->data->tabs_render == ITABS_RENDER_PLANE_ALIGN) + { + tab_len = ih->data->tabs_line.tabs_info[t].text_w; + tab_thick = ih->data->tabs_line.text_h; + } + else + { + tab_len = ih->data->tabs_line.text_h; + tab_thick = ih->data->tabs_line.tabs_info[t].text_w; + } + + /* add the borders */ + if (abs(ih->data->current_tab - t) == 1) /* if neighbor of the current tab */ + tab_len += ITABS_BORDER; + else if (t == ih->data->current_tab) /* if tab is the current tab */ + { + if (ih->data->current_tab == 0 || ih->data->current_tab == (ih->data->number_of_tabs - 1)) + tab_len += 2 * ITABS_BORDER; + else + tab_len += 3 * ITABS_BORDER; + } + else + tab_len += 2 * ITABS_BORDER; + + /* add margins */ + if (ih->data->tabs_render == ITABS_RENDER_PLANE_ALIGN) + tab_len += 2 * ITABS_MARGIN; + else + tab_len += 2 * ITABS_SPACING; + + ih->data->tabs_line.tabs_info[t].tab_len = tab_len; + + ih->data->tabs_line.line_length += tab_len; /* is always the sum on the lengths */ + + if (tab_thick > ih->data->tabs_line.line_thick) /* is always the maximum thickness */ + ih->data->tabs_line.line_thick = tab_thick; + } + + if (ih->data->tabs_render == ITABS_RENDER_PLANE_ALIGN) + ih->data->tabs_line.line_thick += 2 * ITABS_SPACING + 2 * ITABS_BORDER; + else + ih->data->tabs_line.line_thick += 2 * ITABS_MARGIN + 2 * ITABS_BORDER; + + if (ih->data->tabs_line.line_thick < ih->data->tabs_line.scroll_thick) + ih->data->tabs_line.line_thick = ih->data->tabs_line.scroll_thick; + + /* extra pixels of the selected tab */ + ih->data->tabs_line.line_thick += ITABS_CURRENT_EXTRA_PIXELS; +} + +static void iTabsCalcScrollPos(Ihandle* ih) +{ + int x1=0, y1=0, x2=0, y2=0; + + switch(ih->data->tabs_type) + { + case ITABS_TOP: + ih->data->tabs_line.scroll_x = ih->data->w - ih->data->tabs_line.scroll_w - 2; + ih->data->tabs_line.scroll_y = ih->data->h - *(ih->data->tabs_line.line_h); + y1=0; y2=*(ih->data->tabs_line.line_h); + x1=0; x2=ih->data->w-1; + break; + case ITABS_BOTTOM: + ih->data->tabs_line.scroll_x = ih->data->w - ih->data->tabs_line.scroll_w - 2; + ih->data->tabs_line.scroll_y = *(ih->data->tabs_line.line_h) - 2 - ih->data->tabs_line.scroll_h + 1; + y1=ih->data->h - *(ih->data->tabs_line.line_h); y2=ih->data->h-1; + x1=0; x2=ih->data->w-1; + break; + case ITABS_LEFT: + ih->data->tabs_line.scroll_x = *(ih->data->tabs_line.line_w) - 2 - ih->data->tabs_line.scroll_w + 1; + ih->data->tabs_line.scroll_y = 0; + x1=0; x2=*(ih->data->tabs_line.line_w); + y1=0; y2=ih->data->h-1; + break; + case ITABS_RIGHT: + ih->data->tabs_line.scroll_x = ih->data->w - *(ih->data->tabs_line.line_w); + ih->data->tabs_line.scroll_y = 0; + x1=ih->data->w-*(ih->data->tabs_line.line_w); x2=ih->data->w-1; + y1=0; y2=ih->data->h-1; + break; + } + + iupAttribSetStrf(ih, "TIPRECT", "%d %d %d %d", x1, y1, x2, y2); +} + +/* Calculates the visibility of tabs */ +static void iTabsCalcVisibleTabs(Ihandle* ih) +{ + int line_length = *ih->data->max_line_length; + int old_line_length; + int t, t_aux = 0; + + /* Verifies if all the tabs are visible */ + if (*ih->data->max_line_length > ih->data->tabs_line.line_length) + { + /* All the tabs are visible */ + ih->data->tabs_line.scroll_visible = ITABS_FALSE; + ih->data->tabs_line.broken_start_visible = ITABS_FALSE; + ih->data->tabs_line.broken_end_visible = ITABS_FALSE; + ih->data->tabs_line.broken_center_visible = ITABS_FALSE; + + ih->data->tabs_line.start_tab = 0; + ih->data->tabs_line.end_tab = ih->data->number_of_tabs - 1; + + return; + } + + /* Subtracts space of scroll */ + line_length -= ih->data->tabs_line.scroll_len + ITABS_SCROLL_SPACING; + + ih->data->tabs_line.scroll_visible = ITABS_TRUE; + + /* Verifies if current tab is smaller than start tab, adjusting if necessary */ + if (ih->data->current_tab < ih->data->tabs_line.start_tab) + ih->data->tabs_line.start_tab = ih->data->current_tab; + + /* Processes tabs in sequence, until the total length overcome the virtual length */ + t = ih->data->tabs_line.start_tab; + old_line_length = line_length; + + while(1) + { + do + { + while (ih->data->tabs_line.start_tab < ih->data->current_tab) + { + if (ih->data->tabs_line.tabs_info[ih->data->tabs_line.start_tab].tab_len <= line_length) + break; + ih->data->tabs_line.start_tab++; + } + + for(t = ih->data->tabs_line.start_tab, t_aux = 0; + t < ih->data->number_of_tabs; t++, t_aux++) + { + if (ih->data->tabs_line.tabs_info[t].tab_len > line_length) + { + if ((t - 1) < ih->data->current_tab) + { + while (t_aux > 0) + { + line_length += + ih->data->tabs_line.tabs_info[t - t_aux].tab_len; + + if (ih->data->tabs_line.start_tab == 0) + { + line_length -= ITABS_BROKEN_TAB; + ih->data->tabs_line.broken_start_visible = ITABS_TRUE; + } + + ih->data->tabs_line.start_tab++; + + if (ih->data->tabs_line.tabs_info[t].tab_len <= line_length) + break; + + t_aux--; + } + + if (ih->data->tabs_line.tabs_info[t].tab_len > line_length) + { + /* no success */ + ih->data->tabs_line.broken_center_visible = ITABS_TRUE; + break; /* break two loops */ + } + } + else + { + t--; + break; /* break two loops */ + } + } + + line_length -= ih->data->tabs_line.tabs_info[t].tab_len; + ih->data->tabs_line.broken_center_visible = ITABS_FALSE; + } + + if (t == ih->data->number_of_tabs) + t--; + } + while (t < ih->data->current_tab); + + if (ih->data->tabs_line.start_tab > 0 && + ih->data->tabs_line.broken_center_visible != ITABS_TRUE) + { + if (ih->data->tabs_line.tabs_info[ih->data->tabs_line.start_tab - 1].tab_len < + (line_length - ITABS_BROKEN_TAB)) + { + ih->data->tabs_line.start_tab--; + line_length = old_line_length; + continue; + } + } + + break; + } + + if (ih->data->tabs_line.start_tab > 0) + { + t = ih->data->tabs_line.start_tab; + line_length = old_line_length; + line_length -= ITABS_BROKEN_TAB; + ih->data->tabs_line.broken_start_visible = ITABS_TRUE; + + while(1) + { + do + { + while (ih->data->tabs_line.start_tab < ih->data->current_tab) + { + if (ih->data->tabs_line.tabs_info[ih->data->tabs_line.start_tab].tab_len <= line_length) + break; + ih->data->tabs_line.start_tab++; + } + + for(t = ih->data->tabs_line.start_tab, t_aux = 0; + t < ih->data->number_of_tabs; t++, t_aux++) + { + if (ih->data->tabs_line.tabs_info[t].tab_len > line_length) + { + if ((t - 1) < ih->data->current_tab) + { + while (t_aux > 0) + { + line_length += + ih->data->tabs_line.tabs_info[t - t_aux].tab_len; + + if (ih->data->tabs_line.start_tab == 0) + { + line_length -= ITABS_BROKEN_TAB; + ih->data->tabs_line.broken_start_visible = ITABS_TRUE; + } + + ih->data->tabs_line.start_tab++; + + if (ih->data->tabs_line.tabs_info[t].tab_len <= line_length) + break; + + t_aux--; + } + + if (ih->data->tabs_line.tabs_info[t].tab_len > line_length) + { + /* no success */ + ih->data->tabs_line.broken_center_visible = ITABS_TRUE; + break; /* break two loops */ + } + } + else + { + t--; + break; /* break two loops */ + } + } + + line_length -= ih->data->tabs_line.tabs_info[t].tab_len; + ih->data->tabs_line.broken_center_visible = ITABS_FALSE; + } + + if (t == ih->data->number_of_tabs) + t--; + } + while (t < ih->data->current_tab); + + if (ih->data->tabs_line.start_tab > 0 && + ih->data->tabs_line.broken_center_visible != ITABS_TRUE) + { + if (ih->data->tabs_line.tabs_info[ih->data->tabs_line.start_tab - 1].tab_len < + (line_length - ITABS_BROKEN_TAB)) + { + ih->data->tabs_line.start_tab--; + line_length = old_line_length; + continue; + } + } + + break; + } + } + else + ih->data->tabs_line.broken_start_visible = ITABS_FALSE; + + /* space not occupied by tabs is destined for the broken tabs */ + ih->data->tabs_line.broken_tab_space = line_length; + + if (ih->data->tabs_line.broken_start_visible == ITABS_TRUE) + ih->data->tabs_line.broken_tab_space += ITABS_BROKEN_TAB; + + if (ih->data->tabs_line.broken_center_visible == ITABS_TRUE && + ih->data->tabs_line.start_tab == t) + { + /* If there is one visible tab and more tabs to the right, + it must be clipped */ + ih->data->tabs_line.end_tab = ih->data->tabs_line.start_tab; + ih->data->tabs_line.broken_end_visible = ITABS_FALSE; + ih->data->tabs_line.broken_start_visible = ITABS_FALSE; + } + else + { + ih->data->tabs_line.end_tab = t; + ih->data->tabs_line.broken_center_visible = ITABS_FALSE; + + /* If the last tab is not visible, it must be included the + right broken tab, and delete one of tabs, when necessary */ + if (ih->data->tabs_line.end_tab < (ih->data->number_of_tabs - 1)) + { + ih->data->tabs_line.broken_end_visible = ITABS_TRUE; + + if (line_length < ITABS_BROKEN_TAB) + { + if (ih->data->tabs_line.start_tab == ih->data->tabs_line.end_tab) + { + /* no space to broken tabs */ + ih->data->tabs_line.broken_center_visible = ITABS_TRUE; + ih->data->tabs_line.broken_end_visible = ITABS_FALSE; + ih->data->tabs_line.broken_start_visible = ITABS_FALSE; + + ih->data->tabs_line.broken_tab_space += + ih->data->tabs_line.tabs_info[ih->data->tabs_line.start_tab].tab_len; + } + else if (ih->data->current_tab == ih->data->tabs_line.end_tab) + { + ih->data->tabs_line.broken_tab_space += + ih->data->tabs_line.tabs_info[ih->data->tabs_line.start_tab].tab_len; + ih->data->tabs_line.start_tab++; + ih->data->tabs_line.broken_start_visible = ITABS_TRUE; + } + else + { + ih->data->tabs_line.broken_tab_space += + ih->data->tabs_line.tabs_info[ih->data->tabs_line.end_tab].tab_len; + ih->data->tabs_line.end_tab--; + } + } + } + else + ih->data->tabs_line.broken_end_visible = ITABS_FALSE; + } + + if (ih->data->tabs_line.broken_start_visible == ITABS_TRUE && + ih->data->tabs_line.broken_end_visible == ITABS_TRUE) + { + ih->data->tabs_line.broken_space_start = (int) + ceil((double) ih->data->tabs_line.broken_tab_space / 2); + ih->data->tabs_line.broken_space_end = (int) + floor((double) ih->data->tabs_line.broken_tab_space / 2); + } + else if (ih->data->tabs_line.broken_start_visible == ITABS_TRUE) + { + ih->data->tabs_line.broken_space_start = ih->data->tabs_line.broken_tab_space; + ih->data->tabs_line.broken_space_end = 0; + } + else if (ih->data->tabs_line.broken_end_visible == ITABS_TRUE) + { + ih->data->tabs_line.broken_space_end = ih->data->tabs_line.broken_tab_space; + ih->data->tabs_line.broken_space_start = 0; + } + else + { + ih->data->tabs_line.broken_space_end = 0; + ih->data->tabs_line.broken_space_start = 0; + } + + if (ih->data->tabs_line.start_tab == 0) + ih->data->tabs_line.broken_start_visible = ITABS_FALSE; +} + +static void iTabsGetDecorOffset(Ihandle* ih, int *x, int *y) +{ + switch(ih->data->tabs_type) + { + case ITABS_TOP: + *x = ITABS_MARGIN; + *y = *(ih->data->tabs_line.line_h) + ITABS_MARGIN; + break; + + case ITABS_LEFT: + *x = *(ih->data->tabs_line.line_w) + ITABS_MARGIN; + *y = ITABS_MARGIN; + break; + + case ITABS_RIGHT: + case ITABS_BOTTOM: + default: + *x = ITABS_MARGIN; + *y = ITABS_MARGIN; + break; + } +} + +static void iTabsGetDecorSize(Ihandle* ih, int *w, int *h) +{ + switch(ih->data->tabs_type) + { + case ITABS_TOP: + *w = 2 * ITABS_MARGIN; + *h = *(ih->data->tabs_line.line_h) + 2 * ITABS_MARGIN; + break; + + case ITABS_BOTTOM: + *w = 2 * ITABS_MARGIN; + *h = *(ih->data->tabs_line.line_h) + 2 * ITABS_MARGIN; + break; + + case ITABS_LEFT: + *w = *(ih->data->tabs_line.line_w) + 2 * ITABS_MARGIN; + *h = 2 * ITABS_MARGIN; + break; + + case ITABS_RIGHT: + *w = *(ih->data->tabs_line.line_w) + 2 * ITABS_MARGIN; + *h = 2 * ITABS_MARGIN; + break; + } +} + +/* Changes the zbox value and redraws the tabs */ +static void iTabsSetNewCurrentTab(Ihandle* ih, int tab) +{ + char* next_tab_name = IupGetName(iTabsGetTabIhandle(ih, tab)); + if (next_tab_name == NULL) + return; + + ih->data->current_tab = tab; + IupSetAttribute(ih->data->zbox, "VALUE", next_tab_name); + + iTabsCalcVisibleTabs(ih); /* calculates the visibility of tabs (depends on the sizes calculated and on the current tab) */ + + IupUpdate(ih); +} + + +/* ========================================================================= */ +/* IupCanvas Callbacks */ +/* ========================================================================= */ + + +static int iTabsFocus_CB(Ihandle* ih, int focus) +{ + ih->data->has_focus = focus; + IupUpdate(ih); + return IUP_DEFAULT; +} + +static int iTabsResize_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 canvas size */ + cdCanvasActivate(ih->data->cddbuffer); + cdCanvasGetSize(ih->data->cddbuffer, &ih->data->w, &ih->data->h, NULL, NULL); + + iTabsCalcTabSize(ih); /* calculates sizes of Tab line (depends on the TABTITLE of all children and on FONT) */ + iTabsCalcScrollPos(ih); /* calculates the position of the scroll (depends on the sizes calculated) */ + iTabsCalcVisibleTabs(ih); /* calculates the visibility of tabs (depends on the sizes calculated and on the current tab) */ + + return IUP_DEFAULT; +} + +static int iTabsRedraw_CB(Ihandle* ih) +{ + char* clip_rect; + + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + /* Paints the background and draws the border */ + iTabsDrawBackground(ih); + iTabsDrawTabsBorders(ih); + + /* Draws tabs and decorations */ + iTabsDrawLineOfTabs(ih); + + clip_rect = iupAttribGet(ih, "CLIPRECT"); + if (clip_rect) + { + int x1, x2, y1, y2; + sscanf(clip_rect, "%d %d %d %d", &x1, &y1, &x2, &y2); + y1 = cdIupInvertYAxis(y1, ih->data->h); + y2 = cdIupInvertYAxis(y2, ih->data->h); + cdCanvasClipArea(ih->data->cdcanvas, x1, x2, y1, y2); + cdCanvasClip(ih->data->cdcanvas, CD_CLIPAREA); + } + + /* Ends the draw process */ + cdCanvasFlush(ih->data->cddbuffer); + if (ih->data->has_focus) + cdIupDrawFocusRect(ih, ih->data->cdcanvas, ih->data->focus_x1, ih->data->focus_y1, ih->data->focus_x2, ih->data->focus_y2); + + if (clip_rect) + cdCanvasClip(ih->data->cdcanvas, CD_CLIPOFF); + + return IUP_DEFAULT; +} + +/* Callback to popup menu, with the tabs list */ +static int iTabsMenu_CB(Ihandle* ih) +{ + char* number = iupAttribGet(ih, "_IUPTABS_ID"); + int tab_number = 0; + int result; + + sscanf (number, "%d", &tab_number); + + if (ih->data->current_tab != tab_number) + { + result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, tab_number), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, tab_number); + } + + return IUP_DEFAULT; +} + +/* Creates a menu with all the tab labels */ +static Ihandle* iTabsMakeMenuFromTabs(Ihandle* ih) +{ + int c = 0; + Ihandle* menu = IupMenu(NULL); + Ihandle* item = NULL; + + for(c = 0; c < ih->data->number_of_tabs; c++) + { + char* title = iupAttribGet(ih->data->tabs_line.tabs_info[c].ihandle, "TABTITLE"); + if (!title) title = " "; + + item = IupItem(title, NULL); + IupSetCallback(item, "ACTION", (Icallback) iTabsMenu_CB); + + iupAttribSetStrf(item, "_IUPTABS_ID", "%4d", c); + + if (c == ih->data->current_tab) + IupSetAttribute(item, "VALUE", "ON"); + + IupAppend(menu, item); + } + + return menu; +} + +static int iTabsGetNextTab(Ihandle* ih) +{ + int next_tab; + + if (ih->data->current_tab < (ih->data->number_of_tabs - 1)) + next_tab = ih->data->current_tab + 1; + else + next_tab = 0; + + /* find the next active tab */ + while(next_tab != ih->data->current_tab && + !IupGetInt(iTabsGetTabIhandle(ih, next_tab), "ACTIVE")) + { + if (next_tab < (ih->data->number_of_tabs - 1)) + next_tab = next_tab + 1; + else + next_tab = 0; + } + + if (next_tab == ih->data->current_tab) + return -1; + + return next_tab; +} + +static int iTabsGetPreviousTab(Ihandle* ih) +{ + int previous_tab; + if (ih->data->current_tab > 0) + previous_tab = ih->data->current_tab - 1; + else + previous_tab = ih->data->number_of_tabs - 1; + + /* find the previous active tab */ + while(previous_tab != ih->data->current_tab && + !IupGetInt(iTabsGetTabIhandle(ih, previous_tab), "ACTIVE")) + { + if (previous_tab > 0) + previous_tab = previous_tab - 1; + else + previous_tab = ih->data->number_of_tabs - 1; + } + + if (previous_tab == ih->data->current_tab) + return -1; + + return previous_tab; +} + +/* Key press Callback */ +static int iTabsKeyPress_CB(Ihandle* ih, int c, int press) +{ + if (press == 0) + return IUP_DEFAULT; + + if (((c == K_RIGHT || c == K_sRIGHT) && (ih->data->tabs_type == ITABS_TOP || ih->data->tabs_type == ITABS_BOTTOM)) || + ((c == K_DOWN || c == K_sDOWN) && (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT))) + { + int result; + int next_tab = iTabsGetNextTab(ih); + if (next_tab == -1) + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ + + result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, next_tab), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, next_tab); + + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ + } + else if (((c == K_LEFT || c == K_sLEFT) && (ih->data->tabs_type == ITABS_TOP || ih->data->tabs_type == ITABS_BOTTOM)) || + ((c == K_UP || c == K_sUP) && (ih->data->tabs_type == ITABS_LEFT || ih->data->tabs_type == ITABS_RIGHT))) + { + int result; + int previous_tab = iTabsGetPreviousTab(ih); + if (previous_tab == -1) + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ + + result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, previous_tab), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, previous_tab); + + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ + } + + return IUP_DEFAULT; +} + +/* Button press Callback of IUP Canvas */ +static int iTabsButton_CB (Ihandle* ih, int b, int press, int mx, int my) +{ + static int last_tab_press = -1; + int* virtual_width = NULL; + int* virtual_height = NULL; + int width = 0, height = 0, offset = 0; + int* virtual_mx = NULL; + int* virtual_my = NULL; + int click_x = mx, click_y = ih->data->h-1 - my; + int count = 0; + + /* Only events of the left button are handled */ + if (b != IUP_BUTTON1) + return IUP_DEFAULT; + + /* Calculates the bounding box size of the tabs queue */ + switch(ih->data->tabs_type) + { + case ITABS_TOP: + width = ih->data->w; + height = ih->data->tabs_line.line_thick; + virtual_width = &width; + virtual_height = &height; + virtual_mx = &mx; + virtual_my = &my; + *virtual_my = -(*virtual_my - (ih->data->tabs_line.line_thick - 1)); + break; + + case ITABS_BOTTOM: + width = ih->data->w; + height = ih->data->tabs_line.line_thick; + virtual_width = &width; + virtual_height = &height; + virtual_mx = &mx; + virtual_my = &my; + *virtual_my = *virtual_my - ih->data->h + ih->data->tabs_line.line_thick; + break; + + case ITABS_LEFT: + width = ih->data->tabs_line.line_thick; + height = ih->data->h; + virtual_width = &height; + virtual_height = &width; + virtual_mx = &my; + virtual_my = &mx; + *virtual_my = -(*virtual_my - (ih->data->tabs_line.line_thick - 1)); + break; + + case ITABS_RIGHT: + width = ih->data->tabs_line.line_thick; + height = ih->data->h; + virtual_width = &height; + virtual_height = &width; + virtual_mx = &my; + virtual_my = &mx; + *virtual_my = *virtual_my - ih->data->w + ih->data->tabs_line.line_thick; + break; + } + + /* Adjusts the offset when the first tab is not selected */ + if (ih->data->current_tab != 0) + offset = 1; + + /* Checks if the mouse is on the tabs area */ + if ((*virtual_mx > (*virtual_width - 1)) || + (*virtual_my > (*virtual_height - 1)) || + (*virtual_mx < 0) || (*virtual_my < 0)) + { + /* If a button release or any scroll_visible button are pressed, they'll are released */ + if (!press && ih->data->tabs_line.button != ITABS_BUTTON_NONE) + ih->data->tabs_line.button = ITABS_BUTTON_NONE; + + return IUP_DEFAULT; + } + + if (!press && ih->data->tabs_line.button != ITABS_BUTTON_NONE) + ih->data->tabs_line.button += 3; /* increment from BUTPRESS_* to BUTRELEASE_* */ + + /* If there is a scroll_visible, verifies if the click was on one of buttons */ + if (ih->data->tabs_line.scroll_visible == ITABS_TRUE) + { + int scroll_pos, scroll_space; + + if (ih->data->tabs_orientation == ITABS_HORIZONTAL) + { + scroll_space = ih->data->tabs_line.scroll_w; + scroll_pos = click_x - ih->data->tabs_line.scroll_x; + } + else + { + scroll_space = ih->data->tabs_line.scroll_h; + scroll_pos = click_y - ih->data->tabs_line.scroll_y; + + /* the controls are inverted when text is vertical */ + scroll_pos = scroll_space - scroll_pos; + } + + if (click_y > ih->data->tabs_line.scroll_y && click_x > ih->data->tabs_line.scroll_x && + click_y < ih->data->tabs_line.scroll_y+ih->data->tabs_line.scroll_h && click_x < ih->data->tabs_line.scroll_x+ih->data->tabs_line.scroll_w) + { + /* Verifies which button was pressed by user */ + if (scroll_pos > 2 * scroll_space / 3) /* forward button*/ + { + /* If press, to draw it pressed */ + if (press) + { + ih->data->tabs_line.button = ITABS_BUTTONPRESS_FORWARD ; + } + else if (ih->data->tabs_line.button == ITABS_BUTTONRELEASE_FORWARD) + /* else, change the tab */ + { + int result; + int next_tab = iTabsGetNextTab(ih); + if (next_tab == -1) + return IUP_DEFAULT; + + result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, next_tab), iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, next_tab); + } + } + else if (scroll_pos > scroll_space / 3) /* menu button*/ + { + /* If press, to draw it pressed */ + if (press) + { + ih->data->tabs_line.button = ITABS_BUTTONPRESS_MENU ; + } + else if (ih->data->tabs_line.button == ITABS_BUTTONRELEASE_MENU) + /* else, change the tab */ + { + Ihandle* menu = iTabsMakeMenuFromTabs (ih); + IupPopup(menu, IUP_MOUSEPOS, IUP_MOUSEPOS); + IupDestroy(menu); + } + } + else /* backward button*/ + { + /* If press, to draw it pressed */ + if (press) + { + ih->data->tabs_line.button = ITABS_BUTTONPRESS_BACKWARD ; + } + else if (ih->data->tabs_line.button == ITABS_BUTTONRELEASE_BACKWARD) + /* else, change the tab */ + { + int result; + int previous_tab = iTabsGetPreviousTab(ih); + if (previous_tab == -1) + return IUP_DEFAULT; + + result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, previous_tab), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, previous_tab); + } + } + + return IUP_DEFAULT; + } + } + + /* If there is any scroll_visible button pressed, it will be released */ + if (!press && ih->data->tabs_line.button != ITABS_BUTTON_NONE) + { + ih->data->tabs_line.button = ITABS_BUTTON_NONE; + IupUpdate(ih); + return IUP_DEFAULT; + } + + /* Checks when the click was on the left broken tab */ + if (ih->data->tabs_line.broken_start_visible == ITABS_TRUE) + { + if (*virtual_mx >= offset && + *virtual_mx <= (offset + ih->data->tabs_line.broken_space_start - 1) && + *virtual_my <= (ih->data->tabs_line.line_thick - ITABS_CURRENT_EXTRA_PIXELS - 1)) + { + if (press) + last_tab_press = ih->data->tabs_line.start_tab-1; + else if (last_tab_press == ih->data->tabs_line.start_tab-1) + { + int result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, last_tab_press), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, last_tab_press); + } + + return IUP_DEFAULT; + } + else + offset += ih->data->tabs_line.broken_space_start; + } + + /* Checks when the click was on one of tabs */ + for(count = ih->data->tabs_line.start_tab; count <= ih->data->tabs_line.end_tab; count++) + { + if (*virtual_mx >= offset && + *virtual_mx <= (offset + ih->data->tabs_line.tabs_info[count].tab_len - 1)) + { + if (count != ih->data->current_tab) + { + if (*virtual_my <= (ih->data->tabs_line.line_thick - ITABS_CURRENT_EXTRA_PIXELS - 1)) + { + if (press) + last_tab_press = count; + else if (last_tab_press == count) + { + int result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, last_tab_press), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, last_tab_press); + } + + return IUP_DEFAULT; + } + } + } + + offset += ih->data->tabs_line.tabs_info[count].tab_len; + } + + /* Checks when the click was on the right broken tab */ + if (ih->data->tabs_line.broken_end_visible == ITABS_TRUE) + { + if (*virtual_mx >= offset && + *virtual_mx <= (offset + ih->data->tabs_line.broken_space_end - 1) && + *virtual_my <= (ih->data->tabs_line.line_thick - ITABS_CURRENT_EXTRA_PIXELS - 1)) + { + if (press) + last_tab_press = ih->data->tabs_line.end_tab + 1; + else if (last_tab_press == ih->data->tabs_line.end_tab + 1) + { + int result = iTabsCallTabChangeCb(ih, iTabsGetTabIhandle(ih, last_tab_press), + iTabsGetTabIhandle(ih, ih->data->current_tab)); + if (result != IUP_IGNORE) + iTabsSetNewCurrentTab(ih, last_tab_press); + } + + return IUP_DEFAULT; + } + else + offset += ih->data->tabs_line.broken_space_end; + } + + return IUP_DEFAULT; +} + +static void iTabsRefreshTabs(Ihandle* ih) +{ + int t, old_number_of_tabs = ih->data->number_of_tabs; + Ihandle* child, *old_current_tab_handle = NULL; + + if (ih->data->tabs_line.tabs_info) + old_current_tab_handle = ih->data->tabs_line.tabs_info[ih->data->current_tab].ihandle; + + ih->data->number_of_tabs = 0; + child = ih->data->zbox->firstchild; + while(child) + { + if (IupGetName(child) == NULL) + iupAttribSetHandleName(child); + + ih->data->number_of_tabs++; + child = child->brother; + } + + if (old_number_of_tabs < ih->data->number_of_tabs) + ih->data->tabs_line.tabs_info = (ItabsDrawInfo*)realloc(ih->data->tabs_line.tabs_info, ih->data->number_of_tabs * sizeof (ItabsDrawInfo)); + + t = 0; + child = ih->data->zbox->firstchild; + while (child) + { + ih->data->tabs_line.tabs_info[t].ihandle = child; + + if (child == old_current_tab_handle) + ih->data->current_tab = t; /* current tab was moved */ + + child = child->brother; + t++; + } + + if (old_current_tab_handle && + old_current_tab_handle != ih->data->tabs_line.tabs_info[ih->data->current_tab].ihandle) + { + /* current tab was removed, reset to first child */ + ih->data->current_tab = 0; + } +} + + +/* ========================================================================= */ +/* Attributes */ +/* ========================================================================= */ + + +static int iTabsSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + int inherit; + return iupClassObjectSetAttribute(ih->data->zbox, "ALIGNMENT", value, &inherit); +} + +static char* iTabsGetAlignmentAttrib(Ihandle* ih) +{ + int inherit; + char *def_value; + return iupClassObjectGetAttribute(ih->data->zbox, "ALIGNMENT", &def_value, &inherit); +} + +static int iTabsSetTabOrientationAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "VERTICAL")) + ih->data->tabs_orientation = ITABS_VERTICAL; + else + ih->data->tabs_orientation = ITABS_HORIZONTAL; + + iTabsUpdateRender(ih); + + return 0; /* do not store value in hash table */ +} + +static char* iTabsGetTabOrientationAttrib(Ihandle* ih) +{ + if (ih->data->tabs_orientation == ITABS_VERTICAL) + return "VERTICAL"; + else + return "HORIZONTAL"; +} + +static int iTabsSetTabTypeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "BOTTOM")) + ih->data->tabs_type = ITABS_BOTTOM; + else if (iupStrEqualNoCase(value, "LEFT")) + ih->data->tabs_type = ITABS_LEFT; + else if (iupStrEqualNoCase(value, "RIGHT")) + ih->data->tabs_type = ITABS_RIGHT; + else /* "TOP" */ + ih->data->tabs_type = ITABS_TOP; + + iTabsUpdateRender(ih); + + return 0; /* do not store value in hash table */ +} + +static char* iTabsGetTabTypeAttrib(Ihandle* ih) +{ + if (ih->data->tabs_type == ITABS_BOTTOM) + return "BOTTOM"; + else if (ih->data->tabs_type == ITABS_LEFT) + return "LEFT"; + else if (ih->data->tabs_type == ITABS_RIGHT) + return "RIGHT"; + else /* ITABS_TOP */ + return "TOP"; +} + +static int iTabsSetRepaintAttrib(Ihandle* ih, const char* value) +{ + (void)value; + + iTabsCalcTabSize(ih); /* calculate sizes of Tab line (depends on the TABTITLE of all children) */ + iTabsCalcScrollPos(ih); /* calculates the position of the scroll (depends on the sizes calculated) */ + iTabsCalcVisibleTabs(ih); /* calculates the visibility of tabs (depends on the sizes calculated and on the current tab) */ + + IupUpdate(ih); + + return 0; /* do not store value in hash table */ +} + +static int iTabsSetFontActiveAttrib(Ihandle* ih, const char* value) +{ + char* native = IupMapFont(value); + if (!native) native = (char*)value; + + if (native) + { + if (ih->data->font_active) + free(ih->data->font_active); + + ih->data->font_active = iupStrDup(native); + IupUpdate(ih); + } + return 1; +} + +static int iTabsSetFontInactiveAttrib(Ihandle* ih, const char* value) +{ + char* native = IupMapFont(value); + if (!native) native = (char*)value; + + if (native) + { + if (ih->data->font_inactive) + free(ih->data->font_inactive); + + ih->data->font_inactive = iupStrDup(native); + IupUpdate(ih); + } + return 1; +} + +static int iTabsSetFgColorAttrib(Ihandle* ih, const char* value) +{ + ih->data->fgcolor = cdIupConvertColor(value); + IupUpdate(ih); + return 1; +} + +static int iTabsSetBgColorAttrib(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); + + IupUpdate(ih); + return 1; +} + +static int iTabsSetActiveAttrib(Ihandle* ih, const char* value) +{ + iupBaseSetActiveAttrib(ih, value); + IupUpdate(ih); /* post repaint so children is activated/deactivated */ + return 0; /* do not store value in hash table */ +} + +static int iTabsSetValueAttrib(Ihandle* ih, const char* value) +{ + int c; + Ihandle* new_tab = IupGetHandle(value); + + if (new_tab == NULL) + return 0; + + for(c = 0; c < ih->data->number_of_tabs; c++) + { + if (ih->data->tabs_line.tabs_info[c].ihandle == new_tab) + { + iTabsSetNewCurrentTab(ih, c); + break; + } + } + return 0; /* do not store value in hash table */ +} + +static char* iTabsGetValueAttrib(Ihandle* ih) +{ + return IupGetAttribute(ih->data->zbox, "VALUE"); +} + +static int iTabsSetValuePosAttrib(Ihandle* ih, const char* value) +{ + int pos; + + if (!iupStrToInt(value, &pos)) + return 0; + + if (pos<0) pos=0; + if (pos>ih->data->number_of_tabs-1) pos=ih->data->number_of_tabs-1; + + iTabsSetNewCurrentTab(ih, pos); + return 0; /* do not store value in hash table */ +} + +static char* iTabsGetValuePosAttrib(Ihandle* ih) +{ + char *str = iupStrGetMemory(50); + sprintf(str, "%d", ih->data->current_tab); + return str; +} + +static char* iTabsGetClientSizeAttrib(Ihandle* ih) +{ + int width, height, decorwidth, decorheight; + char* str = iupStrGetMemory(20); + width = ih->currentwidth; + height = ih->currentheight; + iTabsGetDecorSize(ih, &decorwidth, &decorheight); + width -= decorwidth; + height -= decorheight; + if (width < 0) width = 0; + if (height < 0) height = 0; + sprintf(str, "%dx%d", width, height); + return str; +} + + +/* ========================================================================= */ +/* Methods */ +/* ========================================================================= */ + + +static Ihandle* iTabsGetInnerContainerMethod(Ihandle* ih) +{ + return ih->data->zbox; +} + +static void iTabsComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int decorwidth, decorheight; + Ihandle* child = ih->data->zbox; /* zbox is always non NULL */ + + iTabsCalcTabSize(ih); /* make sure that decoration is updated, even if UPDATE has not been set after other changes */ + iTabsGetDecorSize(ih, &decorwidth, &decorheight); + + /* update child natural size first */ + iupBaseComputeNaturalSize(child); + + *expand = child->expand; + *w = child->naturalwidth + decorwidth; + *h = child->naturalheight + decorheight; +} + +static void iTabsSetChildrenCurrentSizeMethod(Ihandle* ih, int shrink) +{ + int width, height, decorwidth, decorheight; + + iTabsGetDecorSize(ih, &decorwidth, &decorheight); + + width = ih->currentwidth-decorwidth; + height = ih->currentheight-decorheight; + if (width < 0) width = 0; + if (height < 0) height = 0; + + iupBaseSetCurrentSize(ih->data->zbox, width, height, shrink); +} + +static void iTabsSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + /* IupTabs is the native parent of its children, + so the position is restarted at (0,0) */ + iTabsGetDecorOffset(ih, &x, &y); + + /* Child coordinates are relative to client left-top corner. */ + iupBaseSetPosition(ih->data->zbox, x, y); +} + +static void iTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + iTabsRefreshTabs(ih); /* update the list of tabs */ +} + +static void iTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + iTabsRefreshTabs(ih); /* update the list of tabs */ +} + +static int iTabsMapMethod(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 iTabsUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static void iTabsDestroyMethod(Ihandle* ih) +{ + if (ih->data->font_inactive) + free(ih->data->font_inactive); + + if (ih->data->font_inactive) + free(ih->data->font_inactive); + + free(ih->data->tabs_line.tabs_info); +} + +static int iTabsCreateMethod(Ihandle* ih, void **params) +{ + /* 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->data->zbox = IupZbox(NULL); + ih->firstchild = ih->data->zbox; /* zbox is actually the only child of Tabs */ + ih->data->zbox->parent = ih; + + /* add children */ + if (params) + { + Ihandle** iparams = (Ihandle**)params; + while (*iparams) + { + IupAppend(ih, *iparams); /* this in fact will add the child to the zbox */ + iparams++; + } + } + + /* IupCanvas callbacks */ + IupSetCallback(ih, "RESIZE_CB", (Icallback)iTabsResize_CB); + IupSetCallback(ih, "ACTION", (Icallback)iTabsRedraw_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iTabsButton_CB); + IupSetCallback(ih, "KEYPRESS_CB", (Icallback)iTabsKeyPress_CB); + IupSetCallback(ih, "FOCUS_CB", (Icallback)iTabsFocus_CB); + + /* initialize colors */ + ih->data->bgcolor = -1; + ih->data->fgcolor = CD_BLACK; + ih->data->light_shadow = CD_WHITE; + ih->data->mid_shadow = CD_GRAY; + ih->data->dark_shadow = CD_DARK_GRAY; + + /* Context initialize with values related to type of tabs */ + ih->data->tabs_type = ITABS_TOP; + ih->data->tabs_orientation = ITABS_HORIZONTAL; + + /* No button is pressed */ + ih->data->tabs_line.button = ITABS_BUTTON_NONE ; + + iTabsUpdateRender(ih); + + return IUP_NOERROR; +} + +static Iclass* iTabsGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "tabs"; + ic->format = "g"; /* array of Ihandle */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILD_ONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iTabsCreateMethod; + ic->Destroy = iTabsDestroyMethod; + ic->Map = iTabsMapMethod; + ic->UnMap = iTabsUnMapMethod; + + ic->ComputeNaturalSize = iTabsComputeNaturalSizeMethod; + ic->SetChildrenCurrentSize = iTabsSetChildrenCurrentSizeMethod; + ic->SetChildrenPosition = iTabsSetChildrenPositionMethod; + + ic->GetInnerContainer = iTabsGetInnerContainerMethod; + ic->ChildAdded = iTabsChildAddedMethod; + ic->ChildRemoved = iTabsChildRemovedMethod; + + /* Do not need to set base attributes because they are inherited from IupCanvas */ + + /* IupTabs Callbacks */ + iupClassRegisterCallback(ic, "TABCHANGE_CB", "nn"); + + /* IupTabs only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", iTabsGetAlignmentAttrib, iTabsSetAlignmentAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABTYPE", iTabsGetTabTypeAttrib, iTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABORIENTATION", iTabsGetTabOrientationAttrib, iTabsSetTabOrientationAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REPAINT", NULL, iTabsSetRepaintAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FONT_ACTIVE", NULL, iTabsSetFontActiveAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FONT_INACTIVE", NULL, iTabsSetFontInactiveAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", iTabsGetValueAttrib, iTabsSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUEPOS", iTabsGetValuePosAttrib, iTabsSetValuePosAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "TABTITLE", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABSIZE", NULL, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iTabsSetFgColorAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iTabsSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iTabsSetBgColorAttrib, NULL, "255 255 255", IUPAF_DEFAULT); /* overwrite canvas implementation, set a system default to force a new default */ + + /* Base Container */ + iupClassRegisterAttribute(ic, "EXPAND", iupBaseContainerGetExpandAttrib, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CLIENTSIZE", iTabsGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* overwrite canvas default */ + + return ic; +} + +void IupOldTabsOpen(void) +{ + iupRegisterClass(iTabsGetClass()); +} diff --git a/iup/srccontrols/iup_oldval.c b/iup/srccontrols/iup_oldval.c new file mode 100755 index 0000000..50dae8a --- /dev/null +++ b/iup/srccontrols/iup_oldval.c @@ -0,0 +1,809 @@ +/** \file + * \brief Valuator Control. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupcontrols.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" +#include "iup_register.h" + + + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + /* mouse interaction control */ + int moving; + + /* visual appearance control */ + int w,h; + long bgcolor, + light_shadow, + mid_shadow, + dark_shadow; + int has_focus; + + /* attributes */ + int type; + int show_ticks; + double val, + step, + pagestep, + vmin, + vmax; + + unsigned char* himage; + int himage_w; + int himage_h; + long int* himage_colors; + int himage_numcolors; + + unsigned char* himageinactive; + int himageinactive_w; + int himageinactive_h; + long int* himageinactive_colors; + int himageinactive_numcolors; + + /* drawing canvas */ + cdCanvas *cddbuffer; + cdCanvas *cdcanvas; + + /* Internal methods */ + void (*Draw)(Ihandle* ih); + void (*CalcPosition)(Ihandle*,int,int); +}; + +#define IVAL_HANDLER_LONG 22 /* handler long side */ +#define IVAL_HANDLER_SHORT 16 /* handler short side */ +#define IVAL_TRAIL 4 /* with of the trail */ +#define IVAL_TICK 3 /* size of the tick mark */ +#define IVAL_TRAIL_START (IVAL_HANDLER_LONG/2+1) +#define IVAL_TRAIL_END(_s) (_s-1-IVAL_HANDLER_LONG/2-1) +#define IVAL_TRAIL_LONG(_s) (_s-1-IVAL_HANDLER_LONG-1) + +enum {IVAL_VERTICAL, IVAL_HORIZONTAL}; + +static void iValUpdateImageBgColor(long int* colors, int num_colors, long bgcolor) +{ + int c; + for (c = 0; c < num_colors; c++) + { + if (*colors == -1) + *colors = bgcolor; + colors++; + } + +} + +static void iValSetImage(const char* name, unsigned char** image_out, long int** color_out, + int* w_out, int* h_out, int* numcolors_out) +{ + int x, y, c, width, height, max_color = 0; + unsigned char* image_data; + Ihandle *img = IupGetHandle(name); + + *w_out = width = img->currentwidth; + *h_out = height = img->currentheight; + image_data = (unsigned char*)IupGetAttribute(img, "WID"); + + *image_out = (unsigned char*) realloc(*image_out, width*height*sizeof(unsigned char)); + *color_out = (long int*) realloc(*color_out, 256*sizeof(long int)); + + for(y = height-1 ; y >=0 ; y--) + { + for(x = 0 ; x < width ; x++) + { + (*image_out)[x+width*y] = *image_data; + if (*image_data > max_color) + max_color = *image_data; + image_data++; + } + } + + max_color++; + *numcolors_out = max_color; + + for(c = 0 ; c < max_color; c++) + { + char colorstr[30]; + char *value; + sprintf(colorstr, "%d", c); + value = iupAttribGet(img, colorstr); + if (iupStrEqualNoCase(value, "BGCOLOR")) + (*color_out)[c] = -1; + else + (*color_out)[c] = cdIupConvertColor(value); + } +} + +static void iValRepaint(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 iValDrawVerticalTick(Ihandle* ih, int y) +{ + cdIupDrawHorizSunkenMark(ih->data->cddbuffer, 1, 1+IVAL_TICK, y, ih->data->light_shadow, ih->data->dark_shadow); + cdIupDrawHorizSunkenMark(ih->data->cddbuffer, ih->data->w-2-IVAL_TICK, ih->data->w-2, y, ih->data->light_shadow, ih->data->dark_shadow); +} + +static void iValDrawHorizontalTick(Ihandle* ih, int x) +{ + + cdIupDrawVertSunkenMark(ih->data->cddbuffer, x, 1, 1+IVAL_TICK, ih->data->light_shadow, ih->data->dark_shadow); + cdIupDrawVertSunkenMark(ih->data->cddbuffer, x, ih->data->h-2-IVAL_TICK, ih->data->h-2, ih->data->light_shadow, ih->data->dark_shadow); +} + +static void iValDrawVerticalTicks(Ihandle* ih) +{ + int i; + for (i = 0; i < ih->data->show_ticks-1; i++) + { + iValDrawVerticalTick(ih, (i*(IVAL_TRAIL_LONG(ih->data->h)-2))/(ih->data->show_ticks-1) + IVAL_TRAIL_START+1); + } + + iValDrawVerticalTick(ih, IVAL_TRAIL_END(ih->data->h)); +} + +static void iValDrawHorizontalTicks(Ihandle* ih) +{ + int i; + for (i = 0; i < ih->data->show_ticks-1; i++) + { + iValDrawHorizontalTick(ih, (i*(IVAL_TRAIL_LONG(ih->data->w)-2))/(ih->data->show_ticks-1) + IVAL_TRAIL_START+1); + } + + iValDrawHorizontalTick(ih, IVAL_TRAIL_END(ih->data->w)); +} + +static void iValDrawVertical(Ihandle* ih) +{ + int y, x = (ih->data->w-IVAL_TRAIL)/2; + double vn = (ih->data->val-ih->data->vmin)/(ih->data->vmax-ih->data->vmin); + + /* trail */ + cdIupDrawSunkenRect(ih->data->cddbuffer, x, IVAL_TRAIL_START, x+IVAL_TRAIL-1, IVAL_TRAIL_END(ih->data->h)+1, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + if (ih->data->show_ticks > 2) + iValDrawVerticalTicks(ih); + + if (iupdrvIsActive(ih) && ih->data->himage) + { + x = (ih->data->w - ih->data->himage_w)/2; + y = (int)(vn*(IVAL_TRAIL_LONG(ih->data->h)-2) + IVAL_TRAIL_START+1); + cdCanvasPutImageRectMap(ih->data->cddbuffer,ih->data->himage_w, ih->data->himage_h, ih->data->himage, ih->data->himage_colors, + x, y-ih->data->himage_h/2, 0,0,0,0,0,0); + } + else if (!iupdrvIsActive(ih) && ih->data->himageinactive) + { + x = (ih->data->w - ih->data->himageinactive_w)/2; + y = (int)(vn*(IVAL_TRAIL_LONG(ih->data->h)-2) + IVAL_TRAIL_START+1); + cdCanvasPutImageRectMap(ih->data->cddbuffer,ih->data->himageinactive_w, ih->data->himageinactive_h, ih->data->himageinactive, + ih->data->himageinactive_colors, x, y-ih->data->himageinactive_h/2, 0,0,0,0,0,0); + } + else + { + /* handler border */ + x = (ih->data->w-IVAL_HANDLER_SHORT)/2; + y = (int)(vn*(IVAL_TRAIL_LONG(ih->data->h)-2) + IVAL_TRAIL_START+1); + cdIupDrawRaisenRect(ih->data->cddbuffer, x, y-IVAL_HANDLER_LONG/2-1, x+IVAL_HANDLER_SHORT-1, y+IVAL_HANDLER_LONG/2, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + /* handler background */ + cdCanvasForeground(ih->data->cddbuffer, ih->data->bgcolor ); + cdCanvasBox(ih->data->cddbuffer,x+1, x+IVAL_HANDLER_SHORT-1-2, y-IVAL_HANDLER_LONG/2+1, y+IVAL_HANDLER_LONG/2-1); + + /* handler sunken mark */ + cdIupDrawHorizSunkenMark(ih->data->cddbuffer, x+2, x+IVAL_HANDLER_SHORT-4, y, ih->data->light_shadow, ih->data->dark_shadow); + } +} + +static void iValDrawHorizontal(Ihandle* ih) +{ + int x, y = (ih->data->h-IVAL_TRAIL)/2; + double vn = (ih->data->val-ih->data->vmin)/(ih->data->vmax-ih->data->vmin); + + /* trail */ + cdIupDrawSunkenRect(ih->data->cddbuffer, IVAL_TRAIL_START, y, IVAL_TRAIL_END(ih->data->w)+1, y+IVAL_TRAIL-1, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + if (ih->data->show_ticks > 2) + iValDrawHorizontalTicks(ih); + + if (iupdrvIsActive(ih) && ih->data->himage) + { + y = (ih->data->h - ih->data->himage_h)/2+1; + x = (int)(vn*(IVAL_TRAIL_LONG(ih->data->w)-2) + IVAL_TRAIL_START+1); + cdCanvasPutImageRectMap(ih->data->cddbuffer,ih->data->himage_w, ih->data->himage_h, ih->data->himage, ih->data->himage_colors, + x-ih->data->himage_w/2, y, 0,0,0,0,0,0); + } + else if (!iupdrvIsActive(ih) && ih->data->himageinactive) + { + y = (ih->data->h - ih->data->himageinactive_h)/2+1; + x = (int)(vn*(IVAL_TRAIL_LONG(ih->data->w)-2) + IVAL_TRAIL_START+1); + cdCanvasPutImageRectMap(ih->data->cddbuffer,ih->data->himageinactive_w, ih->data->himageinactive_h, ih->data->himageinactive, ih->data->himageinactive_colors, + x-ih->data->himageinactive_w/2, y, 0,0,0,0,0,0); + } + else + { + /* handler border */ + y = (ih->data->h-IVAL_HANDLER_SHORT)/2; + x = (int)(vn*(IVAL_TRAIL_LONG(ih->data->w)-2) + IVAL_TRAIL_START+1); + cdIupDrawRaisenRect(ih->data->cddbuffer, x-IVAL_HANDLER_LONG/2-1, y, x+IVAL_HANDLER_LONG/2, y+IVAL_HANDLER_SHORT-1, + ih->data->light_shadow, ih->data->mid_shadow, ih->data->dark_shadow); + + /* handler background */ + cdCanvasForeground(ih->data->cddbuffer, ih->data->bgcolor ); + cdCanvasBox(ih->data->cddbuffer,x-IVAL_HANDLER_LONG/2, x+IVAL_HANDLER_LONG/2-2, y+1, y+IVAL_HANDLER_SHORT-1-2); + + /* handler sunken mark */ + cdIupDrawVertSunkenMark(ih->data->cddbuffer, x, y+3, y+IVAL_HANDLER_SHORT-3, ih->data->light_shadow, ih->data->dark_shadow); + } +} + +static void iValCropValue(Ihandle* ih) +{ + if (ih->data->val > ih->data->vmax) + ih->data->val = ih->data->vmax; + else if (ih->data->val < ih->data->vmin) + ih->data->val = ih->data->vmin; +} + +static void iValSetVerticalPosition(Ihandle* ih, int x, int y) +{ + double vn; + (void)x; + y = cdIupInvertYAxis(y, ih->data->h); + vn = ((double)(y-IVAL_TRAIL_START))/((double)IVAL_TRAIL_LONG(ih->data->h)); + ih->data->val = vn*(ih->data->vmax-ih->data->vmin) + ih->data->vmin; + iValCropValue(ih); + iValRepaint(ih); +} + +static void iValSetHorizontalPosition(Ihandle* ih, int x, int y) +{ + double vn; + (void)y; + vn = ((double)(x-IVAL_TRAIL_START))/((double)IVAL_TRAIL_LONG(ih->data->w)); + ih->data->val = vn*(ih->data->vmax-ih->data->vmin) + ih->data->vmin; + iValCropValue(ih); + iValRepaint(ih); +} + +static int iValMotion_CB(Ihandle *ih,int x,int y,char *r) +{ + IFnd cb; + + if (!iup_isbutton1(r)) return IUP_DEFAULT; + if (!ih->data->moving) return IUP_DEFAULT; + + ih->data->CalcPosition(ih,x,y); + + cb = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + if (cb) cb(ih,ih->data->val); + + return IUP_DEFAULT; +} + +static int iValButton_CB(Ihandle *ih,int b,int m,int x,int y) +{ + char* cb_name; + IFnd cb; + if (b!=IUP_BUTTON1) return IUP_DEFAULT; + + if (m) + { + ih->data->CalcPosition(ih, x, y); + ih->data->moving = 1; + cb_name = "BUTTON_PRESS_CB"; + } + else + { + if (!ih->data->moving) return IUP_DEFAULT; + + iValRepaint(ih); + ih->data->moving = 0; + + cb_name = "BUTTON_RELEASE_CB"; + } + + cb = (IFnd) IupGetCallback(ih, cb_name); + if (cb) cb(ih,ih->data->val); + + return IUP_DEFAULT; +} + +static int iValResize_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 render */ + cdCanvasBackground(ih->data->cddbuffer, ih->data->bgcolor); + cdCanvasClear(ih->data->cddbuffer); + ih->data->Draw(ih); + + return IUP_DEFAULT; +} + +static int iValRedraw_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 iValFocus_CB (Ihandle* ih, int focus) +{ + ih->data->has_focus = focus; + iValRepaint(ih); + return IUP_DEFAULT; +} + +static int iValKeypress_CB(Ihandle *ih, int c, int press) +{ + char* cb_name; + IFnd cb; + + if (c != K_LEFT && c != K_UP && + c != K_PGDN && c != K_PGUP && + c != K_RIGHT && c != K_DOWN && + c != K_END && c != K_HOME && + c != K_sLEFT && c != K_sUP && + c != K_sPGDN && c != K_sPGUP && + c != K_sRIGHT && c != K_sDOWN && + c != K_sEND && c != K_sHOME) + return IUP_DEFAULT; + + if (press) + { + switch(c) + { + case K_sHOME: + case K_HOME: + ih->data->val = ih->data->vmax; + break; + case K_sEND: + case K_END: + ih->data->val = ih->data->vmin; + break; + case K_sLEFT: + case K_sDOWN: + case K_LEFT: + case K_DOWN: + ih->data->val -= ih->data->step*(ih->data->vmax-ih->data->vmin); + iValCropValue(ih); + break; + case K_sRIGHT: + case K_sUP: + case K_RIGHT: + case K_UP: + ih->data->val += ih->data->step*(ih->data->vmax-ih->data->vmin); + iValCropValue(ih); + break; + case K_sPGDN: + case K_PGDN: + ih->data->val -= ih->data->pagestep*(ih->data->vmax-ih->data->vmin); + iValCropValue(ih); + break; + case K_sPGUP: + case K_PGUP: + ih->data->val += ih->data->pagestep*(ih->data->vmax-ih->data->vmin); + iValCropValue(ih); + break; + } + + if (fabs(ih->data->val-ih->data->vmin) < 0.9*ih->data->step*(ih->data->vmax-ih->data->vmin)) + ih->data->val = ih->data->vmin; + + if (ih->data->moving) + cb_name = "MOUSEMOVE_CB"; + else + { + ih->data->moving = 1; + cb_name = "BUTTON_PRESS_CB"; + } + } + else + { + ih->data->moving = 0; + cb_name = "BUTTON_RELEASE_CB"; + } + + iValRepaint(ih); + + cb = (IFnd) IupGetCallback(ih, cb_name); + if (cb) cb(ih,ih->data->val); + + return IUP_IGNORE; /* to avoid arrow keys being processed by the system */ +} + +static int iValWheel_CB(Ihandle *ih, float delta) +{ + IFnd cb; + + ih->data->val += ((double)delta)*ih->data->step*(ih->data->vmax-ih->data->vmin); + iValCropValue(ih); + + if (fabs(ih->data->val-ih->data->vmin) < 0.9*ih->data->step*(ih->data->vmax-ih->data->vmin)) + ih->data->val = ih->data->vmin; + + iValRepaint(ih); + + cb = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB"); + if (cb) cb(ih,ih->data->val); + + cb = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB"); + if (cb) cb(ih,ih->data->val); + + return IUP_DEFAULT; +} + + +/*******************************************************************************/ + + +static int iValSetTypeAttrib(Ihandle* ih, const char *value) +{ + /* valid only before map */ + if (ih->handle) + return 0; + + if (iupStrEqualNoCase(value, "VERTICAL")) + { + IupSetAttribute(ih, "RASTERSIZE", "28x124"); + + ih->data->Draw = iValDrawVertical; + ih->data->CalcPosition = iValSetVerticalPosition; + ih->data->type = IVAL_VERTICAL; + } + else /* "HORIZONTAL" */ + { + IupSetAttribute(ih, "RASTERSIZE", "124x28"); + + ih->data->Draw = iValDrawHorizontal; + ih->data->CalcPosition = iValSetHorizontalPosition; + ih->data->type = IVAL_HORIZONTAL; + } + + return 0; /* do not store value in hash table */ +} + +static char* iValGetTypeAttrib(Ihandle* ih) +{ + if (ih->data->type == IVAL_HORIZONTAL) + return "HORIZONTAL"; + else /* (ih->data->type == IVAL_VERTICAL) */ + return "VERTICAL"; +} + +static char* iValGetValueAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->val); + return str; +} + +static int iValSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) + ih->data->val = 0; + else + ih->data->val = atof(value); + iValCropValue(ih); + iValRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static int iValSetShowTicksAttrib(Ihandle* ih, const char* showticks) +{ + int i; + if (iupStrToInt(showticks, &i)) + { + ih->data->show_ticks = i; + iValRepaint(ih); + } + return 0; /* do not store value in hash table */ +} + +static char* iValGetShowTicksAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%d", ih->data->show_ticks); + return str; +} + +static int iValSetStepAttrib(Ihandle* ih, const char* step) +{ + ih->data->step = atof(step); + iValRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iValGetStepAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->step); + return str; +} + +static int iValSetPageStepAttrib(Ihandle* ih, const char* pagestep) +{ + ih->data->step = atof(pagestep); + iValRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iValGetPageStepAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->pagestep); + return str; +} + +static int iValSetMaxAttrib(Ihandle* ih, const char* max) +{ + ih->data->vmax = atof(max); + iValCropValue(ih); + iValRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iValGetMaxAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->vmax); + return str; +} + +static int iValSetMinAttrib(Ihandle* ih, const char* min) +{ + ih->data->vmin = atof(min); + iValCropValue(ih); + iValRepaint(ih); + return 0; /* do not store value in hash table */ +} + +static char* iValGetMinAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(20); + sprintf(str, "%f", ih->data->vmin); + return str; +} + +static int iValSetHandlerImageAttrib(Ihandle* ih, const char* value) +{ + if (!value) + { + if (ih->data->himage) + { + free(ih->data->himage); + free(ih->data->himage_colors); + ih->data->himage = NULL; + ih->data->himage_colors = NULL; + } + } + else + { + iValSetImage(value, &(ih->data->himage), &(ih->data->himage_colors), + &(ih->data->himage_w), &(ih->data->himage_h), &(ih->data->himage_numcolors)); + } + + iValRepaint(ih); + return 1; +} + +static int iValSetHandlerImageInactiveAttrib(Ihandle* ih, const char* value) +{ + if (value==NULL) + { + if (ih->data->himageinactive) + { + free(ih->data->himageinactive); + free(ih->data->himageinactive_colors); + ih->data->himageinactive = NULL; + ih->data->himageinactive_colors = NULL; + } + } + else + { + iValSetImage(value, &(ih->data->himageinactive), &(ih->data->himageinactive_colors), + &(ih->data->himageinactive_w), &(ih->data->himageinactive_h), &(ih->data->himageinactive_numcolors)); + } + + iValRepaint(ih); + return 1; +} + +static int iValSetBgColorAttrib(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->himage) + ih->data->light_shadow = ih->data->mid_shadow; + + if (ih->data->himage) + iValUpdateImageBgColor(ih->data->himage_colors, ih->data->himage_numcolors, ih->data->bgcolor); + if (ih->data->himageinactive) + iValUpdateImageBgColor(ih->data->himageinactive_colors, ih->data->himageinactive_numcolors, ih->data->bgcolor); + + iValRepaint(ih); + return 1; +} + +static int iValSetActiveAttrib(Ihandle* ih, const char* value) +{ + iupBaseSetActiveAttrib(ih, value); + + cdIupCalcShadows(ih->data->bgcolor, &ih->data->light_shadow, &ih->data->mid_shadow, &ih->data->dark_shadow); + if (!iupdrvIsActive(ih) && !ih->data->himage) + ih->data->light_shadow = ih->data->mid_shadow; + + iValRepaint(ih); + return 0; /* do not store value in hash table */ +} + + +/************************************************************************************/ + + +static int iValMapMethod(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 iValUnMapMethod(Ihandle* ih) +{ + if (ih->data->cddbuffer) + cdKillCanvas(ih->data->cddbuffer); + + if (ih->data->cdcanvas) + cdKillCanvas(ih->data->cdcanvas); +} + +static void iValDestroyMethod(Ihandle* ih) +{ + if (ih->data->himage) free(ih->data->himage); + if (ih->data->himage_colors) free(ih->data->himage_colors); + if (ih->data->himageinactive) free(ih->data->himageinactive); + if (ih->data->himageinactive_colors) free(ih->data->himageinactive_colors); +} + +static int iValCreateMethod(Ihandle* ih, void **params) +{ + if (params && params[0]) + iupAttribStoreStr(ih, "TYPE", params[0]); + + /* free the data alocated 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 */ + iValSetTypeAttrib(ih, "HORIZONTAL"); + ih->data->vmax = 1; + ih->data->step = 0.01; + ih->data->pagestep = 0.1; + + IupSetCallback(ih,"RESIZE_CB",(Icallback)iValResize_CB); + IupSetCallback(ih,"ACTION",(Icallback)iValRedraw_CB); + IupSetCallback(ih,"BUTTON_CB",(Icallback)iValButton_CB); + IupSetCallback(ih,"MOTION_CB",(Icallback)iValMotion_CB); + IupSetCallback(ih,"FOCUS_CB",(Icallback)iValFocus_CB); + IupSetCallback(ih,"WHEEL_CB",(Icallback)iValWheel_CB); + IupSetCallback(ih,"KEYPRESS_CB",(Icallback)iValKeypress_CB); + + return IUP_NOERROR; +} + +static Iclass* iValGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "val"; + ic->format = "S"; /* one optional string */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + + /* Class functions */ + ic->Create = iValCreateMethod; + ic->Destroy = iValDestroyMethod; + ic->Map = iValMapMethod; + ic->UnMap = iValUnMapMethod; + + /* IupVal Callbacks */ + iupClassRegisterCallback(ic, "MOUSEMOVE_CB", "d"); + iupClassRegisterCallback(ic, "BUTTON_PRESS_CB", "d"); + iupClassRegisterCallback(ic, "BUTTON_RELEASE_CB", "d"); + + /* IupVal only */ + iupClassRegisterAttribute(ic, "VALUE", iValGetValueAttrib, iValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TYPE", iValGetTypeAttrib, iValSetTypeAttrib, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "SHOWTICKS", iValGetShowTicksAttrib, iValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "STEP", iValGetStepAttrib, iValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "PAGESTEP", iValGetPageStepAttrib, iValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MAX", iValGetMaxAttrib, iValSetMaxAttrib, IUPAF_SAMEASSYSTEM, "1.0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "MIN", iValGetMinAttrib, iValSetMinAttrib, IUPAF_SAMEASSYSTEM, "0.0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "HANDLER_IMAGE", NULL, iValSetHandlerImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "HANDLER_IMAGE_INACTIVE", NULL, iValSetHandlerImageInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NOT_MAPPED); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iValSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupControlBaseGetBgColorAttrib, iValSetBgColorAttrib, NULL, "255 255 255", IUPAF_NO_INHERIT); /* overwrite canvas implementation, set a system default to force a new default */ + + return ic; +} + +void IupOldValOpen(void) +{ + iupRegisterClass(iValGetClass()); +} diff --git a/iup/srccontrols/iupcontrols.def b/iup/srccontrols/iupcontrols.def new file mode 100755 index 0000000..06c8f6f --- /dev/null +++ b/iup/srccontrols/iupcontrols.def @@ -0,0 +1,35 @@ +EXPORTS +IupColorbar +IupColorBrowser +IupDial +IupGauge +IupCells +IupMatrix +IupMatSetAttribute +IupMatStoreAttribute +IupMatGetAttribute +IupMatGetInt +IupMatGetFloat +IupMatSetfAttribute + +IupControlsOpen +IupControlsClose + +iupmaskSet +iupmaskSetInt +iupmaskSetFloat +iupmaskCheck +iupmaskGet +iupmaskGetFloat +iupmaskGetDouble +iupmaskGetInt +iupmaskMatSet +iupmaskMatSetInt +iupmaskMatSetFloat +iupmaskMatCheck +iupmaskMatGet +iupmaskMatGetFloat +iupmaskMatGetDouble +iupmaskMatGetInt +iupmaskRemove +iupmaskMatRemove diff --git a/iup/srccontrols/iupcontrols.dep b/iup/srccontrols/iupcontrols.dep new file mode 100644 index 0000000..773616a --- /dev/null +++ b/iup/srccontrols/iupcontrols.dep @@ -0,0 +1,173 @@ +$(OBJDIR)/iup_cdutil.o: iup_cdutil.c ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../src/iup_attrib.h ../src/iup_str.h \ + ../src/iup_drv.h iup_cdutil.h +$(OBJDIR)/iup_gauge.o: iup_gauge.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../../cd/include/cdiup.h \ + ../../cd/include/cddbuf.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_drv.h ../src/iup_stdcontrols.h \ + iup_controls.h iup_cdutil.h +$(OBJDIR)/iup_cells.o: iup_cells.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../../cd/include/cdiup.h \ + ../../cd/include/cddbuf.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_drv.h ../src/iup_stdcontrols.h \ + iup_controls.h iup_cdutil.h +$(OBJDIR)/iup_colorbar.o: iup_colorbar.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcontrols.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h \ + ../../cd/include/cdiup.h ../../cd/include/cddbuf.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_drv.h \ + ../src/iup_stdcontrols.h iup_controls.h ../src/iup_image.h iup_cdutil.h +$(OBJDIR)/iup_controls.o: iup_controls.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcontrols.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_childtree.h ../src/iup_register.h iup_controls.h \ + ../src/iup_attrib.h +$(OBJDIR)/iup_dial.o: iup_dial.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../../cd/include/cdiup.h \ + ../../cd/include/cddbuf.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_drv.h ../src/iup_stdcontrols.h \ + iup_controls.h iup_cdutil.h +$(OBJDIR)/iup_oldtabs.o: iup_oldtabs.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../../cd/include/cdiup.h \ + ../../cd/include/cddbuf.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_drv.h ../src/iup_drvfont.h \ + ../src/iup_stdcontrols.h ../src/iup_register.h ../src/iup_layout.h \ + iup_controls.h iup_cdutil.h +$(OBJDIR)/iup_oldval.o: iup_oldval.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h \ + ../../cd/include/cdiup.h ../../cd/include/cddbuf.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_drv.h \ + ../src/iup_stdcontrols.h iup_controls.h iup_cdutil.h \ + ../src/iup_register.h +$(OBJDIR)/iup_oldmask.o: iup_oldmask.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcontrols.h ../include/iupmask.h \ + ../src/iup_mask.h ../src/iup_str.h +$(OBJDIR)/iup_colorbrowser.o: color/iup_colorbrowser.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h \ + ../../cd/include/cdiup.h ../../cd/include/cdirgb.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_drv.h \ + ../src/iup_stdcontrols.h iup_controls.h iup_cdutil.h \ + color/iup_colorhsi.h +$(OBJDIR)/iup_colorhsi.o: color/iup_colorhsi.c color/iup_colorhsi.h +$(OBJDIR)/iup_colorbrowserdlg.o: color/iup_colorbrowserdlg.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../include/iupcontrols.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../../cd/include/cdiup.h \ + ../../cd/include/cddbuf.h ../../cd/include/cdirgb.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_strmessage.h \ + ../src/iup_drv.h ../src/iup_stdcontrols.h iup_controls.h iup_cdutil.h \ + ../src/iup_register.h ../src/iup_image.h color/iup_colorhsi.h \ + ../src/iup_childtree.h +$(OBJDIR)/iupmat_key.o: matrix/iupmat_key.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_stdcontrols.h matrix/iupmat_def.h matrix/iupmat_scroll.h \ + matrix/iupmat_focus.h matrix/iupmat_aux.h matrix/iupmat_getset.h \ + matrix/iupmat_key.h matrix/iupmat_mark.h matrix/iupmat_edit.h \ + matrix/iupmat_draw.h +$(OBJDIR)/iupmat_mark.o: matrix/iupmat_mark.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_stdcontrols.h matrix/iupmat_def.h \ + matrix/iupmat_mark.h matrix/iupmat_getset.h matrix/iupmat_draw.h +$(OBJDIR)/iupmat_aux.o: matrix/iupmat_aux.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_drvfont.h ../src/iup_stdcontrols.h \ + matrix/iupmat_def.h matrix/iupmat_aux.h matrix/iupmat_getset.h +$(OBJDIR)/iupmat_mem.o: matrix/iupmat_mem.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_stdcontrols.h matrix/iupmat_def.h \ + matrix/iupmat_mem.h +$(OBJDIR)/iupmat_mouse.o: matrix/iupmat_mouse.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_stdcontrols.h \ + matrix/iupmat_def.h matrix/iupmat_colres.h matrix/iupmat_aux.h \ + matrix/iupmat_focus.h matrix/iupmat_mouse.h matrix/iupmat_key.h \ + matrix/iupmat_mark.h matrix/iupmat_edit.h matrix/iupmat_draw.h \ + matrix/iupmat_scroll.h +$(OBJDIR)/iupmat_numlc.o: matrix/iupmat_numlc.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_stdcontrols.h \ + matrix/iupmat_def.h matrix/iupmat_edit.h matrix/iupmat_mem.h \ + matrix/iupmat_numlc.h matrix/iupmat_draw.h +$(OBJDIR)/iupmat_colres.o: matrix/iupmat_colres.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_stdcontrols.h \ + matrix/iupmat_def.h matrix/iupmat_colres.h matrix/iupmat_draw.h +$(OBJDIR)/iupmat_draw.o: matrix/iupmat_draw.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../../cd/include/cd.h \ + ../../cd/include/cd_old.h ../src/iup_object.h ../src/iup_class.h \ + ../src/iup_table.h ../src/iup_classbase.h ../src/iup_attrib.h \ + ../src/iup_str.h ../src/iup_drv.h ../src/iup_drvfont.h \ + ../src/iup_stdcontrols.h iup_controls.h iup_cdutil.h ../src/iup_image.h \ + matrix/iupmat_def.h matrix/iupmat_cd.h matrix/iupmat_draw.h \ + matrix/iupmat_aux.h matrix/iupmat_getset.h matrix/iupmat_mark.h +$(OBJDIR)/iupmat_focus.o: matrix/iupmat_focus.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_stdcontrols.h \ + matrix/iupmat_def.h matrix/iupmat_aux.h matrix/iupmat_focus.h \ + matrix/iupmat_draw.h +$(OBJDIR)/iupmat_getset.o: matrix/iupmat_getset.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_drvfont.h ../src/iup_str.h \ + ../src/iup_stdcontrols.h iup_controls.h ../src/iup_childtree.h \ + matrix/iupmat_def.h matrix/iupmat_getset.h matrix/iupmat_edit.h \ + matrix/iupmat_draw.h matrix/iupmat_aux.h +$(OBJDIR)/iupmatrix.o: matrix/iupmatrix.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h \ + ../../cd/include/cdiup.h ../../cd/include/cddbuf.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_drv.h \ + ../src/iup_drvfont.h ../src/iup_stdcontrols.h iup_controls.h \ + ../src/iup_register.h matrix/iupmat_def.h matrix/iupmat_getset.h \ + matrix/iupmat_scroll.h matrix/iupmat_aux.h matrix/iupmat_mem.h \ + matrix/iupmat_mouse.h matrix/iupmat_focus.h matrix/iupmat_key.h \ + matrix/iupmat_numlc.h matrix/iupmat_colres.h matrix/iupmat_mark.h \ + matrix/iupmat_edit.h matrix/iupmat_draw.h +$(OBJDIR)/iupmat_scroll.o: matrix/iupmat_scroll.c ../include/iup.h \ + ../include/iupkey.h ../include/iupdef.h ../include/iupcbs.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_stdcontrols.h matrix/iupmat_def.h matrix/iupmat_scroll.h \ + matrix/iupmat_focus.h matrix/iupmat_aux.h matrix/iupmat_edit.h \ + matrix/iupmat_draw.h +$(OBJDIR)/iupmat_edit.o: matrix/iupmat_edit.c ../include/iup.h ../include/iupkey.h \ + ../include/iupdef.h ../include/iupcbs.h ../include/iupcontrols.h \ + ../../cd/include/cd.h ../../cd/include/cd_old.h ../src/iup_object.h \ + ../src/iup_class.h ../src/iup_table.h ../src/iup_classbase.h \ + ../src/iup_attrib.h ../src/iup_str.h ../src/iup_stdcontrols.h \ + ../src/iup_childtree.h matrix/iupmat_def.h matrix/iupmat_scroll.h \ + matrix/iupmat_aux.h matrix/iupmat_edit.h matrix/iupmat_key.h \ + matrix/iupmat_getset.h matrix/iupmat_draw.h diff --git a/iup/srccontrols/make_uname b/iup/srccontrols/make_uname new file mode 100755 index 0000000..cc4b881 --- /dev/null +++ b/iup/srccontrols/make_uname @@ -0,0 +1,3 @@ +#This builds all the libraries of the folder for 1 uname + +tecmake $1 $2 $3 $4 $5 $6 $7 diff --git a/iup/srccontrols/make_uname.bat b/iup/srccontrols/make_uname.bat new file mode 100755 index 0000000..f0a0722 --- /dev/null +++ b/iup/srccontrols/make_uname.bat @@ -0,0 +1,4 @@ +@echo off +REM This builds all the libraries of the folder for 1 uname + +call tecmake %1 %2 %3 %4 %5 %6 diff --git a/iup/srccontrols/matrix/iupmat_aux.c b/iup/srccontrols/matrix/iupmat_aux.c new file mode 100755 index 0000000..f8b85bb --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_aux.c @@ -0,0 +1,480 @@ +/** \file + * \brief iupmatrix control + * auxiliary functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_aux.h" +#include "iupmat_getset.h" + + +static int iMatrixAuxIsFullVisibleLast(Ihandle* ih, int m) +{ + int i, sum = 0; + ImatLinColData *p; + + if (m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + for(i = p->first; i <= p->last; i++) + sum += p->sizes[i]; + + if (sum > p->visible_size) + return 0; + else + return 1; +} + +int iupMatrixAuxIsCellFullVisible(Ihandle* ih, int lin, int col) +{ + if(((lin >= ih->data->lines.first) && + (lin <= ih->data->lines.last) && + (col >= ih->data->columns.first) && + (col <= ih->data->columns.last))) + { + if (col == ih->data->columns.last && !iMatrixAuxIsFullVisibleLast(ih, IMAT_PROCESS_COL)) + return 0; + if (lin == ih->data->lines.last && !iMatrixAuxIsFullVisibleLast(ih, IMAT_PROCESS_LIN)) + return 0; + + return 1; + } + + return 0; +} + +int iupMatrixAuxIsCellVisible(Ihandle* ih, int lin, int col) +{ + if(((lin >= ih->data->lines.first) && + (lin <= ih->data->lines.last) && + (col >= ih->data->columns.first) && + (col <= ih->data->columns.last))) + { + return 1; + } + + return 0; +} + +void iupMatrixAuxGetVisibleCellDim(Ihandle* ih, int lin, int col, int* x, int* y, int* w, int* h) +{ + int i; + + /* find the position where the column starts */ + *x = ih->data->columns.sizes[0]; + for(i = ih->data->columns.first; i < col; i++) + *x += ih->data->columns.sizes[i]; + + /* find the column size */ + *w = ih->data->columns.sizes[col] - 1; + + /* find the position where the line starts */ + *y = ih->data->lines.sizes[0]; + for(i = ih->data->lines.first; i < lin; i++) + *y += ih->data->lines.sizes[i]; + + /* find the line size */ + *h = ih->data->lines.sizes[lin] - 1; +} + +/* Calculate the size, in pixels, of the invisible columns/lines, + the left/above of the first column/line. + In fact the start position of the visible area. + Depends on the first visible column/line. + -> m : choose will operate on lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixAuxUpdateVisiblePos(Ihandle* ih, int m) +{ + char* POS; + int i, sb, visible_pos; + ImatLinColData *p; + + if (m == IMAT_PROCESS_LIN) + { + p = &(ih->data->lines); + sb = IUP_SB_VERT; + POS = "POSY"; + } + else + { + p = &(ih->data->columns); + sb = IUP_SB_HORIZ; + POS = "POSX"; + } + + visible_pos = 0; + for(i = 1; i < p->first; i++) + visible_pos += p->sizes[i]; + + if (ih->data->canvas.sb & sb) + { + float pos; + + if (p->total_size) + { + while ((visible_pos + p->visible_size > p->total_size) && p->first>1) + { + /* invalid position, must recalculate first */ + p->first--; + visible_pos -= p->sizes[p->first]; + } + + pos = (float)visible_pos/(float)p->total_size; + } + else + pos = 0; + + iupMatrixAuxUpdateLast(p); + IupSetfAttribute(ih, POS, "%.5f", (double)pos); + } + else + iupMatrixAuxUpdateLast(p); +} + +/* Calculate which is the last visible column/line of the matrix. + Depends on the first visible column/line. */ +void iupMatrixAuxUpdateLast(ImatLinColData *p) +{ + int i, sum = 0; + + if (p->visible_size > 0) + { + /* Find which is the last column/line + Start in the first visible and continue adding the widths + up to the visible size */ + for(i = p->first; i < p->num; i++) + { + sum += p->sizes[i]; + if(sum >= p->visible_size) + break; + } + + if (i == p->num) + p->last = i-1; + else + p->last = i; + } + else + { + /* There is no space for any column, set the last column as 0 */ + p->last = 0; + } +} + +int iupMatrixAuxGetColumnWidth(Ihandle* ih, int col) +{ + int width = 0, pixels = 0; + char* str = iupStrGetMemory(100); + char* value; + + /* can only be called for valid columns */ + + sprintf(str, "WIDTH%d", col); + value = iupAttribGet(ih, str); + if (!value) + { + sprintf(str, "RASTERWIDTH%d", col); + value = iupAttribGet(ih, str); + if (value) + pixels = 1; + } + + if (!value) + { + /* Use the titles to define the size */ + if (col == 0) + { + if (!ih->data->callback_mode || ih->data->use_title_size) + { + /* find the largest title */ + int lin, max_width = 0; + for(lin = 0; lin < ih->data->lines.num; lin++) + { + char* title_value = iupMatrixCellGetValue(ih, lin, 0); + if (title_value) + { + iupdrvFontGetMultiLineStringSize(ih, title_value, &width, NULL); + if (width > max_width) + max_width = width; + } + } + width = max_width; + } + } + else if (ih->data->use_title_size) + { + char* title_value = iupMatrixCellGetValue(ih, 0, col); + if (title_value) + iupdrvFontGetMultiLineStringSize(ih, title_value, &width, NULL); + } + if (width) + return width + IMAT_PADDING_W + IMAT_FRAME_W; + + if (col != 0) + value = iupAttribGetStr(ih, "WIDTHDEF"); + } + + if (iupStrToInt(value, &width)) + { + if (width <= 0) + return 0; + else + { + if (pixels) + return width + IMAT_PADDING_W + IMAT_FRAME_W; + else + { + int charwidth; + iupdrvFontGetCharSize(ih, &charwidth, NULL); + return iupWIDTH2RASTER(width, charwidth) + IMAT_PADDING_W + IMAT_FRAME_W; + } + } + } + return 0; +} + +int iupMatrixAuxGetLineHeight(Ihandle* ih, int lin) +{ + int height = 0, pixels = 0; + char* str = iupStrGetMemory(100); + char* value; + + /* can only be called for valid lines */ + + sprintf(str, "HEIGHT%d", lin); + value = iupAttribGet(ih, str); + if(!value) + { + sprintf(str, "RASTERHEIGHT%d", lin); + value = iupAttribGet(ih, str); + if(value) + pixels = 1; + } + + if (!value) + { + /* Use the titles to define the size */ + if (lin == 0) + { + if (!ih->data->callback_mode || ih->data->use_title_size) + { + /* find the highest title */ + int col, max_height = 0; + for(col = 0; col < ih->data->columns.num; col++) + { + char* title_value = iupMatrixCellGetValue(ih, 0, col); + if (title_value && title_value[0]) + { + iupdrvFontGetMultiLineStringSize(ih, title_value, NULL, &height); + if (height > max_height) + max_height = height; + } + } + height = max_height; + } + } + else if (ih->data->use_title_size) + { + char* title_value = iupMatrixCellGetValue(ih, lin, 0); + if (title_value && title_value[0]) + iupdrvFontGetMultiLineStringSize(ih, title_value, NULL, &height); + } + if (height) + return height + IMAT_PADDING_H + IMAT_FRAME_H; + + if (lin != 0) + value = iupAttribGetStr(ih, "HEIGHTDEF"); + } + + if (iupStrToInt(value, &height)) + { + if (height <= 0) + return 0; + else + { + if (pixels) + return height + IMAT_PADDING_H + IMAT_FRAME_H; + else + { + int charheight; + iupdrvFontGetCharSize(ih, NULL, &charheight); + return iupHEIGHT2RASTER(height, charheight) + IMAT_PADDING_H + IMAT_FRAME_H; + } + } + } + return 0; +} + +/* Fill the sizes vector with the width/heigh of all the columns/lines. + Calculate the value of total_size */ +static void iMatrixAuxFillSizeVec(Ihandle* ih, int m) +{ + int i; + ImatLinColData *p; + + if (m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + /* Calculate total width/height of the matrix and the width/height of each column */ + p->total_size = 0; + for(i = 0; i < p->num; i++) + { + if (m == IMAT_PROCESS_LIN) + p->sizes[i] = iupMatrixAuxGetLineHeight(ih, i); + else + p->sizes[i] = iupMatrixAuxGetColumnWidth(ih, i); + + if (i > 0) + p->total_size += p->sizes[i]; + } +} + +static void iMatrixAuxUpdateVisibleSize(Ihandle* ih, int m) +{ + char* D; + ImatLinColData *p; + int canvas_size; + + if (m == IMAT_PROCESS_LIN) + { + D = "DY"; + p = &(ih->data->lines); + canvas_size = ih->data->h; + } + else + { + D = "DX"; + p = &(ih->data->columns); + canvas_size = ih->data->w; + } + + /* Matrix useful area is the current size minus the title area */ + p->visible_size = canvas_size - p->sizes[0]; + if (p->visible_size > p->total_size) + p->visible_size = p->total_size; + + if (p->total_size) + IupSetfAttribute(ih, D, "%f", (double)p->visible_size/(double)p->total_size); + else + IupSetAttribute(ih, D, "1.0"); +} + +void iupMatrixAuxCalcSizes(Ihandle* ih) +{ + iMatrixAuxFillSizeVec(ih, IMAT_PROCESS_COL); + iMatrixAuxFillSizeVec(ih, IMAT_PROCESS_LIN); + + iMatrixAuxUpdateVisibleSize(ih, IMAT_PROCESS_COL); + iMatrixAuxUpdateVisibleSize(ih, IMAT_PROCESS_LIN); + + /* when removing lines the first can be positioned after the last line */ + if (ih->data->lines.first > ih->data->lines.num-1) + { + if (ih->data->lines.num==1) + ih->data->lines.first = 1; + else + ih->data->lines.first = ih->data->lines.num-1; + } + if (ih->data->columns.first > ih->data->columns.num-1) + { + if (ih->data->columns.num == 1) + ih->data->columns.first = 1; + else + ih->data->columns.first = ih->data->columns.num-1; + } + + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); + + ih->data->need_calcsize = 0; +} + +int iupMatrixAuxGetLinColFromXY(Ihandle* ih, int x, int y, int* l, int* c) +{ + int size, lin, col; + + size = ih->data->columns.sizes[0]; /* always visible when non zero */ + if (x < size) + col = 0; /* It is in the column of titles */ + else + { + for(col = ih->data->columns.first; col <= ih->data->columns.last; col++) /* for all visible columns */ + { + size += ih->data->columns.sizes[col]; + if (x < size) + break; + } + if (col > ih->data->columns.last) + col = -1; + } + + size = ih->data->lines.sizes[0]; /* always visible when non zero */ + if (y < size) + lin = 0; /* It is in the line of titles */ + else + { + for(lin = ih->data->lines.first; lin <= ih->data->lines.last; lin++) /* for all visible lines */ + { + size += ih->data->lines.sizes[lin]; + if (y < size) + break; + } + if(lin > ih->data->lines.last) + lin = -1; + } + + if (col == -1 || lin == -1) + return 0; + + *l = lin; + *c = col; + return 1; +} + +int iupMatrixAuxCallLeaveCellCb(Ihandle* ih) +{ + IFnii cb = (IFnii)IupGetCallback(ih, "LEAVEITEM_CB"); + if(cb) + return cb(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); + return IUP_DEFAULT; +} + +void iupMatrixAuxCallEnterCellCb(Ihandle* ih) +{ + IFnii cb = (IFnii)IupGetCallback(ih, "ENTERITEM_CB"); + if (cb) + cb(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); +} + +int iupMatrixAuxCallEditionCbLinCol(Ihandle* ih, int lin, int col, int mode, int update) +{ + IFniiii cb; + + if (iupAttribGetBoolean(ih, "READONLY")) + return IUP_IGNORE; + + cb = (IFniiii)IupGetCallback(ih, "EDITION_CB"); + if(cb) + return cb(ih, lin, col, mode, update); + return IUP_DEFAULT; +} diff --git a/iup/srccontrols/matrix/iupmat_aux.h b/iup/srccontrols/matrix/iupmat_aux.h new file mode 100755 index 0000000..296c1f5 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_aux.h @@ -0,0 +1,37 @@ +/** \file + * \brief iupmatrix control + * auxiliary functions. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_AUX_H +#define __IUPMAT_AUX_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixAuxIsCellFullVisible(Ihandle* ih, int lin, int col); +int iupMatrixAuxIsCellVisible(Ihandle* ih, int lin, int col); +void iupMatrixAuxGetVisibleCellDim (Ihandle* ih, int lin, int col, int* x, int* y, int* w, int* h); + +void iupMatrixAuxCalcSizes(Ihandle* ih); + +void iupMatrixAuxUpdateVisiblePos(Ihandle* ih, int m); +void iupMatrixAuxUpdateLast(ImatLinColData *p); + +int iupMatrixAuxGetColumnWidth(Ihandle* ih, int col); +int iupMatrixAuxGetLineHeight (Ihandle* ih, int lin); + +int iupMatrixAuxGetLinColFromXY (Ihandle* ih, int x, int y, int* l, int* c); + +int iupMatrixAuxCallLeaveCellCb (Ihandle* ih); +void iupMatrixAuxCallEnterCellCb (Ihandle* ih); +int iupMatrixAuxCallEditionCbLinCol(Ihandle* ih, int lin, int col, int mode, int update); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_cd.h b/iup/srccontrols/matrix/iupmat_cd.h new file mode 100755 index 0000000..1a10f2b --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_cd.h @@ -0,0 +1,25 @@ +/** \file + * \brief iupmatrix. CD help macros. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_CD_H +#define __IUPMAT_CD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define IUPMAT_LINE(_ih,_x1,_y1,_x2,_y2) cdCanvasLine((_ih)->data->cddbuffer, (_x1), iupMatrixInvertYAxis(_ih, _y1), (_x2), iupMatrixInvertYAxis(_ih, _y2)) +#define IUPMAT_VERTEX(_ih,_x,_y) cdCanvasVertex((_ih)->data->cddbuffer, (_x), iupMatrixInvertYAxis(_ih, _y)) +#define IUPMAT_BOX(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasBox((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMatrixInvertYAxis(_ih, _ymin), iupMatrixInvertYAxis(_ih, _ymax)) +#define IUPMAT_RECT(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasRect((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMatrixInvertYAxis(_ih, _ymin), iupMatrixInvertYAxis(_ih, _ymax)) +#define IUPMAT_CLIPAREA(_ih,_xmin,_xmax,_ymin,_ymax) cdCanvasClipArea((_ih)->data->cddbuffer, (_xmin), (_xmax), iupMatrixInvertYAxis(_ih, _ymin), iupMatrixInvertYAxis(_ih, _ymax)) +#define IUPMAT_TEXT(_ih,_x,_y,_text) cdCanvasText((_ih)->data->cddbuffer, (_x), iupMatrixInvertYAxis(_ih, _y), (_text)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_colres.c b/iup/srccontrols/matrix/iupmat_colres.c new file mode 100755 index 0000000..d44b7df --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_colres.c @@ -0,0 +1,182 @@ +/** \file + * \brief iupmatrix column resize + * + * See Copyright Notice in "iup.h" + */ + +/**************************************************************************/ +/* Interactive Column Resize Functions and WIDTH/HEIGHT change */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_colres.h" +#include "iupmat_draw.h" + + +#define IMAT_COLRES_TOL 3 +#define IMAT_RESIZE_COLOR 0x666666L + + +/* Verify if the mouse is in the intersection between two of column titles, + if so the resize is started */ +int iupMatrixColResStart(Ihandle* ih, int x, int y) +{ + if (ih->data->lines.sizes[0] && y < ih->data->lines.sizes[0] && iupAttribGetBoolean(ih, "RESIZEMATRIX")) + { + int size, col; + + /* Check if is the column of titles */ + size = ih->data->columns.sizes[0]; + if (abs(size-x) < IMAT_COLRES_TOL) + { + ih->data->colres_drag_col_start_x = 0; + ih->data->colres_dragging = 1; + ih->data->colres_drag_col_last_x = -1; + ih->data->colres_drag_col = 0; + return 1; + } + else + { + /* find the column */ + for(col = ih->data->columns.first; col <= ih->data->columns.last; col++) + { + ih->data->colres_drag_col_start_x = size; + size += ih->data->columns.sizes[col]; + if (abs(size-x) < IMAT_COLRES_TOL) + { + ih->data->colres_dragging = 1; + ih->data->colres_drag_col_last_x = -1; + ih->data->colres_drag_col = col; + return 1; + } + } + } + } + return 0; +} + +void iupMatrixColResFinish(Ihandle* ih, int x) +{ + char str[100]; + int width = x - ih->data->colres_drag_col_start_x; + if (width < 0) + width = 0; + + /* delete feedback */ + if (ih->data->colres_drag_col_last_x != -1) + { + int y1 = ih->data->lines.sizes[0]; /* from the bottom of the line of titles */ + int y2 = ih->data->h-1; /* to the bottom of the matrix */ + + cdCanvasWriteMode(ih->data->cdcanvas, CD_XOR); + cdCanvasForeground(ih->data->cdcanvas, IMAT_RESIZE_COLOR); + cdCanvasLine(ih->data->cdcanvas, ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y1), + ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y2)); + cdCanvasWriteMode(ih->data->cdcanvas, CD_REPLACE); + } + + ih->data->colres_dragging = 0; + + sprintf(str, "RASTERWIDTH%d", ih->data->colres_drag_col); + iupAttribSetInt(ih, str, width-IMAT_PADDING_W-IMAT_FRAME_W); + sprintf(str, "WIDTH%d", ih->data->colres_drag_col); + iupAttribSetStr(ih, str, NULL); + + ih->data->need_calcsize = 1; + iupMatrixDraw(ih, 0); +} + +/* Change the column width interactively, just change the line in the screen. + When the user finishes the drag, the iupMatrixColResFinish function is called + to truly change the column width. */ +void iupMatrixColResMove(Ihandle* ih, int x) +{ + int y1, y2; + + int width = x - ih->data->colres_drag_col_start_x; + if (width < 0) + return; + + y1 = ih->data->lines.sizes[0]; /* from the bottom of the line of titles */ + y2 = ih->data->h-1; /* to the bottom of the matrix */ + + cdCanvasWriteMode(ih->data->cdcanvas, CD_XOR); + cdCanvasForeground(ih->data->cdcanvas, IMAT_RESIZE_COLOR); + + /* If it is not the first time, move old line */ + if (ih->data->colres_drag_col_last_x != -1) + { + cdCanvasLine(ih->data->cdcanvas, ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y1), + ih->data->colres_drag_col_last_x, iupMatrixInvertYAxis(ih, y2)); + } + + cdCanvasLine(ih->data->cdcanvas, x, iupMatrixInvertYAxis(ih, y1), + x, iupMatrixInvertYAxis(ih, y2)); + + ih->data->colres_drag_col_last_x = x; + cdCanvasWriteMode(ih->data->cdcanvas, CD_REPLACE); +} + + +static void iMatrixColResResetMatrixCursor(Ihandle* ih) +{ + char *cursor = iupAttribGet(ih, "_IUPMAT_CURSOR"); + if (cursor) + { + IupStoreAttribute(ih, "CURSOR", cursor); + iupAttribSetStr(ih, "_IUPMAT_CURSOR", NULL); + } +} + +/* Change the cursor when it passes over a group of the column titles. */ +void iupMatrixColResCheckChangeCursor(Ihandle* ih, int x, int y) +{ + if(ih->data->lines.sizes[0] && y < ih->data->lines.sizes[0] && iupAttribGetBoolean(ih, "RESIZEMATRIX")) + { + /* It is in the column titles area and the resize mode is on */ + int found = 0, size, col; + + size = ih->data->columns.sizes[0]; + if (abs(size - x) < IMAT_COLRES_TOL) + found = 1; /* line titles */ + else + { + for(col = ih->data->columns.first; col <= ih->data->columns.last && !found; col++) + { + size += ih->data->columns.sizes[col]; + if(abs(size - x) < IMAT_COLRES_TOL) + found = 1; + } + } + + if (found) + { + if (!iupAttribGet(ih, "_IUPMAT_CURSOR")) + iupAttribStoreStr(ih, "_IUPMAT_CURSOR", IupGetAttribute(ih, "CURSOR")); + IupSetAttribute(ih, "CURSOR", "RESIZE_W"); + } + else /* It is in the empty area after the last column */ + iMatrixColResResetMatrixCursor(ih); + } + else + iMatrixColResResetMatrixCursor(ih); +} + +int iupMatrixColResIsResizing(Ihandle* ih) +{ + return ih->data->colres_dragging; +} + diff --git a/iup/srccontrols/matrix/iupmat_colres.h b/iup/srccontrols/matrix/iupmat_colres.h new file mode 100755 index 0000000..ba7f23d --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_colres.h @@ -0,0 +1,24 @@ +/** \file + * \brief iupmatrix column resize. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_COLRES_H +#define __IUPMAT_COLRES_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixColResStart (Ihandle* ih, int x, int y); +void iupMatrixColResFinish (Ihandle* ih, int x); +void iupMatrixColResMove (Ihandle* ih, int x); +void iupMatrixColResCheckChangeCursor(Ihandle* ih, int x, int y); +int iupMatrixColResIsResizing (Ihandle* ih); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_def.h b/iup/srccontrols/matrix/iupmat_def.h new file mode 100755 index 0000000..d45acde --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_def.h @@ -0,0 +1,122 @@ +/** \file + * \brief iupmatrix. definitions. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_DEF_H +#define __IUPMAT_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define IMAT_PROCESS_COL 1 /* Process the columns */ +#define IMAT_PROCESS_LIN 2 /* Process the lines */ + +/***************************************************************************/ +/* Decoration size in pixels */ +/***************************************************************************/ +#define IMAT_PADDING_W 6 +#define IMAT_PADDING_H 6 +#define IMAT_FRAME_W 2 +#define IMAT_FRAME_H 2 + +/* Cell flags */ +#define IUPMAT_FONT 1 /* Has FONTL:C attribute */ +#define IUPMAT_FGCOLOR 2 /* Has FGCOLORL:C attribute */ +#define IUPMAT_BGCOLOR 4 /* Has BGCOLORL:C attribute */ +#define IUPMAT_MARK 8 /* Is marked */ +#define IUPMAT_FRAMEHCOLOR 16 /* Has FRAMEHORIZCOLORL:C */ +#define IUPMAT_FRAMEVCOLOR 32 /* Has FRAMEVERTCOLORL:C */ + +/***************************************************************************/ +/* Structures stored in each matrix */ +/***************************************************************************/ +typedef struct _ImatCell +{ + char *value; /* Cell value */ + unsigned char flags; +} ImatCell; + + +typedef struct _ImatLinColData +{ + int* sizes; /* Width/height of the columns/lines (allocated after map) */ + unsigned char* flags; /* Attribute flags for the columns/lines (allocated after map) */ + + int num; /* Number of columns/lines in the matrix, default/minimum=1, always includes the title */ + int num_alloc; /* Number of columns/lines allocated, default=5 */ + + int first; /* First visible column/line */ + int last; /* Last visible column/line */ + + /* used to configure the scrollbar */ + int total_size; /* Sum of the widths/heights of the columns/lines, not including the title */ + int visible_size; /* Width/height of the visible window, not including the title */ + + int focus_cell; /* index of the current cell */ +} ImatLinColData; + +struct _IcontrolData +{ + iupCanvas canvas; /* from IupCanvas (must reserve it) */ + + ImatCell** cells; /* Cell value, this will be NULL if in callback mode (allocated after map) */ + + Ihandle* texth; /* Text handle */ + Ihandle* droph; /* Dropdown handle */ + Ihandle* datah; /* Current active edition element, may be equal to texth or droph */ + + cdCanvas* cddbuffer; + cdCanvas* cdcanvas; + + ImatLinColData lines; + ImatLinColData columns; + + int has_focus; + int w, h; /* canvas size */ + int callback_mode; + int use_title_size; /* use title contents when calculating cell size */ + int need_calcsize; + int first_redraw; + + /* attributes */ + int mark_continuous, mark_mode, mark_multiple; + int checkframecolor; + + /* Mouse and Keyboard AUX */ + int leftpressed; /* left mouse button is pressed */ + int homekeycount, endkeycount; /* numbers of times that key was pressed */ + + /* ColRes AUX */ + int colres_dragging, /* indicates if it is being made a column resize */ + colres_drag_col, /* column being resized */ + colres_drag_col_start_x, /* position of the start of the column being resized */ + colres_drag_col_last_x; /* previous position */ + + /* Mark AUX */ + int mark_lin1, mark_col1, /* used to store the start cell when a block is being marked */ + mark_lin2, mark_col2, /* used to store the end cell when a block was marked */ + mark_full1, /* indicate if full lines or columns is being selected */ + mark_full2; + + /* Draw AUX, valid only after iupMatrixPrepareDrawData */ + sIFnii font_cb; + IFniiIII fgcolor_cb; + IFniiIII bgcolor_cb; + char *bgcolor, *bgcolor_parent, *fgcolor, *font; /* not need to free */ +}; + + +int iupMatrixIsValid(Ihandle* ih, int check_cells); + +#define iupMatrixInvertYAxis(_ih, _y) ((_ih)->data->h-1 - (_y)) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_draw.c b/iup/srccontrols/matrix/iupmat_draw.c new file mode 100755 index 0000000..7c53fb5 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_draw.c @@ -0,0 +1,866 @@ +/** \file + * \brief iupmatrix control + * draw functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#undef CD_NO_OLD_INTERFACE + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_controls.h" +#include "iup_cdutil.h" +#include "iup_image.h" + +#include "iupmat_def.h" +#include "iupmat_cd.h" +#include "iupmat_draw.h" +#include "iupmat_aux.h" +#include "iupmat_getset.h" +#include "iupmat_mark.h" + + +/* Color attenuation factor in a marked cell, 20% darker */ +#define IMAT_ATENUATION(_x) ((unsigned char)(((_x)*8)/10)) + +/* Text alignment that will be draw. Used by iMatrixDrawCellValue */ +#define IMAT_T_CENTER 1 +#define IMAT_T_LEFT 2 +#define IMAT_T_RIGHT 3 + +#define IMAT_CD_INACTIVE_FGCOLOR 0x666666L + +#define IMAT_COMBOBOX_W 16 + + +typedef int (*IFniiiiiiC)(Ihandle *h, int lin, int col,int x1, int x2, int y1, int y2, cdCanvas* cnv); + + +/**************************************************************************/ +/* Private functions */ +/**************************************************************************/ + + +static int iMatrixDrawGetColAlignment(Ihandle* ih, int col, char* str) +{ + char* align; + sprintf(str, "ALIGNMENT%d", col); + align = iupAttribGet(ih, str); + if (!align) + { + if (col == 0) + return IMAT_T_LEFT; + else + return IMAT_T_CENTER; + } + else if (iupStrEqualNoCase(align, "ARIGHT")) + return IMAT_T_RIGHT; + else if(iupStrEqualNoCase(align, "ACENTER")) + return IMAT_T_CENTER; + else + return IMAT_T_LEFT; +} + +static int iMatrixDrawCallDrawCB(Ihandle* ih, int lin, int col, int x1, int x2, int y1, int y2, IFniiiiiiC draw_cb) +{ + int ret; + cdCanvas* old_cnv; + + IUPMAT_CLIPAREA(ih, x1, x2, y1, y2); + cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); + + old_cnv = cdActiveCanvas(); + if (old_cnv != ih->data->cddbuffer) /* backward compatibility code */ + cdActivate(ih->data->cddbuffer); + + ret = draw_cb(ih, lin, col, x1, x2, iupMatrixInvertYAxis(ih, y1), iupMatrixInvertYAxis(ih, y2), ih->data->cddbuffer); + + cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); + + if (old_cnv && old_cnv != ih->data->cddbuffer) /* backward compatibility code */ + { + cdActivate(old_cnv); + cdCanvasActivate(ih->data->cddbuffer); + } + + if (ret == IUP_DEFAULT) + return 0; + + return 1; +} + +/* Change the CD foreground color, for the selected color to draw a cell with + its FOREGROUND COLOR. This involves checking if there is a color attribute + that cell. If no, uses a color attribute for the line, else if no for the + column, else if no for the entire matrix. Finally, if not find any of + these, use the default color. + -> lin, col - cell coordinates, in IUP format - i.e., l,l represents the left + top cell of the matrix; lin and col values = 0 represents the + title lines and columns. + -> mark - indicate if a cell is marked. If yes, its color is attenuated. +*/ +static unsigned long iMatrixDrawSetFgColor(Ihandle* ih, int lin, int col, int mark) +{ + unsigned char r = 0, g = 0, b = 0; + iupMatrixGetFgRGB(ih, lin, col, &r, &g, &b); + + if (mark) + { + r = IMAT_ATENUATION(r); + g = IMAT_ATENUATION(g); + b = IMAT_ATENUATION(b); + } + + return cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(r, g, b)); +} + +/* Change the CD foreground color, for the selected color to draw a cell with + its BACKGROUND COLOR. This involves checking if there is a color attribute + that cell. If no, uses a color attribute for the line, else if no for the + column, else if no for the entire matrix. Finally, if not find any of + these, use the default color. + -> lin, col - cell coordinates, in IUP format - i.e., l,l represents the left + top cell of the matrix; lin and col values = 0 represents the + title lines and columns. + -> mark - indicate if a cell is marked. If yes, its color is attenuated. +*/ +static unsigned long iMatrixDrawSetBgColor(Ihandle* ih, int lin, int col, int mark, int active) +{ + unsigned char r = 255, g = 255, b = 255; + + iupMatrixGetBgRGB(ih, lin, col, &r, &g, &b); + + if (mark) + { + r = IMAT_ATENUATION(r); + g = IMAT_ATENUATION(g); + b = IMAT_ATENUATION(b); + } + + if (!active) + { + r = cdIupLIGTHER(r); + g = cdIupLIGTHER(g); + b = cdIupLIGTHER(b); + } + + return cdCanvasForeground(ih->data->cddbuffer, cdEncodeColor(r, g, b)); +} + +static void iMatrixDrawFrameHorizLineCell(Ihandle* ih, int lin, int col, int x1, int x2, int y, long framecolor, char* str) +{ + if (ih->data->checkframecolor && (ih->data->callback_mode || ih->data->cells[lin][col].flags & IUPMAT_FRAMEHCOLOR)) + { + unsigned char r,g,b; + sprintf(str, "FRAMEHORIZCOLOR%d:%d", lin, col); + if (iupStrToRGB(iupAttribGet(ih, str), &r, &g, &b)) + framecolor = cdEncodeColor(r, g, b); + } + + cdCanvasForeground(ih->data->cddbuffer, framecolor); + IUPMAT_LINE(ih, x1, y, x2, y); /* bottom horizontal line */ +} + +static void iMatrixDrawFrameVertLineCell(Ihandle* ih, int lin, int col, int x, int y1, int y2, long framecolor, char* str) +{ + if (ih->data->checkframecolor && (ih->data->callback_mode || ih->data->cells[lin][col].flags & IUPMAT_FRAMEVCOLOR)) + { + unsigned char r,g,b; + sprintf(str, "FRAMEVERTCOLOR%d:%d", lin, col); + if (iupStrToRGB(iupAttribGet(ih, str), &r, &g, &b)) + framecolor = cdEncodeColor(r, g, b); + } + + cdCanvasForeground(ih->data->cddbuffer, framecolor); + IUPMAT_LINE(ih, x, y1, x, y2); /* right vertical line */ +} + +static void iMatrixDrawFrameRectTitle(Ihandle* ih, int lin, int col, int x1, int x2, int y1, int y2, long framecolor, char* str) +{ + /* avoid drawing over the frame of the next cell */ + x2 -= IMAT_FRAME_W/2; + y2 -= IMAT_FRAME_H/2; + + iMatrixDrawFrameVertLineCell(ih, lin, col, x2, y1, y2, framecolor, str); /* right vertical line */ + if (col==0) + { + IUPMAT_LINE(ih, x1, y1, x1, y2); /* left vertical line, reuse Foreground */ + x1++; + } + else if (col==1 && ih->data->columns.sizes[0] == 0) + { + /* If does not have line titles then draw the left line of the cell frame */ + IUPMAT_LINE(ih, x1, y1, x1, y2-1); + x1++; + } + + cdCanvasForeground(ih->data->cddbuffer, CD_WHITE); /* Titles have a white line near the frame */ + IUPMAT_LINE(ih, x1, y1+1, x1, y2-1); + + iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2, y2, framecolor, str); /* bottom horizontal line */ + if (lin==0) + { + IUPMAT_LINE(ih, x1, y1, x2, y1); /* top horizontal line, reuse Foreground */ + y1++; + } + else if (lin==1 && ih->data->lines.sizes[0] == 0) + { + /* If does not have column titles then draw the top line of the cell frame */ + IUPMAT_LINE(ih, x1, y1, x2-1, y1); + y1++; + } + + cdCanvasForeground(ih->data->cddbuffer, CD_WHITE); /* Titles have a white line near the frame */ + IUPMAT_LINE(ih, x1, y1, x2-1, y1); +} + +static void iMatrixDrawFrameRectCell(Ihandle* ih, int lin, int col, int x1, int x2, int y1, int y2, long framecolor, char* str) +{ + if (col==1 && ih->data->columns.sizes[0] == 0) + { + /* If does not have line titles then draw the left line of the cell frame */ + iMatrixDrawFrameVertLineCell(ih, lin, col, x1, y1, y2-1-1, framecolor, str); + } + + if (lin==1 && ih->data->lines.sizes[0] == 0) + { + /* If does not have column titles then draw the top line of the cell frame */ + iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2-1-1, y1, framecolor, str); + } + + /* bottom line */ + iMatrixDrawFrameHorizLineCell(ih, lin, col, x1, x2-1, y2-1, framecolor, str); + + /* rigth line */ + iMatrixDrawFrameVertLineCell(ih, lin, col, x2-1, y1, y2-1, framecolor, str); +} + +static int iMatrixDrawSortSign(Ihandle* ih, int x2, int y1, int y2, int col, int active, char* str) +{ + int yc; + char* sort; + + sprintf(str, "SORTSIGN%d", col); + sort = iupAttribGet(ih, str); + if (!sort || iupStrEqualNoCase(sort, "NO")) + return 0; + + /* Remove the space between text and cell frame */ + x2 -= IMAT_PADDING_W/2 + IMAT_FRAME_W/2; + + /* Set the color used to draw the text */ + if (active) + cdCanvasForeground(ih->data->cddbuffer, IMAT_CD_INACTIVE_FGCOLOR); + else + iMatrixDrawSetFgColor(ih, 0, col, 0); + + yc = (int)( (y1 + y2 ) / 2.0 - .5); + + cdCanvasBegin(ih->data->cddbuffer, CD_FILL); + + if (iupStrEqualNoCase(sort, "DOWN")) + { + IUPMAT_VERTEX(ih, x2 - 5, yc + 2); + IUPMAT_VERTEX(ih, x2 - 1, yc - 2); + IUPMAT_VERTEX(ih, x2 - 9, yc - 2); + } + else + { + IUPMAT_VERTEX(ih, x2 - 1, yc + 2); + IUPMAT_VERTEX(ih, x2 - 9, yc + 2); + IUPMAT_VERTEX(ih, x2 - 5, yc - 2); + } + + cdCanvasEnd(ih->data->cddbuffer); + return 1; +} + +static void iMatrixDrawComboFeedback(Ihandle* ih, int x2, int y1, int y2, int active, long framecolor) +{ + int xh2, yh2, x1; + + /* feedback area */ + x2 -= IMAT_PADDING_W/2 + IMAT_FRAME_W/2; + x1 = x2 - IMAT_COMBOBOX_W; + y1 += IMAT_PADDING_H/2 + IMAT_FRAME_H/2; + y2 -= IMAT_PADDING_H/2 + IMAT_FRAME_H/2; + + /* feedback background */ + iMatrixDrawSetBgColor(ih, 0, 0, 0, active); + IUPMAT_BOX(ih, x1, x2, y1, y2); + + /* feedback frame */ + cdCanvasForeground(ih->data->cddbuffer, framecolor); + IUPMAT_RECT(ih, x1, x2, y1, y2); + + /* feedback arrow */ + xh2 = x2 - IMAT_COMBOBOX_W / 2; + yh2 = y2 - (y2 - y1) / 2; + + cdCanvasBegin(ih->data->cddbuffer, CD_FILL); + IUPMAT_VERTEX(ih, xh2, yh2 + 3); + IUPMAT_VERTEX(ih, xh2 + 4, yh2 - 1); + IUPMAT_VERTEX(ih, xh2 - 4, yh2 - 1); + cdCanvasEnd(ih->data->cddbuffer); +} + +static void iMatrixDrawBackground(Ihandle* ih, int x1, int x2, int y1, int y2, int marked, int active, int lin, int col) +{ + /* avoid drawing over the frame of the next cell */ + x2 -= IMAT_FRAME_W/2; + y2 -= IMAT_FRAME_H/2; + + iMatrixDrawSetBgColor(ih, lin, col, marked, active); + IUPMAT_BOX(ih, x1, x2, y1, y2); +} + +/* Put the cell contents in the screen, using the specified color and alignment. + -> y1, y2 : vertical limits of the cell + -> x1, x2 : horizontal limits of the complete cell + -> alignment : alignment type (horizontal) assigned to the text. The options are: + [IMAT_T_CENTER,IMAT_T_LEFT,IMAT_T_RIGHT] + -> marked : mark state + -> lin, col - cell coordinates */ +static void iMatrixDrawCellValue(Ihandle* ih, int x1, int x2, int y1, int y2, int alignment, int marked, int active, int lin, int col, IFniiiiiiC draw_cb) +{ + char *text; + + /* avoid drawing over the frame of the next cell */ + x2 -= IMAT_FRAME_W/2; + y2 -= IMAT_FRAME_H/2; + + /* avoid drawing over the frame of the cell */ + x2 -= IMAT_FRAME_W/2; + y2 -= IMAT_FRAME_H/2; + + if (lin==0 || col==0) + { + /* avoid drawing over the frame of the cell */ + x1 += IMAT_FRAME_W/2; + y1 += IMAT_FRAME_H/2; + + if (col==0) x1 += IMAT_FRAME_W/2; + if (lin==0) y1 += IMAT_FRAME_H/2; + } + else if ((col==1 && ih->data->columns.sizes[0] == 0) || (lin==1 && ih->data->lines.sizes[0] == 0)) + { + /* avoid drawing over the frame of the cell */ + x1 += IMAT_FRAME_W/2; + y1 += IMAT_FRAME_H/2; + } + + if (draw_cb && !iMatrixDrawCallDrawCB(ih, lin, col, x1, x2, y1, y2, draw_cb)) + return; + + text = iupMatrixCellGetValue(ih, lin, col); + + /* Put the text */ + if (text && *text) + { + int num_line, line_height, total_height; + int charheight, ypos; + + num_line = iupStrLineCount(text); + iupdrvFontGetCharSize(ih, NULL, &charheight); + + line_height = charheight; + total_height = (line_height + IMAT_PADDING_H/2) * num_line - IMAT_PADDING_H/2 - IMAT_FRAME_H/2; + + if (lin==0) + { + int text_w; + iupdrvFontGetMultiLineStringSize(ih, text, &text_w, NULL); + if (text_w > x2 - x1 + 1 - IMAT_PADDING_W - IMAT_FRAME_W) + alignment = IMAT_T_LEFT; + } + + /* Set the color used to draw the text */ + if (!active) + cdCanvasForeground(ih->data->cddbuffer, IMAT_CD_INACTIVE_FGCOLOR); + else + iMatrixDrawSetFgColor(ih, lin, col, marked); + + /* Set the clip area to the cell region informed, the text maybe greatter than the cell */ + IUPMAT_CLIPAREA(ih, x1, x2, y1, y2); + cdCanvasClip(ih->data->cddbuffer, CD_CLIPAREA); + + cdCanvasNativeFont(ih->data->cddbuffer, iupMatrixGetFont(ih, lin, col)); + + /* Create an space between text and cell frame */ + x1 += IMAT_PADDING_W/2; x2 -= IMAT_PADDING_W/2; + y1 += IMAT_PADDING_H/2; y2 -= IMAT_PADDING_H/2; + + if (alignment == IMAT_T_CENTER) + cdCanvasTextAlignment(ih->data->cddbuffer, CD_CENTER); + else if(alignment == IMAT_T_LEFT) + cdCanvasTextAlignment(ih->data->cddbuffer, CD_WEST); + else + cdCanvasTextAlignment(ih->data->cddbuffer, CD_EAST); + + if (num_line == 1) + { + ypos = (int)((y1 + y2) / 2.0 - 0.5); + + /* Put the text */ + if (alignment == IMAT_T_CENTER) + IUPMAT_TEXT(ih, (x1 + x2) / 2, ypos, text); + else if(alignment == IMAT_T_LEFT) + IUPMAT_TEXT(ih, x1, ypos, text); + else + IUPMAT_TEXT(ih, x2, ypos, text); + } + else + { + int i; + char *p, *q, *newtext; + + newtext = iupStrDup(text); + p = newtext; + + /* Get the position of the first text to be put in the screen */ + ypos = (int)( (y1 + y2) / 2.0 - 0.5) - total_height/2 + line_height/2; + + for(i = 0; i < num_line; i++) + { + q = strchr(p, '\n'); + if (q) *q = 0; /* Cut the string to contain only one line */ + + /* Draw the text */ + if(alignment == IMAT_T_CENTER) + IUPMAT_TEXT(ih, (x1 + x2) / 2, ypos, p); + else if(alignment == IMAT_T_LEFT) + IUPMAT_TEXT(ih, x1, ypos, p); + else + IUPMAT_TEXT(ih, x2, ypos, p); + + /* Advance the string */ + if (q) p = q + 1; + + /* Advance a line */ + ypos += line_height + IMAT_PADDING_H/2; + } + + free(newtext); + } + + cdCanvasClip(ih->data->cddbuffer, CD_CLIPOFF); + } +} + +static void iMatrixDrawTitleCorner(Ihandle* ih) +{ + char str[100]; + long framecolor = cdIupConvertColor(iupAttribGetStr(ih, "FRAMECOLOR")); + int active = iupdrvIsActive(ih); + IFniiiiiiC draw_cb = (IFniiiiiiC)IupGetCallback(ih, "DRAW_CB"); + + iMatrixDrawBackground(ih, 0, ih->data->columns.sizes[0], 0, ih->data->lines.sizes[0], 0, active, 0, 0); + + iMatrixDrawFrameRectTitle(ih, 0, 0, 0, ih->data->columns.sizes[0], 0, ih->data->lines.sizes[0], framecolor, str); + + iMatrixDrawCellValue(ih, 0, ih->data->columns.sizes[0], 0, ih->data->lines.sizes[0], IMAT_T_CENTER, 0, active, 0, 0, draw_cb); +} + +static void iMatrixDrawMatrix(Ihandle* ih) +{ + iupMatrixPrepareDrawData(ih); + + /* fill the background because there will be empty cells */ + if ((ih->data->lines.num == 1) || (ih->data->columns.num == 1)) + { + cdCanvasBackground(ih->data->cddbuffer, cdIupConvertColor(ih->data->bgcolor_parent)); + cdCanvasClear(ih->data->cddbuffer); + } + + /* Draw the corner between line and column titles, if necessary */ + if (ih->data->lines.sizes[0] && ih->data->columns.sizes[0]) + iMatrixDrawTitleCorner(ih); + + /* If there are columns, then draw their titles */ + iupMatrixDrawColumnTitle(ih, ih->data->columns.first, ih->data->columns.last); + + /* If there are lines, then draw their titles */ + iupMatrixDrawLineTitle(ih, ih->data->lines.first, ih->data->lines.last); + + /* If there are cells in the matrix, then draw them */ + if ((ih->data->lines.num > 1) && (ih->data->columns.num > 1)) + iupMatrixDrawCells(ih, ih->data->lines.first, ih->data->columns.first, + ih->data->lines.last, ih->data->columns.last); +} + +static void iMatrixDrawFocus(Ihandle* ih) +{ + int x1, y1, x2, y2, dx, dy; + + if (iupAttribGetBoolean(ih, "HIDEFOCUS")) + return; + + if (!iupMatrixAuxIsCellVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) + return; + + iupMatrixAuxGetVisibleCellDim(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, &x1, &y1, &dx, &dy); + + x2 = x1 + dx - 1; + y2 = y1 + dy - 1; + + if (ih->data->columns.focus_cell == 1 && ih->data->columns.sizes[0] == 0) + x1++; + if (ih->data->lines.focus_cell == 1 && ih->data->lines.sizes[0] == 0) + y1++; + + cdIupDrawFocusRect(ih, ih->data->cdcanvas, x1, iupMatrixInvertYAxis(ih, y1), x2, iupMatrixInvertYAxis(ih, y2)); +} + + +/**************************************************************************/ +/* Exported functions */ +/**************************************************************************/ + + +/* Draw the line titles, visible, between lin and lastlin, include it. + Line titles marked will be draw with the appropriate feedback. + -> lin1 - First line to have its title drawn + -> lin2 - Last line to have its title drawn */ +void iupMatrixDrawLineTitle(Ihandle* ih, int lin1, int lin2) +{ + int x1, y1, x2, y2; + int lin, alignment, active; + char str[100]; + long framecolor; + IFniiiiiiC draw_cb; + + if (!ih->data->columns.sizes[0]) + return; + + if (lin1 > ih->data->lines.last || + lin2 < ih->data->lines.first) + return; + + if (lin1 < ih->data->lines.first) + lin1 = ih->data->lines.first; + if (lin2 > ih->data->lines.last) + lin2 = ih->data->lines.last; + + /* Start the position of the line title */ + x1 = 0; + x2 = ih->data->columns.sizes[0]; + + y1 = ih->data->lines.sizes[0]; + for(lin = ih->data->lines.first; lin < lin1; lin++) + y1 += ih->data->lines.sizes[lin]; + + framecolor = cdIupConvertColor(iupAttribGetStr(ih, "FRAMECOLOR")); + active = iupdrvIsActive(ih); + draw_cb = (IFniiiiiiC)IupGetCallback(ih, "DRAW_CB"); + + alignment = iMatrixDrawGetColAlignment(ih, 0, str); + + /* Draw the titles */ + for(lin = lin1; lin <= lin2; lin++) + { + /* If it is a hidden line (size = 0), don't draw the title */ + if(ih->data->lines.sizes[lin] == 0) + continue; + + y2 = y1 + ih->data->lines.sizes[lin]; + + /* If it doesn't have title, the loop just calculate the final position */ + if (ih->data->columns.sizes[0]) + { + int marked = iupMatrixLineIsMarked(ih, lin); + + iMatrixDrawBackground(ih, x1, x2, y1, y2, marked, active, lin, 0); + + iMatrixDrawFrameRectTitle(ih, lin, 0, x1, x2, y1, y2, framecolor, str); + + iMatrixDrawCellValue(ih, x1, x2, y1, y2, alignment, marked, active, lin, 0, draw_cb); + } + + y1 = y2; + } +} + +/* Draw the column titles, visible, between col and lastcol, include it. + Column titles marked will be draw with the appropriate feedback. + -> col1 - First column to have its title drawn + -> col2 - Last column to have its title drawn */ +void iupMatrixDrawColumnTitle(Ihandle* ih, int col1, int col2) +{ + int x1, y1, x2, y2; + int col, active; + char str[100]; + long framecolor; + IFniiiiiiC draw_cb; + + if (!ih->data->lines.sizes[0]) + return; + + if (col1 > ih->data->columns.last || + col2 < ih->data->columns.first) + return; + + if (col1 < ih->data->columns.first) + col1 = ih->data->columns.first; + if (col2 > ih->data->columns.last) + col2 = ih->data->columns.last; + + /* Start the position of the first column title */ + y1 = 0; + y2 = ih->data->lines.sizes[0]; + + x1 = ih->data->columns.sizes[0]; + for(col = ih->data->columns.first; col < col1; col++) + x1 += ih->data->columns.sizes[col]; + + framecolor = cdIupConvertColor(iupAttribGetStr(ih, "FRAMECOLOR")); + active = iupdrvIsActive(ih); + draw_cb = (IFniiiiiiC)IupGetCallback(ih, "DRAW_CB"); + + /* Draw the titles */ + for(col = col1; col <= col2; col++) + { + /* If it is an hide column (size = 0), no draw the title */ + if(ih->data->columns.sizes[col] == 0) + continue; + + x2 = x1 + ih->data->columns.sizes[col]; + + /* If it doesn't have title, the loop just calculate the final position */ + if (ih->data->lines.sizes[0]) + { + int sort = 0; + int marked = iupMatrixColumnIsMarked(ih, col); + + iMatrixDrawBackground(ih, x1, x2, y1, y2, marked, active, 0, col); + + iMatrixDrawFrameRectTitle(ih, 0, col, x1, x2, y1, y2, framecolor, str); + + if (iMatrixDrawSortSign(ih, x2, y1, y2, col, active, str)) + sort = IMAT_COMBOBOX_W; /* same space is used by the sort sign */ + + iMatrixDrawCellValue(ih, x1, x2-sort, y1, y2, IMAT_T_CENTER, marked, active, 0, col, draw_cb); + } + + x1 = x2; + } +} + +/* Redraw a block of cells of the matrix. Handle marked cells, change + automatically the background color of them. + - lin1, col1 : cell coordinates that mark the left top corner of the area to be redrawn + - lin2, col2 : cell coordinates that mark the right bottom corner of the area to be redrawn */ +void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2) +{ + int x1, y1, x2, y2, old_x2, old_y1, old_y2; + int alignment, lin, col, active; + long framecolor, emptyarea_color = -1; + char str[100]; + IFnii mark_cb; + IFnii dropcheck_cb; + IFniiiiiiC draw_cb; + + x1 = 0; + x2 = ih->data->w-1; + y1 = 0; + y2 = ih->data->h-1; + + old_x2 = x2; + old_y1 = y1; + old_y2 = y2; + + if (col1 > ih->data->columns.last || + col2 < ih->data->columns.first || + lin1 > ih->data->lines.last || + lin2 < ih->data->lines.first) + return; + + if (col1 < ih->data->columns.first) + col1 = ih->data->columns.first; + if (col2 > ih->data->columns.last) + col2 = ih->data->columns.last; + if (lin1 < ih->data->lines.first) + lin1 = ih->data->lines.first; + if (lin2 > ih->data->lines.last) + lin2 = ih->data->lines.last; + + /* Find the initial position of the first column */ + x1 += ih->data->columns.sizes[0]; + for(col = ih->data->columns.first; col < col1; col++) + x1 += ih->data->columns.sizes[col]; + + /* Find the final position of the last column */ + x2 = x1; + for( ; col <= col2; col++) + x2 += ih->data->columns.sizes[col]; + + /* Find the initial position of the first line */ + y1 += ih->data->lines.sizes[0]; + for(lin = ih->data->lines.first; lin < lin1; lin++) + y1 += ih->data->lines.sizes[lin]; + + /* Find the final position of the last line */ + y2 = y1; + for( ; lin <= lin2; lin++) + y2 += ih->data->lines.sizes[lin]; + + if ((col2 == ih->data->columns.num-1) && (old_x2 > x2)) + { + emptyarea_color = cdIupConvertColor(ih->data->bgcolor_parent); + cdCanvasForeground(ih->data->cddbuffer, emptyarea_color); + + /* If it was drawn until the last column and remains space in the right of it, + then delete this area with the the background color. */ + IUPMAT_BOX(ih, x2, old_x2, old_y1, old_y2); + } + + if ((lin2 == ih->data->lines.num-1) && (old_y2 > y2)) + { + if (emptyarea_color == -1) + emptyarea_color = cdIupConvertColor(ih->data->bgcolor_parent); + cdCanvasForeground(ih->data->cddbuffer, emptyarea_color); + + /* If it was drawn until the last line visible and remains space below it, + then delete this area with the the background color. */ + IUPMAT_BOX(ih, 0, old_x2, y2, old_y2); + } + + /***** Draw the cell values and frame */ + old_y1 = y1; + framecolor = cdIupConvertColor(iupAttribGetStr(ih, "FRAMECOLOR")); + active = iupdrvIsActive(ih); + + mark_cb = (IFnii)IupGetCallback(ih, "MARK_CB"); + dropcheck_cb = (IFnii)IupGetCallback(ih, "DROPCHECK_CB"); + draw_cb = (IFniiiiiiC)IupGetCallback(ih, "DRAW_CB"); + + for(col = col1; col <= col2; col++) /* For all the columns in the region */ + { + if (ih->data->columns.sizes[col] == 0) + continue; + + alignment = iMatrixDrawGetColAlignment(ih, col, str); + + x2 = x1 + ih->data->columns.sizes[col]; + + for(lin = lin1; lin <= lin2; lin++) /* For all lines in the region */ + { + int drop = 0; + int marked = 0; + + if (ih->data->lines.sizes[lin] == 0) + continue; + + y2 = y1 + ih->data->lines.sizes[lin]; + + /* If the cell is marked, then draw it with attenuation color */ + marked = iupMatrixMarkCellGet(ih, lin, col, mark_cb, str); + + iMatrixDrawBackground(ih, x1, x2, y1, y2, marked, active, lin, col); + + iMatrixDrawFrameRectCell(ih, lin, col, x1, x2, y1, y2, framecolor, str); + + if (dropcheck_cb && dropcheck_cb(ih, lin, col) == IUP_DEFAULT) + { + drop = IMAT_COMBOBOX_W; + iMatrixDrawComboFeedback(ih, x2, y1, y2, active, framecolor); + } + + /* draw the cell contents */ + iMatrixDrawCellValue(ih, x1, x2-drop, y1, y2, alignment, marked, active, lin, col, draw_cb); + + y1 = y2; + } + + x1 = x2; + y1 = old_y1; /* must reset also y */ + } +} + +void iupMatrixDraw(Ihandle* ih, int update) +{ + if (!ih->data->first_redraw) + return; + + if (ih->data->need_calcsize) + iupMatrixAuxCalcSizes(ih); + + iMatrixDrawMatrix(ih); + + if (update) + iupMatrixDrawUpdate(ih); +} + +void iupMatrixDrawUpdate(Ihandle* ih) +{ + cdCanvasFlush(ih->data->cddbuffer); + + if (ih->data->has_focus) + iMatrixDrawFocus(ih); +} + +int iupMatrixDrawSetRedrawAttrib(Ihandle* ih, const char* value) +{ + int type; + + if (value == NULL) + type = 0; + else if(value[0] == 'L' || value[0] == 'l') + type = IMAT_PROCESS_LIN; + else if(value[0] == 'C' || value[0] == 'c') + type = IMAT_PROCESS_COL; + else + type = 0; + + if (type) + { + int min = 0, max = 0; + value++; + + if(iupStrToIntInt(value, &min, &max, ':') != 2) + max = min; + + if (min > max) + return 0; + + iupMatrixPrepareDrawData(ih); + + if (ih->data->need_calcsize) + iupMatrixAuxCalcSizes(ih); + + if (ih->data->lines.sizes[0] && ih->data->columns.sizes[0]) + iMatrixDrawTitleCorner(ih); + + if (type == IMAT_PROCESS_LIN) + { + iupMatrixDrawLineTitle(ih, min, max); + iupMatrixDrawCells(ih, min, ih->data->columns.first, max, ih->data->columns.last); + } + else + { + iupMatrixDrawColumnTitle(ih, min, max); + iupMatrixDrawCells(ih, ih->data->lines.first, min, ih->data->lines.last, max); + } + } + else + { + iupMatrixAuxCalcSizes(ih); + iMatrixDrawMatrix(ih); + } + + iupMatrixDrawUpdate(ih); + return 0; +} diff --git a/iup/srccontrols/matrix/iupmat_draw.h b/iup/srccontrols/matrix/iupmat_draw.h new file mode 100755 index 0000000..03337e7 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_draw.h @@ -0,0 +1,31 @@ +/** \file + * \brief iupmatrix control + * draw functions. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_DRAW_H +#define __IUPMAT_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +void iupMatrixDrawCells(Ihandle* ih, int lin1, int col1, int lin2, int col2); +void iupMatrixDrawColumnTitle(Ihandle* ih, int col1, int col2); +void iupMatrixDrawLineTitle(Ihandle* ih, int lin1, int lin2); + +/* Render the visible cells and update display */ +void iupMatrixDraw(Ihandle* ih, int update); + +/* Update the display only */ +void iupMatrixDrawUpdate(Ihandle* ih); + +int iupMatrixDrawSetRedrawAttrib(Ihandle* ih, const char* value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_edit.c b/iup/srccontrols/matrix/iupmat_edit.c new file mode 100755 index 0000000..a7e0a74 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_edit.c @@ -0,0 +1,450 @@ +/** \file +* \brief iupmatrix edit +* Functions used to edit a node name in place. +* +* See Copyright Notice in "iup.h" +*/ + +#include <stdlib.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupcontrols.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" +#include "iup_childtree.h" + +#include "iupmat_def.h" +#include "iupmat_scroll.h" +#include "iupmat_aux.h" +#include "iupmat_edit.h" +#include "iupmat_key.h" +#include "iupmat_getset.h" +#include "iupmat_draw.h" + + +static int iMatrixEditCallDropdownCb(Ihandle* ih, int lin, int col) +{ + IFnnii cb = (IFnnii)IupGetCallback(ih, "DROP_CB"); + if(cb) + { + int ret; + char* value = iupMatrixCellGetValue(ih, lin, col); + if (!value) value = ""; + + iupAttribSetStr(ih->data->droph, "PREVIOUSVALUE", value); + IupSetAttribute(ih->data->droph, "VALUE", "1"); + + ret = cb(ih, ih->data->droph, lin, col); + + /* check if the user set an invalid value */ + if (IupGetInt(ih->data->droph, "VALUE") == 0) + IupSetAttribute(ih->data->droph, "VALUE", "1"); + + if(ret == IUP_DEFAULT) + return 1; + } + + return 0; +} + +static int iMatrixEditDropDownAction_CB(Ihandle* ih, char* t, int i, int v) +{ + Ihandle* ih_matrix = ih->parent; + IFniinsii cb = (IFniinsii)IupGetCallback(ih_matrix, "DROPSELECT_CB"); + if(cb) + { + int ret = cb(ih_matrix, ih_matrix->data->lines.focus_cell, ih_matrix->data->columns.focus_cell, ih, t, i, v); + + /* If the user returns IUP_CONTINUE in a dropselect_cb + the value is accepted and the matrix leaves edition mode. */ + if (ret == IUP_CONTINUE) + { + iupMatrixEditHide(ih_matrix); + iupMatrixDrawUpdate(ih); + } + } + + return IUP_DEFAULT; +} + +static void iMatrixEditChooseElement(Ihandle* ih, int lin, int col) +{ + int drop = iMatrixEditCallDropdownCb(ih, lin, col); + if(drop) + ih->data->datah = ih->data->droph; + else + { + char* value; + + ih->data->datah = ih->data->texth; + + /* dropdown values are set by the user in DROP_CB. + text value is set here from cell contents. */ + value = iupMatrixCellGetValue(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); + if (!value) value = ""; + IupSetAttribute(ih->data->texth, "VALUE", value); + } +} + +static int iMatrixEditCallEditionCb(Ihandle* ih, int mode, int update) +{ + int ret = iupMatrixAuxCallEditionCbLinCol(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, mode, update); + + if (update && ret == IUP_DEFAULT && mode == 0) /* leaving edition mode */ + iupMatrixCellUpdateValue(ih); + + return ret; +} + +static int iMatrixEditCancel(Ihandle* ih, int focus, int update, int ignore) +{ + if (IupGetInt(ih->data->datah, "VISIBLE")) + { + int ret; + + /* Avoid calling EDITION_CB twice. Usually because a killfocus. */ + if (iupAttribGet(ih, "_IUPMAT_CALL_EDITION")) + return IUP_DEFAULT; + + iupAttribSetStr(ih, "_IUPMAT_CALL_EDITION", "1"); + ret = iMatrixEditCallEditionCb(ih, 0, update); + iupAttribSetStr(ih, "_IUPMAT_CALL_EDITION", NULL); + + if (ret == IUP_IGNORE && ignore) + return IUP_IGNORE; + + IupSetAttribute(ih->data->datah, "VISIBLE", "NO"); + IupSetAttribute(ih->data->datah, "ACTIVE", "NO"); + + if (focus) + { + IupSetFocus(ih); + ih->data->has_focus = 1; /* set this so even if getfocus_cb is not called the focus is drawn */ + } +#ifdef SunOS + /* Usually when the edit control is hidden the matrix is automatically repainted by the system, except in SunOS. */ + iupMatrixDrawUpdate(ih); +#endif + } + + return IUP_DEFAULT; +} + +static int iMatrixEditKillFocus_CB(Ihandle* ih) +{ + Ihandle* ih_matrix = ih->parent; + if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Motif")) + { + if (iupAttribGet(ih_matrix, "_IUPMAT_DOUBLE_CLICK")) + return IUP_DEFAULT; + } + + iupMatrixEditForceHidden(ih_matrix); + return IUP_DEFAULT; +} + +int iupMatrixEditHide(Ihandle* ih) +{ + return iMatrixEditCancel(ih, 1, 1, 1); /* set focus + update + use ignore */ +} + +void iupMatrixEditForceHidden(Ihandle* ih) +{ + iMatrixEditCancel(ih, 0, 1, 0); /* no focus + update + no ignore */ +} + +int iupMatrixEditIsVisible(Ihandle* ih) +{ + if (!IupGetInt(ih, "ACTIVE")) + return 0; + + if (!IupGetInt(ih->data->datah, "VISIBLE")) + return 0; + + return 1; +} + +int iupMatrixEditShow(Ihandle* ih) +{ + char* mask; + int w, h, x, y; + + /* work around for Windows when using Multiline */ + if (iupAttribGet(ih, "_IUPMAT_IGNORE_SHOW")) + { + iupAttribSetStr(ih, "_IUPMAT_IGNORE_SHOW", NULL); + return 0; + } + + /* not active */ + if(!IupGetInt(ih, "ACTIVE")) + return 0; + + /* already visible */ + if(IupGetInt(ih->data->datah, "VISIBLE")) + return 0; + + /* notify application */ + if (iMatrixEditCallEditionCb(ih, 1, 0) == IUP_IGNORE) + return 0; + + /* select edit control */ + iMatrixEditChooseElement(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); + + /* position the cell to make it visible */ + /* If the focus is not visible, a scroll is done for that the focus to be visible */ + if (!iupMatrixAuxIsCellFullVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) + iupMatrixScrollToVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); + + /* set attributes */ + iupMatrixPrepareDrawData(ih); + IupStoreAttribute(ih->data->datah, "BGCOLOR", iupMatrixGetBgColor(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)); + IupStoreAttribute(ih->data->datah, "FGCOLOR", iupMatrixGetFgColor(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)); + IupSetAttribute(ih->data->datah, "FONT", iupMatrixGetFont(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)); + + mask = IupMatGetAttribute(ih,"MASK", ih->data->lines.focus_cell, ih->data->columns.focus_cell); + if (mask) + { + IupSetAttribute(ih->data->datah, "MASKCASEI", IupMatGetAttribute(ih,"MASKCASEI", ih->data->lines.focus_cell, ih->data->columns.focus_cell)); + IupSetAttribute(ih->data->datah, "MASK", mask); + } + else + { + mask = IupMatGetAttribute(ih,"MASKINT", ih->data->lines.focus_cell, ih->data->columns.focus_cell); + if (mask) + IupSetAttribute(ih->data->datah, "MASKINT", mask); + else + { + mask = IupMatGetAttribute(ih,"MASKFLOAT", ih->data->lines.focus_cell, ih->data->columns.focus_cell); + if (mask) + IupSetAttribute(ih->data->datah, "MASKFLOAT", mask); + } + } + + /* calc size */ + iupMatrixAuxGetVisibleCellDim(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, &x, &y, &w, &h); + + ih->data->datah->x = x; + ih->data->datah->y = y; + if (IupGetGlobal("GTKVERSION")) + { + /* In GTK, IupCanvas is not the actual container of the IupText/IupList */ + ih->data->datah->x += ih->x; + ih->data->datah->y += ih->y; + } + + ih->data->datah->currentwidth = w; + ih->data->datah->currentheight = h; + iupClassObjectLayoutUpdate(ih->data->datah); + + /* activate and show */ + IupSetAttribute(ih->data->datah, "ACTIVE", "YES"); + IupSetAttribute(ih->data->datah, "VISIBLE", "YES"); + IupSetFocus(ih->data->datah); + + return 1; +} + +static int iMatrixEditTextAction_CB(Ihandle* ih, int c, char* after) +{ + Ihandle* ih_matrix = ih->parent; + IFniiiis cb = (IFniiiis) IupGetCallback(ih_matrix, "ACTION_CB"); + if (cb && c!=0) /* only for valid characters */ + { + int oldc = c; + c = cb(ih_matrix, c, ih_matrix->data->lines.focus_cell, ih_matrix->data->columns.focus_cell, 1, after); + if (c == IUP_IGNORE || c == IUP_CLOSE || c == IUP_CONTINUE) + return c; + else if(c == IUP_DEFAULT) + c = oldc; + return c; + } + + return IUP_DEFAULT; +} + +static int iMatrixEditTextKeyAny_CB(Ihandle* ih, int c) +{ + Ihandle* ih_matrix = ih->parent; + IFniiiis cb = (IFniiiis) IupGetCallback(ih_matrix, "ACTION_CB"); + if (cb && c==0) /* only for other characters */ + { + int oldc = c; + c = cb(ih_matrix, c, ih_matrix->data->lines.focus_cell, ih_matrix->data->columns.focus_cell, 1, IupGetAttribute(ih, "VALUE")); + if(c == IUP_IGNORE || c == IUP_CLOSE || c == IUP_CONTINUE) + return c; + else if(c == IUP_DEFAULT) + c = oldc; + } + + switch (c) + { + case K_cUP: + case K_cDOWN: + case K_cLEFT: + case K_cRIGHT: + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + iupMatrixProcessKeyPress(ih_matrix, c); + return IUP_IGNORE; + } + break; + case K_UP: + if (IupGetInt(ih, "CARET") == 1) + { + /* if at the first line of the text */ + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + iupMatrixProcessKeyPress(ih_matrix, c); + return IUP_IGNORE; + } + } + break; + case K_DOWN: + { + char* value = IupGetAttribute(ih, "VALUE"); + if (value) + { + /* if at the last line of the text */ + if (iupStrLineCount(value) == IupGetInt(ih, "CARET")) + { + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + iupMatrixProcessKeyPress(ih_matrix, c); + return IUP_IGNORE; + } + } + } + } + break; + case K_LEFT: + if (IupGetInt(ih, "CARETPOS") == 0) + { + /* if at the first character */ + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + iupMatrixProcessKeyPress(ih_matrix, c); + return IUP_IGNORE; + } + } + break; + case K_RIGHT: + { + char* value = IupGetAttribute(ih, "VALUE"); + if (value) + { + /* if at the last character */ + if ((int)strlen(value) == IupGetInt(ih, "CARETPOS")) + { + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + iupMatrixProcessKeyPress(ih_matrix, c); + return IUP_IGNORE; + } + } + } + } + break; + case K_ESC: + iMatrixEditCancel(ih_matrix, 1, 0, 0); /* set focus + NO update + NO ignore */ + return IUP_IGNORE; + case K_CR: + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Win32") && IupGetInt(ih, "MULTILINE")) + { + /* work around for Windows when using Multiline */ + iupAttribSetStr(ih_matrix, "_IUPMAT_IGNORE_SHOW", "1"); + } + + if (iupMatrixAuxCallLeaveCellCb(ih_matrix) != IUP_IGNORE) + { + iupMatrixScrollKeyCr(ih_matrix); + iupMatrixAuxCallEnterCellCb(ih_matrix); + } + iupMatrixDrawUpdate(ih_matrix); + return IUP_IGNORE; + } + break; + } + + return IUP_CONTINUE; +} + +static int iMatrixEditDropDownKeyAny_CB(Ihandle* ih, int c) +{ + Ihandle* ih_matrix = ih->parent; + IFniiiis cb = (IFniiiis)IupGetCallback(ih_matrix, "ACTION_CB"); + if (cb) + { + int oldc = c; + c = cb(ih_matrix, c, ih_matrix->data->lines.focus_cell, ih_matrix->data->columns.focus_cell, 1, ""); + if (c == IUP_IGNORE || c == IUP_CLOSE || c == IUP_CONTINUE) + return c; + else if(c == IUP_DEFAULT) + c = oldc; + } + + switch (c) + { + case K_CR: + if (iupMatrixEditHide(ih_matrix) == IUP_DEFAULT) + { + if (iupMatrixAuxCallLeaveCellCb(ih_matrix) != IUP_IGNORE) + { + iupMatrixScrollKeyCr(ih_matrix); + iupMatrixAuxCallEnterCellCb(ih_matrix); + } + iupMatrixDrawUpdate(ih_matrix); + return IUP_IGNORE; + } + break; + case K_ESC: + iMatrixEditCancel(ih_matrix, 1, 0, 0); /* set focus + NO update + NO ignore */ + return IUP_IGNORE; + } + + return IUP_CONTINUE; +} + +char* iupMatrixEditGetValue(Ihandle* ih) +{ + if (ih->data->datah == ih->data->droph) + return IupGetAttribute(ih->data->droph, IupGetAttribute(ih->data->droph, "VALUE")); + else + return IupGetAttribute(ih->data->texth, "VALUE"); +} + +void iupMatrixEditCreate(Ihandle* ih) +{ + /******** EDIT *************/ + ih->data->texth = IupText(NULL); + iupChildTreeAppend(ih, ih->data->texth); + + IupSetCallback(ih->data->texth, "ACTION", (Icallback)iMatrixEditTextAction_CB); + IupSetCallback(ih->data->texth, "K_ANY", (Icallback)iMatrixEditTextKeyAny_CB); + IupSetCallback(ih->data->texth, "KILLFOCUS_CB", (Icallback)iMatrixEditKillFocus_CB); + IupSetAttribute(ih->data->texth, "VALUE", ""); + IupSetAttribute(ih->data->texth, "VISIBLE", "NO"); + IupSetAttribute(ih->data->texth, "ACTIVE", "NO"); + + + /******** DROPDOWN *************/ + ih->data->droph = IupList(NULL); + iupChildTreeAppend(ih, ih->data->droph); + + IupSetCallback(ih->data->droph, "ACTION", (Icallback)iMatrixEditDropDownAction_CB); + IupSetCallback(ih->data->droph, "KILLFOCUS_CB", (Icallback)iMatrixEditKillFocus_CB); + IupSetCallback(ih->data->droph, "K_ANY", (Icallback)iMatrixEditDropDownKeyAny_CB); + IupSetAttribute(ih->data->droph, "DROPDOWN", "YES"); + IupSetAttribute(ih->data->droph, "MULTIPLE", "NO"); + IupSetAttribute(ih->data->droph, "VISIBLE", "NO"); + IupSetAttribute(ih->data->droph, "ACTIVE", "NO"); +} diff --git a/iup/srccontrols/matrix/iupmat_edit.h b/iup/srccontrols/matrix/iupmat_edit.h new file mode 100755 index 0000000..9a7815f --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_edit.h @@ -0,0 +1,26 @@ +/** \file + * \brief iupmatrix. + * Functions used to edit a cell in place. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_EDIT_H +#define __IUPMAT_EDIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixEditIsVisible (Ihandle *ih); +int iupMatrixEditShow (Ihandle* ih); +int iupMatrixEditHide (Ihandle* ih); +void iupMatrixEditForceHidden(Ihandle* ih); +char* iupMatrixEditGetValue (Ihandle* ih); +void iupMatrixEditCreate (Ihandle* ih); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_focus.c b/iup/srccontrols/matrix/iupmat_focus.c new file mode 100755 index 0000000..3c000f8 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_focus.c @@ -0,0 +1,58 @@ +/** \file + * \brief iupmatrix focus control + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_aux.h" +#include "iupmat_focus.h" +#include "iupmat_draw.h" + + +void iupMatrixFocusSet(Ihandle* ih, int lin, int col) +{ + ih->data->lines.focus_cell = lin; + ih->data->columns.focus_cell = col; +} + +int iupMatrixFocus_CB(Ihandle* ih, int focus) +{ + int rc = IUP_DEFAULT; + + if (!iupMatrixIsValid(ih, 1)) + return IUP_DEFAULT; + + if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Motif")) + { + if (focus && iupAttribGet(ih, "_IUPMAT_DOUBLE_CLICK")) + { + iupAttribSetStr(ih, "_IUPMAT_DOUBLE_CLICK", NULL); + return IUP_DEFAULT; + } + } + + ih->data->has_focus = focus; + iupMatrixDrawUpdate(ih); + + if (focus) + iupMatrixAuxCallEnterCellCb(ih); + else + iupMatrixAuxCallLeaveCellCb(ih); + + return rc; +} + + diff --git a/iup/srccontrols/matrix/iupmat_focus.h b/iup/srccontrols/matrix/iupmat_focus.h new file mode 100755 index 0000000..75f5894 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_focus.h @@ -0,0 +1,21 @@ +/** \file + * \brief iupmatrix focus control. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_FOCUS_H +#define __IUPMAT_FOCUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixFocus_CB(Ihandle* ih, int focus); +void iupMatrixFocusSet(Ihandle* ih, int lin, int col); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_getset.c b/iup/srccontrols/matrix/iupmat_getset.c new file mode 100755 index 0000000..34947b6 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_getset.c @@ -0,0 +1,358 @@ +/** \file + * \brief iupmatrix setget control + * attributes set and get + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_drvfont.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" +#include "iup_controls.h" +#include "iup_childtree.h" + +#include "iupmat_def.h" +#include "iupmat_getset.h" +#include "iupmat_edit.h" +#include "iupmat_draw.h" +#include "iupmat_aux.h" + + +int iupMatrixCheckCellPos(Ihandle* ih, int lin, int col) +{ + /* Check if the cell exists */ + if ((lin < 0) || (col < 0) || (lin > ih->data->lines.num-1) || (col > ih->data->columns.num-1)) + return 0; + + return 1; +} + +void iupMatrixCellSetValue(Ihandle* ih, int lin, int col, const char* value) +{ + if (ih->data->callback_mode) + return; + + if (ih->data->cells[lin][col].value) + free(ih->data->cells[lin][col].value); + + ih->data->cells[lin][col].value = iupStrDup(value); + + if (lin==0 || col==0) + ih->data->need_calcsize = 1; +} + +char* iupMatrixCellGetValue (Ihandle* ih, int lin, int col) +{ + if (!ih->handle) + { + char str[100]; + sprintf(str, "%d:%d", lin, col); + return iupAttribGet(ih, str); + } + else + { + if (ih->data->callback_mode) + { + sIFnii value_cb = (sIFnii)IupGetCallback(ih, "VALUE_CB"); + return value_cb(ih, lin, col); + } + else + return ih->data->cells[lin][col].value; + } +} + +void iupMatrixCellSetFlag(Ihandle* ih, int lin, int col, unsigned char attr, int set) +{ + if (!ih->handle) + return; + + if (lin==-1) + { + if ((col < 0) || (col > ih->data->columns.num-1)) + return; + + if (set) + ih->data->columns.flags[col] |= attr; + else + ih->data->columns.flags[col] &= ~attr; + } + else if (col == -1) + { + if ((lin < 0) || (lin > ih->data->lines.num-1)) + return; + + if (set) + ih->data->lines.flags[lin] |= attr; + else + ih->data->lines.flags[lin] &= ~attr; + } + else + { + if (!ih->data->callback_mode) + { + if ((lin < 0) || (col < 0) || (lin > ih->data->lines.num-1) || (col > ih->data->columns.num-1)) + return; + + if (set) + ih->data->cells[lin][col].flags |= attr; + else + ih->data->cells[lin][col].flags &= ~attr; + } + } +} + +void iupMatrixCellUpdateValue(Ihandle* ih) +{ + IFniis value_edit_cb; + char *value = iupMatrixEditGetValue(ih); + + iupMatrixCellSetValue(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, value); + + value_edit_cb = (IFniis)IupGetCallback(ih, "VALUE_EDIT_CB"); + if (value_edit_cb) + value_edit_cb(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, value); + + iupMatrixPrepareDrawData(ih); + iupMatrixDrawCells(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, ih->data->lines.focus_cell, ih->data->columns.focus_cell); +} + +void iupMatrixPrepareDrawData(Ihandle* ih) +{ + /* FGCOLOR, BGCOLOR and FONT */ + iupAttribStoreStr(ih, "_IUPMAT_BGCOLOR_PARENT", iupControlBaseGetParentBgColor(ih)); + iupAttribStoreStr(ih, "_IUPMAT_BGCOLOR", IupGetAttribute(ih, "BGCOLOR")); + iupAttribStoreStr(ih, "_IUPMAT_FGCOLOR", IupGetAttribute(ih, "FGCOLOR")); + iupAttribStoreStr(ih, "_IUPMAT_FONT", IupGetAttribute(ih, "FONT")); + + ih->data->bgcolor_parent = iupAttribGet(ih, "_IUPMAT_BGCOLOR_PARENT"); + ih->data->bgcolor = iupAttribGet(ih, "_IUPMAT_BGCOLOR"); + ih->data->fgcolor = iupAttribGet(ih, "_IUPMAT_FGCOLOR"); + ih->data->font = iupAttribGet(ih, "_IUPMAT_FONT"); + + ih->data->font_cb = (sIFnii)IupGetCallback(ih, "FONT_CB"); + ih->data->fgcolor_cb = (IFniiIII)IupGetCallback(ih, "FGCOLOR_CB"); + ih->data->bgcolor_cb = (IFniiIII)IupGetCallback(ih, "BGCOLOR_CB"); +} + +static char* iMatrixGetCellAttrib(Ihandle* ih, unsigned char attr, int lin, int col, int native_parent) +{ + char* value = NULL; + char attrib_id[100]; + const char* attrib = NULL; + char* attrib_global = NULL; + + if (attr == IUPMAT_FONT) + { + attrib = "FONT"; + attrib_global = ih->data->font; + } + else if (attr == IUPMAT_BGCOLOR) + { + attrib = "BGCOLOR"; + attrib_global = ih->data->bgcolor; + } + else if (attr == IUPMAT_FGCOLOR) + { + attrib = "FGCOLOR"; + attrib_global = ih->data->fgcolor; + } + + /* 1 - check for this cell */ + if (ih->data->callback_mode || ih->data->cells[lin][col].flags & attr) + { + sprintf(attrib_id, "%s%d:%d", attrib, lin, col); + value = iupAttribGet(ih, attrib_id); + } + if (!value) + { + /* 2 - check for this line, if not title col */ + if (col != 0) + { + if (ih->data->lines.flags[lin] & attr) + { + sprintf(attrib_id, "%s%d:*", attrib, lin); + value = iupAttribGet(ih, attrib_id); + } + } + + if (!value) + { + /* 3 - check for this column, if not title line */ + if (lin != 0) + { + if (ih->data->columns.flags[col] & attr) + { + sprintf(attrib_id,"%s*:%d", attrib, col); + value = iupAttribGet(ih, attrib_id); + } + } + + if (!value) + { + /* 4 - check for the matrix or native parent */ + if (native_parent) + value = ih->data->bgcolor_parent; + else + value = attrib_global; + } + } + } + + return value; +} + +static int iMatrixCallColorCB(Ihandle* ih, IFniiIII cb, int lin, int col, unsigned char *r, unsigned char *g, unsigned char *b) +{ + int ir, ig, ib, ret; + ret = cb(ih, lin, col, &ir, &ig, &ib); + *r = iupBYTECROP(ir); + *g = iupBYTECROP(ig); + *b = iupBYTECROP(ib); + return ret; +} + +char* iupMatrixGetFgColor(Ihandle* ih, int lin, int col) +{ + unsigned char r = 0, g = 0, b = 0; + /* called from Edit only */ + if (!ih->data->fgcolor_cb || (iMatrixCallColorCB(ih, ih->data->fgcolor_cb, lin, col, &r, &g, &b) == IUP_IGNORE)) + { + char* fgcolor = iMatrixGetCellAttrib(ih, IUPMAT_FGCOLOR, lin, col, 0); + if (!fgcolor) + { + if (lin ==0 || col == 0) + fgcolor = IupGetGlobal("DLGFGCOLOR"); + else + fgcolor = IupGetGlobal("TXTFGCOLOR"); + } + return fgcolor; + } + else + { + char* buffer = iupStrGetMemory(30); + sprintf(buffer, "%d %d %d", r, g, b); + return buffer; + } +} + +void iupMatrixGetFgRGB(Ihandle* ih, int lin, int col, unsigned char *r, unsigned char *g, unsigned char *b) +{ + /* called from Draw only */ + if (!ih->data->fgcolor_cb || (iMatrixCallColorCB(ih, ih->data->fgcolor_cb, lin, col, r, g, b) == IUP_IGNORE)) + { + char* fgcolor = iMatrixGetCellAttrib(ih, IUPMAT_FGCOLOR, lin, col, 0); + if (!fgcolor) + { + if (lin ==0 || col == 0) + fgcolor = IupGetGlobal("DLGFGCOLOR"); + else + fgcolor = IupGetGlobal("TXTFGCOLOR"); + } + iupStrToRGB(fgcolor, r, g, b); + } +} + +char* iupMatrixGetBgColor(Ihandle* ih, int lin, int col) +{ + unsigned char r = 0, g = 0, b = 0; + /* called from Edit only */ + if (!ih->data->bgcolor_cb || (iMatrixCallColorCB(ih, ih->data->bgcolor_cb, lin, col, &r, &g, &b) == IUP_IGNORE)) + { + int native_parent = 0; + if (lin == 0 || col == 0) + native_parent = 1; + return iMatrixGetCellAttrib(ih, IUPMAT_BGCOLOR, lin, col, native_parent); + } + else + { + char* buffer = iupStrGetMemory(30); + sprintf(buffer, "%d %d %d", r, g, b); + return buffer; + } +} + +#define IMAT_DARKER(_x) (((_x)*9)/10) + +void iupMatrixGetBgRGB(Ihandle* ih, int lin, int col, unsigned char *r, unsigned char *g, unsigned char *b) +{ + /* called from Draw only */ + if (!ih->data->bgcolor_cb || (iMatrixCallColorCB(ih, ih->data->bgcolor_cb, lin, col, r, g, b) == IUP_IGNORE)) + { + int native_parent = 0; + if (lin == 0 || col == 0) + native_parent = 1; + iupStrToRGB(iMatrixGetCellAttrib(ih, IUPMAT_BGCOLOR, lin, col, native_parent), r, g, b); + if (native_parent) + { + int ir = IMAT_DARKER(*r), ig=IMAT_DARKER(*g), ib=IMAT_DARKER(*b); /* use a darker version of the background by 10% */ + *r = iupBYTECROP(ir); + *g = iupBYTECROP(ig); + *b = iupBYTECROP(ib); + } + } +} + +char* iupMatrixGetFont(Ihandle* ih, int lin, int col) +{ + char* font = NULL; + /* called from Draw and Edit only */ + if (ih->data->font_cb) + font = ih->data->font_cb(ih, lin, col); + if (!font) + font = iMatrixGetCellAttrib(ih, IUPMAT_FONT, lin, col, 0); + return font; +} + +char *iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels) +{ + char* str; + int size; + ImatLinColData *lincol_data; + + if(m == IMAT_PROCESS_LIN) + lincol_data = &(ih->data->lines); + else + lincol_data = &(ih->data->columns); + + if (index < 0 || index > lincol_data->num-1) + return NULL; + + if (m == IMAT_PROCESS_LIN) + size = iupMatrixAuxGetLineHeight(ih, index); + else + size = iupMatrixAuxGetColumnWidth(ih, index); + + str = iupStrGetMemory(100); + + if (size) + { + /* remove the decoration added in iupMatrixAuxGet */ + if (m == IMAT_PROCESS_COL) + size -= IMAT_PADDING_W + IMAT_FRAME_W; + else + size -= IMAT_PADDING_H + IMAT_FRAME_H; + + if (!pixels) + { + int charwidth, charheight; + iupdrvFontGetCharSize(ih, &charwidth, &charheight); + if (m == IMAT_PROCESS_COL) + size = iupRASTER2WIDTH(size, charwidth); + else + size = iupRASTER2HEIGHT(size, charheight); + } + } + + sprintf(str, "%d", size); + return str; +} diff --git a/iup/srccontrols/matrix/iupmat_getset.h b/iup/srccontrols/matrix/iupmat_getset.h new file mode 100755 index 0000000..9ae3d07 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_getset.h @@ -0,0 +1,37 @@ +/** \file + * \brief iupmatrix control + * attributes set and get. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_GETSET_H +#define __IUPMAT_GETSET_H + +#ifdef __cplusplus +extern "C" { +#endif + +void iupMatrixCellSetValue(Ihandle* ih, int lin, int col, const char* value); +char* iupMatrixCellGetValue(Ihandle* ih, int lin, int col); + +void iupMatrixCellSetFlag(Ihandle* ih, int lin, int col, unsigned char attr, int set); + +void iupMatrixPrepareDrawData(Ihandle* ih); +char* iupMatrixGetFgColor(Ihandle* ih, int lin, int col); +char* iupMatrixGetBgColor(Ihandle* ih, int lin, int col); +char* iupMatrixGetFont (Ihandle* ih, int lin, int col); +void iupMatrixGetBgRGB(Ihandle* ih, int lin, int col, unsigned char *r, unsigned char *g, unsigned char *b); +void iupMatrixGetFgRGB(Ihandle* ih, int lin, int col, unsigned char *r, unsigned char *g, unsigned char *b); + +void iupMatrixCellUpdateValue(Ihandle* ih); + +char* iupMatrixGetSize(Ihandle* ih, int index, int m, int pixels); + +int iupMatrixCheckCellPos(Ihandle* ih, int lin, int col); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_key.c b/iup/srccontrols/matrix/iupmat_key.c new file mode 100755 index 0000000..ae9ed55 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_key.c @@ -0,0 +1,229 @@ +/** \file + * \brief iupmatrix control + * keyboard control + * + * See Copyright Notice in "iup.h" + */ + +/**************************************************************************/ +/* Functions to control keys in the matrix and in the text edition */ +/**************************************************************************/ + +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_scroll.h" +#include "iupmat_focus.h" +#include "iupmat_aux.h" +#include "iupmat_getset.h" +#include "iupmat_key.h" +#include "iupmat_mark.h" +#include "iupmat_edit.h" +#include "iupmat_draw.h" + + +int iupMatrixProcessKeyPress(Ihandle* ih, int c) +{ + int ret = IUP_IGNORE; /* default for processed keys */ + + /* If the focus is not visible, a scroll is done for that the focus to be visible */ + if (!iupMatrixAuxIsCellFullVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)) + iupMatrixScrollToVisible(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); + + switch (c) + { + case K_cHOME: + case K_sHOME: + case K_HOME: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyHome(ih); + ih->data->homekeycount++; + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_cEND: + case K_sEND: + case K_END: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyEnd(ih); + ih->data->endkeycount++; + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_sTAB: + case K_TAB: + return IUP_CONTINUE; /* do not redraw */ + + case K_cLEFT: + case K_sLEFT: + case K_LEFT: + if (iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyLeft(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_cRIGHT: + case K_sRIGHT: + case K_RIGHT: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyRight(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_cUP: + case K_sUP: + case K_UP: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyUp(ih); + iupMatrixAuxCallEnterCellCb(ih); + break ; + + case K_cDOWN: + case K_sDOWN: + case K_DOWN: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyDown(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_sPGUP: + case K_PGUP: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyPgUp(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_sPGDN: + case K_PGDN: + if(iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + break; + iupMatrixScrollKeyPgDown(ih); + iupMatrixAuxCallEnterCellCb(ih); + break; + + case K_F2: + case K_SP: + case K_CR: + case K_sCR: + if (iupMatrixEditShow(ih)) + return IUP_IGNORE; /* do not redraw */ + break; + + case K_sDEL: + case K_DEL: + { + int lin, col; + char str[100]; + IFnii mark_cb = (IFnii)IupGetCallback(ih, "MARK_CB"); + + iupMatrixPrepareDrawData(ih); + + for(lin = 1; lin < ih->data->lines.num; lin++) + { + for(col = 1; col < ih->data->columns.num; col++) + { + if (iupMatrixMarkCellGet(ih, lin, col, mark_cb, str)) + { + if (iupMatrixAuxCallEditionCbLinCol(ih, lin, col, 1, 1) != IUP_IGNORE) + { + IFniis value_edit_cb; + + iupMatrixCellSetValue(ih, lin, col, NULL); + + value_edit_cb = (IFniis)IupGetCallback(ih, "VALUE_EDIT_CB"); + if (value_edit_cb) + value_edit_cb(ih, lin, col, NULL); + + iupMatrixDrawCells(ih, lin, col, lin, col); + } + } + } + } + break; + } + default: + /* if a valid character is pressed enter edition mode */ + if (iup_isprint(c)) + { + if (iupMatrixEditShow(ih)) + { + if (ih->data->datah == ih->data->texth) + { + char value[2] = {0,0}; + value[0] = (char)c; + IupStoreAttribute(ih->data->datah, "VALUE", value); + IupSetAttribute(ih->data->datah, "CARET", "2"); + } + return IUP_IGNORE; /* do not redraw */ + } + } + ret = IUP_DEFAULT; /* unprocessed keys */ + break; + } + + iupMatrixDrawUpdate(ih); + return ret; +} + +void iupMatrixKeyResetHomeEndCount(Ihandle* ih) +{ + ih->data->homekeycount = 0; + ih->data->endkeycount = 0; +} + +int iupMatrixKeyPress_CB(Ihandle* ih, int c, int press) +{ + int oldc = c; + IFniiiis cb; + + if (!iupMatrixIsValid(ih, 1)) + return IUP_DEFAULT; + + if (!press) + return IUP_DEFAULT; + + cb = (IFniiiis)IupGetCallback(ih, "ACTION_CB"); + if (cb) + { + if (iup_isprint(c)) + { + char value[2]={0,0}; + value[0] = (char)c; + c = cb(ih, c, ih->data->lines.focus_cell, ih->data->columns.focus_cell, 0, value); + } + else + { + c = cb(ih, c, ih->data->lines.focus_cell, ih->data->columns.focus_cell, 0, + iupMatrixCellGetValue(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell)); + } + + if (c == IUP_IGNORE || c == IUP_CLOSE || c == IUP_CONTINUE) + return c; + else if (c == IUP_DEFAULT) + c = oldc; + } + + if (c != K_HOME && c != K_sHOME) + ih->data->homekeycount = 0; + if (c != K_END && c != K_sEND) + ih->data->endkeycount = 0; + + return iupMatrixProcessKeyPress(ih, c); +} diff --git a/iup/srccontrols/matrix/iupmat_key.h b/iup/srccontrols/matrix/iupmat_key.h new file mode 100755 index 0000000..1062dd0 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_key.h @@ -0,0 +1,23 @@ +/** \file + * \brief iupmatrix. keyboard control. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_KEY_H +#define __IUPMAT_KEY_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixKeyPress_CB(Ihandle* ih, int c, int press); +int iupMatrixProcessKeyPress(Ihandle* ih, int c); + +void iupMatrixKeyResetHomeEndCount(Ihandle* ih); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_mark.c b/iup/srccontrols/matrix/iupmat_mark.c new file mode 100755 index 0000000..99aad32 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_mark.c @@ -0,0 +1,720 @@ +/** \file + * \brief iupmatrix control + * cell selection + * + * See Copyright Notice in "iup.h" + */ + +/**************************************************************************/ +/* Functions to cell selection (mark) */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_mark.h" +#include "iupmat_getset.h" +#include "iupmat_draw.h" + + +static void iMatrixMarkLinSet(Ihandle* ih, int lin, int mark) +{ + /* called when MARKMODE=LIN */ + if (mark==-1) + mark = !(ih->data->lines.flags[lin] & IUPMAT_MARK); + + if (mark) + ih->data->lines.flags[lin] |= IUPMAT_MARK; + else + ih->data->lines.flags[lin] &= ~IUPMAT_MARK; +} + +static void iMatrixMarkColSet(Ihandle* ih, int col, int mark) +{ + /* called when MARKMODE=COL */ + if (mark==-1) + mark = !(ih->data->columns.flags[col] & IUPMAT_MARK); + + if (mark) + ih->data->columns.flags[col] |= IUPMAT_MARK; + else + ih->data->columns.flags[col] &= ~IUPMAT_MARK; +} + +static void iMatrixMarkCellSet(Ihandle* ih, int lin, int col, int mark, IFniii markedit_cb, IFnii mark_cb, char* str) +{ + /* called only when MARKMODE=CELL */ + if (mark == -1) + mark = !iupMatrixMarkCellGet(ih, lin, col, mark_cb, str); + + if (ih->data->callback_mode) + { + if (markedit_cb) + markedit_cb(ih, lin, col, mark); + else + { + sprintf(str, "MARK%d:%d", lin, col); + if (mark) + iupAttribSetStr(ih, str, "1"); + else + iupAttribSetStr(ih, str, NULL); + } + } + else + { + if (mark) + ih->data->cells[lin][col].flags |= IUPMAT_MARK; + else + ih->data->cells[lin][col].flags &= ~IUPMAT_MARK; + } +} + +int iupMatrixMarkCellGet(Ihandle* ih, int lin, int col, IFnii mark_cb, char* str) +{ + /* called independent from MARKMODE */ + + if (ih->data->mark_mode == IMAT_MARK_NO) + return 0; + + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + if (ih->data->callback_mode) + { + if (mark_cb) + return mark_cb(ih, lin, col); + else + { + int mark = 0; + char* value; + sprintf(str, "MARK%d:%d", lin, col); + value = iupAttribGet(ih, str); + iupStrToInt(value, &mark); + return mark; + } + } + else + return ih->data->cells[lin][col].flags & IUPMAT_MARK; + } + else + { + if (ih->data->lines.flags[lin] & IUPMAT_MARK || ih->data->columns.flags[col] & IUPMAT_MARK) + return 1; + else + return 0; + } +} + +static void iMatrixMarkItem(Ihandle* ih, int lin1, int col1, int mark, IFniii markedit_cb, IFnii mark_cb, char* str) +{ + int lin, col; + + if (ih->data->mark_full1 == IMAT_PROCESS_LIN) + { + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + for (col = 1; col < ih->data->columns.num; col++) + iMatrixMarkCellSet(ih, lin1, col, mark, markedit_cb, mark_cb, str); + } + else + { + iMatrixMarkLinSet(ih, lin1, mark); + iupMatrixDrawLineTitle(ih, lin1, lin1); + } + + iupMatrixDrawCells(ih, lin1, 1, lin1, ih->data->columns.num-1); + } + else if (ih->data->mark_full1 == IMAT_PROCESS_COL) + { + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + for(lin = 1; lin < ih->data->lines.num; lin++) + iMatrixMarkCellSet(ih, lin, col1, mark, markedit_cb, mark_cb, str); + } + else + { + iMatrixMarkColSet(ih, col1, mark); + iupMatrixDrawColumnTitle(ih, col1, col1); + } + + iupMatrixDrawCells(ih, 1, col1, ih->data->lines.num-1, col1); + } + else if (ih->data->mark_mode == IMAT_MARK_CELL) + { + iMatrixMarkCellSet(ih, lin1, col1, mark, markedit_cb, mark_cb, str); + iupMatrixDrawCells(ih, lin1, col1, lin1, col1); + } +} + +static void iMatrixMarkBlock(Ihandle* ih, int lin1, int col1, int lin2, int col2, int mark, IFniii markedit_cb, IFnii mark_cb, char* str) +{ + int lin, col; + + if (lin1 > lin2) {int t = lin1; lin1 = lin2; lin2 = t;} + if (col1 > col2) {int t = col1; col1 = col2; col2 = t;} + + if (ih->data->mark_full1 == IMAT_PROCESS_LIN) + { + for(lin=lin1; lin<=lin2; lin++) + iMatrixMarkItem(ih, lin, 0, mark, markedit_cb, mark_cb, str); + } + else if(ih->data->mark_full1 == IMAT_PROCESS_COL) + { + for(col=col1; col<=col2; col++) + iMatrixMarkItem(ih, 0, col, mark, markedit_cb, mark_cb, str); + } + else if (ih->data->mark_mode == IMAT_MARK_CELL) + { + for(lin=lin1; lin<=lin2; lin++) + { + for(col=col1; col<=col2; col++) + iMatrixMarkItem(ih, lin, col, mark, markedit_cb, mark_cb, str); + } + } +} + +void iupMatrixMarkMouseBlock(Ihandle* ih, int lin2, int col2) +{ + /* called only when "shift" is pressed and MARKMULTIPLE=YES */ + IFniii markedit_cb = NULL; + IFnii mark_cb = NULL; + char str[100]; + + iupMatrixPrepareDrawData(ih); + + ih->data->mark_full2 = 0; + + if (lin2 == 0 && col2 == 0) + return; + /* If it was pointing for a column title... */ + else if (lin2 == 0) + { + if ((ih->data->mark_mode == IMAT_MARK_CELL && ih->data->mark_multiple) || + ih->data->mark_mode & IMAT_MARK_COL) + ih->data->mark_full2 = IMAT_PROCESS_COL; + } + /* If it was pointing for a line title... */ + else if (col2 == 0) + { + if ((ih->data->mark_mode == IMAT_MARK_CELL && ih->data->mark_multiple) || + ih->data->mark_mode & IMAT_MARK_LIN) + ih->data->mark_full2 = IMAT_PROCESS_LIN; + } + + /* if new block is not the same, does nothing */ + if (ih->data->mark_full1 != ih->data->mark_full2) + return; + + if (ih->data->mark_mode == IMAT_MARK_CELL && ih->data->callback_mode) + { + markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + mark_cb = (IFnii)IupGetCallback(ih, "MARK_CB"); + } + + /* Unmark previous block */ + if (ih->data->mark_lin1 != -1 && ih->data->mark_lin2 != -1 && + ih->data->mark_col1 != -1 && ih->data->mark_col2 != -1) + iMatrixMarkBlock(ih, ih->data->mark_lin1, ih->data->mark_col1, ih->data->mark_lin2, ih->data->mark_col2, 0, markedit_cb, mark_cb, str); + + ih->data->mark_lin2 = lin2; + ih->data->mark_col2 = col2; + + /* Unmark new block */ + iMatrixMarkBlock(ih, ih->data->mark_lin1, ih->data->mark_col1, ih->data->mark_lin2, ih->data->mark_col2, 1, markedit_cb, mark_cb, str); +} + +void iupMatrixMarkMouseReset(Ihandle* ih) +{ + ih->data->mark_lin1 = -1; + ih->data->mark_col1 = -1; + ih->data->mark_lin2 = -1; + ih->data->mark_col2 = -1; + + ih->data->mark_full1 = 0; + ih->data->mark_full2 = 0; +} + +void iupMatrixMarkMouseItem(Ihandle* ih, int ctrl, int lin1, int col1) +{ + int mark = 1, mark_full_all, lin, col; + IFniii markedit_cb = NULL; + IFnii mark_cb = NULL; + char str[100]; + + iupMatrixMarkMouseReset(ih); + iupMatrixPrepareDrawData(ih); + + if (!ih->data->mark_multiple || ih->data->mark_continuous || !ctrl) + { + iupMatrixMarkClearAll(ih, 1); + iupMatrixDraw(ih, 0); + } + else + mark = -1; /* toggle mark state */ + + ih->data->mark_full1 = 0; + mark_full_all = 0; + + if (lin1 == 0 && col1 == 0) + { + if ((ih->data->mark_mode == IMAT_MARK_CELL && ih->data->mark_multiple) || + ih->data->mark_mode == IMAT_MARK_COL || + ih->data->mark_mode == IMAT_MARK_LIN) + mark_full_all = 1; + } + /* If it was pointing for a column title... */ + else if (lin1 == 0) + { + if ((ih->data->mark_mode == IMAT_MARK_CELL && ih->data->mark_multiple) || + ih->data->mark_mode & IMAT_MARK_COL) + ih->data->mark_full1 = IMAT_PROCESS_COL; + } + /* If it was pointing for a line title... */ + else if (col1 == 0) + { + if ((ih->data->mark_mode == IMAT_MARK_CELL && ih->data->mark_multiple) || + ih->data->mark_mode & IMAT_MARK_LIN) + ih->data->mark_full1 = IMAT_PROCESS_LIN; + } + + if (ih->data->mark_mode == IMAT_MARK_CELL && ih->data->callback_mode) + { + markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + mark_cb = (IFnii)IupGetCallback(ih, "MARK_CB"); + } + + if (mark_full_all) + { + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + char str[100]; + for (col = 1; col < ih->data->columns.num; col++) + { + for(lin = 1; lin < ih->data->lines.num; lin++) + iMatrixMarkCellSet(ih, lin, col, mark, markedit_cb, mark_cb, str); + } + } + else if (ih->data->mark_mode == IMAT_MARK_LIN) + { + for(lin = 1; lin < ih->data->lines.num; lin++) + iMatrixMarkLinSet(ih, lin, mark); + + iupMatrixDrawLineTitle(ih, 1, ih->data->lines.num-1); + } + else if (ih->data->mark_mode == IMAT_MARK_COL) + { + for (col = 1; col < ih->data->columns.num; col++) + iMatrixMarkColSet(ih, col, mark); + + iupMatrixDrawColumnTitle(ih, 1, ih->data->columns.num-1); + } + + iupMatrixDrawCells(ih, 1, 1, ih->data->lines.num-1, ih->data->columns.num-1); + } + else + iMatrixMarkItem(ih, lin1, col1, mark, markedit_cb, mark_cb, str); + + ih->data->mark_lin1 = lin1; + ih->data->mark_col1 = col1; +} + +static void iMatrixMarkAllLinCol(ImatLinColData *p, int mark) +{ + int i; + for(i = 1; i < p->num; i++) + { + if (mark) + p->flags[i] |= IUPMAT_MARK; + else + p->flags[i] &= ~IUPMAT_MARK; + } +} + +void iupMatrixMarkClearAll(Ihandle* ih, int check) +{ + /* "!check" is used to clear all marks independent from MARKMODE */ + + if (ih->data->mark_mode == IMAT_MARK_CELL || !check) + { + int lin, col; + IFniii markedit_cb = NULL; + char str[100]; + + if (check) + markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + + for(lin = 1; lin < ih->data->lines.num; lin++) + { + for(col = 1; col < ih->data->columns.num; col++) + iMatrixMarkCellSet(ih, lin, col, 0, markedit_cb, NULL, str); + } + } + + if (ih->data->mark_mode & IMAT_MARK_LIN || !check) + iMatrixMarkAllLinCol(&(ih->data->lines), 0); + + if (ih->data->mark_mode & IMAT_MARK_COL || !check) + iMatrixMarkAllLinCol(&(ih->data->columns), 0); +} + +int iupMatrixColumnIsMarked(Ihandle* ih, int col) +{ + if (col == 0 || /* Line titles are never marked... */ + !(ih->data->mark_mode & IMAT_MARK_COL)) + return 0; + + return ih->data->columns.flags[col] & IUPMAT_MARK; +} + +int iupMatrixLineIsMarked(Ihandle* ih, int lin) +{ + if (lin == 0 || /* Column titles are never marked... */ + !(ih->data->mark_mode & IMAT_MARK_LIN)) + return 0; + + return ih->data->lines.flags[lin] & IUPMAT_MARK; +} + +int iupMatrixSetMarkedAttrib(Ihandle* ih, const char* value) +{ + int lin, col, mark; + char str[100]; + IFniii markedit_cb; + + if (ih->data->mark_mode == IMAT_MARK_NO) + return 0; + + if (!value) + iupMatrixMarkClearAll(ih, 1); + else if (*value == 'C' || *value == 'c') /* columns */ + { + if (ih->data->mark_mode == IMAT_MARK_LIN) + return 0; + + value++; /* skip C mark */ + if ((int)strlen(value) != ih->data->columns.num-1) + return 0; + + markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + + for(col = 1; col < ih->data->columns.num; col++) + { + if (*value++ == '1') + mark = 1; + else + mark = 0; + + /* mark all the cells for that column */ + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + for(lin = 1; lin < ih->data->lines.num; lin++) + iMatrixMarkCellSet(ih, lin, col, mark, markedit_cb, NULL, str); + } + else + iMatrixMarkColSet(ih, col, mark); + } + + if (ih->data->mark_mode & IMAT_MARK_LIN) + iMatrixMarkAllLinCol(&(ih->data->lines), 0); + } + else if (*value == 'L' || *value == 'l') /* lines */ + { + if (ih->data->mark_mode == IMAT_MARK_COL) + return 0; + + value++; /* skip L mark */ + if ((int)strlen(value) != ih->data->lines.num-1) + return 0; + + markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + + for(lin = 1; lin < ih->data->lines.num; lin++) + { + if (*value++ == '1') + mark = 1; + else + mark = 0; + + /* Mark all the cells for that line */ + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + for(col = 1; col < ih->data->columns.num; col++) + iMatrixMarkCellSet(ih, lin, col, mark, markedit_cb, NULL, str); + } + else + iMatrixMarkLinSet(ih, lin, mark); + } + + if (ih->data->mark_mode & IMAT_MARK_COL) + iMatrixMarkAllLinCol(&(ih->data->columns), 0); + } + else if (ih->data->mark_mode == IMAT_MARK_CELL) /* cells */ + { + if ((int)strlen(value) != (ih->data->lines.num-1)*(ih->data->columns.num-1)) + return 0; + + markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + + for(lin = 1; lin < ih->data->lines.num; lin++) + { + for(col = 1; col < ih->data->columns.num; col++) + { + if (*value++ == '1') + mark = 1; + else + mark = 0; + + iMatrixMarkCellSet(ih, lin, col, mark, markedit_cb, NULL, str); + } + } + } + + if (ih->handle) + iupMatrixDraw(ih, 1); + + return 0; +} + +char* iupMatrixGetMarkedAttrib(Ihandle* ih) +{ + int lin, col, size; + IFnii mark_cb; + char str[100]; + char* p, *value = NULL; + int exist_mark = 0; /* Show if there is someone marked */ + + if (ih->data->mark_mode == IMAT_MARK_NO) + return NULL; + + mark_cb = (IFnii)IupGetCallback(ih, "MARK_CB"); + + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + size = (ih->data->lines.num-1) * (ih->data->columns.num-1) + 1; + value = iupStrGetMemory(size); + p = value; + + for(lin = 1; lin < ih->data->lines.num; lin++) + { + for(col = 1; col < ih->data->columns.num; col++) + { + if (iupMatrixMarkCellGet(ih, lin, col, mark_cb, str)) + { + exist_mark = 1; + *p++ = '1'; + } + else + *p++ = '0'; + } + } + *p = 0; + } + else + { + int marked_lines = 0, marked_cols = 0; + + if (ih->data->mark_mode == IMAT_MARK_LINCOL) /* must find which format to return */ + { + /* look for a marked column */ + for(col = 1; col < ih->data->columns.num; col++) + { + if (ih->data->columns.flags[col] & IUPMAT_MARK) + { + marked_cols = 1; /* at least one column is marked */ + break; + } + } + + if (!marked_cols) + marked_lines = 1; + } + else if (ih->data->mark_mode == IMAT_MARK_LIN) + marked_lines = 1; + else if (ih->data->mark_mode == IMAT_MARK_COL) + marked_cols = 1; + + if (marked_lines) + { + size = 1 + (ih->data->lines.num-1) + 1; + value = iupStrGetMemory(size); + p = value; + + *p++ = 'L'; + + for(lin = 1; lin < ih->data->lines.num; lin++) + { + if (ih->data->lines.flags[lin] & IUPMAT_MARK) + { + exist_mark = 1; + *p++ = '1'; + } + else + *p++ = '0'; + } + *p = 0; + } + else if (marked_cols) + { + size = 1 + (ih->data->columns.num-1) + 1; + value = iupStrGetMemory(size); + p = value; + + *p++ = 'C'; + + for(col = 1; col < ih->data->columns.num; col++) + { + if (ih->data->columns.flags[col] & IUPMAT_MARK) + { + exist_mark = 1; + *p++ = '1'; + } + else + *p++ = '0'; + } + *p = 0; + } + } + + return exist_mark? value: NULL; +} + +int iupMatrixSetMarkAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int lin = 0, col = 0; + + if (ih->data->mark_mode == IMAT_MARK_NO) + return 0; + + if (iupStrToIntInt(name_id, &lin, &col, ':') == 2) + { + if (!iupMatrixCheckCellPos(ih, lin, col)) + return 0; + + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + int mark; + + if (lin == 0 || col == 0) /* title can NOT have a mark */ + return 0; + + mark = iupStrBoolean(value); + + if (ih->data->callback_mode) + { + IFniii markedit_cb = (IFniii)IupGetCallback(ih, "MARKEDIT_CB"); + if (markedit_cb) + markedit_cb(ih, lin, col, mark); + else if (mark) + return 1; /* store the attribute */ + } + else + { + if (mark) + ih->data->cells[lin][col].flags |= IUPMAT_MARK; + else + ih->data->cells[lin][col].flags &= ~IUPMAT_MARK; + } + + if (ih->handle) + { + /* This assumes that the matrix has been draw completely previously */ + iupMatrixPrepareDrawData(ih); + iupMatrixDrawCells(ih, lin, col, lin, col); + } + } + else + { + int mark = iupStrBoolean(value); + + if (ih->data->mark_mode & IMAT_MARK_LIN && lin!=0) + { + if (mark) + ih->data->lines.flags[lin] |= IUPMAT_MARK; + else + ih->data->lines.flags[lin] &= ~IUPMAT_MARK; + } + + if (ih->data->mark_mode & IMAT_MARK_COL && col!=0) + { + if (mark) + ih->data->columns.flags[col] |= IUPMAT_MARK; + else + ih->data->columns.flags[col] &= ~IUPMAT_MARK; + } + + if (ih->handle) + { + /* This assumes that the matrix has been draw completely previously */ + iupMatrixPrepareDrawData(ih); + iupMatrixDrawCells(ih, lin, col, lin, col); + } + } + } + + return 0; +} + +char* iupMatrixGetMarkAttrib(Ihandle* ih, const char* name_id) +{ + int lin = 0, col = 0; + + if (ih->data->mark_mode == IMAT_MARK_NO) + return "0"; + + if (iupStrToIntInt(name_id, &lin, &col, ':') == 2) + { + if (!iupMatrixCheckCellPos(ih, lin, col)) + return NULL; + + if (ih->data->mark_mode == IMAT_MARK_CELL) + { + if (lin == 0 || col == 0) /* title can NOT have a mark */ + return NULL; + + if (ih->data->callback_mode) + { + IFnii mark_cb = (IFnii)IupGetCallback(ih, "MARK_CB"); + if (mark_cb) + { + if (mark_cb(ih, lin, col)) + return "1"; + else + return "0"; + } + else + return NULL; /* let check the hash table */ + } + else + { + if (ih->data->cells[lin][col].flags & IUPMAT_MARK) + return "1"; + else + return "0"; + } + } + else + { + if (ih->data->mark_mode & IMAT_MARK_LIN && lin!=0 && ih->data->lines.flags[lin] & IUPMAT_MARK) + return "1"; + + if (ih->data->mark_mode & IMAT_MARK_COL && col!=0 && ih->data->columns.flags[col] & IUPMAT_MARK) + return "1"; + + return "0"; + } + } + + return NULL; +} diff --git a/iup/srccontrols/matrix/iupmat_mark.h b/iup/srccontrols/matrix/iupmat_mark.h new file mode 100755 index 0000000..819916e --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_mark.h @@ -0,0 +1,42 @@ +/** \file + * \brief iupmatrix. cell selection. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_MARK_H +#define __IUPMAT_MARK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Used to mark (or not mark) cells */ +#define IMAT_MARK_NO 0 +#define IMAT_MARK_LIN 1 +#define IMAT_MARK_COL 2 +#define IMAT_MARK_LINCOL 3 +#define IMAT_MARK_CELL 4 + +int iupMatrixSetMarkedAttrib(Ihandle* ih, const char* value); +char* iupMatrixGetMarkedAttrib(Ihandle* ih); +char* iupMatrixGetMarkAttrib(Ihandle* ih, const char* name_id); +int iupMatrixSetMarkAttrib(Ihandle* ih, const char* name_id, const char* value); + +void iupMatrixMarkClearAll(Ihandle* ih, int check); + +int iupMatrixMarkCellGet(Ihandle* ih, int lin, int col, IFnii mark_cb, char* str); + +int iupMatrixColumnIsMarked(Ihandle* ih, int col); +int iupMatrixLineIsMarked (Ihandle* ih, int lin); + +void iupMatrixMarkMouseBlock(Ihandle* ih, int lin2, int col2); +void iupMatrixMarkMouseItem(Ihandle* ih, int ctrl, int lin1, int col1); +void iupMatrixMarkMouseReset(Ihandle* ih); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_mem.c b/iup/srccontrols/matrix/iupmat_mem.c new file mode 100755 index 0000000..eebea7a --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_mem.c @@ -0,0 +1,319 @@ +/** \file + * \brief iupmatrix control memory allocation + * + * See Copyright Notice in "iup.h" + */ + +/**************************************************************************/ +/* Functions to allocate memory */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_mem.h" + + +static void iMatrixGetInitialValues(Ihandle* ih) +{ + int lin, col; + char* value; + char attr[100]; + + for (lin=0; lin<ih->data->lines.num; lin++) + { + for (col=0; col<ih->data->columns.num; col++) + { + sprintf(attr, "%d:%d", lin, col); + value = iupAttribGet(ih, attr); + if (value) + { + /* get the initial value and remove it from the hash table */ + + if (*value) + ih->data->cells[lin][col].value = iupStrDup(value); + + iupAttribSetStr(ih, attr, NULL); + } + } + } +} + +void iupMatrixMemAlloc(Ihandle* ih) +{ + ih->data->lines.num_alloc = ih->data->lines.num; + if (ih->data->lines.num_alloc == 1) + ih->data->lines.num_alloc = 5; + + ih->data->columns.num_alloc = ih->data->columns.num; + if (ih->data->columns.num_alloc == 1) + ih->data->columns.num_alloc = 5; + + if (!ih->data->callback_mode) + { + int lin; + + ih->data->cells = (ImatCell**)calloc(ih->data->lines.num_alloc, sizeof(ImatCell*)); + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) + ih->data->cells[lin] = (ImatCell*)calloc(ih->data->columns.num_alloc, sizeof(ImatCell)); + + iMatrixGetInitialValues(ih); + } + + ih->data->lines.flags = (unsigned char*)calloc(ih->data->lines.num_alloc, sizeof(unsigned char)); + ih->data->columns.flags = (unsigned char*)calloc(ih->data->columns.num_alloc, sizeof(unsigned char)); + ih->data->lines.sizes = (int*)calloc(ih->data->lines.num_alloc, sizeof(int)); + ih->data->columns.sizes = (int*)calloc(ih->data->columns.num_alloc, sizeof(int)); +} + +void iupMatrixMemRelease(Ihandle* ih) +{ + if (ih->data->cells) + { + int lin, col; + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) + { + for (col = 0; col < ih->data->columns.num_alloc; col++) + { + ImatCell* cell = &(ih->data->cells[lin][col]); + if (cell->value) + { + free(cell->value); + cell->value = NULL; + } + } + free(ih->data->cells[lin]); + ih->data->cells[lin] = NULL; + } + free(ih->data->cells); + ih->data->cells = NULL; + } + + if (ih->data->columns.flags) + { + free(ih->data->columns.flags); + ih->data->columns.flags = NULL; + } + + if (ih->data->lines.flags) + { + free(ih->data->lines.flags); + ih->data->lines.flags = NULL; + } + + if (ih->data->columns.sizes) + { + free(ih->data->columns.sizes); + ih->data->columns.sizes = NULL; + } + + if (ih->data->lines.sizes) + { + free(ih->data->lines.sizes); + ih->data->lines.sizes = NULL; + } +} + +void iupMatrixMemReAllocLines(Ihandle* ih, int old_num, int num, int base) +{ + int lin, col, end, diff_num, shift_num; + + /* base is the first line where the change started */ + + /* If it doesn't have enough lines allocated, then allocate more space */ + if (num > ih->data->lines.num_alloc) /* this also implicates that num>old_num */ + { + int old_alloc = ih->data->lines.num_alloc; + ih->data->lines.num_alloc = num; + + if (!ih->data->callback_mode) + { + ih->data->cells = (ImatCell**)realloc(ih->data->cells, ih->data->lines.num_alloc*sizeof(ImatCell*)); + + /* new space are allocated at the end, later we need to move the old data and clear the available space */ + for(lin = old_alloc; lin < num; lin++) + ih->data->cells[lin] = (ImatCell*)calloc(ih->data->columns.num_alloc, sizeof(ImatCell)); + } + + ih->data->lines.sizes = (int*)realloc(ih->data->lines.sizes, ih->data->lines.num_alloc*sizeof(int)); + ih->data->lines.flags = (unsigned char*)realloc(ih->data->lines.flags, ih->data->lines.num_alloc*sizeof(unsigned char)); + } + + if (old_num==num) + return; + + if (num>old_num) /* ADD */ + { + diff_num = num-old_num; /* size of the openned space */ + shift_num = old_num-base; /* size of the data to be moved (base maximum is old_num) */ + end = base+diff_num; + + /* shift the old data, opening space for new data, from base to end */ + /* do it in reverse order to avoid overlapping */ + if (shift_num) + { + if (!ih->data->callback_mode) + for (lin = shift_num-1; lin >= 0; lin--) /* all columns, shift_num lines */ + memmove(ih->data->cells[lin+end], ih->data->cells[lin+base], ih->data->columns.num_alloc*sizeof(ImatCell)); + memmove(ih->data->lines.sizes+end, ih->data->lines.sizes+base, shift_num*sizeof(int)); + memmove(ih->data->lines.flags+end, ih->data->lines.flags+base, shift_num*sizeof(unsigned char)); + } + + /* then clear the new space starting at base */ + if (!ih->data->callback_mode) + for (lin = 0; lin < diff_num; lin++) /* all columns, diff_num lines */ + memset(ih->data->cells[lin+base], 0, ih->data->columns.num_alloc*sizeof(ImatCell)); + memset(ih->data->lines.sizes+base, 0, diff_num*sizeof(int)); + memset(ih->data->lines.flags+base, 0, diff_num*sizeof(unsigned char)); + } + else /* DEL */ + { + diff_num = old_num-num; /* size of the openned space */ + shift_num = num-base; /* size of the data to be moved */ + end = base+diff_num; + + /* release memory from the opened space */ + if (!ih->data->callback_mode) + { + for(lin = base; lin < end; lin++) /* all columns, base-end lines */ + { + for (col = 0; col < ih->data->columns.num_alloc; col++) + { + ImatCell* cell = &(ih->data->cells[lin][col]); + if (cell->value) + { + free(cell->value); + cell->value = NULL; + } + cell->flags = 0; + } + } + } + + /* move the old data to opened space from end to base */ + if (shift_num) + { + if (!ih->data->callback_mode) + for (lin = 0; lin < shift_num; lin++) /* all columns, shift_num lines */ + memmove(ih->data->cells[lin+base], ih->data->cells[lin+end], ih->data->columns.num_alloc*sizeof(ImatCell)); + memmove(ih->data->lines.sizes+base, ih->data->lines.sizes+end, shift_num*sizeof(int)); + memmove(ih->data->lines.flags+base, ih->data->lines.flags+end, shift_num*sizeof(unsigned char)); + } + + /* then clear the remaining space starting at num */ + if (!ih->data->callback_mode) + for (lin = 0; lin < diff_num; lin++) /* all columns, diff_num lines */ + memset(ih->data->cells[lin+num], 0, ih->data->columns.num_alloc*sizeof(ImatCell)); + memset(ih->data->lines.sizes+num, 0, diff_num*sizeof(int)); + memset(ih->data->lines.flags+num, 0, diff_num*sizeof(unsigned char)); + } +} + +void iupMatrixMemReAllocColumns(Ihandle* ih, int old_num, int num, int base) +{ + int lin, col, end, diff_num, shift_num; + + /* base is the first column where the change started */ + + /* If it doesn't have enough columns allocated, then allocate more space */ + if (num > ih->data->columns.num_alloc) /* this also implicates that also num>old_num */ + { + ih->data->columns.num_alloc = num; + + /* new space are allocated at the end, later we need to move the old data and clear the available space */ + + if (!ih->data->callback_mode) + { + for(lin = 0; lin < ih->data->lines.num_alloc; lin++) + ih->data->cells[lin] = (ImatCell*)realloc(ih->data->cells[lin], ih->data->columns.num_alloc*sizeof(ImatCell)); + } + + ih->data->columns.sizes = (int*)realloc(ih->data->columns.sizes, ih->data->columns.num_alloc*sizeof(int)); + ih->data->columns.flags = (unsigned char*)realloc(ih->data->columns.flags, ih->data->columns.num_alloc*sizeof(unsigned char)); + } + + if (old_num==num) + return; + + if (num>old_num) /* ADD */ + { + /* even if (old_num-base)>(num-old_num) memmove will correctly copy the memory */ + /* then clear the openned space starting at base */ + + diff_num = num-old_num; /* size of the openned space */ + shift_num = old_num-base; /* size of the data to be moved (base maximum is old_num) */ + end = base+diff_num; + + /* shift the old data, opening space for new data, from base to end */ + if (shift_num) + { + if (!ih->data->callback_mode) + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) /* all lines, shift_num columns */ + memmove(ih->data->cells[lin]+end, ih->data->cells[lin]+base, shift_num*sizeof(ImatCell)); + memmove(ih->data->columns.sizes+end, ih->data->columns.sizes+base, shift_num*sizeof(int)); + memmove(ih->data->columns.flags+end, ih->data->columns.flags+base, shift_num*sizeof(unsigned char)); + } + + /* then clear the openned space starting at base */ + if (!ih->data->callback_mode) + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) /* all lines, diff_num columns */ + memset(ih->data->cells[lin]+base, 0, diff_num*sizeof(ImatCell)); + memset(ih->data->columns.sizes+base, 0, diff_num*sizeof(int)); + memset(ih->data->columns.flags+base, 0, diff_num*sizeof(unsigned char)); + } + else /* DEL */ + { + diff_num = old_num-num; /* size of the openned space */ + shift_num = num-base; /* size of the data to be moved */ + end = base+diff_num; + + /* release memory from the opened space */ + if (!ih->data->callback_mode) + { + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) /* all lines, base-end columns */ + { + for(col = base; col < end; col++) + { + ImatCell* cell = &(ih->data->cells[lin][col]); + if (cell->value) + { + free(cell->value); + cell->value = NULL; + } + cell->flags = 0; + } + } + } + + /* move the old data to opened space from end to base */ + /* even if (num-base)>(old_num-num) memmove will correctly copy the memory */ + if (shift_num) + { + if (!ih->data->callback_mode) + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) /* all lines, shift_num columns */ + memmove(ih->data->cells[lin]+base, ih->data->cells[lin]+end, shift_num*sizeof(ImatCell)); + memmove(ih->data->columns.sizes+base, ih->data->columns.sizes+end, shift_num*sizeof(int)); + memmove(ih->data->columns.flags+base, ih->data->columns.flags+end, shift_num*sizeof(unsigned char)); + } + + /* then clear the remaining space starting at num */ + if (!ih->data->callback_mode) + for (lin = 0; lin < ih->data->lines.num_alloc; lin++) /* all lines, diff_num columns */ + memset(ih->data->cells[lin]+num, 0, diff_num*sizeof(ImatCell)); + memset(ih->data->columns.sizes+num, 0, diff_num*sizeof(int)); + memset(ih->data->columns.flags+num, 0, diff_num*sizeof(unsigned char)); + } +} diff --git a/iup/srccontrols/matrix/iupmat_mem.h b/iup/srccontrols/matrix/iupmat_mem.h new file mode 100755 index 0000000..05a047b --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_mem.h @@ -0,0 +1,24 @@ +/** \file + * \brief iupmatrix control + * memory allocation. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_MEM_H +#define __IUPMAT_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +void iupMatrixMemAlloc(Ihandle* ih); +void iupMatrixMemRelease(Ihandle* ih); +void iupMatrixMemReAllocLines (Ihandle* ih, int old_num, int num, int base); +void iupMatrixMemReAllocColumns(Ihandle* ih, int old_num, int num, int base); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_mouse.c b/iup/srccontrols/matrix/iupmat_mouse.c new file mode 100755 index 0000000..33b5fe7 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_mouse.c @@ -0,0 +1,212 @@ +/** \file + * \brief iupmatrix control + * mouse events + * + * See Copyright Notice in "iup.h" + */ + +/**************************************************************************/ +/* Functions to handle mouse events */ +/**************************************************************************/ + +#include <stdlib.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_colres.h" +#include "iupmat_aux.h" +#include "iupmat_focus.h" +#include "iupmat_mouse.h" +#include "iupmat_key.h" +#include "iupmat_mark.h" +#include "iupmat_edit.h" +#include "iupmat_draw.h" +#include "iupmat_scroll.h" + + +#define IMAT_DRAG_SCROLL_DELTA 5 + +static void iMatrixMouseCallMoveCb(Ihandle* ih, int lin, int col) +{ + IFnii cb = (IFnii)IupGetCallback(ih, "MOUSEMOVE_CB"); + if (cb) + cb(ih, lin, col); +} + +static int iMatrixMouseCallClickCb(Ihandle* ih, int press, int lin, int col, char* r) +{ + IFniis cb; + + if (press) + cb = (IFniis)IupGetCallback(ih, "CLICK_CB"); + else + cb = (IFniis)IupGetCallback(ih, "RELEASE_CB"); + + if (cb) + return cb(ih, lin, col, r); + + return IUP_DEFAULT; +} + +static void iMatrixMouseLeftPress(Ihandle* ih, int lin, int col, int shift, int ctrl, int dclick) +{ + if (dclick) + { + iupMatrixMarkMouseReset(ih); + + if (lin==0 || col==0) + return; + + /* if a double click NOT in the current cell */ + if (lin != ih->data->lines.focus_cell || col != ih->data->columns.focus_cell) + { + /* leave the previous cell if the matrix previously had the focus */ + if (ih->data->has_focus && iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + return; + + iupMatrixFocusSet(ih, lin, col); + + iupMatrixAuxCallEnterCellCb(ih); + } + + if (iupMatrixEditShow(ih)) + { + if(ih->data->datah == ih->data->droph) + IupSetAttribute(ih->data->datah, "SHOWDROPDOWN", "YES"); + + if (iupStrEqualNoCase(IupGetGlobal("DRIVER"), "Motif")) + if(atoi(IupGetGlobal("MOTIFNUMBER")) < 2203) /* since OpenMotif version 2.2.3 this is not necessary */ + iupAttribSetStr(ih, "_IUPMAT_DOUBLE_CLICK", "1"); + } + } + else /* single click */ + { + if (shift && ih->data->mark_multiple && ih->data->mark_mode != IMAT_MARK_NO) + { + iupMatrixMarkMouseBlock(ih, lin, col); + } + else + { + ih->data->leftpressed = 1; + + if (lin>0 && col>0) + { + if (iupMatrixAuxCallLeaveCellCb(ih) == IUP_IGNORE) + return; + + iupMatrixFocusSet(ih, lin, col); + + /* process mark before EnterCell */ + if (ih->data->mark_mode != IMAT_MARK_NO) + iupMatrixMarkMouseItem(ih, ctrl, lin, col); + + iupMatrixAuxCallEnterCellCb(ih); + } + else + { + /* only process marks if at titles */ + if (ih->data->mark_mode != IMAT_MARK_NO) + iupMatrixMarkMouseItem(ih, ctrl, lin, col); + } + } + } +} + +int iupMatrixMouseButton_CB(Ihandle* ih, int b, int press, int x, int y, char* r) +{ + int lin=-1, col=-1; + + if (!iupMatrixIsValid(ih, 0)) + return IUP_DEFAULT; + + /* reset press state */ + ih->data->leftpressed = 0; + + if (press) + { + /* The edit Focus callback is not called when the user clicks in the parent canvas. + so we have to compensate that. */ + iupMatrixEditForceHidden(ih); + ih->data->has_focus = 1; + } + + iupMatrixAuxGetLinColFromXY(ih, x, y, &lin, &col); + + if (b == IUP_BUTTON1) + { + if (press) + { + iupMatrixKeyResetHomeEndCount(ih); + + if (iupMatrixColResStart(ih, x, y)) + return IUP_DEFAULT; /* Resize of the width a of a column was started */ + + if (lin!=-1 && col!=-1) + iMatrixMouseLeftPress(ih, lin, col, isshift(r), iscontrol(r), isdouble(r)); + } + else + { + if (iupMatrixColResIsResizing(ih)) /* If it was made a column resize, finish it */ + iupMatrixColResFinish(ih, x); + } + } + else + iupMatrixMarkMouseReset(ih); + + if (lin!=-1 && col!=-1) + { + if (iMatrixMouseCallClickCb(ih, press, lin, col, r) == IUP_IGNORE) + return IUP_DEFAULT; + } + + iupMatrixDrawUpdate(ih); + return IUP_DEFAULT; +} + +int iupMatrixMouseMove_CB(Ihandle* ih, int x, int y) +{ + int lin, col; + + if (!iupMatrixIsValid(ih, 0)) + return IUP_DEFAULT; + + if (ih->data->leftpressed && ih->data->mark_multiple && ih->data->mark_mode != IMAT_MARK_NO) + { + if ((x < ih->data->columns.sizes[0] || x < IMAT_DRAG_SCROLL_DELTA) && (ih->data->columns.first > 1)) + iupMatrixScrollLeft(ih); + else if ((x > ih->data->w - IMAT_DRAG_SCROLL_DELTA) && (ih->data->columns.last < ih->data->columns.num-1)) + iupMatrixScrollRight(ih); + + if ((y < ih->data->lines.sizes[0] || y < IMAT_DRAG_SCROLL_DELTA) && (ih->data->lines.first > 1)) + iupMatrixScrollUp(ih); + else if ((y > ih->data->h - IMAT_DRAG_SCROLL_DELTA) && (ih->data->lines.last < ih->data->lines.num-1)) + iupMatrixScrollDown(ih); + + if (iupMatrixAuxGetLinColFromXY(ih, x, y, &lin, &col)) + { + iupMatrixMarkMouseBlock(ih, lin, col); + iupMatrixDrawUpdate(ih); + + iMatrixMouseCallMoveCb(ih, lin, col); + } + return IUP_DEFAULT; + } + else if(iupMatrixColResIsResizing(ih)) /* Make a resize in a column size */ + iupMatrixColResMove(ih, x); + else /* Change cursor when it is passed on a join involving column titles */ + iupMatrixColResCheckChangeCursor(ih, x, y); + + if (iupMatrixAuxGetLinColFromXY(ih, x, y, &lin, &col)) + iMatrixMouseCallMoveCb(ih, lin, col); + + return IUP_DEFAULT; +} diff --git a/iup/srccontrols/matrix/iupmat_mouse.h b/iup/srccontrols/matrix/iupmat_mouse.h new file mode 100755 index 0000000..17a09ec --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_mouse.h @@ -0,0 +1,22 @@ +/** \file + * \brief iMatrixrix control + * mouse events. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_MOUSE_H +#define __IUPMAT_MOUSE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixMouseButton_CB (Ihandle* ih, int b, int press, int x, int y, char* r); +int iupMatrixMouseMove_CB (Ihandle* ih, int x, int y); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_numlc.c b/iup/srccontrols/matrix/iupmat_numlc.c new file mode 100755 index 0000000..e48720a --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_numlc.c @@ -0,0 +1,495 @@ +/** \file + * \brief iupmatrix control + * change number of columns or lines + * + * See Copyright Notice in "iup.h" + */ + +/**************************************************************************/ +/* Functions to change the number of lines and columns of the matrix, */ +/* after it has been created. */ +/**************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_edit.h" +#include "iupmat_mem.h" +#include "iupmat_numlc.h" +#include "iupmat_draw.h" + + +static void iMatrixUpdateLineAttributes(Ihandle* ih, int base, int count, int add) +{ +#define IMAT_NUM_ATTRIB_LINE 6 +#define IMAT_ATTRIB_LINE_ONLY 3 + char* attrib_format[IMAT_NUM_ATTRIB_LINE] = { + "BGCOLOR%d:*", + "FGCOLOR%d:*", + "FONT%d:*", + "BGCOLOR%d:%d", + "FGCOLOR%d:%d", + "FONT%d:%d"}; + char* attrib = iupStrGetMemory(100); + int a, lin, col; + char* value; + + if (add) /* ADD */ + { + /* copy the attributes of the moved cells, from base+count to num */ + /* do it in reverse order to avoid overlapping */ + /* then clear the new space starting from base to base+count */ + + for(a = 0; a < IMAT_NUM_ATTRIB_LINE; a++) + { + for(lin = ih->data->lines.num-1; lin >= base+count; lin--) + { + /* Update the line attributes */ + if (a < IMAT_ATTRIB_LINE_ONLY) + { + sprintf(attrib, attrib_format[a], lin-count); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], lin); + iupAttribStoreStr(ih, attrib, value); + } + /* Update the cell attribute */ + else for(col = 0; col < ih->data->columns.num; col++) + { + sprintf(attrib, attrib_format[a], lin-count, col); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], lin, col); + iupAttribStoreStr(ih, attrib, value); + } + } + + for(lin = base; lin < base+count; lin++) + { + if (a < IMAT_ATTRIB_LINE_ONLY) + { + sprintf(attrib, attrib_format[a], lin); + iupAttribSetStr(ih, attrib, NULL); + } + else for(col = 0; col < ih->data->columns.num; col++) + { + sprintf(attrib, attrib_format[a], lin, col); + iupAttribSetStr(ih, attrib, NULL); + } + } + } + } + else /* DEL */ + { + /* copy the attributes of the moved cells from base+count to base */ + /* then clear the remaining space starting at num */ + + for(a = 0; a < IMAT_NUM_ATTRIB_LINE; a++) + { + for(lin = base; lin < ih->data->lines.num; lin++) + { + /* Update the line attributes */ + if (a < IMAT_ATTRIB_LINE_ONLY) + { + sprintf(attrib, attrib_format[a], lin+count); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], lin); + iupAttribStoreStr(ih, attrib, value); + } + /* Update each cell attribute */ + else for(col = 0; col < ih->data->columns.num; col++) + { + sprintf(attrib, attrib_format[a], lin+count, col); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], lin, col); + iupAttribStoreStr(ih, attrib, value); + } + } + + for(lin = ih->data->lines.num; lin < ih->data->lines.num+count; lin++) + { + if (a < IMAT_ATTRIB_LINE_ONLY) + { + sprintf(attrib, attrib_format[a], lin); + iupAttribSetStr(ih, attrib, NULL); + } + else for(col = 0; col < ih->data->columns.num; col++) + { + sprintf(attrib, attrib_format[a], lin, col); + iupAttribSetStr(ih, attrib, NULL); + } + } + } + } +} + +static void iMatrixUpdateColumnAttributes(Ihandle* ih, int base, int count, int add) +{ +#define IMAT_NUM_ATTRIB_COL 7 +#define IMAT_ATTRIB_COL_ONLY 4 + char* attrib_format[IMAT_NUM_ATTRIB_COL] = { + "ALIGNMENT%d", + "BGCOLOR*:%d", + "FGCOLOR*:%d", + "FONT*:%d", + "BGCOLOR%d:%d", + "FGCOLOR%d:%d", + "FONT%d:%d"}; + char* attrib = iupStrGetMemory(100); + int a, col, lin; + char* value; + + if (add) /* ADD */ + { + /* update the attributes of the moved cells, from base+count to num */ + /* do it in reverse order to avoid overlapping */ + /* then clear the new space starting from base to base+count */ + + for(a = 0; a < IMAT_NUM_ATTRIB_COL; a++) + { + for(col = ih->data->columns.num-1; col >= base+count; col--) + { + /* Update the column attributes */ + if (a < IMAT_ATTRIB_COL_ONLY) + { + sprintf(attrib, attrib_format[a], col-count); + value = iupAttribGet(ih, attrib); + sprintf(attrib,attrib_format[a],col); + iupAttribStoreStr(ih, attrib, value); + } + /* Update the cell attributes */ + else for(lin = 0; lin < ih->data->lines.num; lin++) + { + sprintf(attrib, attrib_format[a], lin, col-count); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], lin, col); + iupAttribStoreStr(ih, attrib, value); + } + } + + for(col = base; col < base+count; col++) + { + if (a < IMAT_ATTRIB_COL_ONLY) + { + sprintf(attrib, attrib_format[a], col); + iupAttribSetStr(ih, attrib, NULL); + } + else for(lin = 0; lin < ih->data->lines.num; lin++) + { + sprintf(attrib, attrib_format[a], lin, col); + iupAttribSetStr(ih, attrib, NULL); + } + } + } + } + else /* DEL */ + { + /* copy the attributes of the moved cells from base+count to base */ + /* then clear the remaining space starting at num */ + + for(a = 0; a < IMAT_NUM_ATTRIB_COL; a++) + { + for(col = base; col < ih->data->columns.num; col++) + { + /* Update the column attributes */ + if (a < IMAT_ATTRIB_COL_ONLY) + { + sprintf(attrib, attrib_format[a], col+count); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], col); + iupAttribStoreStr(ih, attrib, value); + } + /* Update the cell attributes */ + else for(lin = 0; lin < ih->data->lines.num; lin++) + { + sprintf(attrib, attrib_format[a], lin, col+count); + value = iupAttribGet(ih, attrib); + sprintf(attrib, attrib_format[a], lin, col); + iupAttribStoreStr(ih, attrib, value); + } + } + + for(col = ih->data->columns.num; col < ih->data->columns.num+count; col++) + { + if (a < IMAT_ATTRIB_COL_ONLY) + { + sprintf(attrib, attrib_format[a], col); + iupAttribSetStr(ih, attrib, NULL); + } + else for(lin = 0; lin < ih->data->lines.num; lin++) + { + sprintf(attrib, attrib_format[a], lin, col); + iupAttribSetStr(ih, attrib, NULL); + } + } + } + } +} + +static int iMatrixGetStartEnd(const char* value, int *base, int *count, int max, int del) +{ + int ret; + + if (!value) + return 0; + + *base = 0; + *count = 1; + + ret = sscanf(value, "%d-%d", base, count); + if (ret <= 0 || ret > 2) + return 0; + if (ret == 1) + *count = 1; + + if (*count <= 0) + return 0; + + if (del) + { + if (*base <= 0) /* the first valid element is always 1 */ + *base = 1; + + /* when del, base can be at the last element */ + if (*base > max-1) + *base = max-1; + + /* when del, count must be inside the existant range */ + if (*base + *count > max) + *count = max - *base; + } + else + { + (*base)++; /* add after the given index, so increment to position the base */ + + if (*base <= 0) /* the first valid element is always 1 */ + *base = 1; + + /* when add, base can be just after the last element but not more */ + if (*base > max) + *base = max; + + /* when add, count can be any positive value */ + } + + return 1; +} + + +/**************************************************************************/ +/* Exported functions */ +/**************************************************************************/ + +int iupMatrixSetAddLinAttrib(Ihandle* ih, const char* value) +{ + int base, count, lines_num = ih->data->lines.num; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + if (!iMatrixGetStartEnd(value, &base, &count, lines_num, 0)) + return 0; + + /* if the focus cell is after the inserted area */ + if (ih->data->lines.focus_cell >= base) + { + /* leave of the edition mode */ + iupMatrixEditForceHidden(ih); + + /* move it to the same cell */ + ih->data->lines.focus_cell += count; + } + + iupMatrixMemReAllocLines(ih, lines_num, lines_num+count, base); + + ih->data->lines.num += count; + ih->data->need_calcsize = 1; + + if (base < lines_num) /* If before the last line. */ + iMatrixUpdateLineAttributes(ih, base, count, 1); + + iupMatrixDraw(ih, 1); + return 0; +} + +int iupMatrixSetDelLinAttrib(Ihandle* ih, const char* value) +{ + int base, count, lines_num = ih->data->lines.num; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + if (!iMatrixGetStartEnd(value, &base, &count, lines_num, 1)) + return 0; + + /* if the focus cell is after the removed area */ + if (ih->data->lines.focus_cell >= base) + { + /* leave of the edition mode */ + iupMatrixEditForceHidden(ih); + + /* if the focus cell is inside the removed area */ + if (ih->data->lines.focus_cell <= base+count-1) + ih->data->lines.focus_cell = base; /* move it to the first existant cell */ + else + ih->data->lines.focus_cell -= count; /* move it to the same cell */ + } + + iupMatrixMemReAllocLines(ih, lines_num, lines_num-count, base); + + ih->data->lines.num -= count; + ih->data->need_calcsize = 1; + + if (ih->data->lines.focus_cell >= ih->data->lines.num) + ih->data->lines.focus_cell = ih->data->lines.num-1; + if (ih->data->lines.focus_cell <= 0) + ih->data->lines.focus_cell = 1; + + if (base < lines_num) /* If before the last line. (always true when deleting) */ + iMatrixUpdateLineAttributes(ih, base, count, 0); + + iupMatrixDraw(ih, 1); + return 0; +} + +int iupMatrixSetAddColAttrib(Ihandle* ih, const char* value) +{ + int base, count, columns_num = ih->data->columns.num; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + if (!iMatrixGetStartEnd(value, &base, &count, columns_num, 0)) + return 0; + + /* if the focus cell is after the inserted area */ + if (ih->data->columns.focus_cell >= base) + { + /* leave the edition mode */ + iupMatrixEditForceHidden(ih); + + /* move it to the same cell */ + ih->data->columns.focus_cell += count; + } + + iupMatrixMemReAllocColumns(ih, columns_num, columns_num+count, base); + + ih->data->columns.num += count; + ih->data->need_calcsize = 1; + + if (base < columns_num) /* If before the last column. */ + iMatrixUpdateColumnAttributes(ih, base, count, 1); + + iupMatrixDraw(ih, 1); + return 0; +} + +int iupMatrixSetDelColAttrib(Ihandle* ih, const char* value) +{ + int base, count, columns_num = ih->data->columns.num; + + if (!ih->handle) /* do not store the action before map */ + return 0; + + if (!iMatrixGetStartEnd(value, &base, &count, columns_num, 1)) + return 0; + + /* if the focus cell is after the removed area */ + if (ih->data->columns.focus_cell >= base) + { + /* leave the edition mode */ + iupMatrixEditForceHidden(ih); + + /* if the focus cell is inside the removed area */ + if (ih->data->columns.focus_cell <= base+count-1) + ih->data->columns.focus_cell = base; /* move it to the first existant cell */ + else + ih->data->columns.focus_cell -= count; /* move it to the same cell */ + } + + iupMatrixMemReAllocColumns(ih, columns_num, columns_num-count, base); + + ih->data->columns.num -= count; + ih->data->need_calcsize = 1; + + if (ih->data->columns.focus_cell >= ih->data->columns.num) + ih->data->columns.focus_cell = ih->data->columns.num-1; + if (ih->data->columns.focus_cell <= 0) + ih->data->columns.focus_cell = 1; + + if (base < columns_num) /* If before the last column. (always true when deleting) */ + iMatrixUpdateColumnAttributes(ih, base, count, 0); + + iupMatrixDraw(ih, 1); + return 0; +} + +int iupMatrixSetNumLinAttrib(Ihandle* ih, const char* value) +{ + int num = 0; + if (iupStrToInt(value, &num)) + { + if (num < 0) num = 0; + + num++; /* add room for title line */ + + /* can be set before map */ + if (ih->handle) + { + int base; /* base is after the end */ + if (num >= ih->data->lines.num) /* add or alloc */ + base = ih->data->lines.num; + else + base = num; + iupMatrixMemReAllocLines(ih, ih->data->lines.num, num, base); + } + + ih->data->lines.num = num; + ih->data->need_calcsize = 1; + + if (ih->handle) + iupMatrixDraw(ih, 1); + } + + return 0; +} + +int iupMatrixSetNumColAttrib(Ihandle* ih, const char* value) +{ + int num = 0; + if (iupStrToInt(value, &num)) + { + if (num < 0) num = 0; + + num++; /* add room for title column */ + + /* can be set before map */ + if (ih->handle) + { + int base; /* base is after the end */ + if (num >= ih->data->columns.num) /* add or alloc */ + base = ih->data->columns.num; + else + base = num; + iupMatrixMemReAllocColumns(ih, ih->data->columns.num, num, base); + } + + ih->data->columns.num = num; + ih->data->need_calcsize = 1; + + if (ih->handle) + iupMatrixDraw(ih, 1); + } + + return 0; +} diff --git a/iup/srccontrols/matrix/iupmat_numlc.h b/iup/srccontrols/matrix/iupmat_numlc.h new file mode 100755 index 0000000..df5e16f --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_numlc.h @@ -0,0 +1,27 @@ +/** \file + * \brief iupmatrix. change number of collumns or lines. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_NUMLC_H +#define __IUPMAT_NUMLC_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixSetAddLinAttrib(Ihandle* ih, const char* value); +int iupMatrixSetDelLinAttrib(Ihandle* ih, const char* value); +int iupMatrixSetAddColAttrib(Ihandle* ih, const char* value); +int iupMatrixSetDelColAttrib(Ihandle* ih, const char* value); + +int iupMatrixSetNumLinAttrib(Ihandle* ih, const char* value); +int iupMatrixSetNumColAttrib(Ihandle* ih, const char* value); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmat_scroll.c b/iup/srccontrols/matrix/iupmat_scroll.c new file mode 100755 index 0000000..24bbef2 --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_scroll.c @@ -0,0 +1,495 @@ +/** \file + * \brief iupmatrix control + * scrolling + * + * See Copyright Notice in "iup.h" + */ + +#include "iup.h" +#include "iupcbs.h" + +#include <cd.h> + +#include "iup_object.h" +#include "iup_stdcontrols.h" + +#include "iupmat_def.h" +#include "iupmat_scroll.h" +#include "iupmat_focus.h" +#include "iupmat_aux.h" +#include "iupmat_edit.h" +#include "iupmat_draw.h" + + +/* Macros used by "dir" parameter of the iMatrixScrollLine and iMatrixScrollColumn functions */ +#define IMAT_SCROLL_LEFT 0 +#define IMAT_SCROLL_RIGHT 1 +#define IMAT_SCROLL_UP 2 +#define IMAT_SCROLL_DOWN 3 + + +/**************************************************************************/ +/* Private functions */ +/**************************************************************************/ + + +static int iMatrixScrollIsFullVisibleLast(ImatLinColData *p) +{ + int i, sum = 0; + + for(i = p->first; i <= p->last; i++) + sum += p->sizes[i]; + + if (sum > p->visible_size) + return 0; + else + return 1; +} + +/* Scroll columns/lines in the left/top side of the matriz until the last column/line is FULLY visible. + -> m : Define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] */ +static void iMatrixScrollToVisible(Ihandle* ih, int m, int index) +{ + ImatLinColData* p; + + if (m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + if (index < p->first) + { + p->first = index; + return; + } + else if (index > p->last) + { + /* Increment the first column/line until the index is visible */ + while(index > p->last && p->last != (p->num - 1)) + { + p->first++; + iupMatrixAuxUpdateLast(p); + } + } + + if (index == p->last) + { + /* must increment util the last is fully visible */ + while(index == p->last && p->last != (p->num - 1) && !iMatrixScrollIsFullVisibleLast(p)) + { + p->first++; + iupMatrixAuxUpdateLast(p); + } + } +} + +/* Callback to report to the user which visualization area of + the matrix changed. */ +static void iMatrixScrollCallScrollTopCb(Ihandle* ih) +{ + IFnii cb = (IFnii)IupGetCallback(ih, "SCROLLTOP_CB"); + if (cb) + cb(ih, ih->data->lines.first, ih->data->columns.first); +} + +static int iMatrixScrollGetNextNonEmpty(Ihandle* ih, int m, int index) +{ + ImatLinColData* p; + + if (m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + while(index < p->num && p->sizes[index] == 0) + index++; + + if (index > p->num-1) + { + if (p->num == 1) + return 1; + else + return p->num-1; + } + else + return index; +} + +static int iMatrixScrollGetPrevNonEmpty(Ihandle* ih, int m, int index) +{ + ImatLinColData* p; + + if (m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + while(index > 0 && p->sizes[index] == 0) + index--; + + if (index < 1) + return 1; + else + return index; +} + +static void iMatrixScrollSetFocusScrollToVisible(Ihandle* ih, int m, int index) +{ + if (m == IMAT_PROCESS_COL) + iupMatrixFocusSet(ih, ih->data->lines.focus_cell, index); + else + iupMatrixFocusSet(ih, index, ih->data->columns.focus_cell); + + /* set for both because current focus maybe hidden */ + iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); + iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); +} + +/**************************************************************************/ +/* Exported functions */ +/**************************************************************************/ + + +/* Move using the cells of matrix. + Receive as a parameter a pointer to a function that will make the work, + in fact. This is done to avoid a test to each of the manipulation cursor + functions, verifying if it is necessary to call or not the scroll + callback. This is only done here. + -> func - pointer to the function that will make the movement + -> mode - parameter passed to func, specify if the movement request is of + the scrollbar or the keyboard + -> pos - parameter passed to func, that will be the handle position function + of the scrollbar, returning the scrollbar thumb position... + if func is other function, this parameter will be ignored + -> m - parameter passed to func, specify which is the mode of operation: + lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixScrollMoveCursor(iupMatrixScrollMoveF func, Ihandle* ih, int mode, float pos, int m) +{ + int old_lines_first = ih->data->lines.first; + int old_columns_first = ih->data->columns.first; + + iupMatrixEditForceHidden(ih); + + func(ih, mode, pos, m); + + if (ih->data->lines.first != old_lines_first || ih->data->columns.first != old_columns_first) + { + if (ih->data->columns.first != old_columns_first) + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); + + if (ih->data->lines.first != old_lines_first) + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); + + iMatrixScrollCallScrollTopCb(ih); + + iupMatrixDraw(ih, 0); + } +} + +void iupMatrixScrollToVisible(Ihandle* ih, int lin, int col) +{ + int old_lines_first = ih->data->lines.first; + int old_columns_first = ih->data->columns.first; + + iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, col); + iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, lin); + + if (ih->data->lines.first != old_lines_first || ih->data->columns.first != old_columns_first) + { + if (ih->data->columns.first != old_columns_first) + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); + + if (ih->data->lines.first != old_lines_first) + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); + + iMatrixScrollCallScrollTopCb(ih); + + iupMatrixDraw(ih, 1); + } +} + +/* This function is called when the "home" key is pressed. + In the first time, go to the beginning of the line. + In the second time, go to the beginning of the page. + In the third time, go to the beginning of the matrix. + -> mode and pos : DO NOT USED. +*/ +void iupMatrixScrollHome(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) +{ + (void)unused_m; + (void)unused_mode; + (void)unused_pos; + + /* called only for mode==IMAT_SCROLLKEY */ + + if(ih->data->homekeycount == 0) /* go to the beginning of the line */ + { + ih->data->columns.first = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, 1); + iMatrixScrollSetFocusScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.first); + } + else if(ih->data->homekeycount == 1) /* go to the beginning of the visible page */ + { + iupMatrixFocusSet(ih, ih->data->lines.first, ih->data->columns.first); + + /* set for both because current focus maybe hidden */ + iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); + iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); + } + else if(ih->data->homekeycount == 2) /* go to the beginning of the matrix 1:1 */ + { + ih->data->columns.first = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, 1); + ih->data->lines.first = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_LIN, 1); + + iupMatrixFocusSet(ih, ih->data->lines.first, ih->data->columns.first); + + /* set for both because current focus maybe hidden */ + iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); + iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); + } +} + +/* This function is called when the "end" key is pressed. + In the first time, go to the end of the line. + In the second time, go to the end of the page. + In the third time, go to the end of the matrix. + -> mode and pos : DO NOT USED. +*/ +void iupMatrixScrollEnd(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) +{ + (void)unused_m; + (void)unused_mode; + (void)unused_pos; + + /* called only for mode==IMAT_SCROLLKEY */ + + if(ih->data->endkeycount == 0) /* go to the end of the line */ + { + int last_col = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_COL, ih->data->columns.num-1); + iMatrixScrollSetFocusScrollToVisible(ih, IMAT_PROCESS_COL, last_col); + } + else if(ih->data->endkeycount == 1) /* go to the end of the visible page */ + { + iupMatrixFocusSet(ih, ih->data->lines.last, ih->data->columns.last); + + /* set for both because current focus maybe hidden */ + iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); + iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); + } + else if(ih->data->endkeycount == 2) /* go to the end of the matrix */ + { + int last_col = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_COL, ih->data->columns.num-1); + int last_lin = iMatrixScrollGetPrevNonEmpty(ih, IMAT_PROCESS_LIN, ih->data->lines.num-1); + + iupMatrixFocusSet(ih, last_lin, last_col); + + /* set for both because current focus maybe hidden */ + iMatrixScrollToVisible(ih, IMAT_PROCESS_COL, ih->data->columns.focus_cell); + iMatrixScrollToVisible(ih, IMAT_PROCESS_LIN, ih->data->lines.focus_cell); + } +} + +/* This function is called to move a cell to the left or up. + -> mode : indicate if the command was from the keyboard or the scrollbar. If scrollbar, + do not change the focus. + -> pos : DO NOT USED + -> m : define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixScrollLeftUp(Ihandle* ih, int mode, float pos, int m) +{ + ImatLinColData* p; + (void)pos; + + if(m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + if (mode == IMAT_SCROLLKEY) + { + int next = iMatrixScrollGetPrevNonEmpty(ih, m, p->focus_cell-1); + iMatrixScrollSetFocusScrollToVisible(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { + p->first = iMatrixScrollGetPrevNonEmpty(ih, m, p->first-1); + } +} + +/* This function is called to move a cell to the right or down. + -> mode : indicate if the command from the keyboard or the scrollbar. If scrollbar, + do not change the focus. + -> pos : DO NOT USED + -> m : define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixScrollRightDown(Ihandle* ih, int mode, float pos, int m) +{ + ImatLinColData* p; + (void)pos; + + if(m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + if (mode == IMAT_SCROLLKEY) + { + int next = iMatrixScrollGetNextNonEmpty(ih, m, p->focus_cell+1); + iMatrixScrollSetFocusScrollToVisible(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { + p->first = iMatrixScrollGetNextNonEmpty(ih, m, p->first+1); + } +} + +/* This function is called to move a page to the left or up. + -> mode : indicate if the command was from the keyboard or the scrollbar. If scrollbar, + do not change the focus. + -> pos : DO NOT USED + -> m : define the mode of operation: lines (PgLeft) or columns (PgUp) [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixScrollPgLeftUp(Ihandle* ih, int mode, float pos, int m) +{ + ImatLinColData* p; + (void)pos; + + if(m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + if (mode == IMAT_SCROLLKEY) + { + int next = iMatrixScrollGetPrevNonEmpty(ih, m, p->focus_cell - (p->last - p->first)); + iMatrixScrollSetFocusScrollToVisible(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { + p->first = iMatrixScrollGetPrevNonEmpty(ih, m, p->first - (p->last - p->first)); + } +} + +/* This function is called to move a page to the right or down. + -> mode : indicate if the command was from the keyboard or the scrollbar. If scrollbar, + do not change the focus. + -> pos : DO NOT USED + -> m : define the mode of operation: lines (PgDown) or columns (PgRight) [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixScrollPgRightDown(Ihandle* ih, int mode, float pos, int m) +{ + ImatLinColData* p; + (void)pos; + + if(m == IMAT_PROCESS_LIN) + p = &(ih->data->lines); + else + p = &(ih->data->columns); + + if (mode == IMAT_SCROLLKEY) + { + int next = iMatrixScrollGetNextNonEmpty(ih, IMAT_PROCESS_COL, p->focus_cell + (p->last - p->first)); + iMatrixScrollSetFocusScrollToVisible(ih, m, next); + } + else /* IMAT_SCROLLBAR */ + { + p->first = iMatrixScrollGetPrevNonEmpty(ih, m, p->first + (p->last - p->first)); + } +} + +void iupMatrixScrollCr(Ihandle* ih, int unused_mode, float unused_pos, int unused_m) +{ + int oldlin = ih->data->lines.focus_cell; + int oldcol = ih->data->columns.focus_cell; + (void)unused_m; + (void)unused_mode; + (void)unused_pos; + + /* called only for mode==IMAT_SCROLLKEY */ + + /* try the normal processing of next cell down */ + iupMatrixScrollRightDown(ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN); + + if(ih->data->lines.focus_cell == oldlin && ih->data->columns.focus_cell == oldcol) + { + /* If focus was not changed, it was because it is in the last line of the column. + Go to the next column of the same line. */ + iupMatrixScrollRightDown(ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL); + } +} + +/* This function is called when a drag is performed in the scrollbar. + -> x : scrollbar thumb position, value between 0 and 1 + -> mode : DO NOT USED + -> m : define the mode of operation: lines or columns [IMAT_PROCESS_LIN|IMAT_PROCESS_COL] +*/ +void iupMatrixScrollPos(Ihandle* ih, int mode, float pos, int m) +{ + int scroll_pos, index, vp; + float d; + ImatLinColData* p; + (void)mode; + + if (m == IMAT_PROCESS_LIN) + { + p = &(ih->data->lines); + d = IupGetFloat(ih, "DY"); + } + else + { + p = &(ih->data->columns); + d = IupGetFloat(ih, "DX"); + } + + if (p->num == 1) + { + p->first = 1; + return; + } + + scroll_pos = (int)(pos * p->total_size + 0.5); + + vp = 0; + for(index = 1; index < p->num; index++) + { + vp += p->sizes[index]; + if (vp > scroll_pos) + break; + } + + if (index == p->num) + { + if (p->num == 1) + index = 1; + else + index = p->num-1; + } + + p->first = index; +} + +int iupMatrixScroll_CB(Ihandle* ih, int action, float x, float y) +{ + if (!iupMatrixIsValid(ih, 0)) + return IUP_DEFAULT; + + switch(action) + { + case IUP_SBUP : iupMatrixScrollUp(ih); break; + case IUP_SBDN : iupMatrixScrollDown(ih); break; + case IUP_SBPGUP : iupMatrixScrollPgUp(ih); break; + case IUP_SBPGDN : iupMatrixScrollPgDown(ih); break; + case IUP_SBRIGHT : iupMatrixScrollRight(ih); break; + case IUP_SBLEFT : iupMatrixScrollLeft(ih); break; + case IUP_SBPGRIGHT : iupMatrixScrollPgRight(ih); break; + case IUP_SBPGLEFT : iupMatrixScrollPgLeft(ih); break; + case IUP_SBPOSV : iupMatrixScrollPosVer(ih,y); break; + case IUP_SBPOSH : iupMatrixScrollPosHor(ih,x); break; + case IUP_SBDRAGV : iupMatrixScrollPosVer(ih,y); break; + case IUP_SBDRAGH : iupMatrixScrollPosHor(ih,x); break; + } + + iupMatrixDrawUpdate(ih); + + return IUP_DEFAULT; +} diff --git a/iup/srccontrols/matrix/iupmat_scroll.h b/iup/srccontrols/matrix/iupmat_scroll.h new file mode 100755 index 0000000..582442b --- /dev/null +++ b/iup/srccontrols/matrix/iupmat_scroll.h @@ -0,0 +1,69 @@ +/** \file + * \brief iupmatrix control + * scrolling. + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMAT_SCROLL_H +#define __IUPMAT_SCROLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +int iupMatrixScroll_CB(Ihandle* ih, int action, float x, float y); + +void iupMatrixScrollToVisible(Ihandle* ih, int lin, int col); + +typedef void (*iupMatrixScrollMoveF)(Ihandle* ih, int mode, float pos, int m); +void iupMatrixScrollMoveCursor(iupMatrixScrollMoveF func, Ihandle* ih, int mode, float pos, int m); + +/* Used only by the macros bellow */ +void iupMatrixScrollHome (Ihandle* ih, int, float, int); +void iupMatrixScrollEnd (Ihandle* ih, int, float, int); +void iupMatrixScrollLeftUp (Ihandle* ih, int, float, int); +void iupMatrixScrollRightDown (Ihandle* ih, int, float, int); +void iupMatrixScrollPgLeftUp (Ihandle* ih, int, float, int); +void iupMatrixScrollPgRightDown(Ihandle* ih, int, float, int); +void iupMatrixScrollPos (Ihandle* ih, int, float, int); +void iupMatrixScrollCr (Ihandle* ih, int, float, int); + +/* Mode used to "walk" inside the matrix. + It shows if the movement request was from the scrollbar or from a key. + Possible values for the "mode" parameter of the iupMatrixScrollMoveCursor function. + */ +#define IMAT_SCROLLBAR 0 +#define IMAT_SCROLLKEY 1 + +/* Macros to help during the call of iupMatrixScrollMoveCursor function */ + +/* used in the keyboard processing module */ +#define iupMatrixScrollKeyHome(ih) iupMatrixScrollMoveCursor(iupMatrixScrollHome , ih, IMAT_SCROLLKEY, 0, 0) +#define iupMatrixScrollKeyEnd(ih) iupMatrixScrollMoveCursor(iupMatrixScrollEnd , ih, IMAT_SCROLLKEY, 0, 0) +#define iupMatrixScrollKeyPgUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgLeftUp , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollKeyPgDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgRightDown, ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollKeyDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollKeyRight(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL) +#define iupMatrixScrollKeyUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollKeyLeft(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLKEY, 0, IMAT_PROCESS_COL) +#define iupMatrixScrollKeyCr(ih) iupMatrixScrollMoveCursor(iupMatrixScrollCr , ih, IMAT_SCROLLKEY, 0, 0) + +/* Used by the scrollbar callback only */ +#define iupMatrixScrollUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollLeft(ih) iupMatrixScrollMoveCursor(iupMatrixScrollLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +#define iupMatrixScrollDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollRight(ih) iupMatrixScrollMoveCursor(iupMatrixScrollRightDown , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +#define iupMatrixScrollPgUp(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollPgLeft(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgLeftUp , ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +#define iupMatrixScrollPgDown(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgRightDown, ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_LIN) +#define iupMatrixScrollPgRight(ih) iupMatrixScrollMoveCursor(iupMatrixScrollPgRightDown, ih, IMAT_SCROLLBAR, 0, IMAT_PROCESS_COL) +#define iupMatrixScrollPosVer(ih, y) iupMatrixScrollMoveCursor(iupMatrixScrollPos , ih, IMAT_SCROLLBAR, y, IMAT_PROCESS_LIN) +#define iupMatrixScrollPosHor(ih, x) iupMatrixScrollMoveCursor(iupMatrixScrollPos , ih, IMAT_SCROLLBAR, x, IMAT_PROCESS_COL) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/srccontrols/matrix/iupmatrix.c b/iup/srccontrols/matrix/iupmatrix.c new file mode 100755 index 0000000..20d618d --- /dev/null +++ b/iup/srccontrols/matrix/iupmatrix.c @@ -0,0 +1,980 @@ +/** \file + * \brief IupMatrix control core + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <stdarg.h> +#include <string.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupcontrols.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_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_controls.h" +#include "iup_register.h" + +#include "iupmat_def.h" +#include "iupmat_getset.h" +#include "iupmat_scroll.h" +#include "iupmat_aux.h" +#include "iupmat_mem.h" +#include "iupmat_mouse.h" +#include "iupmat_focus.h" +#include "iupmat_key.h" +#include "iupmat_numlc.h" +#include "iupmat_colres.h" +#include "iupmat_mark.h" +#include "iupmat_edit.h" +#include "iupmat_draw.h" + + +int iupMatrixIsValid(Ihandle* ih, int check_cells) +{ + if (!ih->data->cddbuffer) + return 0; + if (check_cells && ((ih->data->columns.num == 0) || (ih->data->lines.num == 0))) + return 0; + return 1; +} + +static int iMatrixSetOriginAttrib(Ihandle* ih, const char* value) +{ + int lin = -1, col = -1; + + /* Get the parameters. The '*' indicates that want to keep the table in + the same line or column */ + if (iupStrToIntInt(value, &lin, &col, ':') != 2) + { + if (lin != -1) + col = ih->data->columns.first; + else if (col != -1) + lin = ih->data->lines.first; + else + return 0; + } + + /* Check if the cell exists */ + if (!iupMatrixCheckCellPos(ih, lin, col)) + return 0; + + /* Can not be a title */ + if((lin < 1) || (col < 1)) + return 0; + + ih->data->columns.first = col; + ih->data->lines.first = lin; + + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_COL); + iupMatrixAuxUpdateVisiblePos(ih, IMAT_PROCESS_LIN); + + iupMatrixDraw(ih, 1); + return 0; +} + +static int iMatrixSetShowAttrib(Ihandle* ih, const char* value) +{ + int lin = -1, col = -1; + + /* Get the parameters. The '*' indicates that want to keep the table in + the same line or column */ + if (iupStrToIntInt(value, &lin, &col, ':') != 2) + { + if (lin != -1) + col = ih->data->columns.first; + else if (col != -1) + lin = ih->data->lines.first; + else + return 0; + } + + /* Check if the cell exists */ + if (!iupMatrixCheckCellPos(ih, lin, col)) + return 0; + + /* Can not be a title */ + if((lin < 1) || (col < 1)) + return 0; + + if (!iupMatrixAuxIsCellFullVisible(ih, lin, col)) + iupMatrixScrollToVisible(ih, lin, col); + + return 0; +} + +static char* iMatrixGetOriginAttrib(Ihandle* ih) +{ + char* val = iupStrGetMemory(100); + sprintf(val, "%d:%d", ih->data->lines.first, ih->data->columns.first); + return val; +} + +static int iMatrixSetFocusCellAttrib(Ihandle* ih, const char* value) +{ + int lin = 0, col = 0; + if (iupStrToIntInt(value, &lin, &col, ':') == 2) + { + if (!iupMatrixCheckCellPos(ih, lin, col)) + return 0; + + if (lin <= 0 || col <= 0) /* title can NOT have the focus */ + return 0; + if (lin >= ih->data->lines.num || col >= ih->data->columns.num) + return 0; + + iupMatrixFocusSet(ih, lin, col); + + if (ih->data->cddbuffer) + iupMatrixDrawUpdate(ih); + } + + return 0; +} + +static char* iMatrixGetFocusCellAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(100); + sprintf(str, "%d:%d", ih->data->lines.focus_cell, ih->data->columns.focus_cell); + return str; +} + +static int iMatrixSetUseTitleSizeAttrib(Ihandle* ih, const char* value) +{ + /* can be set only before map */ + if (ih->handle) + return 0; + + if (iupStrBoolean(value)) + ih->data->use_title_size = 1; + else + ih->data->use_title_size = 0; + + return 0; +} + +static char* iMatrixGetUseTitleSizeAttrib(Ihandle* ih) +{ + if (ih->data->use_title_size) + return "YES"; + else + return "NO"; +} + +static int iMatrixSetValueAttrib(Ihandle* ih, const char* value) +{ + if (IupGetInt(ih->data->datah, "VISIBLE")) + IupStoreAttribute(ih->data->datah, "VALUE", value); + else + iupMatrixCellSetValue(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell, value); + return 0; +} + +static char* iMatrixGetValueAttrib(Ihandle* ih) +{ + if (IupGetInt(ih->data->datah, "VISIBLE")) + return iupMatrixEditGetValue(ih); + else + return iupMatrixCellGetValue(ih, ih->data->lines.focus_cell, ih->data->columns.focus_cell); +} + +static int iMatrixSetCaretAttrib(Ihandle* ih, const char* value) +{ + IupStoreAttribute(ih->data->texth, "CARET", value); + return 1; +} + +static char* iMatrixGetCaretAttrib(Ihandle* ih) +{ + return IupGetAttribute(ih->data->texth, "CARET"); +} + +static int iMatrixSetSelectionAttrib(Ihandle* ih, const char* value) +{ + IupStoreAttribute(ih->data->texth, "SELECTION", value); + return 1; +} + +static char* iMatrixGetSelectionAttrib(Ihandle* ih) +{ + return IupGetAttribute(ih->data->texth, "SELECTION"); +} + +static int iMatrixSetMultilineAttrib(Ihandle* ih, const char* value) +{ + IupStoreAttribute(ih->data->texth, "MULTILINE", value); + if (iupStrBoolean(value)) + IupSetAttribute(ih->data->texth, "SCROLLBAR", "NO"); + return 1; +} + +static char* iMatrixGetMultilineAttrib(Ihandle* ih) +{ + return IupGetAttribute(ih->data->texth, "MULTILINE"); +} + +static char* iMatrixGetNumLinAttrib(Ihandle* ih) +{ + char* num = iupStrGetMemory(100); + sprintf(num, "%d", ih->data->lines.num-1); + return num; +} + +static char* iMatrixGetNumColAttrib(Ihandle* ih) +{ + char* num = iupStrGetMemory(100); + sprintf(num, "%d", ih->data->columns.num-1); + return num; +} + +static int iMatrixSetMarkModeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "CELL")) + ih->data->mark_mode = IMAT_MARK_CELL; + else if (iupStrEqualNoCase(value, "LIN")) + ih->data->mark_mode = IMAT_MARK_LIN; + else if (iupStrEqualNoCase(value, "COL")) + ih->data->mark_mode = IMAT_MARK_COL; + else if(iupStrEqualNoCase(value, "LINCOL")) + ih->data->mark_mode = IMAT_MARK_LINCOL; + else + ih->data->mark_mode = IMAT_MARK_NO; + + if (ih->handle) + { + iupMatrixMarkClearAll(ih, 0); + iupMatrixDraw(ih, 1); + } + return 0; +} + +static char* iMatrixGetMarkModeAttrib(Ihandle* ih) +{ + char* mark2str[] = {"NO", "LIN", "COL", "LINCOL", "CELL"}; + return mark2str[ih->data->mark_mode]; +} + +static int iMatrixSetMarkAreaAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "NOT_CONTINUOUS")) + ih->data->mark_continuous = 0; + else + ih->data->mark_continuous = 1; + + if (ih->handle) + { + iupMatrixMarkClearAll(ih, 0); + iupMatrixDraw(ih, 1); + } + return 0; +} + +static char* iMatrixGetMarkAreaAttrib(Ihandle* ih) +{ + if (ih->data->mark_continuous) + return "CONTINUOUS"; + else + return "NOT_CONTINUOUS"; +} + +static int iMatrixSetMarkMultipleAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + ih->data->mark_multiple = 1; + else + ih->data->mark_multiple = 0; + + if (ih->handle) + { + iupMatrixMarkClearAll(ih, 0); + iupMatrixDraw(ih, 1); + } + return 0; +} + +static char* iMatrixGetMarkMultipleAttrib(Ihandle* ih) +{ + if (ih->data->mark_multiple) + return "YES"; + else + return "NO"; +} + +static int iMatrixSetEditModeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + iupMatrixEditShow(ih); + else + { + iupMatrixEditHide(ih); + iupMatrixDrawUpdate(ih); + } + return 1; +} + +static char* iMatrixGetEditModeAttrib(Ihandle* ih) +{ + if (iupMatrixEditIsVisible(ih)) + return "YES"; + else + return "NO"; +} + +static int iMatrixSetActiveAttrib(Ihandle* ih, const char* value) +{ + iupBaseSetActiveAttrib(ih, value); + iupMatrixDraw(ih, 1); + return 0; +} + +static int iMatrixSetWidthAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int col = 0; + if (iupStrToInt(name_id, &col)) + { + (void)value; + ih->data->need_calcsize = 1; + IupUpdate(ih); + } + return 1; +} + +static char* iMatrixGetWidthAttrib(Ihandle* ih, const char* name_id) +{ + int col; + if (iupStrToInt(name_id, &col)) + return iupMatrixGetSize(ih, col, IMAT_PROCESS_COL, 0); + return NULL; +} + +static int iMatrixSetHeightAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int lin = 0; + if (iupStrToInt(name_id, &lin)) + { + (void)value; + ih->data->need_calcsize = 1; + IupUpdate(ih); + } + return 1; +} + +static char* iMatrixGetHeightAttrib(Ihandle* ih, const char* name_id) +{ + int lin; + if (iupStrToInt(name_id, &lin)) + return iupMatrixGetSize(ih, lin, IMAT_PROCESS_LIN, 0); + return NULL; +} + +static int iMatrixSetRasterWidthAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int col = 0; + if (iupStrToInt(name_id, &col)) + { + (void)value; + ih->data->need_calcsize = 1; + IupUpdate(ih); + } + return 1; +} + +static char* iMatrixGetRasterWidthAttrib(Ihandle* ih, const char* name_id) +{ + int col; + if (iupStrToInt(name_id, &col)) + return iupMatrixGetSize(ih, col, IMAT_PROCESS_COL, 1); + return NULL; +} + +static int iMatrixSetRasterHeightAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int lin = 0; + if (iupStrToInt(name_id, &lin)) + { + (void)value; + ih->data->need_calcsize = 1; + IupUpdate(ih); + } + return 1; +} + +static char* iMatrixGetRasterHeightAttrib(Ihandle* ih, const char* name_id) +{ + int lin; + if (iupStrToInt(name_id, &lin)) + return iupMatrixGetSize(ih, lin, IMAT_PROCESS_LIN, 1); + return NULL; +} + +static char* iMatrixGetAlignmentAttrib(Ihandle* ih, const char* name_id) +{ + char* align; + char str[50]; + sprintf(str, "ALIGNMENT%s", name_id); + align = iupAttribGet(ih, str); + if (!align) + { + int col; + if (iupStrToInt(name_id, &col)) + { + if (col == 0) + return "ALEFT"; + else + return "ACENTER"; + } + } + + return NULL; +} + +static int iMatrixSetIdValueAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int lin = 0, col = 0; + if (iupStrToIntInt(name_id, &lin, &col, ':') == 2) + { + if (iupMatrixCheckCellPos(ih, lin, col)) + iupMatrixCellSetValue(ih, lin, col, value); + } + return 0; +} + +static char* iMatrixGetIdValueAttrib(Ihandle* ih, const char* name_id) +{ + int lin, col; + if (iupStrToIntInt(name_id, &lin, &col, ':') == 2) + { + if (iupMatrixCheckCellPos(ih, lin, col)) + return iupMatrixCellGetValue(ih, lin, col); + } + return NULL; +} + +static int iMatrixSetFlagsAttrib(Ihandle* ih, const char* name_id, const char* value, unsigned char attr) +{ + if (name_id[0]==0) + return 1; + if (name_id[0]=='*' && name_id[1]==':') + { + int col; + name_id += 2; /* skip '*' and ':' */ + if (iupStrToInt(name_id, &col)) + iupMatrixCellSetFlag(ih, -1, col, attr, value!=NULL); + } + else if (name_id[strlen(name_id)-1]=='*') + { + int lin; + if (iupStrToInt(name_id, &lin)) + iupMatrixCellSetFlag(ih, lin, -1, attr, value!=NULL); + } + else + { + int lin, col; + if (iupStrToIntInt(name_id, &lin, &col, ':') == 2) + iupMatrixCellSetFlag(ih, lin, col, attr, value!=NULL); + } + return 1; +} + +static int iMatrixSetBgColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + return iMatrixSetFlagsAttrib(ih, name_id, value, IUPMAT_BGCOLOR); +} + +static int iMatrixSetFgColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + return iMatrixSetFlagsAttrib(ih, name_id, value, IUPMAT_FGCOLOR); +} + +static int iMatrixSetFontAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + return iMatrixSetFlagsAttrib(ih, name_id, value, IUPMAT_FONT); +} + +static int iMatrixSetFrameHorizColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + ih->data->checkframecolor = value!=NULL; + return iMatrixSetFlagsAttrib(ih, name_id, value, IUPMAT_FRAMEHCOLOR); +} + +static int iMatrixSetFrameVertColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + ih->data->checkframecolor = value!=NULL; + return iMatrixSetFlagsAttrib(ih, name_id, value, IUPMAT_FRAMEVCOLOR); +} + +static char* iMatrixGetFontAttrib(Ihandle* ih, const char* name_id) +{ + if (name_id[0]==0) + return iupGetFontAttrib(ih); + return NULL; +} + +static char* iMatrixGetBgColorAttrib(Ihandle* ih, const char* name_id) +{ + if (name_id[0]==0) + { + /* check the hash table */ + char *color = iupAttribGet(ih, "BGCOLOR"); + + /* If not defined return the default for normal cells */ + if (!color) + color = IupGetGlobal("TXTBGCOLOR"); + + return color; + } + return NULL; +} + +static char* iMatrixGetNumColVisibleAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(50); + sprintf(buffer, "%d", ih->data->columns.last - ih->data->columns.first); + return buffer; +} + +static char* iMatrixGetNumLinVisibleAttrib(Ihandle* ih) +{ + char* buffer = iupStrGetMemory(50); + sprintf(buffer, "%d", ih->data->lines.last - ih->data->lines.first); + return buffer; +} + +static char* iMatrixGetMaskDataAttrib(Ihandle* ih) +{ + /* Used only by the OLD iupmask API */ + if (IupGetInt(ih->data->datah, "VISIBLE")) + return IupGetAttribute(ih->data->datah,"OLD_MASK_DATA"); + else + return NULL; +} + + +/*****************************************************************************/ +/* Callbacks registered to the Canvas */ +/*****************************************************************************/ + + +static int iMatrixResize_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); + + iupMatrixEditForceHidden(ih); + + ih->data->need_calcsize = 1; + iupMatrixDraw(ih, 0); + + return IUP_DEFAULT; +} + +static int iMatrixRedraw_CB(Ihandle* ih) +{ + if (!ih->data->cddbuffer) + return IUP_DEFAULT; + + if (!ih->data->first_redraw) + { + ih->data->first_redraw = 1; + iupMatrixDraw(ih, 0); + } + + iupMatrixDrawUpdate(ih); + + return IUP_DEFAULT; +} + + +/***************************************************************************/ + + +static int iMatrixCreateMethod(Ihandle* ih, void **params) +{ + if (params && params[0]) + { + char* action_cb = (char*)params[0]; + iupAttribStoreStr(ih, "ACTION_CB", action_cb); + } + + /* free the data allocated by IupCanvas */ + if (ih->data) free(ih->data); + ih->data = iupALLOCCTRLDATA(); + + /* change the IupCanvas default values */ + iupAttribSetStr(ih, "SCROLLBAR", "YES"); + iupAttribSetStr(ih, "BORDER", "NO"); + iupAttribSetStr(ih, "CURSOR", "IupMatrixCrossCursor"); + + /* IupCanvas callbacks */ + IupSetCallback(ih, "ACTION", (Icallback)iMatrixRedraw_CB); + IupSetCallback(ih, "RESIZE_CB", (Icallback)iMatrixResize_CB); + IupSetCallback(ih, "BUTTON_CB", (Icallback)iupMatrixMouseButton_CB); + IupSetCallback(ih, "MOTION_CB", (Icallback)iupMatrixMouseMove_CB); + IupSetCallback(ih, "KEYPRESS_CB", (Icallback)iupMatrixKeyPress_CB); + IupSetCallback(ih, "FOCUS_CB", (Icallback)iupMatrixFocus_CB); + IupSetCallback(ih, "SCROLL_CB", (Icallback)iupMatrixScroll_CB); + + /* Create the edit fields */ + iupMatrixEditCreate(ih); + + /* defaults */ + ih->data->datah = ih->data->texth; + ih->data->mark_continuous = 1; + ih->data->columns.num = 1; + ih->data->lines.num = 1; + ih->data->need_calcsize = 1; + ih->data->lines.first = 1; + ih->data->columns.first = 1; + ih->data->lines.focus_cell = 1; + ih->data->columns.focus_cell = 1; + ih->data->mark_lin1 = -1; + ih->data->mark_col1 = -1; + ih->data->mark_lin2 = -1; + ih->data->mark_col2 = -1; + ih->data->use_title_size = 0; + + return IUP_NOERROR; +} + +static int iMatrixMapMethod(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); + + if (IupGetCallback(ih, "VALUE_CB")) + { + ih->data->callback_mode = 1; + + if (!IupGetCallback(ih, "VALUE_EDIT_CB")) + iupAttribSetStr(ih, "READONLY", "YES"); + } + + iupMatrixMemAlloc(ih); + + return IUP_NOERROR; +} + +static void iMatrixUnMapMethod(Ihandle* ih) +{ + if(ih->data->cddbuffer) + { + cdKillCanvas(ih->data->cddbuffer); + ih->data->cddbuffer = NULL; + } + + if(ih->data->cdcanvas) + { + cdKillCanvas(ih->data->cdcanvas); + ih->data->cdcanvas = NULL; + } + + iupMatrixMemRelease(ih); +} + +static int iMatrixGetNaturalWidth(Ihandle* ih) +{ + int width = 0, num, col; + + num = iupAttribGetInt(ih, "NUMCOL_VISIBLE")+1; /* include the title column */ + + if (iupAttribGetInt(ih, "NUMCOL_VISIBLE_LAST")) + { + int start = ih->data->columns.num - (num-1); /* title is computed apart */ + if (start<1) start=1; + width += iupMatrixAuxGetColumnWidth(ih, 0); /* compute title */ + for(col = start; col < ih->data->columns.num; col++) + width += iupMatrixAuxGetColumnWidth(ih, col); + } + else + { + if (num > ih->data->columns.num) + num = ih->data->columns.num; + for(col = 0; col < num; col++) + width += iupMatrixAuxGetColumnWidth(ih, col); + } + + return width; +} + +static int iMatrixGetNaturalHeight(Ihandle* ih) +{ + int height = 0, num, lin; + + num = iupAttribGetInt(ih, "NUMLIN_VISIBLE")+1; /* include the title line */ + + if (iupAttribGetInt(ih, "NUMLIN_VISIBLE_LAST")) + { + int start = ih->data->lines.num - (num-1); /* title is computed apart */ + if (start<1) start=1; + height += iupMatrixAuxGetLineHeight(ih, 0); /* compute title */ + for(lin = start; lin < ih->data->lines.num; lin++) + height += iupMatrixAuxGetLineHeight(ih, lin); + } + else + { + if (num > ih->data->lines.num) + num = ih->data->lines.num; + for(lin = 0; lin < num; lin++) + height += iupMatrixAuxGetLineHeight(ih, lin); + } + + return height; +} + +static void iMatrixComputeNaturalSizeMethod(Ihandle* ih, int *w, int *h, int *expand) +{ + int natural_w = 0, natural_h = 0; + (void)expand; /* unset if not a container */ + + if (!ih->handle) + ih->data->canvas.sb = iupBaseGetScrollbar(ih); + + /* add scrollbar */ + if (ih->data->canvas.sb) + { + int sb_size = iupdrvGetScrollbarSize(); + if (ih->data->canvas.sb & IUP_SB_HORIZ) + natural_w += sb_size; + if (ih->data->canvas.sb & IUP_SB_VERT) + natural_h += sb_size; + } + + *w = natural_w + iMatrixGetNaturalWidth(ih); + *h = natural_h + iMatrixGetNaturalHeight(ih); +} + +static void iMatrixCreateCursor(void) +{ + Ihandle *imgcursor; + unsigned char matrx_img_cur_excel[15*15] = + { + 0,0,0,0,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,1,2,2,2,2,1,1,0,0,0,0, + 0,0,0,0,1,2,2,2,2,1,1,0,0,0,0, + 0,0,0,0,1,2,2,2,2,1,1,0,0,0,0, + 1,1,1,1,1,2,2,2,2,1,1,1,1,1,0, + 1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, + 1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, + 1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, + 1,1,1,1,1,2,2,2,2,1,1,1,1,1,1, + 0,1,1,1,1,2,2,2,2,1,1,1,1,1,1, + 0,0,0,0,1,2,2,2,2,1,1,0,0,0,0, + 0,0,0,0,1,2,2,2,2,1,1,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,0,0,0,0, + 0,0,0,0,0,1,1,1,1,1,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + + imgcursor = IupImage(15, 15, matrx_img_cur_excel); + IupSetAttribute(imgcursor, "0", "BGCOLOR"); + IupSetAttribute(imgcursor, "1", "0 0 0"); + IupSetAttribute(imgcursor, "2", "255 255 255"); + IupSetAttribute(imgcursor, "HOTSPOT", "7:7"); /* Centered Hotspot */ + IupSetHandle("IupMatrixCrossCursor", imgcursor); + IupSetHandle("matrx_img_cur_excel", imgcursor); /* for backward compatibility */ +} + +Iclass* iupMatrixGetClass(void) +{ + Iclass* ic = iupClassNew(iupCanvasGetClass()); + + ic->name = "matrix"; + ic->format = "A"; /* one optional callback name */ + ic->nativetype = IUP_TYPECANVAS; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 1; + ic->has_attrib_id = 1; /* has attributes with IDs that must be parsed */ + + /* Class functions */ + ic->Create = iMatrixCreateMethod; + ic->Map = iMatrixMapMethod; + ic->UnMap = iMatrixUnMapMethod; + ic->ComputeNaturalSize = iMatrixComputeNaturalSizeMethod; + + /* Do not need to set base attributes because they are inherited from IupCanvas */ + + /* IupMatrix Callbacks */ + /* --- Interaction --- */ + iupClassRegisterCallback(ic, "ACTION_CB", "iiiis"); + iupClassRegisterCallback(ic, "CLICK_CB", "iis"); + iupClassRegisterCallback(ic, "RELEASE_CB", "iis"); + iupClassRegisterCallback(ic, "MOUSEMOVE_CB", "ii"); + iupClassRegisterCallback(ic, "ENTERITEM_CB", "ii"); + iupClassRegisterCallback(ic, "LEAVEITEM_CB", "ii"); + iupClassRegisterCallback(ic, "SCROLLTOP_CB", "ii"); + /* --- Drawing --- */ + iupClassRegisterCallback(ic, "BGCOLOR_CB", "iiIII"); + iupClassRegisterCallback(ic, "FGCOLOR_CB", "iiIII"); + iupClassRegisterCallback(ic, "FONT_CB", "ii=s"); + iupClassRegisterCallback(ic, "DRAW_CB", "iiiiii"); + iupClassRegisterCallback(ic, "DROPCHECK_CB", "ii"); + /* --- Editing --- */ + iupClassRegisterCallback(ic, "DROP_CB", "nii"); + iupClassRegisterCallback(ic, "DROPSELECT_CB", "iinsii"); + iupClassRegisterCallback(ic, "EDITION_CB", "iii"); + /* --- Callback Mode --- */ + iupClassRegisterCallback(ic, "VALUE_CB", "ii=s"); + iupClassRegisterCallback(ic, "VALUE_EDIT_CB", "iis"); + iupClassRegisterCallback(ic, "MARK_CB", "ii"); + iupClassRegisterCallback(ic, "MARKEDIT_CB", "iii"); + + /* IupMatrix Attributes - CELL */ + iupClassRegisterAttributeId(ic, "IDVALUE", iMatrixGetIdValueAttrib, iMatrixSetIdValueAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FOCUS_CELL", iMatrixGetFocusCellAttrib, iMatrixSetFocusCellAttrib, IUPAF_SAMEASSYSTEM, "1:1", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can be NOT mapped */ + iupClassRegisterAttribute(ic, "VALUE", iMatrixGetValueAttrib, iMatrixSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FGCOLOR", NULL, iMatrixSetFgColorAttrib, IUPAF_NOT_MAPPED); + iupClassRegisterAttributeId(ic, "FONT", iMatrixGetFontAttrib, iMatrixSetFontAttrib, IUPAF_NOT_MAPPED); + iupClassRegisterAttributeId(ic, "FRAMEHORIZCOLOR", NULL, iMatrixSetFrameHorizColorAttrib, IUPAF_NOT_MAPPED); + iupClassRegisterAttributeId(ic, "FRAMEVERTCOLOR", NULL, iMatrixSetFrameVertColorAttrib, IUPAF_NOT_MAPPED); + + /* IupMatrix Attributes - COLUMN */ + iupClassRegisterAttributeId(ic, "ALIGNMENT", iMatrixGetAlignmentAttrib, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "SORTSIGN", NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupMatrix Attributes - SIZE */ + iupClassRegisterAttribute(ic, "NUMLIN", iMatrixGetNumLinAttrib, iupMatrixSetNumLinAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUMCOL", iMatrixGetNumColAttrib, iupMatrixSetNumColAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUMLIN_VISIBLE", iMatrixGetNumLinVisibleAttrib, NULL, IUPAF_SAMEASSYSTEM, "3", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUMCOL_VISIBLE", iMatrixGetNumColVisibleAttrib, NULL, IUPAF_SAMEASSYSTEM, "4", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUMLIN_VISIBLE_LAST", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NUMCOL_VISIBLE_LAST", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "WIDTHDEF", NULL, NULL, IUPAF_SAMEASSYSTEM, "80", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HEIGHTDEF", NULL, NULL, IUPAF_SAMEASSYSTEM, "8", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "WIDTH", iMatrixGetWidthAttrib, iMatrixSetWidthAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "HEIGHT", iMatrixGetHeightAttrib, iMatrixSetHeightAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "RASTERWIDTH", iMatrixGetRasterWidthAttrib, iMatrixSetRasterWidthAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "RASTERHEIGHT", iMatrixGetRasterHeightAttrib, iMatrixSetRasterHeightAttrib, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupMatrix Attributes - MARK */ + iupClassRegisterAttribute(ic, "MARKED", iupMatrixGetMarkedAttrib, iupMatrixSetMarkedAttrib, NULL, NULL, IUPAF_NO_INHERIT); /* noticed that MARKED must be mapped */ + iupClassRegisterAttributeId(ic, "MARK", iupMatrixGetMarkAttrib, iupMatrixSetMarkAttrib, IUPAF_NO_INHERIT); /* noticed that for MARK the matrix must be mapped */ + iupClassRegisterAttribute(ic, "MARK_MODE", iMatrixGetMarkModeAttrib, iMatrixSetMarkModeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARKMODE", iMatrixGetMarkModeAttrib, iMatrixSetMarkModeAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "AREA", iMatrixGetMarkAreaAttrib, iMatrixSetMarkAreaAttrib, IUPAF_SAMEASSYSTEM, "CONTINUOUS", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARKAREA", iMatrixGetMarkAreaAttrib, iMatrixSetMarkAreaAttrib, IUPAF_SAMEASSYSTEM, "CONTINUOUS", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MULTIPLE", iMatrixGetMarkMultipleAttrib, iMatrixSetMarkMultipleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MARKMULTIPLE", iMatrixGetMarkMultipleAttrib, iMatrixSetMarkMultipleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupMatrix Attributes - ACTION (only mapped) */ + iupClassRegisterAttribute(ic, "ADDLIN", NULL, iupMatrixSetAddLinAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DELLIN", NULL, iupMatrixSetDelLinAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDCOL", NULL, iupMatrixSetAddColAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DELCOL", NULL, iupMatrixSetDelColAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ORIGIN", iMatrixGetOriginAttrib, iMatrixSetOriginAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOW", NULL, iMatrixSetShowAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "EDIT_MODE", iMatrixGetEditModeAttrib, iMatrixSetEditModeAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REDRAW", NULL, iupMatrixDrawSetRedrawAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupMatrix Attributes - EDITION */ + iupClassRegisterAttribute(ic, "CARET", iMatrixGetCaretAttrib, iMatrixSetCaretAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", iMatrixGetSelectionAttrib, iMatrixSetSelectionAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MULTILINE", iMatrixGetMultilineAttrib, iMatrixSetMultilineAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MASK", NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* IupMatrix Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "USETITLESIZE", iMatrixGetUseTitleSizeAttrib, iMatrixSetUseTitleSizeAttrib, IUPAF_SAMEASSYSTEM, "NO", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FRAMECOLOR", NULL, NULL, IUPAF_SAMEASSYSTEM, "100 100 100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RESIZEMATRIX", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "HIDEFOCUS", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + /* Overwrite IupCanvas Attributes */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iMatrixSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttributeId(ic, "BGCOLOR", iMatrixGetBgColorAttrib, iMatrixSetBgColorAttrib, IUPAF_NOT_MAPPED); + + /* IupMatrix Attributes - MASK */ + iupClassRegisterAttribute(ic, "OLD_MASK_DATA", iMatrixGetMaskDataAttrib, NULL, NULL, NULL, IUPAF_NO_STRING|IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + if (!IupGetHandle("IupMatrixCrossCursor")) + iMatrixCreateCursor(); + + return ic; +} + + +/*****************************************************************************************************/ + + +Ihandle* IupMatrix(const char* action) +{ + void *params[2]; + params[0] = (void*)action; + params[1] = NULL; + return IupCreatev("matrix", params); +} + +void IupMatSetAttribute(Ihandle* ih, const char* a, int l, int c, char* v) +{ + char* attr = iupStrGetMemory(100); + sprintf(attr, "%s%d:%d", a, l, c); + IupSetAttribute(ih, attr, v); +} + +void IupMatStoreAttribute(Ihandle* ih, const char* a, int l, int c, char* v) +{ + char* attr = iupStrGetMemory(100); + sprintf(attr, "%s%d:%d", a, l, c); + IupStoreAttribute(ih, attr, v); +} + +char* IupMatGetAttribute(Ihandle* ih, const char* a, int l, int c) +{ + char* attr = iupStrGetMemory(100); + sprintf(attr, "%s%d:%d", a, l, c); + return IupGetAttribute(ih, attr); +} + +int IupMatGetInt(Ihandle* ih, const char* a, int l, int c) +{ + char* attr = iupStrGetMemory(100); + sprintf(attr, "%s%d:%d", a, l, c); + return IupGetInt(ih, attr); +} + +float IupMatGetFloat(Ihandle* ih, const char* a, int l, int c) +{ + char* attr = iupStrGetMemory(100); + sprintf(attr, "%s%d:%d", a, l, c); + return IupGetFloat(ih, attr); +} + +void IupMatSetfAttribute(Ihandle* ih, const char* a, int l, int c, char* f, ...) +{ + static char v[SHRT_MAX]; + char* attr = iupStrGetMemory(100); + va_list arglist; + sprintf(attr, "%s%d:%d", a, l, c); + va_start(arglist, f); + vsprintf(v, f, arglist); + va_end(arglist); + IupStoreAttribute(ih, attr, v); +} |