summaryrefslogtreecommitdiff
path: root/iup/srccontrols/iup_cells.c
diff options
context:
space:
mode:
Diffstat (limited to 'iup/srccontrols/iup_cells.c')
-rwxr-xr-xiup/srccontrols/iup_cells.c974
1 files changed, 974 insertions, 0 deletions
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");
+}