tagging release
[dasher.git] / trunk / Src / Gtk2 / dasher_internal_buffer.cpp
blob3c64b2823f639c6de4e65371da26d0ab9635d9de
1 #include <gtk/gtk.h>
2 #include <iostream>
3 #include <string.h>
5 #include "../Common/Common.h"
6 #include "dasher_buffer_set.h"
7 #include "dasher_internal_buffer.h"
9 static void dasher_internal_buffer_class_init(DasherInternalBufferClass *pClass);
10 static void dasher_internal_buffer_init(DasherInternalBuffer *pAction);
11 static void dasher_internal_buffer_destroy(GObject *pObject);
12 static void idasher_buffer_set_interface_init (gpointer g_iface, gpointer iface_data);
13 void dasher_internal_buffer_insert(DasherInternalBuffer *pSelf, const gchar *szText, int iOffset);
14 void dasher_internal_buffer_delete(DasherInternalBuffer *pSelf, int iLength, int iOffset);
15 gchar *dasher_internal_buffer_get_context(DasherInternalBuffer *pSelf, gint iOffset, gint iLength);
16 void dasher_internal_buffer_edit_move(DasherInternalBuffer *pSelf, int iDirection, int iDist);
17 void dasher_internal_buffer_edit_delete(DasherInternalBuffer *pSelf, int iDirection, int iDist);
18 void dasher_internal_buffer_edit_convert(DasherInternalBuffer *pSelf);
19 void dasher_internal_buffer_edit_protect(DasherInternalBuffer *pSelf);
20 void dasher_internal_buffer_conversion_mode(DasherInternalBuffer *pSelf, gboolean bMode);
21 gint dasher_internal_buffer_get_offset(DasherInternalBuffer *pSelf);
23 // Related signal handlers
24 extern "C" void mark_set_handler(GtkWidget *widget, GtkTextIter *pIter, GtkTextMark *pMark, gpointer pUserData);
26 typedef struct _DasherInternalBufferPrivate DasherInternalBufferPrivate;
28 struct _DasherInternalBufferPrivate {
29 GtkTextView *pTextView;
30 GtkTextBuffer *pBuffer;
31 GtkTextTag *pOutputTag;
32 GtkTextTag *pHiddenTag;
33 GtkTextTag *pVisibleTag;
34 gboolean bConversionMode;
35 gint iLastOffset;
36 gint iCurrentState; // 0 = unconverted, 1 = converted
39 GType dasher_internal_buffer_get_type() {
41 static GType dasher_internal_buffer_type = 0;
43 if(!dasher_internal_buffer_type) {
44 static const GTypeInfo dasher_internal_buffer_info = {
45 sizeof(DasherInternalBufferClass),
46 NULL,
47 NULL,
48 (GClassInitFunc) dasher_internal_buffer_class_init,
49 NULL,
50 NULL,
51 sizeof(DasherInternalBuffer),
53 (GInstanceInitFunc) dasher_internal_buffer_init,
54 NULL
57 static const GInterfaceInfo idasher_buffer_set_info = {
58 (GInterfaceInitFunc) idasher_buffer_set_interface_init,
59 NULL,
60 NULL
63 dasher_internal_buffer_type = g_type_register_static(G_TYPE_OBJECT, "DasherInternalBuffer", &dasher_internal_buffer_info, static_cast < GTypeFlags > (0));
65 g_type_add_interface_static (dasher_internal_buffer_type,
66 IDASHER_BUFFER_SET_TYPE,
67 &idasher_buffer_set_info);
70 return dasher_internal_buffer_type;
73 static void dasher_internal_buffer_class_init(DasherInternalBufferClass *pClass) {
74 GObjectClass *pObjectClass = (GObjectClass *) pClass;
75 pObjectClass->finalize = dasher_internal_buffer_destroy;
78 static void dasher_internal_buffer_init(DasherInternalBuffer *pDasherControl) {
79 pDasherControl->private_data = (void *)(new DasherInternalBufferPrivate);
82 static void idasher_buffer_set_interface_init (gpointer g_iface, gpointer iface_data) {
83 IDasherBufferSetInterface *iface = (IDasherBufferSetInterface *)g_iface;
84 iface->insert_text = (void (*)(IDasherBufferSet *pSelf, const gchar *szText, int iOffset))dasher_internal_buffer_insert;
85 iface->delete_text = (void (*)(IDasherBufferSet *pSelf, gint iLength, int iOffset))dasher_internal_buffer_delete;
86 iface->get_context = (gchar *(*)(IDasherBufferSet *pSelf, gint iOffset, gint iLength))dasher_internal_buffer_get_context;
87 iface->edit_move = (void (*)(IDasherBufferSet *pSelf, gint iDirection, gint iDist))dasher_internal_buffer_edit_move;
88 iface->edit_delete = (void (*)(IDasherBufferSet *pSelf, gint iDirection, gint iDist))dasher_internal_buffer_edit_delete;
89 iface->edit_convert = (void (*)(IDasherBufferSet *pSelf))dasher_internal_buffer_edit_convert;
90 iface->edit_protect = (void (*)(IDasherBufferSet *pSelf))dasher_internal_buffer_edit_protect;
91 iface->conversion_mode = (void (*)(IDasherBufferSet *pSelf, gboolean bMode))dasher_internal_buffer_conversion_mode;
92 iface->get_offset = (gint (*)(IDasherBufferSet *pSelf))dasher_internal_buffer_get_offset;
95 static void dasher_internal_buffer_destroy(GObject *pObject) {
96 // FIXME - I think we need to chain up through the finalize methods
97 // of the parent classes here...
99 delete (DasherInternalBufferPrivate *)(((DasherInternalBuffer *)pObject)->private_data);
102 DasherInternalBuffer *dasher_internal_buffer_new(GtkTextView *pTextView) {
103 DasherInternalBuffer *pDasherControl;
104 pDasherControl = (DasherInternalBuffer *)(g_object_new(dasher_internal_buffer_get_type(), NULL));
106 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pDasherControl->private_data);
107 pPrivate->pTextView = pTextView;
108 pPrivate->pBuffer = gtk_text_view_get_buffer(pTextView);
110 pPrivate->pOutputTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, NULL);
112 #if GTK_CHECK_VERSION(2,8,0)
113 pPrivate->pHiddenTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, "invisible", TRUE, NULL);
114 #else
115 // TODO: We really ought to do something a little more sensible with conversion in GTK < 2.8
116 pPrivate->pHiddenTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, NULL);
117 #endif
119 pPrivate->pVisibleTag = gtk_text_buffer_create_tag(pPrivate->pBuffer, NULL, "foreground", "red", NULL);
121 pPrivate->bConversionMode = FALSE;
122 pPrivate->iLastOffset = 1;
123 pPrivate->iCurrentState = 0;
125 g_signal_connect(G_OBJECT(pPrivate->pBuffer), "mark-set", G_CALLBACK(mark_set_handler), pDasherControl);
127 return pDasherControl;
130 void dasher_internal_buffer_insert(DasherInternalBuffer *pSelf, const gchar *szText, int iOffset) {
131 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
133 // std::cout << "i: " << szText << " (" << iOffset << " " << gtk_text_buffer_get_char_count(pPrivate->pBuffer) << ")" << std::endl;
135 DASHER_ASSERT(gtk_text_buffer_get_char_count(pPrivate->pBuffer) == iOffset);
137 gtk_text_buffer_delete_selection(pPrivate->pBuffer, false, true );
139 GtkTextIter sIter;
140 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &sIter, gtk_text_buffer_get_insert(pPrivate->pBuffer));
142 GtkTextTag *pCurrentTag = NULL;
144 if(!pPrivate->bConversionMode)
145 pCurrentTag = pPrivate->pOutputTag;
146 else {
147 switch(pPrivate->iCurrentState) {
148 case 0:
149 pCurrentTag = pPrivate->pVisibleTag;
150 break;
151 case 1:
152 pCurrentTag = pPrivate->pOutputTag;
153 break;
157 if(!pCurrentTag)
158 return;
160 gtk_text_buffer_insert_with_tags(pPrivate->pBuffer, &sIter, szText, -1, pCurrentTag, NULL);
162 gtk_text_view_scroll_mark_onscreen(pPrivate->pTextView, gtk_text_buffer_get_insert(pPrivate->pBuffer));
164 // g_message("Buffer lenght: %d", gtk_text_buffer_get_char_count(pPrivate->pBuffer));
167 void dasher_internal_buffer_delete(DasherInternalBuffer *pSelf, int iLength, int iOffset) {
168 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
170 GtkTextIter *start = new GtkTextIter;
171 GtkTextIter *end = new GtkTextIter;
173 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, end, gtk_text_buffer_get_insert(pPrivate->pBuffer));
175 *start = *end;
177 gtk_text_iter_backward_chars(start, iLength);
178 // g_bIgnoreCursorMove = true;
179 gtk_text_buffer_delete(pPrivate->pBuffer, start, end);
180 gtk_text_view_scroll_mark_onscreen(pPrivate->pTextView, gtk_text_buffer_get_insert(pPrivate->pBuffer));
181 // g_bIgnoreCursorMove = false;
183 delete start;
184 delete end;
186 // std::cout << "d: " << iLength << " (" << iOffset << " " << gtk_text_buffer_get_char_count(pPrivate->pBuffer) << ")" << std::endl;
187 DASHER_ASSERT(gtk_text_buffer_get_char_count(pPrivate->pBuffer) == iOffset);
190 gchar *dasher_internal_buffer_get_context(DasherInternalBuffer *pSelf, gint iOffset, gint iLength) {
191 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
193 // g_message("Buffer lenght: %d", gtk_text_buffer_get_char_count(pPrivate->pBuffer));
195 GtkTextIter start;
196 GtkTextIter end; // Refers to end of context, which is start of selection!
198 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &start, iOffset);
199 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &end, iOffset + iLength);
201 return gtk_text_buffer_get_text( pPrivate->pBuffer, &start, &end, false );
204 // TODO: Check that these signals are being used appropriately
205 void dasher_internal_buffer_change_context(DasherInternalBuffer *pSelf, GtkTextIter *pIter, GtkTextMark *pMark) {
206 const char *szMarkName(gtk_text_mark_get_name(pMark));
207 if(szMarkName && !strcmp(szMarkName,"insert")) {
208 g_signal_emit_by_name(G_OBJECT(pSelf), "offset_changed", G_OBJECT(pSelf), NULL, NULL);
212 void dasher_internal_buffer_edit_move(DasherInternalBuffer *pSelf, int iDirection, int iDist) {
213 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
215 GtkTextIter sPos;
217 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &sPos, gtk_text_buffer_get_insert(pPrivate->pBuffer));
219 if(iDirection == EDIT_FORWARDS) {
220 switch(iDist) {
221 case EDIT_CHAR:
222 gtk_text_iter_forward_char(&sPos);
223 break;
224 case EDIT_WORD:
225 gtk_text_iter_forward_word_end(&sPos);
226 break;
227 case EDIT_LINE:
228 if(!gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos))
230 gtk_text_view_forward_display_line (GTK_TEXT_VIEW(pPrivate->pTextView), &sPos);
231 gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos);
233 break;
234 case EDIT_FILE:
235 gtk_text_iter_forward_to_end(&sPos);
236 break;
239 else {
240 switch(iDist) {
241 case EDIT_CHAR:
242 gtk_text_iter_backward_char(&sPos);
243 break;
244 case EDIT_WORD:
245 gtk_text_iter_backward_word_start(&sPos);
246 break;
247 case EDIT_LINE:
249 if(!gtk_text_view_backward_display_line_start(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos))
250 gtk_text_view_backward_display_line(GTK_TEXT_VIEW(pPrivate->pTextView), &sPos);
251 break;
252 case EDIT_FILE:
253 gtk_text_buffer_get_start_iter(pPrivate->pBuffer, &sPos);
254 break;
258 gtk_text_buffer_place_cursor(pPrivate->pBuffer, &sPos);
259 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(pPrivate->pTextView), gtk_text_buffer_get_insert(pPrivate->pBuffer));
262 void dasher_internal_buffer_edit_delete(DasherInternalBuffer *pSelf, int iDirection, int iDist) {
263 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
265 GtkTextIter sPosStart;
266 GtkTextIter sPosEnd;
268 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &sPosStart, gtk_text_buffer_get_insert(pPrivate->pBuffer));
270 sPosEnd = sPosStart;
272 if(iDirection == EDIT_FORWARDS) {
273 switch(iDist) {
274 case EDIT_CHAR:
275 gtk_text_iter_forward_char(&sPosStart);
276 break;
277 case EDIT_WORD:
278 gtk_text_iter_forward_word_end(&sPosStart);
279 break;
280 case EDIT_LINE:
281 if(!gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart))
283 gtk_text_view_forward_display_line (GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart);
284 gtk_text_view_forward_display_line_end(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart);
286 break;
287 case EDIT_FILE:
288 gtk_text_iter_forward_to_end(&sPosStart);
289 break;
292 else {
293 switch(iDist) {
294 case EDIT_CHAR:
295 gtk_text_iter_backward_char(&sPosStart);
296 break;
297 case EDIT_WORD:
298 gtk_text_iter_backward_word_start(&sPosStart);
299 break;
300 case EDIT_LINE:
301 if(!gtk_text_view_backward_display_line_start(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart))
302 gtk_text_view_backward_display_line(GTK_TEXT_VIEW(pPrivate->pTextView), &sPosStart);
303 break;
304 case EDIT_FILE:
305 gtk_text_buffer_get_start_iter(pPrivate->pBuffer, &sPosStart);
306 break;
310 gtk_text_buffer_delete(pPrivate->pBuffer, &sPosStart, &sPosEnd);
311 gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(pPrivate->pTextView), gtk_text_buffer_get_insert(pPrivate->pBuffer));
314 void dasher_internal_buffer_edit_convert(DasherInternalBuffer *pSelf) {
315 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
317 if(!(pPrivate->bConversionMode))
318 return;
320 GtkTextIter sStartIter;
321 GtkTextIter sEndIter;
322 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &sStartIter, pPrivate->iLastOffset);
323 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, &sEndIter, -1);
324 gtk_text_buffer_apply_tag(pPrivate->pBuffer, pPrivate->pHiddenTag, &sStartIter, &sEndIter);
326 pPrivate->iCurrentState = 1;
327 pPrivate->iLastOffset = gtk_text_buffer_get_char_count(pPrivate->pBuffer);
330 void dasher_internal_buffer_edit_protect(DasherInternalBuffer *pSelf) {
331 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
333 if(!(pPrivate->bConversionMode))
334 return;
336 pPrivate->iCurrentState = 0;
337 pPrivate->iLastOffset = gtk_text_buffer_get_char_count(pPrivate->pBuffer);
340 void dasher_internal_buffer_conversion_mode(DasherInternalBuffer *pSelf, gboolean bMode) {
341 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
343 if(bMode) {
344 pPrivate->bConversionMode = TRUE;
345 pPrivate->iCurrentState = 0;
346 pPrivate->iLastOffset = gtk_text_buffer_get_char_count(pPrivate->pBuffer);
348 else {
349 pPrivate->bConversionMode = FALSE;
350 pPrivate->iCurrentState = 1;
354 void dasher_internal_buffer_clear(DasherInternalBuffer *pSelf) {
355 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
356 GtkTextIter *start, *end;
358 start = new GtkTextIter;
359 end = new GtkTextIter;
361 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, start, 0);
362 gtk_text_buffer_get_iter_at_offset(pPrivate->pBuffer, end, -1);
364 gtk_text_buffer_delete(pPrivate->pBuffer, start, end);
366 /* TODO: this probably shouldn't emit a signal */
367 g_signal_emit_by_name(G_OBJECT(pSelf), "buffer_changed", G_OBJECT(pSelf), NULL, NULL);
369 pPrivate->iCurrentState = 0;
370 pPrivate->iLastOffset = 0;
373 gint dasher_internal_buffer_get_offset(DasherInternalBuffer *pSelf) {
374 DasherInternalBufferPrivate *pPrivate = (DasherInternalBufferPrivate *)(pSelf->private_data);
376 GtkTextIter oIter;
377 gtk_text_buffer_get_iter_at_mark(pPrivate->pBuffer, &oIter, gtk_text_buffer_get_mark(pPrivate->pBuffer, "insert"));
378 return gtk_text_iter_get_offset(&oIter);
382 // Handlers
384 extern "C" void mark_set_handler(GtkWidget *widget, GtkTextIter *pIter, GtkTextMark *pMark, gpointer pUserData) {
385 dasher_internal_buffer_change_context(DASHER_INTERNAL_BUFFER(pUserData), pIter, pMark);