diff options
| -rw-r--r-- | char-table.c | 330 | ||||
| -rw-r--r-- | char-table.h | 22 | ||||
| -rw-r--r-- | gcmap.c | 126 |
3 files changed, 376 insertions, 102 deletions
diff --git a/char-table.c b/char-table.c index 076ef8f..9a4c925 100644 --- a/char-table.c +++ b/char-table.c @@ -1,15 +1,11 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -#define FIRST_CHARACTER 0x0000u -#define LAST_CHARACTER 0xFFFFu #define REFERENCE_CHARACTER "X" #define CELL_WIDTH_FACTOR 4 #define CELL_HEIGHT_FACTOR 2 #define CELL_X_CLEARANCE 2 #define CELL_Y_CLEARANCE 2 -#define BASE_FONT_FAMILY "Sans" -#define BASE_FONT_SIZE 22 G_DEFINE_TYPE(CharTable, gcmap_char_table, GTK_TYPE_DRAWING_AREA) @@ -34,17 +30,11 @@ is_printable_character(gunichar ch) static void format_character(gunichar ch, char *buf) { - if (is_printable_character(ch)) - buf[g_unichar_to_utf8(ch, buf)] = '\0'; -#ifdef TODO /* this part is just for testing */ - else if (ch == 0x7Fu) - stpcpy(buf, "DELETE"); - else - stpcpy(buf, "X"); -#else - else + if (!is_printable_character(ch)) { buf[0u] = '\0'; -#endif + return; + } + buf[g_unichar_to_utf8(ch, buf)] = '\0'; } @@ -67,8 +57,8 @@ fit_text(CharTable *this, const char *text, int *text_w_out, int *text_h_out) /* Set text to measure */ pango_layout_set_text(this->layout, text, -1); - /* Try default size */ - apply_font_size(this, BASE_FONT_SIZE, text_w_out, text_h_out); + /* Try desired size */ + apply_font_size(this, this->font_size, text_w_out, text_h_out); if (*text_w_out <= this->max_w && *text_h_out <= this->max_h) return; @@ -76,7 +66,7 @@ fit_text(CharTable *this, const char *text, int *text_w_out, int *text_h_out) scale_x = (double)this->max_w / (double)*text_w_out; scale_y = (double)this->max_h / (double)*text_h_out; scale = MIN(scale_x, scale_y); - scale = MIN(scale, 1) * BASE_FONT_SIZE; + scale = MIN(scale, 1) * this->font_size; size = (int)scale; size = MAX(size, 1); @@ -95,7 +85,7 @@ fit_text(CharTable *this, const char *text, int *text_w_out, int *text_h_out) do { ok_size++; start: - if (ok_size == BASE_FONT_SIZE) + if (ok_size == this->font_size) break; apply_font_size(this, ok_size + 1, text_w_out, text_h_out); } while (*text_w_out < this->max_w && *text_h_out < this->max_h); @@ -107,27 +97,30 @@ fit_text(CharTable *this, const char *text, int *text_w_out, int *text_h_out) } -static int +static gboolean gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) { - CharTable *this = (CharTable *)widget; + CharTable *this = GCMAP_CHAR_TABLE(widget); GdkRectangle area = event->area; - int r0 = MAX(area.y * this->nrows / widget->allocation.height, 0); - int c0 = MAX(area.x * this->ncols / widget->allocation.width, 0); - int r1 = MIN((area.y + area.height - 1) * this->nrows / widget->allocation.height + 1, this->nrows); - int c1 = MIN((area.x + area.width - 1) * this->ncols / widget->allocation.width + 1, this->ncols); + int r0 = MAX(area.y * this->nrows / this->viewport_h, 0); + int c0 = MAX(area.x * this->ncols / this->viewport_w, 0); + int r1 = MIN((area.y + area.height - 1) * this->nrows / this->viewport_h + 1, r0 + this->nrows); + int c1 = MIN((area.x + area.width - 1) * this->ncols / this->viewport_w + 1, c0 + this->ncols); GtkStyle *style = gtk_widget_get_style(widget); cairo_t *g; char text[16]; int r, c, x0, x1, y0, y1; int text_w, text_h; - size_t index, index1; - gunichar ch; + size_t skip, range, row_skip; + uint32_t cp; g = gdk_cairo_create(widget->window); if (!g) eprintf("gdk_cairo_create:"); + /* Make sure it still looks good even if starting in the middle of row */ + r1 += 1; + /* Configure drawing area */ gdk_cairo_rectangle(g, &area); cairo_clip(g); @@ -137,44 +130,61 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) cairo_paint(g); /* Draw grid lines */ - set_source_colour_blend(g, &style->text[GTK_STATE_NORMAL], 0.5, &style->base[GTK_STATE_NORMAL]); + set_source_colour_blend(g, &style->base[GTK_STATE_NORMAL], 0.10, &style->text[GTK_STATE_NORMAL]); cairo_set_line_width(g, 1.0); /* horizontal */ - y0 = widget->allocation.height * (r0 + 1) / this->nrows; - x0 = widget->allocation.width * c0 / this->ncols; - x1 = widget->allocation.width * c1 / this->ncols; - for (r = r0 + 1; r < r1; r++, y0 = y1) { - y1 = widget->allocation.height * (r + 1) / this->nrows; + y0 = this->viewport_h * (r0 + 1) / this->nrows; + x0 = this->viewport_w * c0 / this->ncols; + x1 = this->viewport_w * c1 / this->ncols; + for (r = r0 + (area.y > 0); r < r1; r++, y0 = y1) { + y1 = this->viewport_h * (r + 1) / this->nrows; cairo_move_to(g, x0, y0 + 0.5); cairo_line_to(g, x1, y0 + 0.5); cairo_stroke(g); } /* vertical */ - x0 = widget->allocation.width * (c0 + 1) / this->ncols; - y0 = widget->allocation.height * r0 / this->nrows; - y1 = widget->allocation.height * r1 / this->nrows; - for (c = c0 + 1; c < c1; c++, x0 = x1) { - x1 = widget->allocation.width * (c + 1) / this->ncols; + x0 = this->viewport_w * (c0 + 1) / this->ncols; + y0 = this->viewport_h * r0 / this->nrows; + y1 = this->viewport_h * r1 / this->nrows; + for (c = c0 + (area.x > 0); c < c1; c++, x0 = x1) { + x1 = this->viewport_w * (c + 1) / this->ncols; cairo_move_to(g, x0 + 0.5, y0); cairo_line_to(g, x0 + 0.5, y1); cairo_stroke(g); } /* Draw gryphs */ + if (this->nranges == 0u) + goto out; set_source_colour(g, &style->text[GTK_STATE_NORMAL]); - index = (size_t)r0 * (size_t)this->ncols + (size_t)c0; - y0 = widget->allocation.height * r0 / this->nrows; - for (r = r0; r < r1; r++, y0 = y1, index = index1) { - index1 = index + (size_t)this->ncols; - x0 = widget->allocation.width * c0 / this->ncols; - y1 = widget->allocation.height * (r + 1) / this->nrows; - for (c = c0; c < c1; c++, index++, x0 = x1) { - ch = FIRST_CHARACTER + (gunichar)index; - if (ch > LAST_CHARACTER) - goto out; - x1 = widget->allocation.width * (c + 1) / this->ncols; + y0 = this->viewport_h * r0 / this->nrows; + range = 0u; + cp = this->ranges[range].first; + skip = (size_t)r0 * (size_t)this->ncols + (size_t)c0; + row_skip = (size_t)this->ncols - (size_t)(c1 - c0); + for (r = r0; r < r1; r++, y0 = y1, skip = row_skip) { + while (skip) { + size_t max_jump = (size_t)(this->ranges[range].last - cp + 1u); + size_t jump = MIN(skip, max_jump); + cp += (uint32_t)jump; + skip -= jump; + if (cp > this->ranges[range].last) { + if (++range == this->nranges) + goto out; + cp = this->ranges[range].first; + } + } + x0 = this->viewport_w * c0 / this->ncols; + y1 = this->viewport_h * (r + 1) / this->nrows; + for (c = c0; c < c1; c++, cp++, x0 = x1) { + if (cp > this->ranges[range].last) { + if (++range == this->nranges) + goto out; + cp = this->ranges[range].first; + } + x1 = this->viewport_w * (c + 1) / this->ncols; - format_character(ch, text); + format_character((gunichar)cp, text); fit_text(this, text, &text_w, &text_h); cairo_move_to(g, (x0 + x1 - text_w) / 2, (y0 + y1 - text_h) / 2); pango_cairo_show_layout(g, this->layout); @@ -183,53 +193,122 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) out: cairo_destroy(g); - return 0; + return FALSE; } -static void -gcmap_char_table_size_allocate(GtkWidget *widget, GtkAllocation *allocation) +static int +update_cell_size(GtkWidget *widget, int ranges_changed) { - CharTable *this = (CharTable *)widget; + CharTable *this = GCMAP_CHAR_TABLE(widget); int text_w, text_h; int cell_w, cell_h; + uint32_t nchars; + int table_h; + size_t i; - GTK_WIDGET_CLASS(gcmap_char_table_parent_class)->size_allocate(widget, allocation); + int old_ncols = this->ncols; + int old_cell_h = this->cell_h; pango_layout_set_text(this->layout, REFERENCE_CHARACTER, -1); - apply_font_size(this, BASE_FONT_SIZE, &text_w, &text_h); + + pango_font_description_set_weight(this->font, PANGO_WEIGHT_NORMAL); + pango_font_description_set_style(this->font, PANGO_STYLE_NORMAL); + apply_font_size(this, this->font_size, &text_w, &text_h); + pango_font_description_set_weight(this->font, this->font_weight); + pango_font_description_set_style(this->font, this->font_style); + cell_w = MAX(text_w, 1) * CELL_WIDTH_FACTOR; cell_h = MAX(text_h, 1) * CELL_HEIGHT_FACTOR; - this->ncols = MAX(widget->allocation.width / cell_w, 1); - this->nrows = MAX(widget->allocation.height / cell_h, 1); - cell_w = widget->allocation.width / this->ncols - 1; - cell_h = widget->allocation.height / this->nrows - 1; + this->ncols = MAX(this->viewport_w / cell_w, 1); + this->nrows = MAX(this->viewport_h / cell_h, 1); + cell_w = MAX(this->viewport_w / this->ncols - 1, 1); + cell_h = MAX(this->viewport_h / this->nrows - 1, 1); this->max_w = cell_w - CELL_X_CLEARANCE * 2; this->max_h = cell_h - CELL_Y_CLEARANCE * 2; this->max_w = this->max_w < 1 ? cell_w : this->max_w; this->max_h = this->max_h < 1 ? cell_h : this->max_h; + this->cell_h = cell_h; + + if (old_ncols == this->ncols && old_cell_h == this->cell_h && !ranges_changed) + return 0; + + nchars = (uint32_t)this->nranges; + for (i = 0u; i < this->nranges; i++) + nchars += this->ranges[i].last - this->ranges[i].first; + this->nchars = nchars; + table_h = (int)(nchars / (uint32_t)this->ncols); + if (nchars % (uint32_t)this->ncols) + table_h += 1; + table_h = table_h > INT_MAX / this->cell_h ? INT_MAX : table_h * this->cell_h; + if (this->table_h == table_h) + return 0; + this->table_h = table_h; + return 1; +} + + +static void +gcmap_char_table_size_request(GtkWidget *widget, GtkRequisition *requisition) +{ + CharTable *this = GCMAP_CHAR_TABLE(widget); + requisition->width = 1; + requisition->height = this->table_h; } +static gboolean +gcmap_char_table_button_press(GtkWidget *widget, GdkEventButton *event) +{ + (void) event; + gtk_widget_grab_focus(widget); + return FALSE; +} static void gcmap_char_table_init(CharTable *this) { - this->nrows = 1; /* will be set by gcmap_char_table_size_allocate */ - this->ncols = 1; /* will be set by gcmap_char_table_size_allocate */ + GtkWidget *widget = GTK_WIDGET(this); - this->font = pango_font_description_new(); - if (!this->font) - eprintf("pango_font_description_new:"); - pango_font_description_set_family(this->font, BASE_FONT_FAMILY); - pango_font_description_set_size(this->font, BASE_FONT_SIZE * PANGO_SCALE); - pango_font_description_set_weight(this->font, PANGO_WEIGHT_NORMAL); + this->nrows = 1; + this->ncols = 1; + this->max_w = 1; + this->max_h = 1; + this->cell_h = 1; + this->table_h = 1; + this->nchars = 0u; + this->viewport_w = 1; + this->viewport_h = 1; - this->layout = gtk_widget_create_pango_layout((GtkWidget *)this, ""); - if (!this->layout) - eprintf("gtk_widget_create_pango_layout:"); + GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); + gtk_widget_set_sensitive(widget, TRUE); + + gtk_widget_add_events(widget, + GDK_BUTTON_PRESS_MASK | + GDK_KEY_PRESS_MASK | + GDK_FOCUS_CHANGE_MASK); + + g_signal_connect(widget, "button-press-event", + G_CALLBACK(&gcmap_char_table_button_press), NULL); + + /* TODO scrolling with control held should change font size (attempt to keep hover glyph in place) */ +} + + +static void +gcmap_char_table_dispose(GObject *object) +{ + CharTable *this = GCMAP_CHAR_TABLE(object); + g_clear_object(&this->layout); + G_OBJECT_CLASS(gcmap_char_table_parent_class)->dispose(object); +} - /* TODO on tear down: pango_font_description_free(this->font); */ - /* TODO on tear down: g_object_unref(this->layout); */ + +static void +gcmap_char_table_finalize(GObject *object) +{ + CharTable *this = GCMAP_CHAR_TABLE(object); + pango_font_description_free(this->font); + G_OBJECT_CLASS(gcmap_char_table_parent_class)->finalize(object); } @@ -237,13 +316,114 @@ static void gcmap_char_table_class_init(CharTableClass *class) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); + GObjectClass *object_class = G_OBJECT_CLASS(class); + object_class->dispose = &gcmap_char_table_dispose; + object_class->finalize = &gcmap_char_table_finalize; widget_class->expose_event = &gcmap_char_table_expose; - widget_class->size_allocate = &gcmap_char_table_size_allocate; + widget_class->size_request = &gcmap_char_table_size_request; +} + + +void +gcmap_char_table_set_font_family(CharTable *this, const char *family) +{ + pango_font_description_set_family(this->font, family); + pango_layout_set_font_description(this->layout, this->font); + pango_layout_context_changed(this->layout); + gtk_widget_queue_resize(GTK_WIDGET(this)); + gtk_widget_queue_draw(GTK_WIDGET(this)); +} + + +void +gcmap_char_table_set_font_weight(CharTable *this, PangoWeight weight) +{ + if (this->font_weight == weight) + return; + this->font_weight = weight; + pango_font_description_set_weight(this->font, this->font_weight); + pango_layout_set_font_description(this->layout, this->font); + pango_layout_context_changed(this->layout); + gtk_widget_queue_draw(GTK_WIDGET(this)); +} + + +void +gcmap_char_table_set_font_style(CharTable *this, PangoStyle style) +{ + if (this->font_style == style) + return; + this->font_style = style; + pango_font_description_set_style(this->font, this->font_style); + pango_layout_set_font_description(this->layout, this->font); + pango_layout_context_changed(this->layout); + gtk_widget_queue_draw(GTK_WIDGET(this)); +} + + +void +gcmap_char_table_set_font_size(CharTable *this, int size) +{ + GtkWidget *widget; + if (this->font_size == MAX(size, 1)) + return; + this->font_size = MAX(size, 1); + pango_font_description_set_size(this->font, this->font_size * PANGO_SCALE); + pango_layout_set_font_description(this->layout, this->font); + pango_layout_context_changed(this->layout); + widget = GTK_WIDGET(this); + gtk_widget_queue_resize(widget); + gtk_widget_queue_draw(widget); +} + + +void +gcmap_char_table_set_ranges(CharTable *this, const struct libcmap_range *ranges, size_t nranges) +{ + GtkWidget *widget; + if (this->ranges == ranges && this->nranges == nranges) + return; + this->ranges = ranges; + this->nranges = nranges; + widget = GTK_WIDGET(this); + if (update_cell_size(widget, 1)) + gtk_widget_queue_resize(widget); + gtk_widget_queue_draw(widget); +} + + +void +gcmap_char_table_viewport_updated(CharTable *this, int viewport_w, int viewport_h) +{ + this->viewport_w = viewport_w; + this->viewport_h = viewport_h; + update_cell_size(GTK_WIDGET(this), 0); } GtkWidget * -gcmap_char_table_new(void) +gcmap_char_table_new(const char *font_family, int font_size, PangoWeight font_weight, PangoStyle font_style) { - return g_object_new(GCMAP_TYPE_CHAR_TABLE, NULL); + CharTable *this = g_object_new(GCMAP_TYPE_CHAR_TABLE, NULL); + GtkWidget *widget = GTK_WIDGET(this); + + this->font_size = font_size; + this->font_weight = font_weight; + this->font_style = font_style; + this->ranges = NULL; + this->nranges = 0u; + + this->font = pango_font_description_new(); + if (!this->font) + eprintf("pango_font_description_new:"); + pango_font_description_set_family(this->font, font_family); + pango_font_description_set_size(this->font, this->font_size * PANGO_SCALE); + pango_font_description_set_weight(this->font, this->font_weight); + pango_font_description_set_style(this->font, this->font_style); + + this->layout = gtk_widget_create_pango_layout(widget, ""); + if (!this->layout) + eprintf("gtk_widget_create_pango_layout:"); + + return widget; } diff --git a/char-table.h b/char-table.h index 87d65d4..33999b2 100644 --- a/char-table.h +++ b/char-table.h @@ -3,7 +3,7 @@ #define GCMAP_TYPE_CHAR_TABLE (gcmap_char_table_get_type()) -#define GCMAP_TYPE_CHAR(OBJ) (G_TYPE_CHECK_INSTANCE_CAST((OBJ), GCMAP_TYPE_CHAR_TABLE, CharTable)) +#define GCMAP_CHAR_TABLE(OBJ) (G_TYPE_CHECK_INSTANCE_CAST((OBJ), GCMAP_TYPE_CHAR_TABLE, CharTable)) #define GCMAP_CHAR_TABLE_CLASS(CLASS) (G_TYPE_CHECK_CLASS_CAST((CLASS), GCMAP_TYPE_CHAR_TABLE, CharTableClass)) #define IS_GCMAP_CHAR_TABLE(OBJ) (G_TYPE_CHECK_INSTANCE_TYPE((OBJ), GCMAP_TYPE_CHAR_TABLE)) #define IS_GCMAP_CHAR_TABLE_CLASS(CLASS) (G_TYPE_CHECK_CLASS_TYPE((CLASS), GCMAP_TYPE_CHAR_TABLE)) @@ -12,9 +12,18 @@ typedef struct _CharTable { GtkDrawingArea parent_instance; - int nrows, ncols, max_w, max_h; + int nrows, ncols; + int max_w, max_h; + int cell_h, table_h; + uint32_t nchars; + int viewport_w, viewport_h; PangoFontDescription *font; PangoLayout *layout; + int font_size; + PangoWeight font_weight; + PangoStyle font_style; + const struct libcmap_range *ranges; + size_t nranges; } CharTable; typedef struct _CharTableClass { @@ -23,4 +32,11 @@ typedef struct _CharTableClass { GType gcmap_char_table_get_type(void); -GtkWidget *gcmap_char_table_new(void); +GtkWidget *gcmap_char_table_new(const char *font_family, int font_size, PangoWeight font_weight, PangoStyle font_style); + +void gcmap_char_table_set_font_family(CharTable *this, const char *family); +void gcmap_char_table_set_font_weight(CharTable *this, PangoWeight weight); +void gcmap_char_table_set_font_style(CharTable *this, PangoStyle style); +void gcmap_char_table_set_font_size(CharTable *this, int size); +void gcmap_char_table_set_ranges(CharTable *this, const struct libcmap_range *ranges, size_t nranges); +void gcmap_char_table_viewport_updated(CharTable *this, int viewport_w, int viewport_h); @@ -4,6 +4,9 @@ USAGE("[-f font-family] [-s [font-size][/[[min]-[max]]]] [-B | -S] [-bi]"); +#define DEFAULT_FONT_FAMILY "Sans" + + #define DEFAULT_LISTING_TYPE "script" #define LIST_LISTINGS(X, D)\ X(BY_SCRIPT, "By _script", DEFAULT_LISTING_TYPE, by_script_selected, populate_scripts, GDK_s) D\ @@ -41,6 +44,7 @@ static GtkWidget *nextgroup; static GtkWidget *prevgroup; static GtkWidget *bylisting[NLISTINGS]; static GtkWidget *vtabtext; +static GtkWidget *chartable; static GtkListStore *fontcombo_store; static GtkAdjustment *fontsize_adjustment; static GtkAccelGroup *accelgroup; @@ -54,17 +58,21 @@ static size_t ngroups_tooltips; #endif -static void -populate_font_families(GtkWidget *widget, GtkListStore *store) +static int +populate_font_families(GtkWidget *widget, GtkListStore *store, const char **selectedp) { const char **names; PangoFontFamily **families; int nfamilies_int; size_t i, nfamilies; GtkTreeIter iter; + size_t selected_index = SIZE_MAX; + size_t default_index = SIZE_MAX; pango_context_list_families(gtk_widget_get_pango_context(GTK_WIDGET(widget)), &families, &nfamilies_int); nfamilies = (size_t)nfamilies_int; + if (nfamilies == 0u) + eprintf("no fonts available"); names = ecalloc(nfamilies, sizeof(*names)); for (i = 0u; i < nfamilies; i++) @@ -73,10 +81,22 @@ populate_font_families(GtkWidget *widget, GtkListStore *store) for (i = 0; i < nfamilies; i++) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, names[i], -1); + if (selected_index == SIZE_MAX && !strcasecmp(names[i], *selectedp)) + selected_index = i; + if (default_index == SIZE_MAX && !strcasecmp(names[i], DEFAULT_FONT_FAMILY)) + default_index = i; } + if (selected_index == SIZE_MAX) + selected_index = default_index; + if (selected_index == SIZE_MAX) + selected_index = 0u; + *selectedp = names[selected_index]; + free(names); g_free(families); + + return (int)selected_index; } @@ -195,6 +215,46 @@ block_tooltip(const struct libcmap_block *block) static void +grouplist_selection_changed(GtkTreeSelection *selection, void *user_data) +{ + const struct libcmap_range *ranges = &all_block.range; + size_t nranges = 1u; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *path; + int index; + + (void) user_data; + + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path(model, &iter); + index = gtk_tree_path_get_indices(path)[0u]; + gtk_tree_path_free(path); + + switch (gtk_combo_box_get_active(GTK_COMBO_BOX(listcombo))) { + case BY_SCRIPT: + if (index-- > 0 && (size_t)index < libcmap_script_list_size) { + ranges = libcmap_script_list[index].ranges; + nranges = libcmap_script_list[index].nranges; + } + break; + + case BY_BLOCK: + if (index-- > 0 && (size_t)index < libcmap_block_list_size) + ranges = &libcmap_block_list[index].range; + break; + + default: + abort(); + } + + gcmap_char_table_set_ranges(GCMAP_CHAR_TABLE(chartable), ranges, nranges); +} + + +static void populate_scripts(GtkListStore *store) { const struct libcmap_script *list = libcmap_script_list; @@ -277,7 +337,7 @@ copybutton_clicked(GtkWidget *button, GtkEditable *editable) static void -fontcombo_changed(GtkComboBox *combo, void *user_data) /* TODO */ +fontcombo_changed(GtkComboBox *combo, void *user_data) { GtkTreeIter iter; char *family; @@ -287,24 +347,27 @@ fontcombo_changed(GtkComboBox *combo, void *user_data) /* TODO */ gtk_tree_model_get(GTK_TREE_MODEL(fontcombo_store), &iter, 0, &family, -1); if (!family) return; + gcmap_char_table_set_font_family(GCMAP_CHAR_TABLE(chartable), family); } static void -bold_toggled(GtkToggleButton *button, void *user_data) /* TODO */ +bold_toggle(GtkToggleButton *button, void *user_data) { int selected = gtk_toggle_button_get_active(button); - (void) selected; (void) user_data; + gcmap_char_table_set_font_weight(GCMAP_CHAR_TABLE(chartable), + selected ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); } static void -italic_toggled(GtkToggleButton *button, void *user_data) /* TODO */ +italic_toggle(GtkToggleButton *button, void *user_data) { int selected = gtk_toggle_button_get_active(button); - (void) selected; (void) user_data; + gcmap_char_table_set_font_style(GCMAP_CHAR_TABLE(chartable), + selected ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); } @@ -313,7 +376,7 @@ fontsize_changed(GtkAdjustment *adjustment, void *user_data) { double size = gtk_adjustment_get_value(adjustment); (void) user_data; - (void) size; /* TODO apply font size */ + gcmap_char_table_set_font_size(GCMAP_CHAR_TABLE(chartable), (int)size); } @@ -665,9 +728,17 @@ vtabtext_changed(GtkWidget *menu_item, void *user_data) static void -create_window(void) +chartable_viewport_size_allocate(GtkWidget *viewport, GtkAllocation *allocation, void *user_data) { + (void) user_data; + (void) viewport; + gcmap_char_table_viewport_updated(GCMAP_CHAR_TABLE(chartable), allocation->width, allocation->height); +} + + +static void +create_window(const char *default_font, PangoWeight default_weight, PangoStyle default_style) { - GtkWidget *vbox, *hbox, *left, *scrolled; + GtkWidget *vbox, *hbox, *left, *scrolled, *viewport; GtkWidget *label, *copybutton, *align, *menubar, *menu; GtkListStore *store; GtkCellRenderer *renderer; @@ -676,7 +747,7 @@ create_window(void) AtkObject *accessible; GClosure *closure; GSList *group; - int i, n; + int i, n, default_font_index; window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "destroy", G_CALLBACK(>k_main_quit), NULL); @@ -745,10 +816,10 @@ create_window(void) gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(fontcombo), renderer, "text", 0, NULL); fontcombo_store = gtk_list_store_new(1, G_TYPE_STRING); gtk_combo_box_set_model(GTK_COMBO_BOX(fontcombo), GTK_TREE_MODEL(fontcombo_store)); - populate_font_families(fontcombo, fontcombo_store); + default_font_index = populate_font_families(fontcombo, fontcombo_store, &default_font); gtk_combo_box_set_focus_on_click(GTK_COMBO_BOX(fontcombo), FALSE); gtk_box_pack_start(GTK_BOX(hbox), fontcombo, FALSE, FALSE, 0); - gtk_combo_box_set_active(GTK_COMBO_BOX(fontcombo), -1); + gtk_combo_box_set_active(GTK_COMBO_BOX(fontcombo), default_font_index); g_signal_connect(fontcombo, "changed", G_CALLBACK(&fontcombo_changed), NULL); accessible = gtk_widget_get_accessible(fontcombo); atk_object_set_name(accessible, "Font family"); @@ -756,13 +827,13 @@ create_window(void) bold = gtk_toggle_button_new_with_mnemonic(GTK_STOCK_BOLD); gtk_button_set_use_stock(GTK_BUTTON(bold), TRUE); gtk_button_set_focus_on_click(GTK_BUTTON(bold), FALSE); - g_signal_connect(bold, "toggled", G_CALLBACK(&bold_toggled), NULL); + g_signal_connect(bold, "toggled", G_CALLBACK(&bold_toggle), NULL); gtk_box_pack_start(GTK_BOX(hbox), bold, FALSE, FALSE, 0); italic = gtk_toggle_button_new_with_mnemonic(GTK_STOCK_ITALIC); gtk_button_set_use_stock(GTK_BUTTON(italic), TRUE); gtk_button_set_focus_on_click(GTK_BUTTON(italic), FALSE); - g_signal_connect(italic, "toggled", G_CALLBACK(&italic_toggled), NULL); + g_signal_connect(italic, "toggled", G_CALLBACK(&italic_toggle), NULL); gtk_box_pack_start(GTK_BOX(hbox), italic, FALSE, FALSE, 0); obj = gtk_adjustment_new(default_font_size, min_font_size, max_font_size, @@ -794,6 +865,8 @@ create_window(void) gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(grouplist), FALSE); g_signal_connect(grouplist, "query-tooltip", G_CALLBACK(&grouplist_query_tooltip), NULL); gtk_widget_set_has_tooltip(GTK_WIDGET(grouplist), TRUE); + g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(grouplist)), "changed", + G_CALLBACK(&grouplist_selection_changed), NULL); gtk_container_add(GTK_CONTAINER(scrolled), grouplist); gtk_box_pack_start(GTK_BOX(left), scrolled, TRUE, TRUE, 0); @@ -805,16 +878,20 @@ create_window(void) /* TODO character map tab pane (should have focus: gtk_widget_grab_focus(GTK_WIDGET(...)) */ scrolled = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_NONE); - gtk_container_add(GTK_CONTAINER(scrolled), gcmap_char_table_new()); + chartable = gcmap_char_table_new(default_font, (int)default_font_size, default_weight, default_style); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), chartable); + viewport = gtk_bin_get_child(GTK_BIN(scrolled)); + g_signal_connect(viewport, "size-allocate", G_CALLBACK(&chartable_viewport_size_allocate), NULL); + /* TODO scroll shall snap to beginning of a row */ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Character _table")); #ifdef TODO scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_NONE); - gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO")); + gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO")); // gtk_scrolled_window_add_with_viewport gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Character _details")); #endif @@ -822,7 +899,7 @@ create_window(void) scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_NONE); - gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO")); + gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO")); // gtk_scrolled_window_add_with_viewport gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Glyph v_ariants")); #endif @@ -830,7 +907,7 @@ create_window(void) scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_NONE); - gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO")); + gtk_container_add(GTK_CONTAINER(scrolled), gtk_label_new("TODO")); // gtk_scrolled_window_add_with_viewport gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Font c_omparison")); #endif @@ -941,7 +1018,7 @@ main(int argc, char *argv[]) int default_font_size_set = 0; int min_font_size_set = 0; int max_font_size_set = 0; - const char *font_family = "Sans"; + const char *font_family = DEFAULT_FONT_FAMILY; ARGBEGIN { case 'B': @@ -1009,7 +1086,9 @@ main(int argc, char *argv[]) icon = "gcmap"; gtk_window_set_default_icon_name(icon); - create_window(); + create_window(font_family, + use_bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, + use_italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); gtk_window_set_icon_name(GTK_WINDOW(window), icon); gtk_window_set_wmclass(GTK_WINDOW(window), "gcmap", "gcmap"); gtk_window_set_role(GTK_WINDOW(window), "gcmap"); @@ -1023,8 +1102,7 @@ main(int argc, char *argv[]) groups_tooltips = group_tooltips[listing]; ngroups_tooltips = ngroup_tooltips[listing]; - (void) font_family; /* TODO select font family */ - /* TODO select character (U+0000) and group (locate the on containing it, go to All if not found) */ + /* TODO select character (U+0000) and group (locate the one containing it, go to All if not found) */ gtk_window_present(GTK_WINDOW(window)); gtk_main(); |
