Hopefully solved the problem of waiting for windows to draw themselves once and for...
[rodin/chimara.git] / libchimara / style.c
1 #include "style.h"
2
3 extern ChimaraGlkPrivate *glk_data;
4
5 /**
6  * glk_set_style:
7  * @styl The style to apply
8  *
9  * This changes the style of the current output stream.  After a style change,
10  * new text which is printed to that stream will be given the new style. For a
11  * window stream, the text will appear in that style. For other types of
12  * streams, this has no effect.
13  */
14 void
15 glk_set_style(glui32 style)
16 {
17         g_return_if_fail(glk_data->current_stream != NULL);
18         glk_set_style_stream(glk_data->current_stream, style);
19 }
20
21 /* Internal function: mapping from style enum to tag name */
22 gchar*
23 get_tag_name(glui32 style)
24 {
25         switch(style) {
26                 case style_Normal: return "normal";
27                 case style_Emphasized: return "emphasized";
28                 case style_Preformatted: return "preformatted";
29                 case style_Header: return "header";
30                 case style_Subheader: return "subheader";
31                 case style_Alert: return "alert";
32                 case style_Note: return "note";
33                 case style_BlockQuote: return "block-quote";
34                 case style_Input: return "input";
35                 case style_User1: return "user1";
36                 case style_User2: return "user2";
37         }
38
39         WARNING("Unsupported style");
40         return "normal";
41 }
42
43 void
44 glk_set_style_stream(strid_t stream, glui32 style) {
45         stream->style = get_tag_name(style);
46 }
47
48 /* Internal function: call this to initialize the default styles to a textbuffer. */
49 void
50 style_init_textbuffer(GtkTextBuffer *buffer)
51 {
52         g_return_if_fail(buffer != NULL);
53
54         gtk_text_buffer_create_tag(buffer, "normal", NULL);
55         gtk_text_buffer_create_tag(buffer, "emphasized", "style", PANGO_STYLE_ITALIC, NULL);
56         gtk_text_buffer_create_tag(buffer, "preformatted", "font-desc", glk_data->monospace_font_desc, NULL);
57         gtk_text_buffer_create_tag(buffer, "header", "size-points", 16.0, "weight", PANGO_WEIGHT_BOLD, NULL);
58         gtk_text_buffer_create_tag(buffer, "subheader", "size-points", 12.0, "weight", PANGO_WEIGHT_BOLD, NULL);
59         gtk_text_buffer_create_tag(buffer, "alert", "foreground", "#aa0000", "weight", PANGO_WEIGHT_BOLD, NULL);
60         gtk_text_buffer_create_tag(buffer, "note", "foreground", "#aaaa00", "weight", PANGO_WEIGHT_BOLD, NULL);
61         gtk_text_buffer_create_tag(buffer, "block-quote", "justification", GTK_JUSTIFY_CENTER, "style", PANGO_STYLE_ITALIC, NULL);
62         gtk_text_buffer_create_tag(buffer, "input", NULL);
63         gtk_text_buffer_create_tag(buffer, "user1", NULL);
64         gtk_text_buffer_create_tag(buffer, "user2", NULL);
65 }
66
67 void
68 color_format(glui32 val, gchar *buffer)
69 {
70         sprintf(buffer, "#%02X%02X%02X",
71                 ((val & 0xff0000) >> 16),
72                 ((val & 0x00ff00) >> 8),
73                 (val & 0x0000ff)
74         );
75 }
76
77 /* Internal function: changes a GTK tag to correspond with the given style. */
78 void
79 apply_stylehint_to_tag(GtkTextTag *tag, glui32 hint, glsi32 val)
80 {
81         g_return_if_fail(tag != NULL);
82
83         GObject *tag_object = G_OBJECT(tag);
84         gint reverse_color = 0;
85
86         /* FIXME where should we keep track of this?
87         g_object_get(tag, "reverse_color", &reverse_color, NULL);
88         */
89
90         int i = 0;
91         gchar color[20];
92         switch(hint) {
93         case stylehint_Indentation:
94                 g_object_set(tag_object, "left_margin", 5*val, NULL);
95                 g_object_set(tag_object, "right_margin", 5*val, NULL);
96                 break;
97         
98         case stylehint_ParaIndentation:
99                 g_object_set(tag_object, "indent", 5*val, NULL);
100                 break;
101
102         case stylehint_Justification:
103                 switch(val) {
104                         case stylehint_just_LeftFlush:  i = GTK_JUSTIFY_LEFT; break;
105                         case stylehint_just_LeftRight:  i = GTK_JUSTIFY_FILL; break;
106                         case stylehint_just_Centered:   i = GTK_JUSTIFY_CENTER; break;
107                         case stylehint_just_RightFlush: i = GTK_JUSTIFY_RIGHT; break;
108                         default: 
109                                 WARNING("Unknown justification");
110                                 i = GTK_JUSTIFY_LEFT;
111                 }
112                 g_object_set(tag_object, "justification", i, NULL);
113                 break;
114
115         case stylehint_Weight:
116                 switch(val) {
117                         case -1: i = PANGO_WEIGHT_LIGHT; break;
118                         case  0: i = PANGO_WEIGHT_NORMAL; break;
119                         case  1: i = PANGO_WEIGHT_BOLD; break;
120                         default: WARNING("Unknown font weight");
121                 }
122                 g_object_set(tag_object, "weight", i, NULL);
123                 break;
124
125         case stylehint_Size:
126                 g_object_set(tag_object, "size", 14+(2*val), NULL);
127                 break;
128
129         case stylehint_Oblique:
130                 g_object_set(tag_object, "style", val ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL, NULL);
131                 break;
132
133         case stylehint_Proportional:
134                 g_object_set(tag_object, "font-desc", val ? glk_data->default_font_desc : glk_data->monospace_font_desc, NULL);
135                 break;
136
137         case stylehint_TextColor:
138                 color_format(val, color);
139
140                 if(!reverse_color)
141                         g_object_set(tag_object, "foreground", color, NULL);
142                 else
143                         g_object_set(tag_object, "background", color, NULL);
144
145                 break;
146
147         case stylehint_BackColor:
148                 color_format(val, color);
149
150                 if(!reverse_color)
151                         g_object_set(tag_object, "background", color, NULL);
152                 else
153                         g_object_set(tag_object, "foreground", color, NULL);
154
155                 break;
156
157         case stylehint_ReverseColor:
158                 if(reverse_color != val) {
159                         /* Flip the fore- and background colors */
160                         gchar* foreground_color;
161                         gchar* background_color;
162                         g_object_get(tag_object, "foreground", &foreground_color, NULL);
163                         g_object_get(tag_object, "background", &background_color, NULL);
164                         g_object_set(tag_object, "foreground", background_color, NULL);
165                         g_object_set(tag_object, "background", foreground_color, NULL);
166                         g_free(foreground_color);
167                         g_free(background_color);
168                 }
169                 break;
170
171         default:
172                 WARNING("Unknown style hint");
173         }
174 }
175
176 void
177 glk_stylehint_set(glui32 wintype, glui32 style, glui32 hint, glsi32 val)
178 {
179
180         gchar *tag_name = get_tag_name(style);
181
182         /* Iterate over all the window and update their styles if nessecary */
183         winid_t win = glk_window_iterate(NULL, NULL);
184         while(win != NULL) {
185                 if(wintype != wintype_TextBuffer)
186                         continue; /* FIXME: add support for text grid windows */
187
188                 if(wintype == wintype_AllTypes || glk_window_get_type(win) == wintype) {
189                         GtkWidget *textview = win->widget;
190                         GtkTextBuffer *textbuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(textview) );
191                         GtkTextTagTable *table = gtk_text_buffer_get_tag_table(textbuffer);
192                         GtkTextTag *to_change = gtk_text_tag_table_lookup(table, tag_name);
193
194                         apply_stylehint_to_tag(to_change, hint, val);
195                 }
196         }
197 }
198
199 void
200 glk_stylehint_clear(glui32 wintype, glui32 styl, glui32 hint)
201 {
202 }
203
204 glui32
205 glk_style_distinguish(winid_t win, glui32 styl1, glui32 styl2)
206 {
207         return styl1 != styl2;
208 }