* Added initial support for styles! (no style hints as of yet though)
[rodin/chimara.git] / src / style.c
index bce151662326275c8c91563f92a33fe3b7a9e24b..d2eb235d698209463bc61cef27b042a41bcb7319 100644 (file)
@@ -1,8 +1,197 @@
-#include "glk.h"
+#include "style.h"
 
+extern ChimaraGlkPrivate *glk_data;
+
+/**
+ * glk_set_style:
+ * @styl The style to apply
+ *
+ * This changes the style of the current output stream.  After a style change,
+ * new text which is printed to that stream will be given the new style. For a
+ * window stream, the text will appear in that style. For other types of
+ * streams, this has no effect.
+ */
+void
+glk_set_style(glui32 style)
+{
+       g_return_if_fail(glk_data->current_stream != NULL);
+       glk_set_style_stream(glk_data->current_stream, style);
+}
+
+/* Internal function: mapping from style enum to tag name */
+gchar*
+get_tag_name(glui32 style)
+{
+       switch(style) {
+               case style_Normal: return "normal";
+               case style_Emphasized: return "emphasized";
+               case style_Preformatted: return "preformatted";
+               case style_Header: return "header";
+               case style_Subheader: return "subheader";
+               case style_Alert: return "alert";
+               case style_Note: return "note";
+               case style_BlockQuote: return "block-quote";
+               case style_Input: return "input";
+               case style_User1: return "user1";
+               case style_User2: return "user2";
+       }
+
+       WARNING("Unsupported style");
+       return "normal";
+}
+
+void
+glk_set_style_stream(strid_t stream, glui32 style) {
+       stream->style = get_tag_name(style);
+}
+
+/* Internal function: call this to initialize the default styles to a textbuffer. */
 void
-glk_set_style(glui32 styl)
+style_init_textbuffer(GtkTextBuffer *buffer)
 {
-       /* No nothing yet */
-       return;
+       g_return_if_fail(buffer != NULL);
+
+       gtk_text_buffer_create_tag(buffer, "normal", NULL);
+       gtk_text_buffer_create_tag(buffer, "emphasized", "style", PANGO_STYLE_ITALIC, NULL);
+       gtk_text_buffer_create_tag(buffer, "preformatted", "font-desc", glk_data->monospace_font_desc, NULL);
+       gtk_text_buffer_create_tag(buffer, "header", "size-points", 16.0, "weight", PANGO_WEIGHT_BOLD, NULL);
+       gtk_text_buffer_create_tag(buffer, "subheader", "size-points", 12.0, "weight", PANGO_WEIGHT_BOLD, NULL);
+       gtk_text_buffer_create_tag(buffer, "alert", "foreground", "#aa0000", "weight", PANGO_WEIGHT_BOLD, NULL);
+       gtk_text_buffer_create_tag(buffer, "note", "foreground", "#aaaa00", "weight", PANGO_WEIGHT_BOLD, NULL);
+       gtk_text_buffer_create_tag(buffer, "block-quote", "justification", GTK_JUSTIFY_CENTER, "style", PANGO_STYLE_ITALIC, NULL);
+       gtk_text_buffer_create_tag(buffer, "input", NULL);
+       gtk_text_buffer_create_tag(buffer, "user1", NULL);
+       gtk_text_buffer_create_tag(buffer, "user2", NULL);
+}
+
+void
+color_format(glui32 val, gchar *buffer)
+{
+       sprintf(buffer, "#%02X%02X%02X",
+               ((val & 0xff0000) >> 16),
+               ((val & 0x00ff00) >> 8),
+               (val & 0x0000ff)
+       );
+}
+
+/* Internal function: changes a GTK tag to correspond with the given style. */
+void
+apply_stylehint_to_tag(GtkTextTag *tag, glui32 hint, glsi32 val)
+{
+       g_return_if_fail(tag != NULL);
+
+       GObject *tag_object = G_OBJECT(tag);
+       gint reverse_color = 0;
+
+       /* FIXME where should we keep track of this?
+       g_object_get(tag, "reverse_color", &reverse_color, NULL);
+       */
+
+       int i = 0;
+       gchar color[20];
+       switch(hint) {
+       case stylehint_Indentation:
+               g_object_set(tag_object, "left_margin", 5*val, NULL);
+               g_object_set(tag_object, "right_margin", 5*val, NULL);
+               break;
+       
+       case stylehint_ParaIndentation:
+               g_object_set(tag_object, "indent", 5*val, NULL);
+               break;
+
+       case stylehint_Justification:
+               switch(val) {
+                       case stylehint_just_LeftFlush:  i = GTK_JUSTIFY_LEFT; break;
+                       case stylehint_just_LeftRight:  i = GTK_JUSTIFY_FILL; break;
+                       case stylehint_just_Centered:   i = GTK_JUSTIFY_CENTER; break;
+                       case stylehint_just_RightFlush: i = GTK_JUSTIFY_RIGHT; break;
+                       default: 
+                               WARNING("Unknown justification");
+                               i = GTK_JUSTIFY_LEFT;
+               }
+               g_object_set(tag_object, "justification", i, NULL);
+               break;
+
+       case stylehint_Weight:
+               switch(val) {
+                       case -1: i = PANGO_WEIGHT_LIGHT; break;
+                       case  0: i = PANGO_WEIGHT_NORMAL; break;
+                       case  1: i = PANGO_WEIGHT_BOLD; break;
+                       default: WARNING("Unknown font weight");
+               }
+               g_object_set(tag_object, "weight", i, NULL);
+               break;
+
+       case stylehint_Size:
+               g_object_set(tag_object, "size", 14+(2*val), NULL);
+               break;
+
+       case stylehint_Oblique:
+               g_object_set(tag_object, "style", val ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL, NULL);
+               break;
+
+       case stylehint_Proportional:
+               g_object_set(tag_object, "font-desc", val ? glk_data->default_font_desc : glk_data->monospace_font_desc, NULL);
+               break;
+
+       case stylehint_TextColor:
+               color_format(val, color);
+
+               if(!reverse_color)
+                       g_object_set(tag_object, "foreground", color, NULL);
+               else
+                       g_object_set(tag_object, "background", color, NULL);
+
+               break;
+
+       case stylehint_BackColor:
+               color_format(val, color);
+
+               if(!reverse_color)
+                       g_object_set(tag_object, "background", color, NULL);
+               else
+                       g_object_set(tag_object, "foreground", color, NULL);
+
+               break;
+
+       case stylehint_ReverseColor:
+               if(reverse_color != val) {
+                       /* Flip the fore- and background colors */
+                       gchar* foreground_color;
+                       gchar* background_color;
+                       g_object_get(tag_object, "foreground", &foreground_color, NULL);
+                       g_object_get(tag_object, "background", &background_color, NULL);
+                       g_object_set(tag_object, "foreground", background_color, NULL);
+                       g_object_set(tag_object, "background", foreground_color, NULL);
+                       g_free(foreground_color);
+                       g_free(background_color);
+               }
+               break;
+
+       default:
+               WARNING("Unknown style hint");
+       }
+}
+
+void
+glk_stylehint_set(glui32 wintype, glui32 style, glui32 hint, glsi32 val)
+{
+
+       gchar *tag_name = get_tag_name(style);
+
+       /* Iterate over all the window and update their styles if nessecary */
+       winid_t win = glk_window_iterate(NULL, NULL);
+       while(win != NULL) {
+               if(wintype != wintype_TextBuffer)
+                       continue; /* FIXME: add support for text grid windows */
+
+               if(wintype == wintype_AllTypes || glk_window_get_type(win) == wintype) {
+                       GtkWidget *textview = win->widget;
+                       GtkTextBuffer *textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(textview) );
+                       GtkTextTagTable *table = gtk_text_buffer_get_tag_table(textbuffer);
+                       GtkTextTag *to_change = gtk_text_tag_table_lookup(table, tag_name);
+
+                       apply_stylehint_to_tag(to_change, hint, val);
+               }
+       }
 }