Merge branch 'master' into gtk3
[projects/chimara/chimara.git] / libchimara / style.c
index 125dbd6d38128c41032eba935b7a34a4c1d25ca7..65d6c4e062154fc728b32a08fa39f472e74bd47c 100644 (file)
@@ -186,36 +186,43 @@ GtkTextTag *
 gtk_text_tag_copy(GtkTextTag *tag)
 {
        GtkTextTag *copy;
+       char *tag_name;
+       GParamSpec **properties;
+       unsigned nprops, count;
 
        g_return_val_if_fail(tag != NULL, NULL);
 
-       copy = gtk_text_tag_new(tag->name);
-       gtk_text_attributes_copy_values(tag->values, copy->values);
-       
-       #define _COPY_FLAG(flag) copy->flag = tag->flag
-               _COPY_FLAG (bg_color_set);
-               _COPY_FLAG (bg_color_set);
-               _COPY_FLAG (bg_stipple_set);
-               _COPY_FLAG (fg_color_set);
-               _COPY_FLAG (fg_stipple_set);
-               _COPY_FLAG (justification_set);
-               _COPY_FLAG (left_margin_set);
-               _COPY_FLAG (indent_set);
-               _COPY_FLAG (rise_set);
-               _COPY_FLAG (strikethrough_set);
-               _COPY_FLAG (right_margin_set);
-               _COPY_FLAG (pixels_above_lines_set);
-               _COPY_FLAG (pixels_below_lines_set);
-               _COPY_FLAG (pixels_inside_wrap_set);
-               _COPY_FLAG (tabs_set);
-               _COPY_FLAG (underline_set);
-               _COPY_FLAG (wrap_mode_set);
-               _COPY_FLAG (bg_full_height_set);
-               _COPY_FLAG (invisible_set);
-               _COPY_FLAG (editable_set);
-               _COPY_FLAG (language_set);
-               _COPY_FLAG (scale_set);
-       #undef _COPY_FLAG
+       g_object_get(tag, "name", &tag_name, NULL);
+       copy = gtk_text_tag_new(tag_name);
+       g_free(tag_name);
+
+       /* Copy all the original tag's properties to the new tag */
+       properties = g_object_class_list_properties( G_OBJECT_GET_CLASS(tag), &nprops );
+       for(count = 0; count < nprops; count++) {
+
+               /* Only copy properties that are readable, writable, not construct-only,
+               and not deprecated */
+               GParamFlags flags = properties[count]->flags;
+               if(flags & G_PARAM_CONSTRUCT_ONLY
+                       || flags & G_PARAM_DEPRECATED
+                       || !(flags & G_PARAM_READABLE)
+                       || !(flags & G_PARAM_WRITABLE))
+                       continue;
+
+               const char *prop_name = g_param_spec_get_name(properties[count]);
+               GValue prop_value = G_VALUE_INIT;
+
+               g_value_init( &prop_value, G_PARAM_SPEC_VALUE_TYPE(properties[count]) );
+               g_object_get_property( G_OBJECT(tag), prop_name, &prop_value );
+               /* Don't copy the PangoTabArray if it is NULL, that prints a warning */
+               if(strcmp(prop_name, "tabs") == 0 && g_value_get_boxed(&prop_value) == NULL) {
+                       g_value_unset(&prop_value);
+                       continue;
+               }
+               g_object_set_property( G_OBJECT(copy), prop_name, &prop_value );
+               g_value_unset(&prop_value);
+       }
+       g_free(properties);
 
        /* Copy the data that was added manually */
        gpointer reverse_color = g_object_get_data( G_OBJECT(tag), "reverse-color" );
@@ -1097,22 +1104,46 @@ PangoFontDescription *
 get_current_font(guint32 wintype)
 {
        ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
-       GtkTextTag *tag;
+       GHashTable *styles, *glk_styles;
+       PangoFontDescription *font;
 
        switch(wintype) {
        case wintype_TextGrid:
-               tag = g_hash_table_lookup(glk_data->styles->text_grid, "default");
-               return pango_font_description_from_string("Monospace");
+               styles = glk_data->styles->text_grid;
+               glk_styles = glk_data->glk_styles->text_grid;
+               font = pango_font_description_from_string("Monospace");
                break;
        case wintype_TextBuffer:
-               tag = g_hash_table_lookup(glk_data->styles->text_buffer, "default");
-               return pango_font_description_from_string("Serif");
+               styles = glk_data->styles->text_buffer;
+               glk_styles = glk_data->glk_styles->text_buffer;
+               font = pango_font_description_from_string("Serif");
                break;
        default:
                return NULL;
        }
 
-       PangoFontDescription *font;
+       PangoAttrList *list = pango_attr_list_new();
+
+       text_tag_to_attr_list( g_hash_table_lookup(styles, "default"), list );
+       PangoAttrIterator *it = pango_attr_list_get_iterator(list);
+       pango_attr_iterator_get_font(it, font, NULL, NULL);
+       pango_attr_iterator_destroy(it);
+
+       text_tag_to_attr_list( g_hash_table_lookup(styles, "normal"), list );
+       it = pango_attr_list_get_iterator(list);
+       pango_attr_iterator_get_font(it, font, NULL, NULL);
+       pango_attr_iterator_destroy(it);
+
+       text_tag_to_attr_list( g_hash_table_lookup(glk_styles, "glk-normal"), list );
+       it = pango_attr_list_get_iterator(list);
+       pango_attr_iterator_get_font(it, font, NULL, NULL);
+       pango_attr_iterator_destroy(it);
+
+       /* Make a copy of the family, preventing it's destruction at the end of this function. */
+       pango_font_description_set_family( font, pango_font_description_get_family(font) );
+
+       pango_attr_list_unref(list);
+
        return font;
 }
 
@@ -1248,3 +1279,44 @@ style_stream_colors(strid_t str, GdkColor **foreground, GdkColor **background)
                        g_object_get(str->window->zcolor, "background-gdk", background, NULL);
        }
 }
+
+/* Apply styles to a segment of text in a GtkTextBuffer
+ */
+void
+style_apply(winid_t win, GtkTextIter *start, GtkTextIter *end)
+{
+       GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
+       GtkTextTagTable *tags = gtk_text_buffer_get_tag_table(buffer);
+
+       GtkTextTag *default_tag = gtk_text_tag_table_lookup(tags, "default");
+       GtkTextTag *style_tag = gtk_text_tag_table_lookup(tags, win->window_stream->style);
+       GtkTextTag *glk_style_tag = gtk_text_tag_table_lookup(tags, win->window_stream->glk_style);
+
+       // Player's style overrides
+       gtk_text_buffer_apply_tag(buffer, style_tag, start, end);
+
+       // GLK Program's style overrides
+       gtk_text_buffer_apply_tag(buffer, glk_style_tag, start, end);
+
+       // Default style
+       gtk_text_buffer_apply_tag(buffer, default_tag, start, end);
+
+       // Link style overrides
+       if(win->window_stream->hyperlink_mode) {
+               GtkTextTag *link_style_tag = gtk_text_tag_table_lookup(tags, "hyperlink");
+               GtkTextTag *link_tag = win->current_hyperlink->tag;
+               gtk_text_buffer_apply_tag(buffer, link_style_tag, start, end);
+               gtk_text_buffer_apply_tag(buffer, link_tag, start, end);
+       }
+
+       // GLK Program's style overrides using garglk_set_zcolors()
+       if(win->zcolor != NULL) {
+               gtk_text_buffer_apply_tag(buffer, win->zcolor, start, end);
+       }
+
+       // GLK Program's style overrides using garglk_set_reversevideo()
+       if(win->zcolor_reversed != NULL) {
+               gtk_text_buffer_apply_tag(buffer, win->zcolor_reversed, start, end);
+       }
+}
+