Merge lp:~ryanriffle/writer/instant_style_apply into lp:writer
- instant_style_apply
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tuur Dutoit | Approve | ||
Review via email:
|
Commit message
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.
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Riffle (ryanriffle) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ryan Riffle (ryanriffle) wrote : | # |
Is this going to be reviewed?
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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 | } |
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.