editor: Extract text handling into text_layout
[profile/ivi/weston.git] / clients / editor.c
1 /*
2  * Copyright © 2012 Openismus GmbH
3  * Copyright © 2012 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <linux/input.h>
30 #include <cairo.h>
31
32 #include "window.h"
33 #include "text-client-protocol.h"
34
35 static const char *font_name = "sans-serif";
36 static int font_size = 14;
37
38 struct text_layout {
39         cairo_glyph_t *glyphs;
40         int num_glyphs;
41         cairo_text_cluster_t *clusters;
42         int num_clusters;
43         cairo_text_cluster_flags_t cluster_flags;
44         cairo_scaled_font_t *font;
45 };
46
47 struct text_entry {
48         struct widget *widget;
49         struct window *window;
50         char *text;
51         int active;
52         struct text_model *model;
53         struct text_layout *layout;
54 };
55
56 struct editor {
57         struct text_model_factory *text_model_factory;
58         struct display *display;
59         struct window *window;
60         struct widget *widget;
61         struct text_entry *entry;
62         struct text_entry *editor;
63 };
64
65 static struct text_layout *
66 text_layout_create(void)
67 {
68         struct text_layout *layout;
69         cairo_surface_t *surface;
70         cairo_t *cr;
71
72         layout = malloc(sizeof *layout);
73         if (!layout)
74                 return NULL;
75
76         layout->glyphs = NULL;
77         layout->num_glyphs = 0;
78
79         layout->clusters = NULL;
80         layout->num_clusters = 0;
81
82         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
83         cr = cairo_create(surface);
84         cairo_set_font_size(cr, font_size);
85         cairo_select_font_face(cr, font_name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
86         layout->font = cairo_get_scaled_font(cr);
87         cairo_scaled_font_reference(layout->font);
88
89         cairo_destroy(cr);
90         cairo_surface_destroy(surface);
91
92         return layout;
93 }
94
95 static void
96 text_layout_destroy(struct text_layout *layout)
97 {
98         if (layout->glyphs)
99                 cairo_glyph_free(layout->glyphs);
100
101         if (layout->clusters)
102                 cairo_text_cluster_free(layout->clusters);
103
104         cairo_scaled_font_destroy(layout->font);
105
106         free(layout);
107 }
108
109 static void
110 text_layout_set_text(struct text_layout *layout,
111                      const char *text)
112 {
113         if (layout->glyphs)
114                 cairo_glyph_free(layout->glyphs);
115
116         if (layout->clusters)
117                 cairo_text_cluster_free(layout->clusters);
118
119         layout->glyphs = NULL;
120         layout->num_glyphs = 0;
121         layout->clusters = NULL;
122         layout->num_clusters = 0;
123
124         cairo_scaled_font_text_to_glyphs(layout->font, 0, 0, text, -1,
125                                          &layout->glyphs, &layout->num_glyphs,
126                                          &layout->clusters, &layout->num_clusters,
127                                          &layout->cluster_flags);
128 }
129
130 static void
131 text_layout_draw(struct text_layout *layout, cairo_t *cr)
132 {
133         cairo_save(cr);
134         cairo_set_scaled_font(cr, layout->font);
135         cairo_show_glyphs(cr, layout->glyphs, layout->num_glyphs);
136         cairo_restore(cr);
137 }
138
139
140 static void text_entry_redraw_handler(struct widget *widget, void *data);
141 static void text_entry_button_handler(struct widget *widget,
142                                       struct input *input, uint32_t time,
143                                       uint32_t button,
144                                       enum wl_pointer_button_state state, void *data);
145
146 static void
147 text_entry_append(struct text_entry *entry, const char *text)
148 {
149         entry->text = realloc(entry->text, strlen(entry->text) + strlen(text) + 1);
150         strcat(entry->text, text);
151         text_layout_set_text(entry->layout, entry->text);
152 }
153
154
155 static void
156 text_model_commit_string(void *data,
157                          struct text_model *text_model,
158                          const char *text,
159                          uint32_t index)
160 {
161         struct text_entry *entry = data;
162
163         text_entry_append(entry, text); 
164
165         widget_schedule_redraw(entry->widget);
166 }
167
168 static void
169 text_model_preedit_string(void *data,
170                           struct text_model *text_model,
171                           const char *text,
172                           uint32_t index)
173 {
174 }
175
176 static void
177 text_model_preedit_styling(void *data,
178                            struct text_model *text_model)
179 {
180 }
181
182 static void
183 text_model_key(void *data,
184                struct text_model *text_model)
185 {
186 }
187
188 static void
189 text_model_selection_replacement(void *data,
190                                  struct text_model *text_model)
191 {
192 }
193
194 static void
195 text_model_direction(void *data,
196                      struct text_model *text_model)
197 {
198 }
199
200 static void
201 text_model_locale(void *data,
202                   struct text_model *text_model)
203 {
204 }
205
206 static void
207 text_model_activated(void *data,
208                      struct text_model *text_model)
209 {
210         struct text_entry *entry = data;
211
212         entry->active = 1;
213
214         widget_schedule_redraw(entry->widget);
215 }
216
217 static void
218 text_model_deactivated(void *data,
219                        struct text_model *text_model)
220 {
221         struct text_entry *entry = data;
222
223         entry->active = 0;
224
225         widget_schedule_redraw(entry->widget);
226 }
227
228 static const struct text_model_listener text_model_listener = {
229         text_model_commit_string,
230         text_model_preedit_string,
231         text_model_preedit_styling,
232         text_model_key,
233         text_model_selection_replacement,
234         text_model_direction,
235         text_model_locale,
236         text_model_activated,
237         text_model_deactivated
238 };
239
240 static struct text_entry*
241 text_entry_create(struct editor *editor, const char *text)
242 {
243         struct text_entry *entry;
244
245         entry = malloc(sizeof *entry);
246
247         entry->widget = widget_add_widget(editor->widget, entry);
248         entry->window = editor->window;
249         entry->text = strdup(text);
250         entry->active = 0;
251         entry->model = text_model_factory_create_text_model(editor->text_model_factory);
252         text_model_add_listener(entry->model, &text_model_listener, entry);
253
254         entry->layout = text_layout_create();
255         text_layout_set_text(entry->layout, entry->text);
256
257         widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
258         widget_set_button_handler(entry->widget, text_entry_button_handler);
259
260         return entry;
261 }
262
263 static void
264 text_entry_destroy(struct text_entry *entry)
265 {
266         widget_destroy(entry->widget);
267         text_model_destroy(entry->model);
268         text_layout_destroy(entry->layout);
269         free(entry->text);
270         free(entry);
271 }
272
273 static void
274 redraw_handler(struct widget *widget, void *data)
275 {
276         struct editor *editor = data;
277         cairo_surface_t *surface;
278         struct rectangle allocation;
279         cairo_t *cr;
280
281         surface = window_get_surface(editor->window);
282         widget_get_allocation(editor->widget, &allocation);
283
284         cr = cairo_create(surface);
285         cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
286         cairo_clip(cr);
287
288         cairo_translate(cr, allocation.x, allocation.y);
289
290         /* Draw background */
291         cairo_push_group(cr);
292         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
293         cairo_set_source_rgba(cr, 1, 1, 1, 1);
294         cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
295         cairo_fill(cr);
296
297         cairo_pop_group_to_source(cr);
298         cairo_paint(cr);
299
300         cairo_destroy(cr);
301         cairo_surface_destroy(surface);
302 }
303
304 static void
305 text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
306                     int32_t width, int32_t height)
307 {
308         widget_set_allocation(entry->widget, x, y, width, height);
309 }
310
311 static void
312 resize_handler(struct widget *widget,
313                int32_t width, int32_t height, void *data)
314 {
315         struct editor *editor = data;
316         struct rectangle allocation;
317
318         widget_get_allocation(editor->widget, &allocation);
319
320         text_entry_allocate(editor->entry,
321                             allocation.x + 20, allocation.y + 20,
322                             width - 40, height / 2 - 40);
323         text_entry_allocate(editor->editor,
324                             allocation.x + 20, allocation.y + height / 2 + 20,
325                             width - 40, height / 2 - 40);
326 }
327
328 static void
329 text_entry_activate(struct text_entry *entry,
330                     struct wl_seat *seat)
331 {
332         struct wl_surface *surface = window_get_wl_surface(entry->window);
333
334         text_model_activate(entry->model,
335                             seat,
336                             surface);
337 }
338
339 static void
340 text_entry_deactivate(struct text_entry *entry,
341                       struct wl_seat *seat)
342 {
343         text_model_deactivate(entry->model,
344                               seat);
345 }
346
347 static void
348 text_entry_redraw_handler(struct widget *widget, void *data)
349 {
350         struct text_entry *entry = data;
351         cairo_surface_t *surface;
352         struct rectangle allocation;
353         cairo_t *cr;
354
355         surface = window_get_surface(entry->window);
356         widget_get_allocation(entry->widget, &allocation);
357
358         cr = cairo_create(surface);
359         cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
360         cairo_clip(cr);
361
362         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
363
364         cairo_push_group(cr);
365         cairo_translate(cr, allocation.x, allocation.y);
366
367         cairo_set_source_rgba(cr, 1, 1, 1, 1);
368         cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
369         cairo_fill(cr);
370
371         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
372
373         if (entry->active) {
374                 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
375                 cairo_set_line_width (cr, 3);
376                 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
377                 cairo_stroke(cr);
378         }
379
380         cairo_set_source_rgba(cr, 0, 0, 0, 1);
381
382         cairo_translate(cr, 10, allocation.height / 2);
383         text_layout_draw(entry->layout, cr);
384         cairo_pop_group_to_source(cr);
385         cairo_paint(cr);
386
387         cairo_destroy(cr);
388         cairo_surface_destroy(surface);
389 }
390
391 static void
392 text_entry_button_handler(struct widget *widget,
393                           struct input *input, uint32_t time,
394                           uint32_t button,
395                           enum wl_pointer_button_state state, void *data)
396 {
397         struct text_entry *entry = data;
398
399         if (button != BTN_LEFT) {
400                 return;
401         }
402
403         if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
404                 struct wl_seat *seat = input_get_seat(input);
405
406                 text_entry_activate(entry, seat);
407         }
408 }
409
410 static void
411 editor_button_handler(struct widget *widget,
412                       struct input *input, uint32_t time,
413                       uint32_t button,
414                       enum wl_pointer_button_state state, void *data)
415 {
416         struct editor *editor = data;
417
418         if (button != BTN_LEFT) {
419                 return;
420         }
421
422         if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
423                 struct wl_seat *seat = input_get_seat(input);
424
425                 text_entry_deactivate(editor->entry, seat);
426                 text_entry_deactivate(editor->editor, seat);
427         }
428 }
429
430 static void
431 global_handler(struct wl_display *display, uint32_t id,
432                const char *interface, uint32_t version, void *data)
433 {
434         struct editor *editor = data;
435
436         if (!strcmp(interface, "text_model_factory")) {
437                 editor->text_model_factory = wl_display_bind(display, id,
438                                                              &text_model_factory_interface);
439         }
440 }
441
442 int
443 main(int argc, char *argv[])
444 {
445         struct editor editor;
446
447         editor.display = display_create(argc, argv);
448         if (editor.display == NULL) {
449                 fprintf(stderr, "failed to create display: %m\n");
450                 return -1;
451         }
452         wl_display_add_global_listener(display_get_display(editor.display),
453                                        global_handler, &editor);
454
455
456         editor.window = window_create(editor.display);
457         editor.widget = frame_create(editor.window, &editor);
458
459         editor.entry = text_entry_create(&editor, "Entry");
460         editor.editor = text_entry_create(&editor, "Editor");
461
462         window_set_title(editor.window, "Text Editor");
463
464         widget_set_redraw_handler(editor.widget, redraw_handler);
465         widget_set_resize_handler(editor.widget, resize_handler);
466         widget_set_button_handler(editor.widget, editor_button_handler);
467
468         window_schedule_resize(editor.window, 500, 400);
469
470         display_run(editor.display);
471
472         text_entry_destroy(editor.entry);
473         text_entry_destroy(editor.editor);
474
475         return 0;
476 }