From d577d991b97ae2b5ee1af23641bcffc3f83af5b2 Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 4 Nov 2009 11:56:41 -0800 Subject: Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux. --- iup/src/gtk/iupgtk_text.c | 1716 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1716 insertions(+) create mode 100755 iup/src/gtk/iupgtk_text.c (limited to 'iup/src/gtk/iupgtk_text.c') diff --git a/iup/src/gtk/iupgtk_text.c b/iup/src/gtk/iupgtk_text.c new file mode 100755 index 0000000..4c2906a --- /dev/null +++ b/iup/src/gtk/iupgtk_text.c @@ -0,0 +1,1716 @@ +/** \file + * \brief Text Control + * + * See Copyright Notice in "iup.h" + */ + +#include + +#include +#include +#include +#include +#include + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_mask.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_key.h" +#include "iup_array.h" +#include "iup_text.h" + +#include "iupgtk_drv.h" + +#ifndef PANGO_WEIGHT_SEMIBOLD +#define PANGO_WEIGHT_SEMIBOLD 600 +#endif + +void iupdrvTextAddSpin(int *w, int h) +{ + int spin_size = 16; + *w += spin_size; + (void)h; +} + +void iupdrvTextAddBorders(int *x, int *y) +{ + int border_size = 2*5; + (*x) += border_size; + (*y) += border_size; +} + +static void gtkTextParseParagraphFormat(Ihandle* formattag, GtkTextTag* tag) +{ + int val; + char* format; + + format = iupAttribGet(formattag, "INDENT"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "indent", val, NULL); + + format = iupAttribGet(formattag, "ALIGNMENT"); + if (format) + { + if (iupStrEqualNoCase(format, "JUSTIFY")) + val = GTK_JUSTIFY_FILL; + else if (iupStrEqualNoCase(format, "RIGHT")) + val = GTK_JUSTIFY_RIGHT; + else if (iupStrEqualNoCase(format, "CENTER")) + val = GTK_JUSTIFY_CENTER; + else /* "LEFT" */ + val = GTK_JUSTIFY_LEFT; + + g_object_set(G_OBJECT(tag), "justification", val, NULL); + } + + format = iupAttribGet(formattag, "TABSARRAY"); + { + PangoTabArray *tabs; + int pos, i = 0; + PangoTabAlign align; + char* str; + + tabs = pango_tab_array_new(32, FALSE); + + while (format) + { + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + pos = atoi(str); + free(str); + + str = iupStrCopyUntil((char**)&format, ' '); + if (!str) break; + +/* if (iupStrEqualNoCase(str, "DECIMAL")) unsupported for now + align = PANGO_TAB_NUMERIC; + else if (iupStrEqualNoCase(str, "RIGHT")) + align = PANGO_TAB_RIGHT; + else if (iupStrEqualNoCase(str, "CENTER")) + align = PANGO_TAB_CENTER; + else */ /* "LEFT" */ + align = PANGO_TAB_LEFT; + free(str); + + pango_tab_array_set_tab(tabs, i, align, IUPGTK_PIXELS2PANGOUNITS(pos)); + i++; + if (i == 32) break; + } + + g_object_set(G_OBJECT(tag), "tabs", tabs, NULL); + pango_tab_array_free(tabs); + } + + format = iupAttribGet(formattag, "SPACEBEFORE"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "pixels-above-lines", val, NULL); + + format = iupAttribGet(formattag, "SPACEAFTER"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "pixels-below-lines", val, NULL); + + format = iupAttribGet(formattag, "LINESPACING"); + if (format && iupStrToInt(format, &val)) + g_object_set(G_OBJECT(tag), "pixels-inside-wrap", val, NULL); +} + +static void gtkTextParseCharacterFormat(Ihandle* formattag, GtkTextTag* tag) +{ + int val; + char* format; + + format = iupAttribGet(formattag, "LANGUAGE"); + if (format) + g_object_set(G_OBJECT(tag), "language", format, NULL); + + format = iupAttribGet(formattag, "STRETCH"); + if (format) + { + if (iupStrEqualNoCase(format, "EXTRA_CONDENSED")) + val = PANGO_STRETCH_EXTRA_CONDENSED; + else if (iupStrEqualNoCase(format, "CONDENSED")) + val = PANGO_STRETCH_CONDENSED; + else if (iupStrEqualNoCase(format, "SEMI_CONDENSED")) + val = PANGO_STRETCH_SEMI_CONDENSED; + else if (iupStrEqualNoCase(format, "SEMI_EXPANDED")) + val = PANGO_STRETCH_SEMI_EXPANDED; + else if (iupStrEqualNoCase(format, "EXPANDED")) + val = PANGO_STRETCH_EXPANDED; + else if (iupStrEqualNoCase(format, "EXTRA_EXPANDED")) + val = PANGO_STRETCH_EXTRA_EXPANDED; + else /* "NORMAL" */ + val = PANGO_STRETCH_NORMAL; + + g_object_set(G_OBJECT(tag), "stretch", val, NULL); + } + + format = iupAttribGet(formattag, "RISE"); + if (format) + { + val = 0; + + if (iupStrEqualNoCase(format, "SUPERSCRIPT")) + { + g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL); + val = 10; /* 10 pixels up */ + } + else if (iupStrEqualNoCase(format, "SUBSCRIPT")) + { + g_object_set(G_OBJECT(tag), "scale", PANGO_SCALE_X_SMALL, NULL); + val = -10; /* 10 pixels down */ + } + else + iupStrToInt(format, &val); + + val = IUPGTK_PIXELS2PANGOUNITS(val); + g_object_set(G_OBJECT(tag), "rise", val, NULL); + } + + format = iupAttribGet(formattag, "SMALLCAPS"); + if (format) + { + if (iupStrBoolean(format)) + val = PANGO_VARIANT_SMALL_CAPS; + else + val = PANGO_VARIANT_NORMAL; + g_object_set(G_OBJECT(tag), "variant", val, NULL); + } + + format = iupAttribGet(formattag, "ITALIC"); + if (format) + { + if (iupStrBoolean(format)) + val = PANGO_STYLE_ITALIC; + else + val = PANGO_STYLE_NORMAL; + g_object_set(G_OBJECT(tag), "style", val, NULL); + } + + format = iupAttribGet(formattag, "STRIKEOUT"); + if (format) + { + val = iupStrBoolean(format); + g_object_set(G_OBJECT(tag), "strikethrough", val, NULL); + } + + format = iupAttribGet(formattag, "PROTECTED"); + if (format) + { + val = iupStrBoolean(format); + g_object_set(G_OBJECT(tag), "editable", val, NULL); + } + + format = iupAttribGet(formattag, "FONTSIZE"); + if (format && iupStrToInt(format, &val)) + { + if (val < 0) /* in pixels */ + { + val = IUPGTK_PIXELS2PANGOUNITS(-val); + g_object_set(G_OBJECT(tag), "size", val, NULL); + } + else /* in points */ + g_object_set(G_OBJECT(tag), "size-points", (double)val, NULL); + } + + format = iupAttribGet(formattag, "FONTSCALE"); + if (format) + { + float fval = 0; + if (iupStrEqualNoCase(format, "XX-SMALL")) + fval = (float)PANGO_SCALE_XX_SMALL; + else if (iupStrEqualNoCase(format, "X-SMALL")) + fval = (float)PANGO_SCALE_X_SMALL; + else if (iupStrEqualNoCase(format, "SMALL")) + fval = (float)PANGO_SCALE_SMALL; + else if (iupStrEqualNoCase(format, "MEDIUM")) + fval = (float)PANGO_SCALE_MEDIUM; + else if (iupStrEqualNoCase(format, "LARGE")) + fval = (float)PANGO_SCALE_LARGE; + else if (iupStrEqualNoCase(format, "X-LARGE")) + fval = (float)PANGO_SCALE_X_LARGE; + else if (iupStrEqualNoCase(format, "XX-LARGE")) + fval = (float)PANGO_SCALE_XX_LARGE; + else + iupStrToFloat(format, &fval); + + if (fval > 0) + g_object_set(G_OBJECT(tag), "scale", (double)fval, NULL); + } + + format = iupAttribGet(formattag, "FONTFACE"); + if (format) + g_object_set(G_OBJECT(tag), "family", format, NULL); + + format = iupAttribGet(formattag, "FGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(tag), "foreground-gdk", &color, NULL); + } + } + + format = iupAttribGet(formattag, "BGCOLOR"); + if (format) + { + unsigned char r, g, b; + if (iupStrToRGB(format, &r, &g, &b)) + { + GdkColor color; + iupgdkColorSet(&color, r, g, b); + g_object_set(G_OBJECT(tag), "background-gdk", &color, NULL); + } + } + + format = iupAttribGet(formattag, "UNDERLINE"); + if (format) + { + if (iupStrEqualNoCase(format, "SINGLE")) + val = PANGO_UNDERLINE_SINGLE; + else if (iupStrEqualNoCase(format, "DOUBLE")) + val = PANGO_UNDERLINE_DOUBLE; + else /* "NONE" */ + val = PANGO_UNDERLINE_NONE; + + g_object_set(G_OBJECT(tag), "underline", val, NULL); + } + + format = iupAttribGet(formattag, "WEIGHT"); + if (format) + { + if (iupStrEqualNoCase(format, "EXTRALIGHT")) + val = PANGO_WEIGHT_ULTRALIGHT; + else if (iupStrEqualNoCase(format, "LIGHT")) + val = PANGO_WEIGHT_LIGHT; + else if (iupStrEqualNoCase(format, "SEMIBOLD")) + val = PANGO_WEIGHT_SEMIBOLD; + else if (iupStrEqualNoCase(format, "BOLD")) + val = PANGO_WEIGHT_BOLD; + else if (iupStrEqualNoCase(format, "EXTRABOLD")) + val = PANGO_WEIGHT_ULTRABOLD; + else if (iupStrEqualNoCase(format, "HEAVY")) + val = PANGO_WEIGHT_HEAVY; + else /* "NORMAL" */ + val = PANGO_WEIGHT_NORMAL; + + g_object_set(G_OBJECT(tag), "weight", val, NULL); + } +} + +static void gtkTextMoveIterToLinCol(GtkTextBuffer *buffer, GtkTextIter *iter, int lin, int col) +{ + int line_count, line_length; + + lin--; /* IUP starts at 1 */ + col--; + + line_count = gtk_text_buffer_get_line_count(buffer); + if (lin < 0) lin = 0; + if (lin >= line_count) + lin = line_count-1; + + gtk_text_buffer_get_iter_at_line(buffer, iter, lin); + line_length = gtk_text_iter_get_chars_in_line(iter); + + if (col < 0) col = 0; + if (col > line_length) + col = line_length; /* after the last character */ + + gtk_text_iter_set_line_offset(iter, col); +} + +static void gtkTextGetLinColFromPosition(const GtkTextIter *iter, int *lin, int *col) +{ + *lin = gtk_text_iter_get_line(iter); + *col = gtk_text_iter_get_line_offset(iter); + + (*lin)++; /* IUP starts at 1 */ + (*col)++; +} + +static int gtkTextGetCharSize(Ihandle* ih) +{ + int charwidth; + PangoFontMetrics* metrics; + PangoContext* context; + PangoFontDescription* fontdesc = (PangoFontDescription*)iupgtkGetPangoFontDescAttrib(ih); + if (!fontdesc) + return 0; + + context = gdk_pango_context_get(); + metrics = pango_context_get_metrics(context, fontdesc, pango_context_get_language(context)); + charwidth = pango_font_metrics_get_approximate_char_width(metrics); + pango_font_metrics_unref(metrics); + return charwidth; +} + +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtkTextMoveIterToLinCol(buffer, &iter, lin, col); + *pos = gtk_text_iter_get_offset(&iter); +} + +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos); + gtkTextGetLinColFromPosition(&iter, lin, col); +} + +static int gtkTextConvertXYToPos(Ihandle* ih, int x, int y) +{ + if (ih->data->is_multiline) + { + GtkTextIter iter; + gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(ih->handle), GTK_TEXT_WINDOW_WIDGET, x, y, &x, &y); + gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(ih->handle), &iter, x, y); + return gtk_text_iter_get_offset(&iter); + } + else + { + int trailing, off_x, off_y, pos; + + /* transform to Layout coordinates */ + gtk_entry_get_layout_offsets(GTK_ENTRY(ih->handle), &off_x, &off_y); + x = IUPGTK_PIXELS2PANGOUNITS(x - off_x); + y = IUPGTK_PIXELS2PANGOUNITS(y - off_y); + + pango_layout_xy_to_index(gtk_entry_get_layout(GTK_ENTRY(ih->handle)), x, y, &pos, &trailing); + return pos; + } +} + +static void gtkTextScrollToVisible(Ihandle* ih) +{ + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkTextMark* mark = gtk_text_buffer_get_insert(buffer); + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(ih->handle), mark); +} + + +/*******************************************************************************************/ + + +static int gtkTextSetSelectionAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &start_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextIter end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1); + return 0; + } + + if (ih->data->is_multiline) + { + int lin_start=1, col_start=1, lin_end=1, col_end=1; + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0; + if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0; + + gtkTextMoveIterToLinCol(buffer, &start_iter, lin_start, col_start); + gtkTextMoveIterToLinCol(buffer, &end_iter, lin_end, col_end); + + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + { + int start=1, end=1; + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + + gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end); + } + + return 0; +} + +static char* gtkTextGetSelectionAttrib(Ihandle* ih) +{ + char *str; + + if (ih->data->is_multiline) + { + int start_col, start_lin, end_col, end_lin; + + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + gtkTextGetLinColFromPosition(&start_iter, &start_lin, &start_col); + gtkTextGetLinColFromPosition(&end_iter, &end_lin, &end_col); + + str = iupStrGetMemory(100); + sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col); + return str; + } + } + else + { + int start, end; + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + start++; /* IUP starts at 1 */ + end++; + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + } + + return NULL; +} + +static int gtkTextSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + + if (!value) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &start_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, 0); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextIter end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), 0, -1); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start); + gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end); + + gtk_text_buffer_select_range(buffer, &start_iter, &end_iter); + } + else + gtk_editable_select_region(GTK_EDITABLE(ih->handle), start, end); + + return 0; +} + +static char* gtkTextGetSelectionPosAttrib(Ihandle* ih) +{ + int start, end; + char *str; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + start = gtk_text_iter_get_offset(&start_iter); + end = gtk_text_iter_get_offset(&end_iter); + + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + } + else + { + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + str = iupStrGetMemory(100); + sprintf(str, "%d:%d", (int)start, (int)end); + return str; + } + } + + return NULL; +} + +static int gtkTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_text_buffer_delete(buffer, &start_iter, &end_iter); + gtk_text_buffer_insert(buffer, &start_iter, iupgtkStrConvertToUTF8(value), -1); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + else + { + int start, end; + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_editable_delete_selection(GTK_EDITABLE(ih->handle)); + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &start); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + + return 0; +} + +static char* gtkTextGetSelectedTextAttrib(Ihandle* ih) +{ + if (ih->data->is_multiline) + { + GtkTextIter start_iter, end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + return iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE))); + } + else + { + int start, end; + if (gtk_editable_get_selection_bounds(GTK_EDITABLE(ih->handle), &start, &end)) + { + char* selectedtext = gtk_editable_get_chars(GTK_EDITABLE(ih->handle), start, end); + char* str = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(selectedtext)); + g_free(selectedtext); + return str; + } + } + + return NULL; +} + +static int gtkTextSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + iupStrToIntInt(value, &lin, &col, ','); + + gtkTextMoveIterToLinCol(buffer, &iter, lin, col); + + gtk_text_buffer_place_cursor(buffer, &iter); + gtkTextScrollToVisible(ih); + } + else + { + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + if (pos < 0) pos = 0; + + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + } + + return 0; +} + +static char* gtkTextGetCaretAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(50); + + if (ih->data->is_multiline) + { + int col, lin; + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer)); + gtkTextGetLinColFromPosition(&iter, &lin, &col); + + sprintf(str, "%d,%d", lin, col); + } + else + { + int pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + } + + return str; +} + +static int gtkTextSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos); + gtk_text_buffer_place_cursor(buffer, &iter); + gtkTextScrollToVisible(ih); + } + else + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + + return 0; +} + +static char* gtkTextGetCaretPosAttrib(Ihandle* ih) +{ + int pos; + char* str = iupStrGetMemory(50); + + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer)); + pos = gtk_text_iter_get_offset(&iter); + } + else + pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + + sprintf(str, "%d", (int)pos); + return str; +} + +static int gtkTextSetScrollToAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + + iupStrToIntInt(value, &lin, &col, ','); + if (lin < 1) lin = 1; + if (col < 1) col = 1; + + gtkTextMoveIterToLinCol(buffer, &iter, lin, col); + gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0); + } + else + { + int pos = 1; + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to GTK referece */ + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + } + + return 0; +} + +static int gtkTextSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos); + gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ih->handle), &iter, 0, FALSE, 0, 0); + } + else + gtk_editable_set_position(GTK_EDITABLE(ih->handle), pos); + + return 0; +} + +static int gtkTextSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) value = ""; + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_set_text(buffer, iupgtkStrConvertToUTF8(value), -1); + } + else + gtk_entry_set_text(GTK_ENTRY(ih->handle), iupgtkStrConvertToUTF8(value)); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static char* gtkTextGetValueAttrib(Ihandle* ih) +{ + char* value; + + if (ih->data->is_multiline) + { + GtkTextIter start_iter; + GtkTextIter end_iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_start_iter(buffer, &start_iter); + gtk_text_buffer_get_end_iter(buffer, &end_iter); + value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, TRUE))); + } + else + value = iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(gtk_entry_get_text(GTK_ENTRY(ih->handle)))); + + if (!value) value = ""; + + return value; +} + +static int gtkTextSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) + return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_insert_at_cursor(buffer, iupgtkStrConvertToUTF8(value), -1); + } + else + { + gint pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + return 0; +} + +static int gtkTextSetAppendAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline) + { + GtkTextIter iter; + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_end_iter(buffer, &iter); + if (ih->data->append_newline) + gtk_text_buffer_insert(buffer, &iter, "\n", 1); + gtk_text_buffer_insert(buffer, &iter, iupgtkStrConvertToUTF8(value), -1); + } + else + { + gint pos = strlen(gtk_entry_get_text(GTK_ENTRY(ih->handle)))+1; + gtk_editable_insert_text(GTK_EDITABLE(ih->handle), iupgtkStrConvertToUTF8(value), -1, &pos); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int gtkTextSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + float xalign; + GtkJustification justification; + + if (iupStrEqualNoCase(value, "ARIGHT")) + { + xalign = 1.0f; + justification = GTK_JUSTIFY_RIGHT; + } + else if (iupStrEqualNoCase(value, "ACENTER")) + { + xalign = 0.5f; + justification = GTK_JUSTIFY_CENTER; + } + else /* "ALEFT" */ + { + xalign = 0; + justification = GTK_JUSTIFY_LEFT; + } + + if (ih->data->is_multiline) + gtk_text_view_set_justification(GTK_TEXT_VIEW(ih->handle), justification); + else + gtk_entry_set_alignment(GTK_ENTRY(ih->handle), xalign); + + return 1; +} + +static int gtkTextSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + if (ih->data->is_multiline) + { + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding); + gtk_text_view_set_right_margin(GTK_TEXT_VIEW(ih->handle), ih->data->horiz_padding); + ih->data->vert_padding = 0; + } + else + { +#if GTK_CHECK_VERSION(2, 10, 0) + GtkBorder border; + border.bottom = border.top = ih->data->vert_padding; + border.left = border.right = ih->data->horiz_padding; + gtk_entry_set_inner_border(GTK_ENTRY(ih->handle), &border); +#endif + } + } + return 0; +} + +static int gtkTextSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + + if (!ih->data->is_multiline && ih->handle) + gtk_entry_set_max_length(GTK_ENTRY(ih->handle), ih->data->nc); + + return 0; +} + +static int gtkTextSetClipboardAttrib(Ihandle *ih, const char *value) +{ + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + if (iupStrEqualNoCase(value, "COPY")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_text_buffer_copy_clipboard(buffer, clipboard); + } + else + gtk_editable_copy_clipboard(GTK_EDITABLE(ih->handle)); + } + else if (iupStrEqualNoCase(value, "CUT")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_text_buffer_cut_clipboard(buffer, clipboard, TRUE); + } + else + gtk_editable_cut_clipboard(GTK_EDITABLE(ih->handle)); + } + else if (iupStrEqualNoCase(value, "PASTE")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + GtkClipboard *clipboard = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", FALSE)); + gtk_text_buffer_paste_clipboard(buffer, clipboard, NULL, TRUE); + } + else + gtk_editable_paste_clipboard(GTK_EDITABLE(ih->handle)); + } + else if (iupStrEqualNoCase(value, "CLEAR")) + { + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_delete_selection(buffer, FALSE, TRUE); + } + else + gtk_editable_delete_selection(GTK_EDITABLE(ih->handle)); + } + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int gtkTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_multiline) + gtk_text_view_set_editable(GTK_TEXT_VIEW(ih->handle), !iupStrBoolean(value)); + else + gtk_editable_set_editable(GTK_EDITABLE(ih->handle), !iupStrBoolean(value)); + return 0; +} + +static char* gtkTextGetReadOnlyAttrib(Ihandle* ih) +{ + int editable; + if (ih->data->is_multiline) + editable = gtk_text_view_get_editable(GTK_TEXT_VIEW(ih->handle)); + else + editable = gtk_editable_get_editable(GTK_EDITABLE(ih->handle)); + if (!editable) + return "YES"; + else + return "NO"; +} + +static char* gtkTextGetPangoLayoutAttrib(Ihandle* ih) +{ + if (ih->data->is_multiline) + return NULL; + else + return (char*)gtk_entry_get_layout(GTK_ENTRY(ih->handle)); +} + +static int gtkTextSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_multiline) + { + GtkScrolledWindow* scrolled_window = (GtkScrolledWindow*)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + unsigned char r, g, b; + + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + if (iupStrToRGB(parent_value, &r, &g, &b)) + { + GtkWidget* sb; + + iupgtkBaseSetBgColor((GtkWidget*)scrolled_window, r, g, b); + +#if GTK_CHECK_VERSION(2, 8, 0) + sb = gtk_scrolled_window_get_hscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); + + sb = gtk_scrolled_window_get_vscrollbar(scrolled_window); + if (sb) iupgtkBaseSetBgColor(sb, r, g, b); +#endif + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int gtkTextSetTabSizeAttrib(Ihandle* ih, const char* value) +{ + PangoTabArray *tabs; + int tabsize, charwidth; + if (!ih->data->is_multiline) + return 0; + + iupStrToInt(value, &tabsize); + charwidth = gtkTextGetCharSize(ih); + tabsize *= charwidth; + tabs = pango_tab_array_new_with_positions(1, FALSE, PANGO_TAB_LEFT, tabsize); + gtk_text_view_set_tabs(GTK_TEXT_VIEW(ih->handle), tabs); + pango_tab_array_free(tabs); + return 1; +} + +static int gtkTextSetOverwriteAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->is_multiline) + return 0; + gtk_text_view_set_overwrite(GTK_TEXT_VIEW(ih->handle), iupStrBoolean(value)); + return 0; +} + +static char* gtkTextGetOverwriteAttrib(Ihandle* ih) +{ + if (!ih->data->is_multiline) + return "NO"; + if (gtk_text_view_get_overwrite(GTK_TEXT_VIEW(ih->handle))) + return "YES"; + else + return "NO"; +} + +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag) +{ + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter; + GtkTextTag* tag; + char *selection; + + if (!ih->data->is_multiline) + return; + + selection = iupAttribGet(formattag, "SELECTION"); + if (selection) + { + /* simulate Windows behavior and change the current selection */ + gtkTextSetSelectionAttrib(ih, selection); + iupAttribSetStr(ih, "SELECTION", NULL); + } + else + { + char* selectionpos = iupAttribGet(formattag, "SELECTIONPOS"); + if (selectionpos) + { + /* simulate Windows behavior and change the current selection */ + gtkTextSetSelectionPosAttrib(ih, selectionpos); + iupAttribSetStr(ih, "SELECTIONPOS", NULL); + } + } + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (!gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + { + GtkTextMark* mark = gtk_text_buffer_get_insert(buffer); + gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, mark); + gtk_text_buffer_get_iter_at_mark(buffer, &end_iter, mark); + } + + tag = gtk_text_buffer_create_tag(buffer, NULL, NULL); + gtkTextParseParagraphFormat(formattag, tag); + gtkTextParseCharacterFormat(formattag, tag); + gtk_text_buffer_apply_tag(buffer, tag, &start_iter, &end_iter); + + /* reset the selection */ + gtkTextSetSelectionAttrib(ih, NULL); +} + +static int gtkTextSetRemoveFormattingAttrib(Ihandle* ih, const char* value) +{ + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter; + + if (!ih->data->is_multiline) + return 0; + + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + if (gtk_text_buffer_get_selection_bounds(buffer, &start_iter, &end_iter)) + gtk_text_buffer_remove_all_tags(buffer, &start_iter, &end_iter); + + (void)value; + return 0; +} + + +/************************************************************************************************/ + +static gboolean gtkTextSpinOutput(GtkSpinButton *spin, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + { + iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", (int)spin->adjustment->value); + return TRUE; /* disable output update */ + } + else + { + iupAttribSetStr(ih, "_IUPGTK_SPIN_OLDVALUE", gtk_entry_get_text(GTK_ENTRY(ih->handle))); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + return FALSE; + } +} + +static gint gtkTextSpinInput(GtkSpinButton *spin, gdouble *val, Ihandle* ih) +{ + (void)spin; + *val = (double)iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE"); + /* called only when SPINAUTO=NO */ + return TRUE; /* disable input update */ +} + +static void gtkTextSpinValueChanged(GtkSpinButton* spin, Ihandle* ih) +{ + IFni cb; + + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + cb = (IFni)IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + int pos, ret; + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE"); + else + pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle); + + ret = cb(ih, pos); + if (ret == IUP_IGNORE) + { + /* this is not working: g_signal_stop_emission_by_name(spin, "value_changed"); */ + } + } + + (void)spin; +} + +static int gtkTextSetSpinMinAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int min; + if (iupStrToInt(value, &min)) + { + int max = iupAttribGetInt(ih, "SPINMAX"); + + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + + gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max); + + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int gtkTextSetSpinMaxAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int max; + if (iupStrToInt(value, &max)) + { + int min = iupAttribGetInt(ih, "SPINMIN"); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + + gtk_spin_button_set_range((GtkSpinButton*)ih->handle, (double)min, (double)max); + + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int gtkTextSetSpinIncAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int inc; + if (iupStrToInt(value, &inc)) + gtk_spin_button_set_increments((GtkSpinButton*)ih->handle, (double)inc, (double)(inc*10)); + } + return 1; +} + +static int gtkTextSetSpinValueAttrib(Ihandle* ih, const char* value) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int pos; + if (iupStrToInt(value, &pos)) + { + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + + gtk_spin_button_set_value((GtkSpinButton*)ih->handle, (double)pos); + + g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkTextSpinValueChanged), ih); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + iupAttribSetInt(ih, "_IUPGTK_SPIN_VALUE", pos); + } + } + return 1; +} + +static char* gtkTextGetSpinValueAttrib(Ihandle* ih) +{ + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + int pos; + char *str = iupStrGetMemory(50); + + if (iupAttribGet(ih, "_IUPGTK_SPIN_NOAUTO")) + pos = iupAttribGetInt(ih, "_IUPGTK_SPIN_VALUE"); + else + pos = gtk_spin_button_get_value_as_int((GtkSpinButton*)ih->handle); + + sprintf(str, "%d", pos); + return str; + } + return NULL; +} + + +/**********************************************************************************************************/ + + +static void gtkTextMoveCursor(GtkWidget *w, GtkMovementStep step, gint count, gboolean extend_selection, Ihandle* ih) +{ + int col, lin, pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + if (ih->data->is_multiline) + { + GtkTextIter iter; + + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer)); + gtkTextGetLinColFromPosition(&iter, &lin, &col); + pos = gtk_text_iter_get_offset(&iter); + } + else + { + pos = gtk_editable_get_position(GTK_EDITABLE(ih->handle)); + col = pos; + col++; /* IUP starts at 1 */ + lin = 1; + } + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + + cb(ih, lin, col, pos); + } + + (void)w; + (void)step; + (void)count; + (void)extend_selection; +} + +static gboolean gtkTextKeyReleaseEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih) +{ + gtkTextMoveCursor(NULL, 0, 0, 0, ih); + (void)widget; + (void)evt; + return FALSE; +} + +static gboolean gtkTextButtonEvent(GtkWidget *widget, GdkEventButton *evt, Ihandle *ih) +{ + gtkTextMoveCursor(NULL, 0, 0, 0, ih); + return iupgtkButtonEvent(widget, evt, ih); +} + +static int gtkTextCallActionCb(Ihandle* ih, const char* insert_value, int len, int start, int end) +{ + char *new_value, *value; + int ret = -1, key = 0; + + IFnis cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (!cb && !ih->data->mask) + return -1; /* continue */ + + value = gtkTextGetValueAttrib(ih); /* new_value is the internal buffer */ + + if (!insert_value) + { + new_value = iupStrDup(value); + if (end<0) end = strlen(value)+1; + iupStrRemove(new_value, start, end, 1); + } + else + { + if (value[0]==0) + new_value = iupStrDup(insert_value); + else + { + if (len < end-start) + { + new_value = iupStrDup(value); + new_value = iupStrInsert(new_value, insert_value, start, end); + } + else + new_value = iupStrInsert(value, insert_value, start, end); + } + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (!new_value) + return -1; /* continue */ + + if (ih->data->nc && (int)strlen(new_value) > ih->data->nc) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + return 0; /* abort */ + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + ret = 0; /* abort */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + ret = 0; /* abort */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + ret = cb_ret; /* abort and replace */ + } + + if (new_value != value) free(new_value); + return ret; /* continue */ +} + +static void gtkTextEntryDeleteText(GtkEditable *editable, int start, int end, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0) + g_signal_stop_emission_by_name (editable, "delete_text"); +} + +static void gtkTextEntryInsertText(GtkEditable *editable, char *insert_value, int len, int *pos, Ihandle* ih) +{ + int ret; + + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, *pos, *pos); + if (ret == 0) + g_signal_stop_emission_by_name(editable, "insert_text"); + else if (ret != -1) + { + insert_value[0] = (char)ret; /* replace key */ + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_editable_insert_text(editable, insert_value, 1, pos); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + g_signal_stop_emission_by_name(editable, "insert_text"); + } +} + +static void gtkTextBufferDeleteRange(GtkTextBuffer *textbuffer, GtkTextIter *start_iter, GtkTextIter *end_iter, Ihandle* ih) +{ + int start, end; + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + start = gtk_text_iter_get_offset(start_iter); + end = gtk_text_iter_get_offset(end_iter); + + if (gtkTextCallActionCb(ih, NULL, 0, start, end)==0) + g_signal_stop_emission_by_name (textbuffer, "delete_range"); +} + +static void gtkTextBufferInsertText(GtkTextBuffer *textbuffer, GtkTextIter *pos_iter, gchar *insert_value, gint len, Ihandle* ih) +{ + int ret, pos; + + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + pos = gtk_text_iter_get_offset(pos_iter); + + ret = gtkTextCallActionCb(ih, iupStrGetMemoryCopy(iupgtkStrConvertFromUTF8(insert_value)), len, pos, pos); + if (ret == 0) + g_signal_stop_emission_by_name(textbuffer, "insert_text"); + else if (ret != -1) + { + insert_value[0] = (char)ret; /* replace key */ + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", "1"); + gtk_text_buffer_insert(textbuffer, pos_iter, insert_value, 1); + iupAttribSetStr(ih, "_IUPGTK_DISABLE_TEXT_CB", NULL); + + g_signal_stop_emission_by_name(textbuffer, "insert_text"); + } +} + +static void gtkTextChanged(void* dummy, Ihandle* ih) +{ + if (iupAttribGet(ih, "_IUPGTK_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + (void)dummy; +} + +/**********************************************************************************************************/ + + +static int gtkTextMapMethod(Ihandle* ih) +{ + GtkScrolledWindow* scrolled_window = NULL; + + if (ih->data->is_multiline) + { + GtkPolicyType hscrollbar_policy, vscrollbar_policy; + int wordwrap = 0; + + ih->handle = gtk_text_view_new(); + if (!ih->handle) + return IUP_ERROR; + + scrolled_window = (GtkScrolledWindow*)gtk_scrolled_window_new(NULL, NULL); + if (!scrolled_window) + return IUP_ERROR; + + gtk_container_add((GtkContainer*)scrolled_window, ih->handle); + gtk_widget_show((GtkWidget*)scrolled_window); + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)scrolled_window); + + /* formatting is always supported when MULTILINE=YES */ + ih->data->has_formatting = 1; + + if (iupAttribGetBoolean(ih, "WORDWRAP")) + { + wordwrap = 1; + ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */ + } + + if (iupAttribGetBoolean(ih, "BORDER")) + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_IN); + else + gtk_scrolled_window_set_shadow_type(scrolled_window, GTK_SHADOW_NONE); + + if (ih->data->sb & IUP_SB_HORIZ) + { + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + hscrollbar_policy = GTK_POLICY_AUTOMATIC; + else + hscrollbar_policy = GTK_POLICY_ALWAYS; + } + else + hscrollbar_policy = GTK_POLICY_NEVER; + + if (ih->data->sb & IUP_SB_VERT) + { + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + vscrollbar_policy = GTK_POLICY_AUTOMATIC; + else + vscrollbar_policy = GTK_POLICY_ALWAYS; + } + else + vscrollbar_policy = GTK_POLICY_NEVER; + + gtk_scrolled_window_set_policy(scrolled_window, hscrollbar_policy, vscrollbar_policy); + + if (wordwrap) + gtk_text_view_set_wrap_mode((GtkTextView*)ih->handle, GTK_WRAP_WORD); + + gtk_widget_add_events(ih->handle, GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK); + } + else + { + if (iupAttribGetBoolean(ih, "SPIN")) + ih->handle = gtk_spin_button_new_with_range(0, 100, 1); + else + ih->handle = gtk_entry_new(); + + if (!ih->handle) + return IUP_ERROR; + + /* formatting is never supported when MULTILINE=NO */ + ih->data->has_formatting = 0; + + gtk_entry_set_has_frame((GtkEntry*)ih->handle, IupGetInt(ih, "BORDER")); + + if (iupAttribGetBoolean(ih, "PASSWORD")) + gtk_entry_set_visibility((GtkEntry*)ih->handle, FALSE); + + if (GTK_IS_SPIN_BUTTON(ih->handle)) + { + gtk_spin_button_set_numeric((GtkSpinButton*)ih->handle, FALSE); + gtk_spin_button_set_digits((GtkSpinButton*)ih->handle, 0); + + gtk_spin_button_set_wrap((GtkSpinButton*)ih->handle, iupAttribGetBoolean(ih, "SPINWRAP")); + + g_signal_connect(G_OBJECT(ih->handle), "value-changed", G_CALLBACK(gtkTextSpinValueChanged), ih); + g_signal_connect(G_OBJECT(ih->handle), "output", G_CALLBACK(gtkTextSpinOutput), ih); + + if (!iupAttribGetBoolean(ih, "SPINAUTO")) + { + g_signal_connect(G_OBJECT(ih->handle), "input", G_CALLBACK(gtkTextSpinInput), ih); + iupAttribSetStr(ih, "_IUPGTK_SPIN_NOAUTO", "1"); + } + } + } + + /* add to the parent, all GTK controls must call this. */ + iupgtkBaseAddToParent(ih); + + if (!iupAttribGetBoolean(ih, "CANFOCUS")) + GTK_WIDGET_FLAGS(ih->handle) &= ~GTK_CAN_FOCUS; + + g_signal_connect(G_OBJECT(ih->handle), "enter-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "leave-notify-event", G_CALLBACK(iupgtkEnterLeaveEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-in-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "focus-out-event", G_CALLBACK(iupgtkFocusInOutEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(iupgtkKeyPressEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "show-help", G_CALLBACK(iupgtkShowHelp), ih); + + g_signal_connect_after(G_OBJECT(ih->handle), "move-cursor", G_CALLBACK(gtkTextMoveCursor), ih); /* only report some caret movements */ + g_signal_connect_after(G_OBJECT(ih->handle), "key-release-event", G_CALLBACK(gtkTextKeyReleaseEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "button-press-event", G_CALLBACK(gtkTextButtonEvent), ih); /* if connected "after" then it is ignored */ + g_signal_connect(G_OBJECT(ih->handle), "button-release-event",G_CALLBACK(gtkTextButtonEvent), ih); + g_signal_connect(G_OBJECT(ih->handle), "motion-notify-event",G_CALLBACK(iupgtkMotionNotifyEvent), ih); + + if (ih->data->is_multiline) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ih->handle)); + g_signal_connect(G_OBJECT(buffer), "delete-range", G_CALLBACK(gtkTextBufferDeleteRange), ih); + g_signal_connect(G_OBJECT(buffer), "insert-text", G_CALLBACK(gtkTextBufferInsertText), ih); + g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(gtkTextChanged), ih); + } + else + { + g_signal_connect(G_OBJECT(ih->handle), "delete-text", G_CALLBACK(gtkTextEntryDeleteText), ih); + g_signal_connect(G_OBJECT(ih->handle), "insert-text", G_CALLBACK(gtkTextEntryInsertText), ih); + g_signal_connect(G_OBJECT(ih->handle), "changed", G_CALLBACK(gtkTextChanged), ih); + } + + if (scrolled_window) + gtk_widget_realize((GtkWidget*)scrolled_window); + gtk_widget_realize(ih->handle); + + /* configure for DRAG&DROP */ + if (IupGetCallback(ih, "DROPFILES_CB")) + iupAttribSetStr(ih, "DRAGDROP", "YES"); + + /* update a mnemonic in a label if necessary */ + iupgtkUpdateMnemonic(ih); + + if (ih->data->formattags) + iupTextUpdateFormatTags(ih); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)gtkTextConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTextInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = gtkTextMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Common GTK only (when text is in a secondary element) */ + iupClassRegisterAttribute(ic, "PANGOLAYOUT", gtkTextGetPangoLayoutAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, gtkTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupText only */ + iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, gtkTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VALUE", gtkTextGetValueAttrib, gtkTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", gtkTextGetSelectedTextAttrib, gtkTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", gtkTextGetSelectionAttrib, gtkTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", gtkTextGetSelectionPosAttrib, gtkTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", gtkTextGetCaretAttrib, gtkTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", gtkTextGetCaretPosAttrib, gtkTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, gtkTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, gtkTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", gtkTextGetReadOnlyAttrib, gtkTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, gtkTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, gtkTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, gtkTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, gtkTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMIN", NULL, gtkTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMAX", NULL, gtkTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPININC", NULL, gtkTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINVALUE", gtkTextGetSpinValueAttrib, gtkTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + + /* IupText Windows and GTK only */ + iupClassRegisterAttribute(ic, "ADDFORMATTAG", NULL, iupTextSetAddFormatTagAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ADDFORMATTAG_HANDLE", NULL, iupTextSetAddFormatTagHandleAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, gtkTextSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ALEFT", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "DRAGDROP", NULL, iupgtkSetDragDropAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FORMATTING", iupTextGetFormattingAttrib, iupTextSetFormattingAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "OVERWRITE", gtkTextGetOverwriteAttrib, gtkTextSetOverwriteAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "REMOVEFORMATTING", NULL, gtkTextSetRemoveFormattingAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABSIZE", NULL, gtkTextSetTabSizeAttrib, "8", NULL, IUPAF_DEFAULT); /* force new default value */ + iupClassRegisterAttribute(ic, "PASSWORD", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT); +} -- cgit v1.2.3