* GNT - The GLib Ncurses Toolkit * GNT is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #define GNT_LOG_DOMAIN "Utils" #include <libxml/parser.h> void gnt_util_get_text_bound(const char *text, int *width, int *height) const char *s = text, *last; /* XXX: ew ... everyone look away */ if (*s == '\n' || *s == '\r') len = gnt_util_onscreen_width(last, s); len = gnt_util_onscreen_width(last, s); *width = max + (count > 1); int gnt_util_onscreen_width(const char *start, const char *end) end = start + strlen(start); width += g_unichar_iswide(g_utf8_get_char(start)) ? 2 : 1; start = g_utf8_next_char(start); const char *gnt_util_onscreen_width_to_pointer(const char *string, int len, int *w) const char *str = string; len = gnt_util_onscreen_width(string, NULL); while (width < len && *str) { size = g_unichar_iswide(g_utf8_get_char(str)) ? 2 : 1; str = g_utf8_next_char(str); char *gnt_util_onscreen_fit_string(const char *string, int maxw) maxw = getmaxx(stdscr) - 4; str = g_string_new(NULL); if ((end = strchr(start, '\n')) != NULL || (end = strchr(start, '\r')) != NULL) { if (gnt_util_onscreen_width(start, end) > maxw) end = gnt_util_onscreen_width_to_pointer(start, maxw, NULL); str = g_string_append_len(str, start, end - start); str = g_string_append_c(str, '\n'); if (*end == '\n' || *end == '\r') return g_string_free(str, FALSE); GntDuplicateFunc key_dup; GntDuplicateFunc value_dup; duplicate_values(gpointer key, gpointer value, gpointer data) struct duplicate_fns *fns = data; g_hash_table_insert(fns->table, fns->key_dup ? fns->key_dup(key) : key, fns->value_dup ? fns->value_dup(value) : value); GHashTable *gnt_hash_table_duplicate(GHashTable *src, GHashFunc hash, GEqualFunc equal, GDestroyNotify key_d, GDestroyNotify value_d, GntDuplicateFunc key_dup, GntDuplicateFunc value_dup) GHashTable *dest = g_hash_table_new_full(hash, equal, key_d, value_d); struct duplicate_fns fns = {key_dup, value_dup, dest}; g_hash_table_foreach(src, duplicate_values, &fns); gboolean gnt_boolean_handled_accumulator(GSignalInvocationHint *ihint, const GValue *handler_return, gboolean continue_emission; signal_handled = g_value_get_boolean (handler_return); g_value_set_boolean (return_accu, signal_handled); continue_emission = !signal_handled; return continue_emission; add_binding(gpointer key, gpointer value, gpointer data) GntBindableActionParam *act = value; const char *name = g_hash_table_lookup(bv->hash, act->action); const char *k = gnt_key_lookup(key); gnt_tree_add_row_after(bv->tree, (gpointer)k, gnt_tree_create_row(bv->tree, k, name), NULL, NULL); add_action(gpointer key, gpointer value, gpointer data) g_hash_table_insert(bv->hash, value, key); GntWidget *gnt_widget_bindings_view(GntWidget *widget) GntBindable *bind = GNT_BINDABLE(widget); GntWidget *tree = gnt_tree_new_with_columns(2); GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bind)); GHashTable *hash = g_hash_table_new(g_direct_hash, g_direct_equal); BindingView bv = {hash, GNT_TREE(tree)}; gnt_tree_set_compare_func(bv.tree, (GCompareFunc)g_utf8_collate); g_hash_table_foreach(klass->actions, add_action, &bv); g_hash_table_foreach(klass->bindings, add_binding, &bv); if (GNT_TREE(tree)->list == NULL) { gnt_widget_destroy(tree); gnt_tree_adjust_columns(bv.tree); g_hash_table_destroy(hash); gnt_widget_from_xmlnode(xmlNode *node, GntWidget **data[], int max) GntWidget *widget = NULL; char *id, *prop, *content; if (node == NULL || node->name == NULL || node->type != XML_ELEMENT_NODE) name = (char*)node->name; content = (char*)xmlNodeGetContent(node); if (strcmp(name + 1, "window") == 0 || strcmp(name + 1, "box") == 0) { gboolean vert = (*name == 'v'); widget = gnt_window_box_new(FALSE, vert); widget = gnt_box_new(FALSE, vert); title = (char*)xmlGetProp(node, (xmlChar*)"title"); gnt_box_set_title(GNT_BOX(widget), title); prop = (char*)xmlGetProp(node, (xmlChar*)"fill"); if (sscanf(prop, "%d", &val) == 1) gnt_box_set_fill(GNT_BOX(widget), !!val); prop = (char*)xmlGetProp(node, (xmlChar*)"align"); if (sscanf(prop, "%d", &val) == 1) gnt_box_set_alignment(GNT_BOX(widget), val); prop = (char*)xmlGetProp(node, (xmlChar*)"pad"); if (sscanf(prop, "%d", &val) == 1) gnt_box_set_pad(GNT_BOX(widget), val); for (ch = node->children; ch; ch=ch->next) gnt_box_add_widget(GNT_BOX(widget), gnt_widget_from_xmlnode(ch, data, max)); } else if (strcmp(name, "button") == 0) { widget = gnt_button_new(content); } else if (strcmp(name, "label") == 0) { widget = gnt_label_new(content); } else if (strcmp(name, "entry") == 0) { widget = gnt_entry_new(content); } else if (strcmp(name, "combobox") == 0) { widget = gnt_combo_box_new(); } else if (strcmp(name, "checkbox") == 0) { widget = gnt_check_box_new(content); } else if (strcmp(name, "tree") == 0) { } else if (strcmp(name, "textview") == 0) { widget = gnt_text_view_new(); } else if (strcmp(name + 1, "line") == 0) { widget = gnt_line_new(*name == 'v'); gnt_warning("Invalid widget name %s", name); id = (char*)xmlGetProp(node, (xmlChar*)"id"); if (sscanf(id, "%d", &i) == 1 && i >= 0 && i < max) { prop = (char*)xmlGetProp(node, (xmlChar*)"border"); if (sscanf(prop, "%d", &val) == 1) { GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER); prop = (char*)xmlGetProp(node, (xmlChar*)"shadow"); if (sscanf(prop, "%d", &val) == 1) { GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_NO_BORDER); void gnt_util_parse_widgets(const char *string, int num, ...) ctxt = xmlNewParserCtxt(); doc = xmlCtxtReadDoc(ctxt, (xmlChar*)string, NULL, NULL, XML_PARSE_NOBLANKS); data = g_new0(GntWidget **, num); for (id = 0; id < num; id++) data[id] = va_arg(list, gpointer); node = xmlDocGetRootElement(doc); gnt_widget_from_xmlnode(node, data, num); util_parse_html_to_tv(xmlNode *node, GntTextView *tv, GntTextFormatFlags flag) gboolean insert_nl_s = FALSE, insert_nl_e = FALSE; if (node == NULL || node->name == NULL || node->type != XML_ELEMENT_NODE) name = (char*)node->name; if (g_ascii_strcasecmp(name, "b") == 0 || g_ascii_strcasecmp(name, "strong") == 0 || g_ascii_strcasecmp(name, "i") == 0 || g_ascii_strcasecmp(name, "blockquote") == 0) { flag |= GNT_TEXT_FLAG_BOLD; } else if (g_ascii_strcasecmp(name, "u") == 0) { flag |= GNT_TEXT_FLAG_UNDERLINE; } else if (g_ascii_strcasecmp(name, "br") == 0) { } else if (g_ascii_strcasecmp(name, "a") == 0) { flag |= GNT_TEXT_FLAG_UNDERLINE; url = (char *)xmlGetProp(node, (xmlChar*)"href"); } else if (g_ascii_strcasecmp(name, "h1") == 0 || g_ascii_strcasecmp(name, "h2") == 0 || g_ascii_strcasecmp(name, "h3") == 0 || g_ascii_strcasecmp(name, "h4") == 0 || g_ascii_strcasecmp(name, "h5") == 0 || g_ascii_strcasecmp(name, "h6") == 0) { } else if (g_ascii_strcasecmp(name, "title") == 0) { flag |= GNT_TEXT_FLAG_BOLD | GNT_TEXT_FLAG_UNDERLINE; /* XXX: Process other possible tags */ gnt_text_view_append_text_with_flags(tv, "\n", flag); for (ch = node->children; ch; ch = ch->next) { if (ch->type == XML_ELEMENT_NODE) { util_parse_html_to_tv(ch, tv, flag); } else if (ch->type == XML_TEXT_NODE) { content = (char*)xmlNodeGetContent(ch); gnt_text_view_append_text_with_flags(tv, content, flag); char *href = g_strdup_printf(" (%s)", url); gnt_text_view_append_text_with_flags(tv, href, flag); gnt_text_view_append_text_with_flags(tv, "\n", flag); gboolean gnt_util_parse_xhtml_to_textview(const char *string, GntTextView *tv) GntTextFormatFlags flag = GNT_TEXT_FLAG_NORMAL; ctxt = xmlNewParserCtxt(); doc = xmlCtxtReadDoc(ctxt, (xmlChar*)string, NULL, NULL, XML_PARSE_NOBLANKS | XML_PARSE_RECOVER); node = xmlDocGetRootElement(doc); util_parse_html_to_tv(node, tv, flag); /* Setup trigger widget */ free_trigger_button(TriggerButton *b) key_pressed(GntWidget *widget, const char *text, TriggerButton *trig) if (text && trig->text && strcmp(text, trig->text) == 0) { gnt_widget_activate(trig->button); void gnt_util_set_trigger_widget(GntWidget *wid, const char *text, GntWidget *button) TriggerButton *tb = g_new0(TriggerButton, 1); tb->text = g_strdup(text); g_signal_connect(G_OBJECT(wid), "key_pressed", G_CALLBACK(key_pressed), tb); g_signal_connect_swapped(G_OBJECT(button), "destroy", G_CALLBACK(free_trigger_button), tb);