~writer-devs/writer/trunk

« back to all changes in this revision

Viewing changes to src/Utils/TextEditor.vala

  • Committer: Tuur Dutoit
  • Date: 2014-10-26 10:41:33 UTC
  • Revision ID: me@tuurdutoit.be-20141026104133-gzvzgh1m6ntrrc9o
Renamed Editor to TextEditor and EditorToolBar to TextToolBar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***
 
2
The MIT License (MIT)
 
3
 
 
4
Copyright (c) 2014 Tuur Dutoit
 
5
 
 
6
Permission is hereby granted, free of charge, to any person obtaining a copy
 
7
of this software and associated documentation files (the "Software"), to deal
 
8
in the Software without restriction, including without limitation the rights
 
9
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
10
copies of the Software, and to permit persons to whom the Software is
 
11
furnished to do so, subject to the following conditions:
 
12
 
 
13
The above copyright notice and this permission notice shall be included in all
 
14
copies or substantial portions of the Software.
 
15
 
 
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
18
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
19
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
20
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
21
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
22
SOFTWARE.
 
23
***/
 
24
 
 
25
 
 
26
using Gtk;
 
27
using Gdk;
 
28
using Pango;
 
29
using Writer.Utils;
 
30
 
 
31
namespace Writer {
 
32
    public class TextEditor : TextBuffer {
 
33
    
 
34
        public TextView text_view;
 
35
        
 
36
        public signal void cursor_moved ();
 
37
        public signal void text_inserted ();
 
38
    
 
39
        public TextEditor () {
 
40
            setup_tagtable (this);
 
41
            text_view = new TextView.with_buffer (this);
 
42
            
 
43
            this.notify["cursor-position"].connect (cursor_moved_callback);
 
44
            this.insert_text.connect_after (text_inserted_callback);
 
45
            
 
46
            text_view.key_press_event.connect (key_press_callback);
 
47
            text_view.pixels_below_lines = 20;
 
48
        }
 
49
        
 
50
        // Get a TextTagTable with all the default tags
 
51
        private void setup_tagtable (TextBuffer buffer) {
 
52
            
 
53
            buffer.create_tag ("bold", "weight", 700);
 
54
            buffer.create_tag ("italic", "style", Pango.Style.ITALIC);
 
55
            buffer.create_tag ("underline", "underline", Pango.Underline.SINGLE);
 
56
            buffer.create_tag ("strikethrough", "strikethrough", true);
 
57
            
 
58
            buffer.create_tag ("align-left", "justification", Gtk.Justification.LEFT);
 
59
            buffer.create_tag ("align-center", "justification", Gtk.Justification.CENTER);
 
60
            buffer.create_tag ("align-right", "justification", Gtk.Justification.RIGHT);
 
61
            buffer.create_tag ("align-fill", "justification", Gtk.Justification.FILL);
 
62
            
 
63
        }
 
64
        
 
65
        
 
66
        /*
 
67
         * Styles (apply, remove, check)
 
68
         */
 
69
         
 
70
        public void apply_style (string name) {
 
71
            if (has_selection)
 
72
                get_selection_range ().apply_style (name);
 
73
        }
 
74
        
 
75
        public void remove_style (string name) {
 
76
            if (has_selection)
 
77
                get_selection_range ().remove_style (name);
 
78
        }
 
79
        
 
80
        public void toggle_style (string name) {
 
81
            if (has_selection)
 
82
                get_selection_range ().toggle_style (name);
 
83
        }
 
84
        
 
85
        public bool has_style (string name) {
 
86
            if (has_selection)
 
87
                return get_selection_range ().has_style (name);
 
88
            else
 
89
                return iter_has_style (get_cursor (), name);
 
90
        }
 
91
        
 
92
        
 
93
        public Gtk.Justification get_justification () {
 
94
            if (has_selection)
 
95
                return get_selection_range ().get_justification ();
 
96
            else
 
97
                return get_justification_at_iter (get_cursor ());
 
98
        }
 
99
        
 
100
        public Gtk.Justification get_justification_at_iter (TextIter iter) {
 
101
            if (iter_has_style (iter, "align-center"))
 
102
                return Gtk.Justification.CENTER;
 
103
            else if (iter_has_style (iter, "align-right"))
 
104
                return Gtk.Justification.RIGHT;
 
105
            else if (iter_has_style (iter, "align-fill"))
 
106
                return Gtk.Justification.FILL;
 
107
            else
 
108
                return Gtk.Justification.LEFT;
 
109
        }
 
110
        
 
111
        public int get_justification_as_int () {
 
112
            if (has_selection)
 
113
                return get_selection_range ().get_justification_as_int ();
 
114
            else
 
115
                return get_justification_as_int_at_iter (get_cursor ());
 
116
        }
 
117
        
 
118
        public int get_justification_as_int_at_iter (TextIter iter) {
 
119
            if (iter_has_style (iter, "align-center"))
 
120
                return 1;
 
121
            else if (iter_has_style (iter, "align-right"))
 
122
                return 2;
 
123
            else if (iter_has_style (iter, "align-fill"))
 
124
                return 3;
 
125
            else
 
126
                return 0;
 
127
        }
 
128
        
 
129
        public void set_justification (string align) {
 
130
            get_paragraph (get_cursor ()).set_justification (align);
 
131
        }
 
132
        
 
133
        
 
134
        public void set_font (FontDescription font) {
 
135
            get_selection_range ().set_font (font);
 
136
        }
 
137
        
 
138
        public void set_font_from_string (string font) {
 
139
            get_selection_range ().set_font_from_string (font);
 
140
        }
 
141
        
 
142
        
 
143
        public void set_font_color (Gdk.Color color) {
 
144
            get_selection_range ().set_font_color (color);
 
145
        }
 
146
        
 
147
        public void set_font_color_from_string (string color) {
 
148
            get_selection_range ().set_font_color_from_string (color);
 
149
        }
 
150
        
 
151
        
 
152
        
 
153
        /*
 
154
         * Inserts
 
155
         */
 
156
        
 
157
        public void insert_comment () {
 
158
            print ("Insert Comment\n");
 
159
        }
 
160
        
 
161
        public void insert_image () {
 
162
            print ("Insert Image\n");
 
163
        }
 
164
        
 
165
        public void insert_link () {
 
166
            print ("Insert Link\n");
 
167
        }
 
168
        
 
169
        public void insert_table (int cols, int rows) {
 
170
            print ("Insert Table of %d columns by %d rows\n", cols, rows);
 
171
        }
 
172
        
 
173
        
 
174
        public void insert_line () {
 
175
            TextIter insert_cursor = get_cursor ();
 
176
            insert_line_at_iter (insert_cursor);
 
177
        }
 
178
        
 
179
        public void insert_paragraph () {
 
180
            TextIter cursor = get_cursor ();
 
181
            insert_paragraph_at_iter (cursor);
 
182
        }
 
183
        
 
184
        public void insert_line_at_iter (TextIter iter) {
 
185
            //TODO
 
186
            // Cursor does not move to next line
 
187
            // Only happens when inserting at the end of the buffer
 
188
            // Bug reported in GTK+
 
189
            
 
190
            insert (ref iter, "\u2028", -1);
 
191
        }
 
192
        
 
193
        public void insert_paragraph_at_iter (TextIter iter) {
 
194
            insert (ref iter, "\n", -1);
 
195
        }
 
196
        
 
197
        
 
198
        
 
199
        
 
200
        /*
 
201
         * paragraphs
 
202
         */
 
203
        
 
204
        // Moves iter to the start of the paragraph it is located in
 
205
        public TextIter get_paragraph_start (TextIter iter) {
 
206
            iter.backward_find_char ((char) => {
 
207
                if (char.to_string () == "\n")
 
208
                    return true;
 
209
                else
 
210
                    return false;
 
211
            }, null);
 
212
            return iter;
 
213
        }
 
214
        
 
215
        // Moves iter to the end of the paragraph it is located in
 
216
        public TextIter get_paragraph_end (TextIter iter) {
 
217
            iter.forward_find_char ((char) => {
 
218
                if (char.to_string () == "\n")
 
219
                    return true;
 
220
                else
 
221
                    return false;
 
222
            }, null);
 
223
            return iter;
 
224
        }
 
225
        
 
226
        public TextRange get_paragraph (TextIter iter) {
 
227
            TextIter start = get_paragraph_start (iter);
 
228
            TextIter end = get_paragraph_end (iter);
 
229
            
 
230
            return new TextRange (this, start, end);
 
231
        }
 
232
        
 
233
        
 
234
        
 
235
        
 
236
        /*
 
237
         * Search
 
238
         */
 
239
        
 
240
        public void search (string text) {
 
241
            if (text.length > 0)
 
242
                search_string (text);
 
243
            else
 
244
                clear_search ();
 
245
        }
 
246
        
 
247
        public void search_string (string text) {
 
248
            print ("Searching for: %s\n", text);
 
249
        }
 
250
        
 
251
        public void clear_search () {
 
252
            print ("Clearing search");
 
253
        }
 
254
        
 
255
        
 
256
        
 
257
        /*
 
258
         * Utilities
 
259
         */
 
260
        
 
261
        public TextIter get_cursor () {
 
262
            TextIter iter;
 
263
            get_iter_at_mark (out iter, get_insert ());
 
264
            return iter;
 
265
        }
 
266
        
 
267
        public TextRange get_cursor_as_range () {
 
268
            var cursor = get_cursor ();
 
269
            return new TextRange (this, cursor, cursor);
 
270
        }
 
271
        
 
272
        public TextRange get_selection_range () {
 
273
            TextIter start; TextIter end;
 
274
            get_selection_bounds (out start, out end);
 
275
            return new TextRange (this, start, end);
 
276
        }
 
277
        
 
278
        public bool iter_has_tag (TextIter iter, TextTag tag) {
 
279
            return iter.has_tag (tag) || iter.begins_tag (tag) || iter.ends_tag (tag);
 
280
        }
 
281
        
 
282
        public bool iter_has_style (TextIter iter, string name) {
 
283
            var tag = tag_table.lookup (name);
 
284
            return iter_has_tag (iter, tag);
 
285
        }
 
286
        
 
287
        public TextIter copy_iter (TextIter iter) {
 
288
            TextIter copy;
 
289
            get_iter_at_offset (out copy, iter.get_offset ());
 
290
            return copy;
 
291
        }
 
292
        
 
293
        
 
294
        
 
295
        
 
296
        
 
297
        /*
 
298
         * Signal callbacks
 
299
         */
 
300
        
 
301
        private void cursor_moved_callback () {
 
302
            // Emit 'cursor_moved' signal
 
303
            cursor_moved ();
 
304
        }
 
305
        
 
306
        private void text_inserted_callback (TextIter cursor, string new_text, int length) {
 
307
            TextIter previous;
 
308
            get_iter_at_offset (out previous, cursor.get_offset () - length);
 
309
            
 
310
            if (iter_has_style (previous, "bold"))
 
311
                apply_tag_by_name ("bold", previous, cursor);
 
312
            if (iter_has_style (previous, "italic"))
 
313
                apply_tag_by_name ("italic", previous, cursor);
 
314
            if (iter_has_style (previous, "underline"))
 
315
                apply_tag_by_name ("underline", previous, cursor);
 
316
            if (iter_has_style (previous, "strikethrough"))
 
317
                apply_tag_by_name ("strikethrough", previous, cursor);
 
318
            
 
319
            
 
320
            // Emit signals
 
321
            text_inserted ();
 
322
            cursor_moved ();
 
323
        }
 
324
        
 
325
        private bool key_press_callback (EventKey event) {
 
326
            if (Gdk.keyval_name (event.keyval) == "Return") {
 
327
                ModifierType modifiers = Gtk.accelerator_get_default_mod_mask ();
 
328
                
 
329
                if ((event.state & modifiers) == Gdk.ModifierType.SHIFT_MASK)
 
330
                    insert_line ();
 
331
                else
 
332
                    insert_paragraph ();
 
333
                
 
334
                return true;
 
335
            }
 
336
            else {                
 
337
                return false;
 
338
            }
 
339
        }
 
340
    
 
341
    }
 
342
}
 
 
b'\\ No newline at end of file'