tagging release
[dasher.git] / Src / Gtk2 / dasher_internal_buffer.cpp
blob71e4497e86cbffc7cfa26d7d8f85822c58fae47c
1 #include <gtk/gtk.h>
2 #include <string.h>
4 #include "dasher_buffer_set.h"
5 #include "dasher_internal_buffer.h"
7 static void dasher_internal_buffer_class_init(DasherInternalBufferClass *pClass);
8 static void dasher_internal_buffer_init(DasherInternalBuffer *pAction);
9 static void dasher_internal_buffer_destroy(GObject *pObject);
10 static void idasher_buffer_set_interface_init (gpointer g_iface, gpointer iface_data);
11 void dasher_internal_buffer_insert(DasherInternalBuffer *pSelf, const gchar *szText);
12 void dasher_internal_buffer_delete(DasherInternalBuffer *pSelf, int iLength);
13 gchar *dasher_internal_buffer_get_context(DasherInternalBuffer *pSelf, gint iOffset, gint iLength);
14 void dasher_internal_buffer_edit_move(DasherInternalBuffer *pSelf, int iDirection, int iDist);
15 void dasher_internal_buffer_edit_delete(DasherInternalBuffer *pSelf, int iDirection, int iDist);
16 void dasher_internal_buffer_edit_convert(DasherInternalBuffer *pSelf);
17 void dasher_internal_buffer_edit_protect(DasherInternalBuffer *pSelf);
18 void dasher_internal_buffer_conversion_mode(DasherInternalBuffer *pSelf, gboolean bMode);
19 gint dasher_internal_buffer_get_offset(DasherInternalBuffer *pSelf);
21 // Related signal handlers
22 extern "C" void mark_set_handler(GtkWidget *widget, GtkTextIter *pIter, GtkTextMark *pMark, gpointer pUserData);
24 typedef struct _DasherInternalBufferPrivate DasherInternalBufferPrivate;
26 struct _DasherInternalBufferPrivate {
27 GtkTextView *pTextView;
28 GtkTextBuffer *pBuffer;
29 GtkTextTag *pOutputTag;
30 GtkTextTag *pHiddenTag;
31 GtkTextTag *pVisibleTag;
32 gboolean bConversionMode;
33 gint iLastOffset;
34 gint iCurrentState; // 0 = unconverted, 1 = converted
37 GType dasher_internal_buffer_get_type() {
39 static GType dasher_internal_buffer_type = 0;
41 if(!dasher_internal_buffer_type) {
42 static const GTypeInfo dasher_internal_buffer_info = {
43 sizeof(DasherInternalBufferClass),
44 NULL,
45 NULL,
46 (GClassInitFunc) dasher_internal_buffer_class_init,
47 NULL,
48 NULL,
49 sizeof(DasherInternalBuffer),
51 (GInstanceInitFunc) dasher_internal_buffer_init,
52 NULL
55 static const GInterfaceInfo idasher_buffer_set_info = {
56 (GInterfaceInitFunc) idasher_buffer_set_interface_init,
57 NULL,
58 NULL
61 dasher_internal_buffer_type = g_type_register_static(G_TYPE_OBJECT, "DasherInternalBuffer", &dasher_internal_buffer_info, static_cast < GTypeFlags > (0));
63 g_type_add_interface_static (dasher_internal_buffer_type,
64 IDASHER_BUFFER_SET_TYPE,
65 &idasher_buffer_set_info);
68 return dasher_internal_buffer_type;
71 static void dasher_internal_buffer_class_init(DasherInternalBufferClass *pClass) {
72 GObjectClass *pObjectClass = (GObjectClass *) pClass;
73 pObjectClass->finalize = dasher_internal_buffer_destroy;
76 static void dasher_internal_buffer_init(DasherInternalBuffer *pDasherControl) {
77 pDasherControl->private_data = (void *)(new DasherInternalBufferPrivate);
80 static void idasher_buffer_set_interface_init (gpointer g_iface, gpointer iface_data) {
81 IDasherBufferSetInterface *iface = (IDasherBufferSetInterface *)g_iface;
82 iface->insert_text = (void (*)(IDasherBufferSet *pSelf, const gchar *szText))dasher_internal_buffer_insert;
83 iface->delete_text = (void (*)(IDasherBufferSet *pSelf, gint iLength))dasher_internal_buffer_delete;
84 iface->get_context = (gchar *(*)(IDasherBufferSet *pSelf, gint iOffset, gint iLength))dasher_internal_buffer_get_context;
85 iface->edit_move = (void (*)(IDasherBufferSet *pSelf, gint iDirection, gint iDist))dasher_internal_buffer_edit_move;
86 iface->edit_delete = (void (*)(IDasherBufferSet *pSelf, gint iDirection, gint iDist))dasher_internal_buffer_edit_delete;
87 iface->edit_convert = (void (*)(IDasherBufferSet *pSelf))dasher_internal_buffer_edit_convert;
88 iface->edit_protect = (void (*)(IDasherBufferSet *pSelf))dasher_internal_buffer_edit_protect;
89 iface->conversion_mode = (void (*)(IDasherBufferSet *pSelf, gboolean bMode))dasher_internal_buffer_conversion_mode;
90 iface->get_offset = (gint (*)(IDasherBufferSet *pSelf))dasher_internal_buffer_get_offset;
93 static void dasher_internal_buffer_destroy(GObject *pObject) {
94 // FIXME - I think we need to chain up through the finalize methods
95 // of the parent classes here...
97 delete (DasherInternalBufferPrivate *)(((DasherInternalBuffer *)pObject)->private_data);
100 DasherInternalBuffer *dasher_internal_buffer_new(GtkTextView *pTextView) {
101 DasherInternalBuffer *pDasherControl;
102 pDasherControl = (DasherInternalBuffer *)(g_object_new(dasher_internal_buffer_get_type(), NULL));
104 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pDasherControl->private_data);
105 pPrivate->pTextView = pTextView;
106 pPrivate->pBuffer = gtk_text_view_get_buffer(pTextView);
108 pPrivate->pOutputTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, NULL);
110 #if GTK_CHECK_VERSION(2,8,0)
111 pPrivate->pHiddenTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, "invisible", TRUE, NULL);
112 #else
113 // TODO: We really ought to do something a little more sensible with conversion in GTK < 2.8
114 pPrivate->pHiddenTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, NULL);
115 #endif
117 pPrivate->pVisibleTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, "foreground", "red", NULL);
119 pPrivate->bConversionMode = FALSE;
120 pPrivate->iLastOffset = 1;
121 pPrivate->iCurrentState = 0;
123 g_signal_connect(G_OBJECT(pPrivate->pBuffer), "mark-set", G_CALLBACK(mark_set_handler), pDasherControl);
125 return pDasherControl;
128 void dasher_internal_buffer_insert(DasherInternalBuffer *pSelf, const gchar *szText) {
129 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
131 gtk_text_buffer_delete_selection(pPrivate->pBuffer, false, true );
133 GtkTextIter sIter;
134 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &sIter, gtk_text_buffer_get_insert(pPrivate->pBuffer));
136 GtkTextTag *pCurrentTag = NULL;
138 if(!pPrivate->bConversionMode)
139 pCurrentTag = pPrivate->pOutputTag;
140 else {
141 switch(pPrivate->iCurrentState) {
142 case 0:
143 pCurrentTag = pPrivate->pVisibleTag;
144 break;
145 case 1:
146 pCurrentTag = pPrivate->pOutputTag;
147 break;
151 if(!pCurrentTag)
152 return;
154 gtk_text_buffer_insert_with_tags(pPrivate->pBuffer, &sIter, szText, -1, pCurrentTag, NULL);
156 gtk_text_view_scroll_mark_onscreen(pPrivate->pTextView, gtk_text_buffer_get_insert(pPrivate->pBuffer));
158 // g_message("Buffer lenght: %d", gtk_text_buffer_get_char_count(pPrivate->pBuffer));
161 void dasher_internal_buffer_delete(DasherInternalBuffer *pSelf, int iLength) {
162 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
164 GtkTextIter *start = new GtkTextIter;
165 GtkTextIter *end = new GtkTextIter;
167 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, end, gtk_text_buffer_get_insert(pPrivate->pBuffer));
169 *start = *end;
171 gtk_text_iter_backward_chars(start, iLength);
172 // g_bIgnoreCursorMove = true;
173 gtk_text_buffer_delete(pPrivate->pBuffer, start, end);
174 gtk_text_view_scroll_mark_onscreen(pPrivate->pTextView, gtk_text_buffer_get_insert(pPrivate->pBuffer));
175 // g_bIgnoreCursorMove = false;
177 delete start;
178 delete end;
181 gchar *dasher_internal_buffer_get_context(DasherInternalBuffer *pSelf, gint iOffset, gint iLength) {
182 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
184 // g_message("Buffer lenght: %d", gtk_text_buffer_get_char_count(pPrivate->pBuffer));
186 GtkTextIter start;
187 GtkTextIter end; // Refers to end of context, which is start of selection!
189 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &start, iOffset);
190 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &end, iOffset + iLength);
192 return gtk_text_buffer_get_text( pPrivate->pBuffer, &start, &end, false );
195 void dasher_internal_buffer_change_context(DasherInternalBuffer *pSelf, GtkTextIter *pIter, GtkTextMark *pMark) {
196 const char *szMarkName(gtk_text_mark_get_name(pMark));
197 if(szMarkName && !strcmp(szMarkName,"insert")) {
198 g_signal_emit_by_name(G_OBJECT(pSelf), "context_changed", G_OBJECT(pSelf), NULL, NULL);
202 void dasher_internal_buffer_edit_move(DasherInternalBuffer *pSelf, int iDirection, int iDist) {
203 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
205 GtkTextIter sPos;
207 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &sPos, gtk_text_buffer_get_insert(pPrivate->pBuffer));
209 if(iDirection == EDIT_FORWARDS) {
210 switch(iDist) {
211 case EDIT_CHAR:
212 gtk_text_iter_forward_char(&sPos);
213 break;
214 case EDIT_WORD:
215 gtk_text_iter_forward_word_end(&sPos);
216 break;
217 case EDIT_LINE:
218 if(!gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos))
220 gtk_text_view_forward_display_line (GTK_TEXT_VIEW(pPrivate->pTextView), &sPos);
221 gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos);
223 break;
224 case EDIT_FILE:
225 gtk_text_iter_forward_to_end(&sPos);
226 break;
229 else {
230 switch(iDist) {
231 case EDIT_CHAR:
232 gtk_text_iter_backward_char(&sPos);
233 break;
234 case EDIT_WORD:
235 gtk_text_iter_backward_word_start(&sPos);
236 break;
237 case EDIT_LINE:
239 if(!gtk_text_view_backward_display_line_start(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos))
240 gtk_text_view_backward_display_line(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos);
241 break;
242 case EDIT_FILE:
243 gtk_text_buffer_get_start_iter(pPrivate->pBuffer, &sPos);
244 break;
248 gtk_text_buffer_place_cursor(pPrivate->pBuffer, &sPos);
249 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(pPrivate->pTextView), gtk_text_buffer_get_insert(pPrivate->pBuffer));
252 void dasher_internal_buffer_edit_delete(DasherInternalBuffer *pSelf, int iDirection, int iDist) {
253 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
255 GtkTextIter sPosStart;
256 GtkTextIter sPosEnd;
258 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &sPosStart, gtk_text_buffer_get_insert(pPrivate->pBuffer));
260 sPosEnd = sPosStart;
262 if(iDirection == EDIT_FORWARDS) {
263 switch(iDist) {
264 case EDIT_CHAR:
265 gtk_text_iter_forward_char(&sPosStart);
266 break;
267 case EDIT_WORD:
268 gtk_text_iter_forward_word_end(&sPosStart);
269 break;
270 case EDIT_LINE:
271 if(!gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart))
273 gtk_text_view_forward_display_line (GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart);
274 gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart);
276 break;
277 case EDIT_FILE:
278 gtk_text_iter_forward_to_end(&sPosStart);
279 break;
282 else {
283 switch(iDist) {
284 case EDIT_CHAR:
285 gtk_text_iter_backward_char(&sPosStart);
286 break;
287 case EDIT_WORD:
288 gtk_text_iter_backward_word_start(&sPosStart);
289 break;
290 case EDIT_LINE:
291 if(!gtk_text_view_backward_display_line_start(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart))
292 gtk_text_view_backward_display_line(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart);
293 break;
294 case EDIT_FILE:
295 gtk_text_buffer_get_start_iter(pPrivate->pBuffer, &sPosStart);
296 break;
300 gtk_text_buffer_delete(pPrivate->pBuffer, &sPosStart, &sPosEnd);
301 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(pPrivate->pTextView), gtk_text_buffer_get_insert(pPrivate->pBuffer));
304 void dasher_internal_buffer_edit_convert(DasherInternalBuffer *pSelf) {
305 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
307 if(!(pPrivate->bConversionMode))
308 return;
310 GtkTextIter sStartIter;
311 GtkTextIter sEndIter;
312 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &sStartIter, pPrivate->iLastOffset);
313 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &sEndIter, -1);
314 gtk_text_buffer_apply_tag(pPrivate->pBuffer, pPrivate->pHiddenTag, &sStartIter, &sEndIter);
316 pPrivate->iCurrentState = 1;
317 pPrivate->iLastOffset = gtk_text_buffer_get_char_count(pPrivate->pBuffer);
320 void dasher_internal_buffer_edit_protect(DasherInternalBuffer *pSelf) {
321 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
323 if(!(pPrivate->bConversionMode))
324 return;
326 pPrivate->iCurrentState = 0;
327 pPrivate->iLastOffset = gtk_text_buffer_get_char_count(pPrivate->pBuffer);
330 void dasher_internal_buffer_conversion_mode(DasherInternalBuffer *pSelf, gboolean bMode) {
331 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
333 if(bMode) {
334 pPrivate->bConversionMode = TRUE;
335 pPrivate->iCurrentState = 0;
336 pPrivate->iLastOffset = gtk_text_buffer_get_char_count(pPrivate->pBuffer);
338 else {
339 pPrivate->bConversionMode = FALSE;
340 pPrivate->iCurrentState = 1;
344 void dasher_internal_buffer_clear(DasherInternalBuffer *pSelf) {
345 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
346 GtkTextIter *start, *end;
348 start = new GtkTextIter;
349 end = new GtkTextIter;
351 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, start, 0);
352 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, end, -1);
354 gtk_text_buffer_delete(pPrivate->pBuffer, start, end);
356 /* TODO: this probably shouldn't emit a signal */
357 g_signal_emit_by_name(G_OBJECT(pSelf), "context_changed", G_OBJECT(pSelf), NULL, NULL);
359 pPrivate->iCurrentState = 0;
360 pPrivate->iLastOffset = 0;
363 gint dasher_internal_buffer_get_offset(DasherInternalBuffer *pSelf) {
364 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
366 GtkTextIter oIter;
367 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &oIter, gtk_text_buffer_get_mark(pPrivate->pBuffer, "insert"));
368 return gtk_text_iter_get_offset(&oIter);
372 // Handlers
374 extern "C" void mark_set_handler(GtkWidget *widget, GtkTextIter *pIter, GtkTextMark *pMark, gpointer pUserData) {
375 dasher_internal_buffer_change_context(DASHER_INTERNAL_BUFFER(pUserData), pIter, pMark);