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