Merge lp:~ryanriffle/writer/instant_style_apply into lp:writer

Proposed by Ryan Riffle
Status: Merged
Merged at revision: 75
Proposed branch: lp:~ryanriffle/writer/instant_style_apply
Merge into: lp:writer
Diff against target: 635 lines (+171/-116)
2 files modified
src/Utils/TextEditor.vala (+137/-85)
src/Widgets/TextToolBar.vala (+34/-31)
To merge this branch: bzr merge lp:~ryanriffle/writer/instant_style_apply
Reviewer Review Type Date Requested Status
Tuur Dutoit Approve
Review via email: mp+244681@code.launchpad.net

Description of the change

I made clicking bold, italic, and underline apply the style instead of having to select the text first. Also in TextToolbar I added focus_on_click = false to the other buttons aside from bold.

I had to change the way TextEditor.cursor_moved is called, because the notify caused cursor_moved_callback to be called before text_insert_callback was called, therefore resetting the styles. Also added a mouse click event because Gtk.TextView.move_cursor signal does not emit if the user clicks somewhere in the text.

To post a comment you must log in.
Revision history for this message
Ryan Riffle (ryanriffle) wrote :

I am not sure what the design should be. Whether you want to use a dictionary for the added members or a new TextStyle class. Just let me know and I can change it.

Revision history for this message
Ryan Riffle (ryanriffle) wrote :

Is this going to be reviewed?

Revision history for this message
Tuur Dutoit (tuur-dutoit-f) wrote :

Yes, of course. I'm sorry, I've been lazy the last few days (after exams...). Tomorrow I'll get some work done.

Revision history for this message
Tuur Dutoit (tuur-dutoit-f) wrote :

That's very good, I'm merging it in.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Utils/TextEditor.vala'
2--- src/Utils/TextEditor.vala 2014-10-26 10:41:33 +0000
3+++ src/Utils/TextEditor.vala 2014-12-14 05:22:00 +0000
4@@ -30,73 +30,110 @@
5
6 namespace Writer {
7 public class TextEditor : TextBuffer {
8-
9+
10 public TextView text_view;
11-
12+ public bool style_bold;
13+ public bool style_italic;
14+ public bool style_underline;
15+ public bool style_strikethrough;
16+
17 public signal void cursor_moved ();
18 public signal void text_inserted ();
19-
20+
21 public TextEditor () {
22 setup_tagtable (this);
23 text_view = new TextView.with_buffer (this);
24-
25- this.notify["cursor-position"].connect (cursor_moved_callback);
26+
27+ style_bold = false;
28+ style_italic = false;
29+ style_underline = false;
30+ style_strikethrough = false;
31+
32+ text_view.move_cursor.connect (cursor_moved_callback);
33+ text_view.button_release_event.connect (editor_clicked_callback);
34 this.insert_text.connect_after (text_inserted_callback);
35-
36+
37 text_view.key_press_event.connect (key_press_callback);
38 text_view.pixels_below_lines = 20;
39 }
40-
41+
42 // Get a TextTagTable with all the default tags
43 private void setup_tagtable (TextBuffer buffer) {
44-
45+
46 buffer.create_tag ("bold", "weight", 700);
47 buffer.create_tag ("italic", "style", Pango.Style.ITALIC);
48 buffer.create_tag ("underline", "underline", Pango.Underline.SINGLE);
49 buffer.create_tag ("strikethrough", "strikethrough", true);
50-
51+
52 buffer.create_tag ("align-left", "justification", Gtk.Justification.LEFT);
53 buffer.create_tag ("align-center", "justification", Gtk.Justification.CENTER);
54 buffer.create_tag ("align-right", "justification", Gtk.Justification.RIGHT);
55 buffer.create_tag ("align-fill", "justification", Gtk.Justification.FILL);
56-
57+
58 }
59-
60-
61+
62+
63 /*
64 * Styles (apply, remove, check)
65 */
66-
67+
68 public void apply_style (string name) {
69 if (has_selection)
70 get_selection_range ().apply_style (name);
71+
72+ if (name == "bold")
73+ style_bold = true;
74+ else if (name == "italic")
75+ style_italic = true;
76+ else if (name == "underline")
77+ style_underline = true;
78+ else if (name == "strikethrough")
79+ style_strikethrough = true;
80 }
81-
82+
83 public void remove_style (string name) {
84 if (has_selection)
85 get_selection_range ().remove_style (name);
86+
87+ if (name == "bold")
88+ style_bold = false;
89+ else if (name == "italic")
90+ style_italic = false;
91+ else if (name == "underline")
92+ style_underline = false;
93+ else if (name == "strikethrough")
94+ style_strikethrough = false;
95 }
96-
97+
98 public void toggle_style (string name) {
99 if (has_selection)
100 get_selection_range ().toggle_style (name);
101+
102+ if (name == "bold")
103+ style_bold = !style_bold;
104+ else if (name == "italic")
105+ style_italic = !style_italic;
106+ else if (name == "underline")
107+ style_underline = !style_underline;
108+ else if (name == "strikethrough")
109+ style_strikethrough = !style_strikethrough;
110 }
111-
112+
113 public bool has_style (string name) {
114 if (has_selection)
115 return get_selection_range ().has_style (name);
116 else
117 return iter_has_style (get_cursor (), name);
118 }
119-
120-
121+
122+
123 public Gtk.Justification get_justification () {
124 if (has_selection)
125 return get_selection_range ().get_justification ();
126 else
127 return get_justification_at_iter (get_cursor ());
128 }
129-
130+
131 public Gtk.Justification get_justification_at_iter (TextIter iter) {
132 if (iter_has_style (iter, "align-center"))
133 return Gtk.Justification.CENTER;
134@@ -107,14 +144,14 @@
135 else
136 return Gtk.Justification.LEFT;
137 }
138-
139+
140 public int get_justification_as_int () {
141 if (has_selection)
142 return get_selection_range ().get_justification_as_int ();
143 else
144 return get_justification_as_int_at_iter (get_cursor ());
145 }
146-
147+
148 public int get_justification_as_int_at_iter (TextIter iter) {
149 if (iter_has_style (iter, "align-center"))
150 return 1;
151@@ -125,82 +162,82 @@
152 else
153 return 0;
154 }
155-
156+
157 public void set_justification (string align) {
158 get_paragraph (get_cursor ()).set_justification (align);
159 }
160-
161-
162+
163+
164 public void set_font (FontDescription font) {
165 get_selection_range ().set_font (font);
166 }
167-
168+
169 public void set_font_from_string (string font) {
170 get_selection_range ().set_font_from_string (font);
171 }
172-
173-
174+
175+
176 public void set_font_color (Gdk.Color color) {
177 get_selection_range ().set_font_color (color);
178 }
179-
180+
181 public void set_font_color_from_string (string color) {
182 get_selection_range ().set_font_color_from_string (color);
183 }
184-
185-
186-
187+
188+
189+
190 /*
191 * Inserts
192 */
193-
194+
195 public void insert_comment () {
196 print ("Insert Comment\n");
197 }
198-
199+
200 public void insert_image () {
201 print ("Insert Image\n");
202 }
203-
204+
205 public void insert_link () {
206 print ("Insert Link\n");
207 }
208-
209+
210 public void insert_table (int cols, int rows) {
211 print ("Insert Table of %d columns by %d rows\n", cols, rows);
212 }
213-
214-
215+
216+
217 public void insert_line () {
218 TextIter insert_cursor = get_cursor ();
219 insert_line_at_iter (insert_cursor);
220 }
221-
222+
223 public void insert_paragraph () {
224 TextIter cursor = get_cursor ();
225 insert_paragraph_at_iter (cursor);
226 }
227-
228+
229 public void insert_line_at_iter (TextIter iter) {
230 //TODO
231 // Cursor does not move to next line
232 // Only happens when inserting at the end of the buffer
233 // Bug reported in GTK+
234-
235+
236 insert (ref iter, "\u2028", -1);
237 }
238-
239+
240 public void insert_paragraph_at_iter (TextIter iter) {
241 insert (ref iter, "\n", -1);
242 }
243-
244-
245-
246-
247+
248+
249+
250+
251 /*
252 * paragraphs
253 */
254-
255+
256 // Moves iter to the start of the paragraph it is located in
257 public TextIter get_paragraph_start (TextIter iter) {
258 iter.backward_find_char ((char) => {
259@@ -211,7 +248,7 @@
260 }, null);
261 return iter;
262 }
263-
264+
265 // Moves iter to the end of the paragraph it is located in
266 public TextIter get_paragraph_end (TextIter iter) {
267 iter.forward_find_char ((char) => {
268@@ -222,121 +259,136 @@
269 }, null);
270 return iter;
271 }
272-
273+
274 public TextRange get_paragraph (TextIter iter) {
275 TextIter start = get_paragraph_start (iter);
276 TextIter end = get_paragraph_end (iter);
277-
278+
279 return new TextRange (this, start, end);
280 }
281-
282-
283-
284-
285+
286+
287+
288+
289 /*
290 * Search
291 */
292-
293+
294 public void search (string text) {
295 if (text.length > 0)
296 search_string (text);
297 else
298 clear_search ();
299 }
300-
301+
302 public void search_string (string text) {
303 print ("Searching for: %s\n", text);
304 }
305-
306+
307 public void clear_search () {
308 print ("Clearing search");
309 }
310-
311-
312-
313+
314+
315+
316 /*
317 * Utilities
318 */
319-
320+
321 public TextIter get_cursor () {
322 TextIter iter;
323 get_iter_at_mark (out iter, get_insert ());
324 return iter;
325 }
326-
327+
328 public TextRange get_cursor_as_range () {
329 var cursor = get_cursor ();
330 return new TextRange (this, cursor, cursor);
331 }
332-
333+
334 public TextRange get_selection_range () {
335 TextIter start; TextIter end;
336 get_selection_bounds (out start, out end);
337 return new TextRange (this, start, end);
338 }
339-
340+
341 public bool iter_has_tag (TextIter iter, TextTag tag) {
342 return iter.has_tag (tag) || iter.begins_tag (tag) || iter.ends_tag (tag);
343 }
344-
345+
346 public bool iter_has_style (TextIter iter, string name) {
347 var tag = tag_table.lookup (name);
348 return iter_has_tag (iter, tag);
349 }
350-
351+
352 public TextIter copy_iter (TextIter iter) {
353 TextIter copy;
354 get_iter_at_offset (out copy, iter.get_offset ());
355 return copy;
356 }
357-
358-
359-
360-
361-
362+
363+
364+
365+ private void update_styles () {
366+ var iter = get_cursor();
367+
368+ style_bold = iter_has_style (iter, "bold");
369+ style_italic = iter_has_style (iter, "italic");
370+ style_underline = iter_has_style (iter, "underline");
371+ style_strikethrough = iter_has_style (iter, "strikethrough");
372+ }
373+
374 /*
375 * Signal callbacks
376 */
377-
378+
379 private void cursor_moved_callback () {
380 // Emit 'cursor_moved' signal
381+ update_styles ();
382 cursor_moved ();
383 }
384-
385+
386 private void text_inserted_callback (TextIter cursor, string new_text, int length) {
387 TextIter previous;
388 get_iter_at_offset (out previous, cursor.get_offset () - length);
389-
390- if (iter_has_style (previous, "bold"))
391+
392+ if (style_bold)
393 apply_tag_by_name ("bold", previous, cursor);
394- if (iter_has_style (previous, "italic"))
395+ if (style_italic)
396 apply_tag_by_name ("italic", previous, cursor);
397- if (iter_has_style (previous, "underline"))
398+ if (style_underline)
399 apply_tag_by_name ("underline", previous, cursor);
400- if (iter_has_style (previous, "strikethrough"))
401+ if (style_strikethrough)
402 apply_tag_by_name ("strikethrough", previous, cursor);
403-
404-
405+
406+
407 // Emit signals
408 text_inserted ();
409 cursor_moved ();
410 }
411-
412+
413 private bool key_press_callback (EventKey event) {
414 if (Gdk.keyval_name (event.keyval) == "Return") {
415 ModifierType modifiers = Gtk.accelerator_get_default_mod_mask ();
416-
417+
418 if ((event.state & modifiers) == Gdk.ModifierType.SHIFT_MASK)
419 insert_line ();
420 else
421 insert_paragraph ();
422-
423+
424 return true;
425 }
426- else {
427+ else {
428 return false;
429 }
430 }
431-
432+
433+ private bool editor_clicked_callback (EventButton event) {
434+ update_styles ();
435+ cursor_moved ();
436+
437+ return false;
438+ }
439+
440 }
441-}
442\ No newline at end of file
443+}
444
445=== modified file 'src/Widgets/TextToolBar.vala'
446--- src/Widgets/TextToolBar.vala 2014-12-07 19:18:49 +0000
447+++ src/Widgets/TextToolBar.vala 2014-12-14 05:22:00 +0000
448@@ -29,7 +29,7 @@
449
450 namespace Writer.Widgets {
451 public class TextToolBar : Gtk.Toolbar {
452-
453+
454 private TextEditor editor;
455 public FontButton font_button;
456 public ColorButton font_color_button;
457@@ -42,20 +42,20 @@
458 public ModeButton align_button;
459 public Gtk.SeparatorToolItem item_separator;
460 public Popover insert_popover;
461-
462+
463 public TextToolBar (TextEditor editor) {
464 this.get_style_context ().add_class ("writer-toolbar");
465-
466+
467 this.editor = editor;
468 editor.cursor_moved.connect (cursor_moved);
469-
470+
471 setup_ui ();
472 }
473-
474+
475 public void setup_ui () {
476-
477+
478 // Make Widgets
479-
480+
481 var paragraph_combobox = new Gtk.ComboBoxText ();
482 paragraph_combobox.append ("Paragraph", ("Paragraph"));
483 paragraph_combobox.append ("Title", ("Title"));
484@@ -67,7 +67,7 @@
485 paragraph_combobox.set_active_id ("Paragraph");
486 var paragraph_item = new ToolItem ();
487 paragraph_item.add (paragraph_combobox);
488-
489+
490 var font_item = new ToolItem ();
491 font_button = new Gtk.FontButton ();
492 font_button.use_font = true;
493@@ -80,7 +80,7 @@
494
495 var font_color_item = new Gtk.ToolItem ();
496 font_color_item.add (font_color_button);
497-
498+
499 var styles_item = new ToolItem ();
500 var styles_buttons = new ButtonGroup ();
501 bold_button = new Gtk.ToggleButton ();
502@@ -89,16 +89,19 @@
503 styles_buttons.pack_start (bold_button);
504 italic_button = new Gtk.ToggleButton ();
505 italic_button.add (new Image.from_icon_name ("format-text-italic-symbolic", Gtk.IconSize.BUTTON));
506+ italic_button.focus_on_click = false;
507 styles_buttons.pack_start (italic_button);
508 underline_button = new Gtk.ToggleButton ();
509 underline_button.add (new Image.from_icon_name ("format-text-underline-symbolic", Gtk.IconSize.BUTTON));
510+ underline_button.focus_on_click = false;
511 styles_buttons.pack_start (underline_button);
512 strikethrough_button = new Gtk.ToggleButton ();
513 strikethrough_button.add (new Image.from_icon_name ("format-text-strikethrough-symbolic", Gtk.IconSize.BUTTON));
514+ strikethrough_button.focus_on_click = false;
515 styles_buttons.pack_start (strikethrough_button);
516 styles_item.add (styles_buttons);
517
518-
519+
520 var align_item = new ToolItem ();
521 align_button = new ModeButton ();
522 align_button.append (new Gtk.Image.from_icon_name ("format-justify-left-symbolic", Gtk.IconSize.BUTTON));
523@@ -106,7 +109,7 @@
524 align_button.append (new Gtk.Image.from_icon_name ("format-justify-right-symbolic", Gtk.IconSize.BUTTON));
525 align_button.append (new Gtk.Image.from_icon_name ("format-justify-fill-symbolic", Gtk.IconSize.BUTTON));
526 align_item.add (align_button);
527-
528+
529 var indent_button = new ButtonGroup ();
530 var indent_more_button = new Button.from_icon_name ("format-indent-more-symbolic", Gtk.IconSize.BUTTON);
531 var indent_less_button = new Button.from_icon_name ("format-indent-less-symbolic", Gtk.IconSize.BUTTON);
532@@ -114,9 +117,9 @@
533 indent_button.add (indent_less_button);
534 var indent_item = new Gtk.ToolItem ();
535 indent_item.add (indent_button);
536-
537+
538 item_separator = new Gtk.SeparatorToolItem ();
539-
540+
541 //TODO: Set 'Insert' as title, not as Entry
542 // It looks like this isn't supported by GTK+
543 // WTF!?
544@@ -129,8 +132,8 @@
545 insert_menu.set_active (0);
546 var insert_item = new Gtk.ToolItem ();
547 insert_item.add (insert_menu);
548-
549-
550+
551+
552 //Set border_width on ToolItems
553 paragraph_item.border_width = 5;
554 font_item.border_width = 5;
555@@ -139,7 +142,7 @@
556 align_item.border_width = 5;
557 indent_item.border_width = 5;
558 insert_item.border_width = 5;
559-
560+
561 // Add Widgets
562 this.add (paragraph_item);
563 this.add (font_item);
564@@ -149,15 +152,15 @@
565 this.add (indent_item);
566 this.add (item_separator);
567 this.add (insert_item);
568-
569-
570-
571+
572+
573+
574 // Connect signals
575-
576+
577 align_button.mode_changed.connect (() => {
578 change_align (align_button.selected);
579 });
580-
581+
582 font_button.font_set.connect (() => {
583 editor.set_font_from_string (font_button.get_font_name ());
584 });
585@@ -166,7 +169,7 @@
586 font_color_button.get_color (out color);
587 editor.set_font_color (color);
588 });
589-
590+
591 bold_button.button_press_event.connect ((event) => {
592 if (event.type == EventType.BUTTON_PRESS)
593 editor.toggle_style ("bold");
594@@ -187,16 +190,16 @@
595 editor.toggle_style ("strikethrough");
596 return false;
597 });
598-
599+
600 }
601-
602-
603-
604-
605+
606+
607+
608+
609 /*
610 * Signal callbacks
611 */
612-
613+
614 public void change_align (int index) {
615 switch (index) {
616 case 1:
617@@ -209,15 +212,15 @@
618 editor.set_justification ("left"); break;
619 }
620 }
621-
622+
623 public void cursor_moved () {
624 bold_button.active = editor.has_style ("bold");
625 italic_button.active = editor.has_style ("italic");
626 underline_button.active = editor.has_style ("underline");
627 strikethrough_button.active = editor.has_style ("strikethrough");
628-
629+
630 align_button.selected = editor.get_justification_as_int ();
631-
632+
633 //TODO
634 // Update font and color buttons
635 }

Subscribers

People subscribed via source and target branches

to all changes: