/* * Copyright (C) 2012-2017 Robin Haberkorn * * This program 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 3 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, see . */ requires 2.0.20 %ctop{ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include /* * NOTE: These definitions are also in sciteco.h, * but we cannot include them from a plain C file. */ #define IS_CTL(C) ((C) < ' ') #define CTL_ECHO(C) ((C) | 0x40) #define CTL_KEY_ESC 27 #define GDK_TO_PANGO_COLOR(X) \ ((guint16)((X) * G_MAXUINT16)) %} %h{ #include %} class Gtk:Canonicalized:Label from Gtk:Label { private PangoColor fg; private guint16 fg_alpha; private PangoColor bg; private guint16 bg_alpha; override (Gtk:Widget) void style_updated(Gtk:Widget *widget) { Self *self = SELF(widget); GtkStyleContext *style; GdkRGBA normal_color; PARENT_HANDLER(widget); style = gtk_widget_get_style_context(widget); gtk_style_context_get_color(style, GTK_STATE_NORMAL, &normal_color); self->_priv->bg.red = GDK_TO_PANGO_COLOR(normal_color.red); self->_priv->bg.green = GDK_TO_PANGO_COLOR(normal_color.green); self->_priv->bg.blue = GDK_TO_PANGO_COLOR(normal_color.blue); self->_priv->bg_alpha = GDK_TO_PANGO_COLOR(normal_color.alpha); /* * If Pango does not support transparent foregrounds, * it will at least use a high-contrast foreground. * NOTE: It would be very hard to get an appropriate background * color even if Gtk supports it since the label itself may * not have one but one of its parents. * FIXME: We may want to honour the background color, * so we can at least get decent reverse text when setting * the background color in the CSS. */ self->_priv->fg.red = G_MAXUINT16 - self->_priv->bg.red; self->_priv->fg.green = G_MAXUINT16 - self->_priv->bg.green; self->_priv->fg.blue = G_MAXUINT16 - self->_priv->bg.blue; /* try hard to get a transparent foreground anyway */ self->_priv->fg_alpha = G_MAXUINT16; } public GtkWidget * new(const gchar *str) { Self *widget = GET_NEW; self_set_text(widget, str); return GTK_WIDGET(widget); } private void add_highlight_attribs(Pango:Attr:List *attribs, Pango:Color *fg, guint16 fg_alpha, Pango:Color *bg, guint16 bg_alpha, guint index, gsize len) { PangoAttribute *attr; #if PANGO_VERSION_CHECK(1,38,0) attr = pango_attr_foreground_alpha_new(fg_alpha); attr->start_index = index; attr->end_index = index + len; pango_attr_list_insert(attribs, attr); attr = pango_attr_background_alpha_new(bg_alpha); attr->start_index = index; attr->end_index = index + len; pango_attr_list_insert(attribs, attr); #endif attr = pango_attr_foreground_new(fg->red, fg->green, fg->blue); attr->start_index = index; attr->end_index = index + len; pango_attr_list_insert(attribs, attr); attr = pango_attr_background_new(bg->red, bg->green, bg->blue); attr->start_index = index; attr->end_index = index + len; pango_attr_list_insert(attribs, attr); } public void parse_string(const gchar *str, gssize len, Pango:Color *fg, guint16 fg_alpha, Pango:Color *bg, guint16 bg_alpha, Pango:Attr:List **attribs, gchar **text) { gsize text_len = 1; /* for trailing 0 */ gint index = 0; if (len < 0) len = strlen(str); /* * Approximate size of unformatted text. */ for (gint i = 0; i < len; i++) text_len += IS_CTL(str[i]) ? 3 : 1; *attribs = pango_attr_list_new(); *text = g_malloc(text_len); while (len > 0) { /* * NOTE: This mapping is similar to * View::set_presentations() */ switch (*str) { case CTL_KEY_ESC: self_add_highlight_attribs(*attribs, fg, fg_alpha, bg, bg_alpha, index, 1); (*text)[index++] = '$'; break; case '\r': self_add_highlight_attribs(*attribs, fg, fg_alpha, bg, bg_alpha, index, 2); (*text)[index++] = 'C'; (*text)[index++] = 'R'; break; case '\n': self_add_highlight_attribs(*attribs, fg, fg_alpha, bg, bg_alpha, index, 2); (*text)[index++] = 'L'; (*text)[index++] = 'F'; break; case '\t': self_add_highlight_attribs(*attribs, fg, fg_alpha, bg, bg_alpha, index, 3); (*text)[index++] = 'T'; (*text)[index++] = 'A'; (*text)[index++] = 'B'; break; default: if (IS_CTL(*str)) { self_add_highlight_attribs(*attribs, fg, fg_alpha, bg, bg_alpha, index, 2); (*text)[index++] = '^'; (*text)[index++] = CTL_ECHO(*str); } else { (*text)[index++] = *str; } break; } str++; len--; } /* null-terminate generated text */ (*text)[index] = '\0'; } public void set_text(self, const gchar *str) { PangoAttrList *attribs = NULL; gchar *plaintext = NULL; if (str) self_parse_string(str, -1, &self->_priv->fg, self->_priv->fg_alpha, &self->_priv->bg, self->_priv->bg_alpha, &attribs, &plaintext); gtk_label_set_attributes(GTK_LABEL(self), attribs); pango_attr_list_unref(attribs); gtk_label_set_text(GTK_LABEL(self), plaintext); g_free(plaintext); } }