2 * Copyright (C) 2008-2012 Robert Ancell
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 2 of the License, or (at your option) any later
7 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
11 public class MathDisplay
: Gtk
.Viewport
13 /* Equation being displayed */
14 private MathEquation _equation
;
15 public MathEquation equation
{ get { return _equation
; } }
18 Gtk
.TextView text_view
;
20 /* Buffer that shows errors etc */
21 Gtk
.TextBuffer info_buffer
;
23 /* Spinner widget that shows if we're calculating a response */
26 public MathDisplay (MathEquation equation
)
30 var main_box
= new Gtk
.Box (Gtk
.Orientation
.VERTICAL
, 0);
33 text_view
= new Gtk
.TextView
.with_buffer (equation
);
34 text_view
.set_wrap_mode (Gtk
.WrapMode
.WORD
);
35 text_view
.set_accepts_tab (false);
36 text_view
.set_pixels_above_lines (8);
37 text_view
.set_pixels_below_lines (2);
38 /* TEMP: Disabled for now as GTK+ doesn't properly render a right aligned right margin, see bug #482688 */
39 /*text_view.set_right_margin (6);*/
40 text_view
.set_justification (Gtk
.Justification
.RIGHT
);
41 text_view
.ensure_style ();
42 var font_desc
= text_view
.get_style ().font_desc
.copy ();
43 font_desc
.set_size (16 * Pango
.SCALE
);
44 text_view
.modify_font (font_desc
);
45 text_view
.set_name ("displayitem");
46 text_view
.get_accessible ().set_role (Atk
.Role
.EDITBAR
);
47 //FIXME:<property name="AtkObject::accessible-description" translatable="yes" comments="Accessible description for the area in which results are displayed">Result Region</property>
48 text_view
.key_press_event
.connect (key_press_cb
);
50 main_box
.pack_start (text_view
, true, true, 0);
52 var info_box
= new Gtk
.Box (Gtk
.Orientation
.HORIZONTAL
, 6);
53 main_box
.pack_start (info_box
, false, true, 0);
55 var info_view
= new Gtk
.TextView ();
56 info_view
.set_wrap_mode (Gtk
.WrapMode
.WORD
);
57 info_view
.set_can_focus (true); // FIXME: This should be false but it locks the cursor inside the main view for some reason
58 info_view
.set_cursor_visible (false); // FIXME: Just here so when incorrectly gets focus doesn't look editable
59 info_view
.set_editable (false);
60 info_view
.set_justification (Gtk
.Justification
.RIGHT
);
61 /* TEMP: Disabled for now as GTK+ doesn't properly render a right aligned right margin, see bug #482688 */
62 /*info_view.set_right_margin (6);*/
63 info_box
.pack_start (info_view
, true, true, 0);
64 info_buffer
= info_view
.get_buffer ();
66 spinner
= new Gtk
.Spinner ();
67 info_box
.pack_end (spinner
, false, false, 0);
68 style
= info_view
.get_style ();
69 for (var i
= 0; i
< 5; i
++)
70 modify_bg (i
, style
.base[i
]);
77 equation
.notify
["status"].connect ((pspec
) => { status_changed_cb (); });
80 equation
.notify
["error-token-end"].connect ((pspec
) => { error_status_changed_cb (); });
83 protected override bool key_press_event (Gdk
.EventKey event
)
85 return text_view
.key_press_event (event
);
88 private bool key_press_cb (Gdk
.EventKey event
)
90 /* Treat keypad keys as numbers even when numlock is off */
94 case Gdk
.Key
.KP_Insert
:
95 new_keyval
= Gdk
.Key
.@
0;
98 new_keyval
= Gdk
.Key
.@
1;
100 case Gdk
.Key
.KP_Down
:
101 new_keyval
= Gdk
.Key
.@
2;
103 case Gdk
.Key
.KP_Page_Down
:
104 new_keyval
= Gdk
.Key
.@
3;
106 case Gdk
.Key
.KP_Left
:
107 new_keyval
= Gdk
.Key
.@
4;
109 case Gdk
.Key
.KP_Begin
: /* This is apparently what "5" does when numlock is off. */
110 new_keyval
= Gdk
.Key
.@
5;
112 case Gdk
.Key
.KP_Right
:
113 new_keyval
= Gdk
.Key
.@
6;
115 case Gdk
.Key
.KP_Home
:
116 new_keyval
= Gdk
.Key
.@
7;
119 new_keyval
= Gdk
.Key
.@
8;
121 case Gdk
.Key
.KP_Page_Up
:
122 new_keyval
= Gdk
.Key
.@
9;
128 var new_event
= event
; // FIXME: Does this copy?
129 new_event
.keyval
= new_keyval
;
130 return key_press_event (new_event
);
133 var state
= event
.state
& (Gdk
.ModifierType
.CONTROL_MASK
| Gdk
.ModifierType
.MOD1_MASK
);
134 var c
= Gdk
.keyval_to_unicode (event
.keyval
);
137 if (event
.keyval
== Gdk
.Key
.Return
|| event
.keyval
== Gdk
.Key
.KP_Enter
)
143 /* Clear on escape */
144 if ((event
.keyval
== Gdk
.Key
.Escape
&& state
== 0) ||
145 (event
.keyval
== Gdk
.Key
.BackSpace
&& state
== Gdk
.ModifierType
.CONTROL_MASK
) ||
146 (event
.keyval
== Gdk
.Key
.Delete
&& state
== Gdk
.ModifierType
.SHIFT_MASK
))
152 /* Numeric keypad will often insert '.' regardless of locale */
153 if (event
.keyval
== Gdk
.Key
.KP_Decimal
)
155 equation
.insert_numeric_point ();
164 equation
.insert ("×");
169 equation
.insert ("÷");
174 equation
.insert_subtract ();
180 if (state
== Gdk
.ModifierType
.CONTROL_MASK
)
182 switch (event
.keyval
)
184 case Gdk
.Key
.bracketleft
:
185 equation
.insert ("⌈");
187 case Gdk
.Key
.bracketright
:
188 equation
.insert ("⌉");
191 equation
.insert_exponent ();
194 equation
.factorize ();
197 equation
.insert ("⁻¹");
200 equation
.insert ("π");
203 equation
.insert ("√");
206 equation
.insert ("µ");
209 equation
.insert ("⁻");
211 case Gdk
.Key
.apostrophe
:
212 equation
.insert ("°");
216 if (state
== Gdk
.ModifierType
.MOD1_MASK
)
218 switch (event
.keyval
)
220 case Gdk
.Key
.bracketleft
:
221 equation
.insert ("⌊");
223 case Gdk
.Key
.bracketright
:
224 equation
.insert ("⌋");
229 if (state
== Gdk
.ModifierType
.CONTROL_MASK
|| equation
.number_mode
== NumberMode
.SUPERSCRIPT
)
231 switch (event
.keyval
)
235 equation
.insert ("⁰");
239 equation
.insert ("¹");
243 equation
.insert ("²");
247 equation
.insert ("³");
251 equation
.insert ("⁴");
255 equation
.insert ("⁵");
259 equation
.insert ("⁶");
263 equation
.insert ("⁷");
267 equation
.insert ("⁸");
271 equation
.insert ("⁹");
275 else if (state
== Gdk
.ModifierType
.MOD1_MASK
|| equation
.number_mode
== NumberMode
.SUBSCRIPT
)
277 switch (event
.keyval
)
281 equation
.insert ("₀");
285 equation
.insert ("₁");
289 equation
.insert ("₂");
293 equation
.insert ("₃");
297 equation
.insert ("₄");
301 equation
.insert ("₅");
305 equation
.insert ("₆");
309 equation
.insert ("₇");
313 equation
.insert ("₈");
317 equation
.insert ("₉");
325 private void status_changed_cb ()
327 info_buffer
.set_text (equation
.status
, -1);
328 if (equation
.in_solve
&& !spinner
.get_visible ())
333 else if (!equation
.in_solve
&& spinner
.get_visible ())
340 private void error_status_changed_cb ()
342 /* If both start and end location of error token are the same, no need to select anything. */
343 if (equation
.error_token_end
- equation
.error_token_start
== 0)
346 Gtk
.TextIter start
, end
;
347 equation
.get_start_iter (out start
);
348 equation
.get_start_iter (out end
);
350 start
.set_offset ((int) equation
.error_token_start
);
351 end
.set_offset ((int) equation
.error_token_end
);
353 equation
.select_range (start
, end
);