1 /*
2 
3   copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4 
5   All rights reserved.
6 
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10 
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in the
15      documentation and/or other materials provided with the distribution.
16   3. Neither the name of authors nor the names of its contributors
17      may be used to endorse or promote products derived from this software
18      without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30   SUCH DAMAGE.
31 
32 */
33 
34 #include <config.h>
35 
36 #include "uim-cand-win-tbl-gtk.h"
37 #include <string.h>
38 #include <stdlib.h>
39 #include <uim/uim.h>
40 #include <uim/uim-scm.h>
41 
42 #define DEFAULT_MIN_WINDOW_WIDTH 80
43 
44 enum {
45   TERMINATOR = -1,
46   COLUMN_HEADING,
47   COLUMN_CANDIDATE,
48   COLUMN_ANNOTATION,
49   LISTSTORE_NR_COLUMNS
50 };
51 
52 #define TABLE_NR_COLUMNS 13
53 #define TABLE_NR_ROWS 8
54 #define TABLE_NR_CELLS (TABLE_NR_COLUMNS * TABLE_NR_ROWS)
55 #define CELLINDEX(row,col) ((row) * TABLE_NR_COLUMNS + (col))
56 /* 106 keyboard */
57 static gchar default_tbl_cell2label[TABLE_NR_CELLS] = {
58   '1','2','3','4','5', '6','7','8','9','0',   '-','^','\\',
59   'q','w','e','r','t', 'y','u','i','o','p',   '@','[','\0',
60   'a','s','d','f','g', 'h','j','k','l',';',   ':',']','\0',
61   'z','x','c','v','b', 'n','m',',','.','/',   '\0','\0',' ',
62   '!','"','#','$','%', '&','\'','(',')','\0', '=','~','|',
63   'Q','W','E','R','T', 'Y','U','I','O','P',   '`','{','\0',
64   'A','S','D','F','G', 'H','J','K','L','+',   '*','}','\0',
65   'Z','X','C','V','B', 'N','M','<','>','?',   '_','\0','\0',
66 };
67 /* table consists of four blocks
68  *   blockLR  blockA
69  *   blockLRS blockAS
70  */
71 #define BLOCK_A_ROW_START 0
72 #define BLOCK_A_ROW_END 4
73 #define BLOCK_A_COLUMN_START 10
74 #define BLOCK_A_COLUMN_END TABLE_NR_COLUMNS
75 #define BLOCK_LRS_ROW_START BLOCK_A_ROW_END
76 #define BLOCK_LRS_ROW_END TABLE_NR_ROWS
77 #define BLOCK_LRS_COLUMN_START 0
78 #define BLOCK_LRS_COLUMN_END BLOCK_A_COLUMN_START
79 #define BLOCK_AS_ROW_START BLOCK_LRS_ROW_START
80 #define BLOCK_AS_ROW_END BLOCK_LRS_ROW_END
81 #define BLOCK_AS_COLUMN_START BLOCK_LRS_COLUMN_END
82 #define BLOCK_AS_COLUMN_END TABLE_NR_COLUMNS
83 #define BLOCK_LR_NR_CELLS (BLOCK_A_ROW_END * BLOCK_A_COLUMN_START)
84 #define BLOCK_LRS_NR_CELLS ((BLOCK_LRS_ROW_END - BLOCK_LRS_ROW_START) * (BLOCK_LRS_COLUMN_END - BLOCK_LRS_COLUMN_START))
85 
86 #define BLOCK_SPACING 20
87 #define HOMEPOSITION_SPACING 2
88 #define SPACING_LEFT_BLOCK_COLUMN 4
89 #define SPACING_RIGHT_BLOCK_COLUMN (BLOCK_A_COLUMN_START - 1)
90 #define SPACING_UP_BLOCK_ROW (BLOCK_A_ROW_END - 1)
91 #define SPACING_LEFTHAND_FAR_COLUMN 3
92 #define SPACING_RIGHTHAND_FAR_COLUMN 5
93 #define SPACING_UPPER_FAR_ROW 0
94 #define SPACING_SHIFT_UPPER_FAR_ROW 4
95 
96 struct index_button {
97   gint cand_index_in_page;
98   GtkButton *button;
99 };
100 
101 static void	uim_cand_win_tbl_gtk_init		(UIMCandWinTblGtk *cwin);
102 static void	uim_cand_win_tbl_gtk_class_init	(UIMCandWinGtkClass *klass);
103 static void	uim_cand_win_tbl_gtk_dispose	(GObject *obj);
104 static gchar	*init_tbl_cell2label(void);
105 static void	button_clicked(GtkButton *button, gpointer data);
106 static void	clear_button(struct index_button *idxbutton,
107                              const gchar *tbl_cell2label, gint cell_index);
108 static void	show_table(GtkTable *view, GPtrArray *buttons);
109 static GtkButton *get_button(GPtrArray *buttons, gint idx);
110 
111 
112 static GType cand_win_tbl_type = 0;
113 static GTypeInfo const object_info = {
114   sizeof (UIMCandWinTblGtkClass),
115   (GBaseInitFunc) NULL,
116   (GBaseFinalizeFunc) NULL,
117   (GClassInitFunc) uim_cand_win_tbl_gtk_class_init,
118   (GClassFinalizeFunc) NULL,
119   NULL,                       /* class_data */
120   sizeof (UIMCandWinTblGtk),
121   0,                          /* n_preallocs */
122   (GInstanceInitFunc) uim_cand_win_tbl_gtk_init,
123 };
124 
125 static GtkWindowClass *parent_class = NULL;
126 
127 GType
uim_cand_win_tbl_gtk_get_type(void)128 uim_cand_win_tbl_gtk_get_type(void)
129 {
130   if (!cand_win_tbl_type)
131     cand_win_tbl_type = g_type_register_static(UIM_TYPE_CAND_WIN_GTK, "UIMCandWinTblGtk",
132 					   &object_info, (GTypeFlags)0);
133   return cand_win_tbl_type;
134 }
135 
136 GType
uim_cand_win_tbl_gtk_register_type(GTypeModule * module)137 uim_cand_win_tbl_gtk_register_type(GTypeModule *module)
138 {
139   if (!cand_win_tbl_type)
140     cand_win_tbl_type = g_type_module_register_type(module,
141 						UIM_TYPE_CAND_WIN_GTK,
142 						"UIMCandWinTblGtk",
143 						&object_info, 0);
144   return cand_win_tbl_type;
145 }
146 
147 static void
uim_cand_win_tbl_gtk_class_init(UIMCandWinGtkClass * klass)148 uim_cand_win_tbl_gtk_class_init (UIMCandWinGtkClass *klass)
149 {
150   GObjectClass *object_class = (GObjectClass *) klass;
151 
152   parent_class = g_type_class_peek_parent (klass);
153   object_class->dispose = uim_cand_win_tbl_gtk_dispose;
154 
155   klass->set_index = (void (*)(UIMCandWinGtk *, gint))uim_cand_win_tbl_gtk_set_index;
156   klass->set_page = (void (*)(UIMCandWinGtk *, gint))uim_cand_win_tbl_gtk_set_page;
157 }
158 
159 static void
uim_cand_win_tbl_gtk_init(UIMCandWinTblGtk * ctblwin)160 uim_cand_win_tbl_gtk_init (UIMCandWinTblGtk *ctblwin)
161 {
162   gint row, col;
163   GtkWidget *viewport;
164   UIMCandWinGtk *cwin;
165   cwin = UIM_CAND_WIN_GTK(ctblwin);
166 
167   ctblwin->buttons = g_ptr_array_new();
168   ctblwin->tbl_cell2label = init_tbl_cell2label();
169 
170   cwin->view = gtk_table_new(TABLE_NR_ROWS, TABLE_NR_COLUMNS, FALSE);
171   viewport = gtk_viewport_new(NULL, NULL);
172   gtk_container_add(GTK_CONTAINER(viewport), cwin->view);
173   gtk_container_add(GTK_CONTAINER(cwin->scrolled_window), viewport);
174   gtk_container_set_resize_mode(GTK_CONTAINER(viewport), GTK_RESIZE_PARENT);
175   for (row = 0; row < TABLE_NR_ROWS; row++) {
176     for (col = 0; col < TABLE_NR_COLUMNS; col++) {
177       GtkWidget *button;
178       struct index_button *idxbutton;
179       button = gtk_button_new_with_label("  ");
180       g_signal_connect(button, "clicked", G_CALLBACK(button_clicked), ctblwin);
181       gtk_table_attach_defaults(GTK_TABLE(cwin->view), button,
182                                 col, col + 1, row, row + 1);
183       idxbutton = g_malloc(sizeof(struct index_button));
184       if (idxbutton) {
185         idxbutton->button = GTK_BUTTON(button);
186         clear_button(idxbutton, ctblwin->tbl_cell2label, CELLINDEX(row, col));
187       }
188       g_ptr_array_add(ctblwin->buttons, idxbutton);
189     }
190   }
191   gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_LEFT_BLOCK_COLUMN,
192       BLOCK_SPACING);
193   gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_RIGHT_BLOCK_COLUMN,
194       BLOCK_SPACING);
195   gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_UP_BLOCK_ROW,
196       BLOCK_SPACING);
197   gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_LEFTHAND_FAR_COLUMN,
198       HOMEPOSITION_SPACING);
199   gtk_table_set_col_spacing(GTK_TABLE(cwin->view), SPACING_RIGHTHAND_FAR_COLUMN,
200       HOMEPOSITION_SPACING);
201   gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_UPPER_FAR_ROW,
202       HOMEPOSITION_SPACING);
203   gtk_table_set_row_spacing(GTK_TABLE(cwin->view), SPACING_SHIFT_UPPER_FAR_ROW,
204       HOMEPOSITION_SPACING);
205 
206   gtk_widget_show_all(cwin->view);
207   gtk_widget_show(viewport);
208 
209   gtk_widget_set_size_request(cwin->num_label, DEFAULT_MIN_WINDOW_WIDTH, -1);
210   gtk_window_set_default_size(GTK_WINDOW(cwin), DEFAULT_MIN_WINDOW_WIDTH, -1);
211   gtk_window_set_resizable(GTK_WINDOW(cwin), FALSE);
212 }
213 
214 static gchar *
init_tbl_cell2label(void)215 init_tbl_cell2label(void)
216 {
217   gchar *table;
218   uim_lisp list;
219   size_t len = 0;
220   uim_lisp *ary0, *ary;
221   guint i;
222 
223   list = uim_scm_symbol_value("uim-candwin-prog-layout");
224   if (list == NULL || !uim_scm_listp(list)) {
225     return default_tbl_cell2label;
226   }
227   ary0 = ary = (uim_lisp *)uim_scm_list2array(list, &len, NULL);
228   if (ary == NULL || len <= 0) {
229     free(ary0);
230     return default_tbl_cell2label;
231   }
232   table = (gchar *)g_malloc0(TABLE_NR_CELLS);
233   if (table == NULL) {
234     free(ary0);
235     return default_tbl_cell2label;
236   }
237   for (i = 0; i < len && i < TABLE_NR_CELLS; i++, ary++) {
238     char *str;
239     if (!uim_scm_strp(*ary)) {
240       /* XXX: output notify message? */
241       g_free(table);
242       free(ary0);
243       return default_tbl_cell2label;
244     }
245     str = uim_scm_c_str(*ary);
246     if (str) {
247       /* XXX: only use first char */
248       table[i] = *str;
249       free(str);
250     }
251   }
252   free(ary0);
253   return table;
254 }
255 
256 static void
button_clicked(GtkButton * button,gpointer data)257 button_clicked(GtkButton *button, gpointer data)
258 {
259   UIMCandWinTblGtk *ctblwin = data;
260   UIMCandWinGtk *cwin = UIM_CAND_WIN_GTK(ctblwin);
261   gint i;
262   gint idx = -1;
263 
264   for (i = 0; i < TABLE_NR_CELLS; i++) {
265     GtkButton *p;
266     struct index_button *idxbutton;
267     idxbutton = g_ptr_array_index(ctblwin->buttons, i);
268     if (!idxbutton) {
269       continue;
270     }
271     p = idxbutton->button;
272     if (p == button) {
273       idx = idxbutton->cand_index_in_page;
274       break;
275     }
276   }
277   if (idx >= 0 && cwin->display_limit) {
278     if (idx >= (gint)cwin->display_limit) {
279       idx %= cwin->display_limit;
280     }
281     cwin->candidate_index = cwin->page_index * cwin->display_limit + idx;
282   } else {
283     cwin->candidate_index = idx;
284   }
285   if (cwin->candidate_index >= (gint)cwin->nr_candidates) {
286     cwin->candidate_index = -1;
287   }
288   g_signal_emit_by_name(G_OBJECT(cwin), "index-changed");
289 }
290 
291 static void
uim_cand_win_tbl_gtk_dispose(GObject * obj)292 uim_cand_win_tbl_gtk_dispose (GObject *obj)
293 {
294   UIMCandWinTblGtk *ctblwin;
295 
296   g_return_if_fail(UIM_IS_CAND_WIN_TBL_GTK(obj));
297 
298   ctblwin = UIM_CAND_WIN_TBL_GTK(obj);
299 
300   if (ctblwin->tbl_cell2label != default_tbl_cell2label) {
301     g_free(ctblwin->tbl_cell2label);
302     ctblwin->tbl_cell2label = NULL;
303   }
304   if (ctblwin->buttons) {
305     guint i;
306     for (i = 0; i < ctblwin->buttons->len; i++) {
307       g_free(ctblwin->buttons->pdata[i]);
308       /* GtkButton is destroyed by container */
309     }
310     g_ptr_array_free(ctblwin->buttons, TRUE);
311     ctblwin->buttons = NULL;
312   }
313 
314   if (G_OBJECT_CLASS (parent_class)->dispose)
315     G_OBJECT_CLASS (parent_class)->dispose(obj);
316 }
317 
318 UIMCandWinTblGtk *
uim_cand_win_tbl_gtk_new(void)319 uim_cand_win_tbl_gtk_new (void)
320 {
321   GObject *obj = g_object_new(UIM_TYPE_CAND_WIN_TBL_GTK,
322 			      "type", GTK_WINDOW_POPUP,
323 			      NULL);
324   return UIM_CAND_WIN_TBL_GTK(obj);
325 }
326 
327 static GtkButton*
assign_cellbutton(GPtrArray * buttons,const gchar * tbl_cell2label,const gchar labelchar,gint cand_index,gint display_limit,gboolean * has_label)328 assign_cellbutton(GPtrArray *buttons, const gchar *tbl_cell2label,
329     const gchar labelchar, gint cand_index, gint display_limit,
330     gboolean *has_label)
331 {
332   gint i;
333   struct index_button *idxbutton;
334 
335   if (labelchar != '\0') {
336     /* find button by labelchar */
337     for (i = 0; i < TABLE_NR_CELLS; i++) {
338       if (tbl_cell2label[i] == labelchar) {
339         idxbutton = g_ptr_array_index(buttons, i);
340         if (!idxbutton) {
341           continue;
342         }
343         if (idxbutton->cand_index_in_page != -1) {
344           break; /* already used */
345         }
346         idxbutton->cand_index_in_page = cand_index;
347         *has_label = TRUE;
348         return idxbutton->button;
349       }
350     }
351   }
352   /* labelchar not found || already used */
353 
354   /* find free cell */
355   for (i = 0; i < TABLE_NR_CELLS; i++) {
356     if (display_limit && display_limit <= BLOCK_LR_NR_CELLS + BLOCK_LRS_NR_CELLS
357         && i % TABLE_NR_COLUMNS >= BLOCK_A_COLUMN_START) {
358       /* skip blockA which is far from home position */
359       i += TABLE_NR_COLUMNS - BLOCK_A_COLUMN_START - 1;
360       continue;
361     }
362     idxbutton = g_ptr_array_index(buttons, i);
363     if (!idxbutton) {
364       continue;
365     }
366     if (idxbutton->cand_index_in_page == -1) {
367       idxbutton->cand_index_in_page = cand_index;
368       *has_label = FALSE;
369       return idxbutton->button;
370     }
371   }
372 
373   /* failed to assign button */
374   *has_label = FALSE;
375   return NULL;
376 }
377 
378 void
uim_cand_win_tbl_gtk_set_index(UIMCandWinTblGtk * ctblwin,gint index)379 uim_cand_win_tbl_gtk_set_index(UIMCandWinTblGtk *ctblwin, gint index)
380 {
381   gint new_page;
382   UIMCandWinGtk *cwin;
383 
384   g_return_if_fail(UIM_IS_CAND_WIN_TBL_GTK(ctblwin));
385   cwin = UIM_CAND_WIN_GTK(ctblwin);
386 
387   if (index >= (gint) cwin->nr_candidates)
388     cwin->candidate_index = 0;
389   else
390     cwin->candidate_index = index;
391 
392   if (cwin->candidate_index >= 0 && cwin->display_limit)
393     new_page = cwin->candidate_index / cwin->display_limit;
394   else
395     new_page = cwin->page_index;
396 
397   if (cwin->page_index != new_page)
398     uim_cand_win_gtk_set_page(cwin, new_page);
399 
400   uim_cand_win_gtk_update_label(cwin);
401 }
402 
403 static void
clear_button(struct index_button * idxbutton,const gchar * tbl_cell2label,gint cell_index)404 clear_button(struct index_button *idxbutton, const gchar *tbl_cell2label,
405     gint cell_index)
406 {
407   GtkButton *button = NULL;
408   gboolean is_blank_cell = (tbl_cell2label[cell_index] == '\0') ? TRUE : FALSE;
409 
410   idxbutton->cand_index_in_page = -1;
411   button = idxbutton->button;
412   gtk_button_set_relief(button,
413       is_blank_cell ? GTK_RELIEF_NONE : GTK_RELIEF_HALF);
414   gtk_widget_set_sensitive(GTK_WIDGET(button), FALSE);
415   gtk_button_set_label(button, "  ");
416 }
417 
418 static void
clear_all_buttons(GPtrArray * buttons,const gchar * tbl_cell2label)419 clear_all_buttons(GPtrArray *buttons, const gchar *tbl_cell2label)
420 {
421   gint i;
422 
423   for (i = 0; i < TABLE_NR_CELLS; i++) {
424     struct index_button *idxbutton;
425 
426     idxbutton = g_ptr_array_index(buttons, i);
427     if (idxbutton && idxbutton->cand_index_in_page != -1) {
428       clear_button(idxbutton, tbl_cell2label, i);
429     }
430   }
431 }
432 
433 static void
update_table_button(GtkTreeModel * model,GPtrArray * buttons,const gchar * tbl_cell2label,gint display_limit)434 update_table_button(GtkTreeModel *model, GPtrArray *buttons,
435     const gchar *tbl_cell2label, gint display_limit)
436 {
437   GtkTreeIter ti;
438   gboolean has_next;
439   gint cand_index = 0;
440 
441   clear_all_buttons(buttons, tbl_cell2label);
442   has_next = gtk_tree_model_get_iter_first(model, &ti);
443   while (has_next) {
444     gchar *heading = NULL;
445     gchar *cand_str = NULL;
446     GtkButton *button = NULL;
447 
448     gtk_tree_model_get(model, &ti, COLUMN_HEADING, &heading,
449         COLUMN_CANDIDATE, &cand_str, TERMINATOR);
450     if (cand_str != NULL) {
451       gboolean has_label = FALSE;
452       gchar ch = (heading == NULL) ? '\0' : heading[0];
453       button = assign_cellbutton(buttons, tbl_cell2label, ch, cand_index,
454           display_limit, &has_label);
455       if (button != NULL) {
456         gtk_button_set_relief(button,
457             has_label ? GTK_RELIEF_NORMAL : GTK_RELIEF_HALF);
458         gtk_widget_set_sensitive(GTK_WIDGET(button), TRUE);
459         gtk_button_set_label(button, cand_str);
460       }
461     }
462 
463     g_free(cand_str);
464     g_free(heading);
465     cand_index++;
466     has_next = gtk_tree_model_iter_next(model, &ti);
467   }
468 }
469 
470 void
uim_cand_win_tbl_gtk_set_page(UIMCandWinTblGtk * ctblwin,gint page)471 uim_cand_win_tbl_gtk_set_page(UIMCandWinTblGtk *ctblwin, gint page)
472 {
473   guint len, new_page;
474   gint new_index;
475   UIMCandWinGtk *cwin;
476 
477   g_return_if_fail(UIM_IS_CAND_WIN_TBL_GTK(ctblwin));
478   cwin = UIM_CAND_WIN_GTK(ctblwin);
479   g_return_if_fail(cwin->stores);
480 
481   len = cwin->stores->len;
482   g_return_if_fail(len);
483 
484   if (page < 0)
485     new_page = len - 1;
486   else if (page >= (gint) len)
487     new_page = 0;
488   else
489     new_page = page;
490 
491   if (cwin->stores->pdata[new_page]) {
492     update_table_button(GTK_TREE_MODEL(cwin->stores->pdata[new_page]),
493                         ctblwin->buttons, ctblwin->tbl_cell2label,
494                         cwin->display_limit);
495     show_table(GTK_TABLE(cwin->view), ctblwin->buttons);
496   }
497 
498   cwin->page_index = new_page;
499 
500   if (cwin->display_limit) {
501     if (cwin->candidate_index >= 0)
502       new_index
503         = (new_page * cwin->display_limit) + (cwin->candidate_index % cwin->display_limit);
504     else
505       new_index = -1;
506   } else {
507     new_index = cwin->candidate_index;
508   }
509 
510   if (new_index >= (gint) cwin->nr_candidates)
511     new_index = cwin->nr_candidates - 1;
512 
513   uim_cand_win_gtk_set_index(cwin, new_index);
514 }
515 
516 static gboolean
is_empty_block(GPtrArray * buttons,gint rowstart,gint rowend,gint colstart,gint colend)517 is_empty_block(GPtrArray *buttons, gint rowstart, gint rowend, gint colstart, gint colend)
518 {
519   gint row, col;
520   for (row = rowstart; row < rowend; row++) {
521     for (col = colstart; col < colend; col++) {
522       struct index_button *idxbutton;
523       idxbutton = g_ptr_array_index(buttons, CELLINDEX(row, col));
524       if (idxbutton && idxbutton->cand_index_in_page != -1) {
525         return FALSE;
526       }
527     }
528   }
529   return TRUE;
530 }
531 
532 static void
show_table(GtkTable * view,GPtrArray * buttons)533 show_table(GtkTable *view, GPtrArray *buttons)
534 {
535   /* hide empty blocks.
536    * pattern0(full table)
537    *   blockLR  blockA
538    *   blockLRS blockAS  (for shift key)
539    * pattern1(minimal blocks)
540    *   blockLR
541    * pattern2(without shift blocks)
542    *   blockLR  blockA
543    * pattern3(without symbol blocks)
544    *   blockLR
545    *   blockLRS
546    */
547   gint row, col;
548   gint hide_row, hide_col;
549   gint row_spacing, col_spacing;
550   gboolean blockA, blockAS, blockLRS;
551   blockA = !is_empty_block(buttons, BLOCK_A_ROW_START, BLOCK_A_ROW_END,
552       BLOCK_A_COLUMN_START, BLOCK_A_COLUMN_END);
553   blockAS = !is_empty_block(buttons, BLOCK_AS_ROW_START, BLOCK_AS_ROW_END,
554       BLOCK_AS_COLUMN_START, BLOCK_AS_COLUMN_END);
555   blockLRS = !is_empty_block(buttons, BLOCK_LRS_ROW_START, BLOCK_LRS_ROW_END,
556       BLOCK_LRS_COLUMN_START, BLOCK_LRS_COLUMN_END);
557 
558   hide_row = TABLE_NR_ROWS;
559   hide_col = TABLE_NR_COLUMNS;
560   if (blockAS) { /* pattern0(full table) */
561     hide_row = TABLE_NR_ROWS;
562     hide_col = TABLE_NR_COLUMNS;
563   } else if (blockLRS) {
564     if (blockA) { /* pattern0(full table) */
565       hide_row = TABLE_NR_ROWS;
566       hide_col = TABLE_NR_COLUMNS;
567     } else { /* pattern3(without symbol blocks) */
568       hide_row = TABLE_NR_ROWS;
569       hide_col = BLOCK_A_COLUMN_START;
570     }
571   } else if (blockA) { /* pattern2(without shift blocks) */
572     hide_row = BLOCK_A_ROW_END;
573     hide_col = TABLE_NR_COLUMNS;
574   } else { /* pattern1(minimal blocks) */
575     hide_row = BLOCK_A_ROW_END;
576     hide_col = BLOCK_A_COLUMN_START;
577   }
578 
579   for (row = 0; row < TABLE_NR_ROWS; row++) {
580     for (col = 0; col < TABLE_NR_COLUMNS; col++) {
581       GtkButton *button = NULL;
582       button = get_button(buttons, CELLINDEX(row, col));
583       if (row >= hide_row || col >= hide_col) {
584         gtk_widget_hide(GTK_WIDGET(button));
585       } else {
586         gtk_widget_show(GTK_WIDGET(button));
587       }
588     }
589   }
590   if (hide_col <= BLOCK_A_COLUMN_START) {
591     col_spacing = 0;
592   } else {
593     col_spacing = BLOCK_SPACING;
594   }
595   if (hide_row <= BLOCK_LRS_ROW_START) {
596     row_spacing = 0;
597   } else {
598     row_spacing = BLOCK_SPACING;
599   }
600   gtk_table_set_col_spacing(view, SPACING_RIGHT_BLOCK_COLUMN, col_spacing);
601   gtk_table_set_row_spacing(view, SPACING_UP_BLOCK_ROW, row_spacing);
602   if (row_spacing) {
603     gtk_table_set_row_spacing(view, SPACING_SHIFT_UPPER_FAR_ROW,
604         HOMEPOSITION_SPACING);
605   } else {
606     gtk_table_set_row_spacing(view, SPACING_SHIFT_UPPER_FAR_ROW, 0);
607   }
608   /* gtk_table_resize(view, hide_row, hide_col); */
609   gtk_widget_show(GTK_WIDGET(view));
610 }
611 
612 static GtkButton *
get_button(GPtrArray * buttons,gint idx)613 get_button(GPtrArray *buttons, gint idx)
614 {
615   GtkButton *button = NULL;
616   struct index_button *idxbutton;
617 
618   idxbutton = g_ptr_array_index(buttons, idx);
619   if (idxbutton) {
620     button = idxbutton->button;
621   }
622   return button;
623 }
624