Fix some build warnings.
[platform/upstream/ibus.git] / ui / gtk3 / candidatepanel.vala
1 /* vim:set et sts=4 sw=4:
2  *
3  * ibus - The Input Bus
4  *
5  * Copyright(c) 2011 Peng Huang <shawn.p.huang@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or(at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA  02111-1307  USA
21  */
22
23 public class CandidatePanel : Gtk.HBox{
24     private bool m_vertical = true;
25     private Gtk.Window m_toplevel;
26     private Gtk.Box m_vbox;
27
28     private Gtk.Label m_preedit_label;
29     private Gtk.Label m_aux_label;
30     private CandidateArea m_candidate_area;
31     private HSeparator m_hseparator;
32
33     private Gdk.Rectangle m_cursor_location;
34
35     public signal void cursor_up();
36     public signal void cursor_down();
37     public signal void page_up();
38     public signal void page_down();
39     public signal void candidate_clicked(uint index,
40                                          uint button,
41                                          uint state);
42
43     public CandidatePanel() {
44         // Call base class constructor
45         GLib.Object(
46             name : "IBusCandidate",
47             visible: true
48         );
49
50         m_toplevel = new Gtk.Window(Gtk.WindowType.POPUP);
51         m_toplevel.add_events(Gdk.EventMask.BUTTON_PRESS_MASK);
52         m_toplevel.button_press_event.connect((w, e) => {
53             if (e.button != 1 || (e.state & Gdk.ModifierType.CONTROL_MASK) == 0)
54                 return false;
55             set_vertical(!m_vertical);
56             return true;
57         });
58
59         Handle handle = new Handle();
60         handle.set_visible(true);
61         pack_start(handle, false, false, 0);
62
63         m_vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
64         m_vbox.set_visible(true);
65         pack_start(m_vbox, false, false, 0);
66
67         m_toplevel.add(this);
68
69         create_ui();
70     }
71
72     public void set_vertical(bool vertical) {
73         if (m_vertical == vertical)
74             return;
75         m_vertical = vertical;
76         m_candidate_area.set_vertical(vertical);
77     }
78
79     private void set_orientation(IBus.Orientation orientation) {
80         switch (orientation) {
81         case IBus.Orientation.VERTICAL:
82             m_candidate_area.set_vertical(true);
83             break;
84         case IBus.Orientation.HORIZONTAL:
85             m_candidate_area.set_vertical(false);
86             break;
87         case IBus.Orientation.SYSTEM:
88             m_candidate_area.set_vertical(m_vertical);
89             break;
90         }
91     }
92
93     public void set_cursor_location(int x, int y, int width, int height) {
94         Gdk.Rectangle location = Gdk.Rectangle(){
95             x = x, y = y, width = width, height = height };
96         if (m_cursor_location == location)
97             return;
98         m_cursor_location = location;
99         adjust_window_position();
100     }
101
102     private void set_labels(IBus.Text[] labels) {
103         m_candidate_area.set_labels(labels);
104     }
105
106     public void set_preedit_text(IBus.Text? text, uint cursor) {
107         if (text != null) {
108             m_preedit_label.set_text(text.get_text());
109             m_preedit_label.show();
110         } else {
111             m_preedit_label.set_text("");
112             m_preedit_label.hide();
113         }
114         update();
115     }
116
117     public void set_auxiliary_text(IBus.Text? text) {
118         if (text != null) {
119             m_aux_label.set_text(text.get_text());
120             m_aux_label.show();
121         } else {
122             m_aux_label.set_text("");
123             m_aux_label.hide();
124         }
125         update();
126     }
127
128     public void set_lookup_table(IBus.LookupTable? table) {
129         IBus.Text[] candidates = {};
130         uint cursor_in_page = 0;
131         bool show_cursor = true;
132         IBus.Text[] labels = {};
133         IBus.Orientation orientation = IBus.Orientation.SYSTEM;
134
135         if (table != null) {
136             uint page_size = table.get_page_size();
137             uint ncandidates = table.get_number_of_candidates();
138             uint cursor = table.get_cursor_pos();
139             cursor_in_page = table.get_cursor_in_page();
140             show_cursor = table.is_cursor_visible();
141
142             uint page_start_pos = cursor / page_size * page_size;
143             uint page_end_pos = uint.min(page_start_pos + page_size, ncandidates);
144             for (uint i = page_start_pos; i < page_end_pos; i++)
145                 candidates += table.get_candidate(i);
146
147             for (uint i = 0; i < page_size; i++) {
148                 IBus.Text? label = table.get_label(i);
149                 if (label != null)
150                     labels += label;
151             }
152
153             orientation = (IBus.Orientation)table.get_orientation();
154         }
155
156         m_candidate_area.set_candidates(candidates, cursor_in_page, show_cursor);
157         set_labels(labels);
158
159         if (table != null) {
160             // Do not change orientation if table is null to avoid recreate
161             // candidates area.
162             set_orientation(orientation);
163         }
164
165         if (candidates.length != 0)
166             m_candidate_area.show_all();
167         else
168             m_candidate_area.hide();
169
170         update();
171     }
172
173     private void update() {
174         if (m_candidate_area.get_visible() ||
175             m_preedit_label.get_visible() ||
176             m_aux_label.get_visible())
177             m_toplevel.show();
178         else
179             m_toplevel.hide();
180
181         if (m_aux_label.get_visible() &&
182             (m_candidate_area.get_visible() || m_preedit_label.get_visible()))
183             m_hseparator.show();
184         else
185             m_hseparator.hide();
186     }
187
188     public override void get_preferred_width(out int minimum_width, out int natural_width) {
189         base.get_preferred_width(out minimum_width, out natural_width);
190         m_toplevel.resize(1, 1);
191     }
192
193     public override void get_preferred_height(out int minimum_width, out int natural_width) {
194         base.get_preferred_height(out minimum_width, out natural_width);
195         m_toplevel.resize(1, 1);
196     }
197
198     private void create_ui() {
199         m_preedit_label = new Gtk.Label(null);
200         m_preedit_label.set_size_request(20, -1);
201         m_preedit_label.set_alignment(0.0f, 0.5f);
202         m_preedit_label.set_padding(8, 0);
203         m_preedit_label.set_no_show_all(true);
204
205         m_aux_label = new Gtk.Label(null);
206         m_aux_label.set_size_request(20, -1);
207         m_aux_label.set_alignment(0.0f, 0.5f);
208         m_aux_label.set_padding(8, 0);
209         m_aux_label.set_no_show_all(true);
210
211         m_candidate_area = new CandidateArea(m_vertical);
212         m_candidate_area.candidate_clicked.connect(
213                 (w, i, b, s) => candidate_clicked(i, b, s));
214         m_candidate_area.page_up.connect((c) => page_up());
215         m_candidate_area.page_down.connect((c) => page_down());
216         m_candidate_area.cursor_up.connect((c) => cursor_up());
217         m_candidate_area.cursor_down.connect((c) => cursor_down());
218
219         m_hseparator = new HSeparator();
220         m_hseparator.set_visible(true);
221
222         pack_all_widgets();
223     }
224
225     private void pack_all_widgets() {
226         m_vbox.pack_start(m_preedit_label, false, false, 4);
227         m_vbox.pack_start(m_aux_label, false, false, 4);
228         m_vbox.pack_start(m_hseparator, false, false, 0);
229         m_vbox.pack_start(m_candidate_area, false, false, 0);
230     }
231
232     public new void show() {
233         m_toplevel.show_all();
234     }
235
236     public new void hide() {
237         m_toplevel.hide();
238     }
239
240     private void move(int x, int y) {
241         m_toplevel.move(x, y);
242     }
243
244     private void adjust_window_position() {
245         Gdk.Point cursor_right_bottom = {
246                 m_cursor_location.x + m_cursor_location.width,
247                 m_cursor_location.y + m_cursor_location.height
248         };
249
250         Gtk.Allocation allocation;
251         m_toplevel.get_allocation(out allocation);
252         Gdk.Point window_right_bottom = {
253             cursor_right_bottom.x + allocation.width,
254             cursor_right_bottom.y + allocation.height
255         };
256
257         Gdk.Window root = Gdk.get_default_root_window();
258         int root_width = root.get_width();
259         int root_height = root.get_height();
260
261         int x, y;
262         if (window_right_bottom.x > root_width)
263             x = root_width - allocation.width;
264         else
265             x = cursor_right_bottom.x;
266
267         if (window_right_bottom.y > root_height)
268             y = m_cursor_location.y - allocation.height;
269         else
270             y = cursor_right_bottom.y;
271
272         move(x, y);
273     }
274 }