Clone in a terminal:
Commit 8655a43
Johan Mattsson - 2014-11-18T19:08:54+00:00
8655a43bc50a8fbf7d0e522d29a92711c28d8617johan.mattsson.m@gmail.com

Copy and paste in name and description tab

Changed files (7)

Diff

diff --git a/birdfont/GtkWindow.vala b/birdfont/GtkWindow.valaindex 8b9dd1e..4a3ae17 100644--- a/birdfont/GtkWindow.vala+++ b/birdfont/GtkWindow.vala@@ -391,6 +391,21 @@ public class GtkWindow : Gtk.Window, NativeWindow { 		} 	} 	+	public void set_clipboard_text (string text) {+		clipboard.set_text (text, -1);+	}+	+	public string get_clipboard_text () {+		string? t;+		+		t = clipboard.wait_for_text ();+		if (t != null) {+			return ((!) t).dup ();+		}+		+		return "".dup ();+	}+	 	public void set_clipboard (string svg) { 		TargetEntry t = { "image/svg+xml", 0, 0 }; 		TargetEntry[] targets = { t };diff --git a/libbirdfont/ClipTool.vala b/libbirdfont/ClipTool.valaindex d920911..7b20ec3 100644--- a/libbirdfont/ClipTool.vala+++ b/libbirdfont/ClipTool.vala@@ -16,11 +16,22 @@ namespace BirdFont {  public class ClipTool : Tool { +	public static void copy_text (TextArea t) {+		MainWindow.native_window.set_clipboard_text (t.get_selected_text ());		+	}++	public static void paste_text (TextArea t) {+		if (t.carret_is_visible) {+			t.insert_text (MainWindow.native_window.get_clipboard_text ());+		}+	}+ 	public static void copy () { 		FontDisplay fd = MainWindow.get_current_display (); 		string svg_data; 		string bf_data; 		string data;+		TextArea t; 		 		if (fd is Glyph) { 			svg_data = ExportTool.export_selected_paths_to_svg ();@@ -28,11 +39,9 @@ public class ClipTool : Tool { 			data = svg_data + bf_data; 			MainWindow.native_window.set_clipboard (data); 			MainWindow.native_window.set_inkscape_clipboard (data);-		}-		-		if (fd is OverView) {+		} else if (fd is OverView) { 			copy_overview_glyphs ();-		}			+		} 	}  	/** Copy entire glyph. */@@ -77,6 +86,7 @@ public class ClipTool : Tool { 		Glyph g = MainWindow.get_current_glyph (); 		double x, y, w, h; 		double dx, dy;+		TextArea t; 		 		if (fd is Glyph) { 			paste_paths (false);@@ -89,15 +99,11 @@ public class ClipTool : Tool { 			foreach (Path path in g.active_paths) { 				path.move (dx, dy); 			}-		}-		-		if (fd is KerningDisplay) {+		} else if (fd is KerningDisplay) { 			paste_letters_to_kerning_tab ();-		}-		-		if (fd is OverView) {+		} else if (fd is OverView) { 			paste_to_overview ();-		}	+		} 	} 	 	static void paste_paths (bool paste_guide_lines) {diff --git a/libbirdfont/DescriptionDisplay.vala b/libbirdfont/DescriptionDisplay.valaindex 09e7e73..0f371ed 100644--- a/libbirdfont/DescriptionDisplay.vala+++ b/libbirdfont/DescriptionDisplay.vala@@ -203,29 +203,53 @@ public class DescriptionDisplay : FontDisplay { 		} 		 		focus = (!) keyboard_focus;-		if (!KeyBindings.has_alt () && !KeyBindings.has_ctrl ()) {-			switch (c) {-				case Key.RIGHT:-					focus.move_carret_next ();-					break;-				case Key.LEFT:-					focus.move_carret_previous ();-					break;-				case Key.BACK_SPACE:+		switch (c) {+			case 'a':+				if (KeyBindings.has_ctrl ()) {+					focus.select_all ();+				}+				break;+			case 'c':+				if (KeyBindings.has_ctrl ()) {+					ClipTool.copy_text (focus);+				}+				break;+			case 'v':+				if (KeyBindings.has_ctrl ()) {+					ClipTool.paste_text (focus);+				}+				break;+			case Key.RIGHT:+				focus.move_carret_next ();+				break;+			case Key.LEFT:+				focus.move_carret_previous ();+				break;+			case Key.BACK_SPACE:+				if (focus.has_selection ()) {+					focus.delete_selected_text ();+				} else { 					focus.remove_last_character ();-					break;-				case Key.ENTER:-					focus.insert_text ("\n");-					break;				-				default:-					if (!is_modifier_key (keyval)) {-						s = (!) c.to_string ();-						if (s.validate () && keyboard_focus != null) {-							focus.insert_text (s);-						}+				}+				break;+			case Key.ENTER:+				focus.insert_text ("\n");+				break;+			case Key.DEL:+				if (focus.has_selection ()) {+					focus.delete_selected_text ();+				} else {+					focus.remove_next_character ();+				}+				break;		+			default:+				if (!is_modifier_key (keyval)) {+					s = (!) c.to_string ();+					if (s.validate () && keyboard_focus != null) {+						focus.insert_text (s); 					}-					break;-			}+				}+				break; 		} 		 		GlyphCanvas.redraw ();@@ -233,21 +257,20 @@ public class DescriptionDisplay : FontDisplay {  	public override void button_press (uint button, double x, double y) { 		TextArea t;+		TextArea old; 		CheckBox c; 		-		if (keyboard_focus != null) {-			t = (!) keyboard_focus;-			t.draw_carret = false;-			keyboard_focus = null;-		}-		 		foreach (Widget w in widgets) {-			if (w.widget_x <= x <= w.widget_x + w.get_width ()-				&&  w.widget_y <= y <= w.widget_y + w.get_height ()) {-				+			if (w.is_over (x, y)) { 				if (w is TextArea) { 					t = (TextArea) w;+					if (keyboard_focus != null && (!) keyboard_focus != t) {+						old = (!) keyboard_focus;+						old.draw_carret = false;+					}+					 					t.draw_carret = true;+					t.button_press (button, x, y); 					keyboard_focus = t; 				} else if (w is CheckBox) { 					c = (CheckBox) w;@@ -260,10 +283,25 @@ public class DescriptionDisplay : FontDisplay { 	} 	 	public override void button_release (int button, double x, double y) {+		TextArea t;+		+		if (keyboard_focus != null) {+			t = (!) keyboard_focus;+			t.button_release (button, x, y);+		}+					 		GlyphCanvas.redraw (); 	}  	public override void motion_notify (double x, double y) {+		TextArea t;+		+		if (keyboard_focus != null) {+			t = (!) keyboard_focus;+			if (t.motion (x, y)) {+				GlyphCanvas.redraw ();+			}+		} 	}  	public override string get_label () {diff --git a/libbirdfont/KeyBindings.vala b/libbirdfont/KeyBindings.valaindex e6568b8..3a3c9cb 100644--- a/libbirdfont/KeyBindings.vala+++ b/libbirdfont/KeyBindings.vala@@ -73,7 +73,8 @@ bool is_modifier_key (uint i) { 		Key.TAB == i ||  		Key.CAPS_LOCK == i ||  		Key.LOGO_RIGHT == i ||-		Key.ENTER == i;+		Key.ENTER == i ||+		Key.DEL == i; }  /** Modifier flags */diff --git a/libbirdfont/NativeWindow.vala b/libbirdfont/NativeWindow.valaindex 9cd6edc..0a267a4 100644--- a/libbirdfont/NativeWindow.vala+++ b/libbirdfont/NativeWindow.vala@@ -69,6 +69,13 @@ public interface NativeWindow : GLib.Object {  	/** Load images in a background thread. */ 	public abstract void run_background_thread (Task t);+	+	/** Copy text to clipboard. */+	public abstract void set_clipboard_text (string text);+	+	/** Get text from clipboard. */+	public abstract string get_clipboard_text ();+	 }  }diff --git a/libbirdfont/Renderer/TextArea.vala b/libbirdfont/Renderer/TextArea.valaindex eaa90b4..37fa58a 100644--- a/libbirdfont/Renderer/TextArea.vala+++ b/libbirdfont/Renderer/TextArea.vala@@ -25,13 +25,26 @@ public class TextArea : Widget { 	public double padding = 3.3; 	public bool single_line = false; 	-	public bool draw_carret = false;+	public bool draw_carret {+		get { return carret_is_visible; }+		set { +			carret_is_visible = value; +			if (!value) {+				update_selection = false;+				selection_end = carret;+			}+		}+	}+	public bool carret_is_visible = false; 	public bool draw_border = true;  	public double width; 	public double height;  	int carret = 0;+	int selection_end = -1;+	bool update_selection = false;+	 	string text = ""; 	int text_length = 0; 		@@ -73,6 +86,32 @@ public class TextArea : Widget { 		text_changed (text); 	} 	+	public string get_selected_text () {+		int start, stop;+		+		if (!has_selection ()) {+			return "".dup ();+		}+		+		start = (carret < selection_end) ? carret : selection_end;+		stop = (carret > selection_end) ? carret : selection_end;+		+		return text.substring (start, stop - start);+	}+	+	public void select_all () {+		carret = 0;+		selection_end = text_length;+	}+	+	public void delete_selected_text () {+		int start = (carret < selection_end) ? carret : selection_end;+		int stop = (carret > selection_end) ? carret : selection_end;+		set_text (text.substring (0, start) + text.substring (stop));+		selection_end = -1;+		carret = start;+	}+	 	public void remove_last_character () { 		int last_index = 0; 		int index = 0;@@ -83,15 +122,39 @@ public class TextArea : Widget { 		} 		 		set_text (text.substring (0, last_index) + text.substring (carret));+		selection_end = -1;+		carret = last_index;+	}+	+	public void remove_next_character () {+		int index = carret;+		unichar c;		+		text.get_next_char (ref index, out c);+		set_text (text.substring (0, carret) + text.substring (index)); 	} 	 	public void move_carret_next () { 		int index = 0;+		int index_space; 		unichar c; 		char* s = (char*) text + carret; 		string n = (string) s;++		if (!has_selection () && KeyBindings.has_shift ()) {+			selection_end = carret;+		} else if (!KeyBindings.has_shift ()) {+			selection_end = -1;+		} 		 		n.get_next_char (ref index, out c);+		+		if (KeyBindings.has_ctrl ()) {+			index_space = n.index_of (" ", index);+			if (index_space != -1) {+				index = index_space;+			}+		}+		 		carret += index; 	} @@ -99,13 +162,31 @@ public class TextArea : Widget { 		int last_index = 0; 		int index = 0; 		unichar c;+		int index_space; 		 		while (text.get_next_char (ref index, out c) && index < carret) { 			last_index = index; 		} 		+		if (!has_selection () && KeyBindings.has_shift ()) {+			selection_end = carret;+		} else if (!KeyBindings.has_shift ()) {+			selection_end = -1;+		}++		if (KeyBindings.has_ctrl ()) {+			index_space = text.last_index_of (" ", last_index);+			if (index_space != -1) {+				last_index = index_space;+			}+		}+				 		carret = last_index; 	}+	+	public bool has_selection () {+		return selection_end >= 0 && selection_end != carret;+	} 		 	public void insert_text (string t) { 		string s;@@ -116,6 +197,10 @@ public class TextArea : Widget { 			s = t; 		} +		if (has_selection ()) {+			delete_selected_text ();+		}+ 		string nt = text.substring (0, carret); 		int tl = s.length; 		nt += s;@@ -127,7 +212,8 @@ public class TextArea : Widget { 		text_changed (text); 	} 	-	public void layout () {+	/** @return offset to click in text. */+	public int layout (double click_x = -1, double click_y = -1) { 		Text word; 		double p; 		double tx, ty;@@ -136,15 +222,16 @@ public class TextArea : Widget { 		double width = this.width - 2 * padding; 		double height = this.height - 2 * padding; 		bool carret_visibility;-		-		iter_pos = 0;+		int carret_position = text_length;+ 		word = new Text (); 		word.set_font_size (font_size); 		 		tx = 0; 		ty = font_size;+		iter_pos = 0; 		while (iter_pos < text_length) {-			w = get_next_word (out carret_visibility);+			w = get_next_word (out carret_visibility, ref iter_pos); 			 			if (w == "") { 				break;@@ -161,6 +248,11 @@ public class TextArea : Widget { 				} 			} 			+			if (widget_y + ty - font_size <= click_y <= widget_y + ty + padding+				&& widget_x + tx <= click_x) {+				carret_position = find_carret_pos_in_word (word, iter_pos, tx, click_x);+			}+										 			if (w != "\n") { 				tx += p; 			}@@ -177,6 +269,63 @@ public class TextArea : Widget { 		} 		 		this.height = fmax (min_height, ty + 2 * padding);++		if (click_x > 0 && click_x < widget_x + padding) {+			carret_position = 0;+		}+				+		return carret_position;+	}+	+	private int find_carret_pos_in_word (Text word, int iter_pos, double tx, double click_x) {+		double wx = widget_x + tx + padding;+		double ratio = word.get_scale ();+		int i = 0;+		double d = 0;+		double min_d = Math.fabs (click_x - wx);+		int carret_position;+		string w = word.text;+		+		carret_position = iter_pos - w.length;+		word.iterate ((glyph, kerning, last) => {+			glyph.add_help_lines ();+			+			i += ((!) glyph.get_unichar ().to_string ()).length;+			wx += (glyph.get_width () + kerning) * ratio;+			d = Math.fabs (wx - click_x);+			if (d < min_d) {+				min_d = d;+				carret_position = iter_pos - w.length + i;+			}+		});+			+		d = Math.fabs (click_x - wx);+		if (d < min_d) {+			min_d = d;+			carret_position = iter_pos + i;+		}+		+		return carret_position;+	}+	+	public void button_press (uint button, double x, double y) {+		if (is_over (x, y)) {+			carret = layout (x, y);+			selection_end = carret;+			update_selection = true;+		}+	}++	public void button_release (uint button, double x, double y) {+		update_selection = false;+	}+	+	public bool motion (double x, double y) {+		if (update_selection) {+			selection_end = layout (x, y);+		}+		+		return update_selection; 	} 	 	public override void draw (Context cr) {@@ -189,6 +338,8 @@ public class TextArea : Widget { 		double width; 		double x = widget_x; 		double y = widget_y;+		int selection_start, selection_stop;+		unichar c; 		 		layout (); @@ -210,8 +361,7 @@ public class TextArea : Widget { 		} 		 		cr.save ();-		-		iter_pos = 0;+ 		word = new Text (); 		 		width = this.width - padding;@@ -220,14 +370,71 @@ public class TextArea : Widget { 		scale = word.get_scale (); 		y += font_size; 		-		if (draw_carret && iter_pos == 0 && text_length == 0) {-			draw_carret_at (cr, x + padding, y + padding);+		if (draw_carret && carret == 0) {+			draw_carret_at (cr, x + padding, y + padding - 1);+		}+		+		// draw selection background+		if (selection_end >= 0 && selection_end != carret) {+			tx = 0;+			ty = 0;++			selection_start = carret < selection_end ? carret : selection_end;+			selection_stop = carret > selection_end ? carret : selection_end;+			+			cr.save ();+			cr.set_source_rgba (234 / 255.0, 77 / 255.0, 26 / 255.0, 1);+			iter_pos = 0;+			+			tx = 0;+			ty = 0;+			iter_pos = 0;+			while (iter_pos < text_length) {+				w = get_next_word (out carret_at_end_of_word, ref iter_pos);+				+				if (w == "") {+					break;+				}+				+				word.set_text (w);+				p = word.get_sidebearing_extent ();+				+				if (tx + p > width || w == "\n") {+					tx = 0;+					ty += font_size;+				}+				+				if (w != "\n") {+					iter_pos -= w.length;+					word.iterate ((glyph, kerning, last) => {+						double selection_y;+						double cw;+						+						glyph.add_help_lines ();+						+						iter_pos += ((!) glyph.get_unichar ().to_string ()).length;+						cw = (glyph.get_width () + kerning) * word.get_scale ();+						tx += cw;+						+						if (selection_start < iter_pos <= selection_stop) { +							selection_y = y + ty + scale * - word.font.bottom_limit - font_size;+							cr.rectangle (x + tx - 1 - cw, selection_y, cw + 1, font_size);+							cr.fill ();+						}+					});+				}+			}+			+			cr.restore (); 		} 		++		// draw characters 		tx = 0; 		ty = 0;+		iter_pos = 0; 		while (iter_pos < text_length) {-			w = get_next_word (out carret_at_end_of_word);+			w = get_next_word (out carret_at_end_of_word, ref iter_pos); 			 			if (w == "") { 				break;@@ -263,7 +470,20 @@ public class TextArea : Widget { 		cr.restore ();		 	} 	-	string get_next_word (out bool carret_at_end_of_word) {+	unichar get_next_char (ref int iter_pos) {+		unichar n;++		if (iter_pos >= text_length) {+			return '\0';+		}+		+		n = text.get_char (iter_pos);+		iter_pos += ((!) n.to_string ()).length;		+		+		return n;+	}+	+	string get_next_word (out bool carret_at_end_of_word, ref int iter_pos) { 		int i; 		int ni; 		int pi;diff --git a/libbirdfont/Widget.vala b/libbirdfont/Widget.valaindex 4f53a1e..c53853a 100644--- a/libbirdfont/Widget.vala+++ b/libbirdfont/Widget.vala@@ -42,6 +42,11 @@ public abstract class Widget : GLib.Object { 		cr.line_to (x, y + radius); 		cr.close_path ();			 	}++	public bool is_over (double x, double y) {+		return widget_x <= x <= widget_x + get_width () +			&&  widget_y <= y <= widget_y + get_height ();+	} }  }

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112