diff options
| author | Mattias Andrée <m@maandree.se> | 2026-10-16 22:06:31 +0200 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2026-10-16 22:06:31 +0200 |
| commit | 17ebf437626fb21858c88421e7599e8f03661b78 (patch) | |
| tree | eb31fadc360560ed7e3c55b819ed3053ab7af70f | |
| parent | Fix No Block (diff) | |
| download | gcmap-17ebf437626fb21858c88421e7599e8f03661b78.tar.gz gcmap-17ebf437626fb21858c88421e7599e8f03661b78.tar.bz2 gcmap-17ebf437626fb21858c88421e7599e8f03661b78.tar.xz | |
Misc
Signed-off-by: Mattias Andrée <m@maandree.se>
| -rw-r--r-- | TODO | 30 | ||||
| -rw-r--r-- | char-table.c | 269 | ||||
| -rw-r--r-- | char-table.h | 11 | ||||
| -rw-r--r-- | gcmap.c | 196 | ||||
| -rw-r--r-- | logical-scroll-pane.c | 24 |
5 files changed, 477 insertions, 53 deletions
@@ -1,3 +1,20 @@ +Add drag-and-drop support, both in to find a character and out to copy a character + +Scroll with wheel, page up/down, or scroll bar shall adjust the character selection to remain in view + +Show font and upscaled (based on same font size) glyph when Shift is held +(note: selection change via gcmap_char_table_key_press may require update) + +Show font and upscaled (based on same font size) glyph when mouse button 3 (right) +is held down; this shall also select the character and do so continuously while +moving the pointer + +Middle-clicking should find the character stored in PRIMARY (SECONDARY if Mod1 is held down) + +Keep selected character in view when resizing the chart or the cells + +Optionally show metrics + Add bookmarks expander under the tabbed pane Mark whenever a fallback font is used for a glyph @@ -17,9 +34,20 @@ Add support for command line operands: select listed fonts by path Add editor to font drop-down to make it easier to select a font -Scrolling inside a GtkScrolledWindow or LogicalScrollPane shall steal focus +Scrolling inside a GtkScrolledWindow or LogicalScrollPane shall steal focus (gtk_widget_grab_focus) Scrolling with Control held down shall change zoom. The hovered cell shall remain visible, preferably at the same Y position as the pointer. The pointer shall jump to the new position of the cell so account for it being impossible to ensure that cell remains at the same X position as the pointer. + +Under "Go" add option to go to the same character in: + - All + - Block + - Primary script + - Next secondary script + - Previous secondary script + +Add command line options for opening into a specific character or codepoint + +Fix XXX's diff --git a/char-table.c b/char-table.c index 4aec952..7534600 100644 --- a/char-table.c +++ b/char-table.c @@ -54,6 +54,22 @@ apply_font_size(CharTable *this, int size, int *text_w_out, int *text_h_out) } +PURE static uint32_t +get_codepoint(CharTable *this, uint32_t index) +{ + size_t i = 0u; + uint32_t count; + + while (index >= (count = (uint32_t)LIBCMAP_RANGE_SIZE(&this->ranges[i]))) { + index -= count; + if (++i == this->nranges) + abort(); + } + + return this->ranges[i].first + index; +} + + static void fit_text(CharTable *this, const char *text, int *text_w_out, int *text_h_out) { @@ -110,18 +126,20 @@ get_exposed_cells(GtkWidget *widget, GdkEventExpose *event, struct cells *cells_ GdkRectangle area = event->area; LogicalScrollPane *scrolls = LOGICAL_SCROLL_PANE(gtk_widget_get_parent(widget)); GtkAdjustment *vadjustment = logical_scroll_pane_get_vadjustment(scrolls); + double y; - cells_out->r0 = area.y * this->nrows / this->viewport_h; - cells_out->c0 = area.x * this->ncols / this->viewport_w; - cells_out->r1 = (area.y + area.height - 1) * this->nrows / this->viewport_h + 1; - cells_out->c1 = (area.x + area.width - 1) * this->ncols / this->viewport_w + 1; + cells_out->r0 = area.y * this->nrows / (this->viewport_h + 1); + cells_out->c0 = area.x * this->ncols / (this->viewport_w + 1); + cells_out->r1 = (area.y + area.height - 1) * this->nrows / (this->viewport_h + 1) + 1; + cells_out->c1 = (area.x + area.width - 1) * this->ncols / (this->viewport_w + 1) + 1; cells_out->r0 = MAX(cells_out->r0, 0); cells_out->c0 = MAX(cells_out->c0, 0); cells_out->r1 = MIN(cells_out->r1, cells_out->r0 + this->nrows); cells_out->c1 = MIN(cells_out->c1, cells_out->c0 + this->ncols); - cells_out->r_off = MAX((int)vadjustment->value, 0); + y = round(vadjustment->value); + cells_out->r_off = MAX((int)y, 0); } @@ -136,7 +154,8 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) char text[16]; int r, c, x0, x1, y0, y1, text_w, text_h; size_t skip, range, row_skip, max_jump, jump; - uint32_t cp; + uint32_t cp, index; + GtkStateType selectedState = gtk_widget_has_focus(widget) ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE; get_exposed_cells(widget, event, &cells); @@ -166,8 +185,8 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) x1 = (this->viewport_w + 1) * cells.c1 / this->ncols; for (r = cells.r0 + (area.y > 0); r < cells.r1; r++, y0 = y1) { y1 = (this->viewport_h + 1) * (r + 1) / this->nrows; - cairo_move_to(g, x0, y0 + 0.5); - cairo_line_to(g, x1, y0 + 0.5); + cairo_move_to(g, x0, y0 - 0.5); + cairo_line_to(g, x1, y0 - 0.5); cairo_stroke(g); } /* vertical */ @@ -176,8 +195,8 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) y1 = (this->viewport_h + 1) * cells.r1 / this->nrows; for (c = cells.c0 + (area.x > 0); c < cells.c1; c++, x0 = x1) { x1 = (this->viewport_w + 1) * (c + 1) / this->ncols; - cairo_move_to(g, x0 + 0.5, y0); - cairo_line_to(g, x0 + 0.5, y1); + cairo_move_to(g, x0 - 0.5, y0); + cairo_line_to(g, x0 - 0.5, y1); cairo_stroke(g); } @@ -188,8 +207,9 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) cp = this->ranges[range].first; skip = (size_t)cells.r0 + (size_t)cells.r_off; skip = skip * (size_t)this->ncols + (size_t)cells.c0; + index = (uint32_t)skip; row_skip = (size_t)this->ncols - (size_t)(cells.c1 - cells.c0); - for (r = cells.r0; r < cells.r1; r++, y0 = y1, skip = row_skip) { + for (r = cells.r0; r < cells.r1; r++, y0 = y1, skip = row_skip, index += (uint32_t)row_skip) { while (skip) { max_jump = (size_t)(this->ranges[range].last - cp + 1u); jump = MIN(skip, max_jump); @@ -203,7 +223,7 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) } x0 = (this->viewport_w + 1) * cells.c0 / this->ncols; y1 = (this->viewport_h + 1) * (r + 1) / this->nrows; - for (c = cells.c0; c < cells.c1; c++, cp++, x0 = x1) { + for (c = cells.c0; c < cells.c1; c++, cp++, index++, x0 = x1) { if (cp > this->ranges[range].last) { if (++range == this->nranges) goto out; @@ -211,10 +231,20 @@ gcmap_char_table_expose(GtkWidget *widget, GdkEventExpose *event) } x1 = (this->viewport_w + 1) * (c + 1) / this->ncols; + if (index == this->selected) { + set_source_colour(g, &style->base[selectedState]); + cairo_rectangle(g, x0, y0, x1 - x0 - 1.0, y1 - y0 - 1.0); + cairo_fill(g); + set_source_colour(g, &style->text[selectedState]); + } + 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); + + if (index == this->selected) + set_source_colour(g, &style->text[GTK_STATE_ACTIVE]); } } @@ -257,6 +287,13 @@ update_cell_size(GtkWidget *widget, int ranges_changed) this->ncols = MAX(this->ncols, 1); this->nrows = MAX(this->nrows, 1); + if (this->snap_cols_to_2pow) + while (this->ncols & (this->ncols - 1)) + this->ncols &= this->ncols - 1; + if (this->snap_rows_to_2pow) + while (this->nrows & (this->nrows - 1)) + this->nrows &= this->nrows - 1; + cell_w = (this->viewport_w + 1) / this->ncols - 1; cell_h = (this->viewport_h + 1) / this->nrows - 1; cell_w = MAX(cell_w, 1); @@ -268,9 +305,9 @@ update_cell_size(GtkWidget *widget, int ranges_changed) this->cell_h = cell_h; if (ranges_changed) { - nchars = (uint32_t)this->nranges; + nchars = 0u; for (i = 0u; i < this->nranges; i++) - nchars += this->ranges[i].last - this->ranges[i].first; + nchars += (uint32_t)LIBCMAP_RANGE_SIZE(&this->ranges[i]); this->nchars = nchars; } } @@ -298,14 +335,94 @@ gcmap_char_table_size_request(GtkWidget *widget, GtkRequisition *requisition) requisition->height = 1; } + +static void +select_clicked_character(GtkWidget *widget, int meta, unsigned click_count, double x, double y) +{ + CharTable *this = GCMAP_CHAR_TABLE(widget); + LogicalScrollPane *scrolls = LOGICAL_SCROLL_PANE(gtk_widget_get_parent(widget)); + GtkAdjustment *vadjustment = logical_scroll_pane_get_vadjustment(scrolls); + double yadj = round(vadjustment->value); + int r0 = (int)yadj; + int r = (int)y * this->nrows / (this->viewport_h + 1); + int c = (int)x * this->ncols / (this->viewport_w + 1); + uint32_t selected; + r = MIN(MAX(0, r), this->nrows - 1); + c = MIN(MAX(0, c), this->ncols - 1); + selected = ((uint32_t)r + (uint32_t)r0) * (uint32_t)this->ncols + (uint32_t)c; + if (selected >= this->nchars) { + this->multiclick_count = 0u; + } else if (selected != this->selected) { + click_count = 1u; + clicked: + this->selected = selected; + if (this->selection_callback) + (*this->selection_callback)(selected, get_codepoint(this, selected), meta, click_count >= 2u); + this->multiclick_count = click_count == 1u ? 1u : 0u; + gtk_widget_queue_draw(GTK_WIDGET(this)); /* XXX just redraw the affected cells */ + } else if (click_count > this->multiclick_count) { + goto clicked; + } else { + this->multiclick_count = 0u; + } +} + + static gboolean -gcmap_char_table_button_press(GtkWidget *widget, GdkEventButton *event) +gcmap_char_table_button_press(GtkWidget *widget, GdkEventButton *event, void *user_data) { - (void) event; + unsigned click_count; + (void) user_data; gtk_widget_grab_focus(widget); - return FALSE; + if (event->button == 1 || event->button == 3) { + switch ((unsigned)event->type) { + default: + case GDK_BUTTON_PRESS: click_count = 1u; break; + case GDK_2BUTTON_PRESS: click_count = 2u; break; + case GDK_3BUTTON_PRESS: click_count = 3u; break; + } + select_clicked_character(widget, !!(event->state & GDK_MOD1_MASK), click_count, event->x, event->y); + } else { + GCMAP_CHAR_TABLE(widget)->multiclick_count = 0u; + } + return TRUE; +} + + +static gboolean +gcmap_char_table_key_press(GtkWidget *widget, GdkEventKey *event, void *user_data) +{ + CharTable *this = GCMAP_CHAR_TABLE(widget); + int meta; + + (void) user_data; + + if (event->state & GDK_CONTROL_MASK) + return FALSE; + + meta = !!(event->state & GDK_MOD1_MASK); + + switch (event->keyval) { + case GDK_KEY_Left: case GDK_KEY_KP_Left: gcmap_char_table_adjust_cell_selection(this, -1, 0, meta); break; + case GDK_KEY_Right: case GDK_KEY_KP_Right: gcmap_char_table_adjust_cell_selection(this, +1, 0, meta); break; + case GDK_KEY_Up: case GDK_KEY_KP_Up: gcmap_char_table_adjust_cell_selection(this, -this->ncols, 0, meta); break; + case GDK_KEY_Down: case GDK_KEY_KP_Down: gcmap_char_table_adjust_cell_selection(this, +this->ncols, 0, meta); break; + case GDK_KEY_Home: case GDK_KEY_KP_Home: gcmap_char_table_select_cell(this, 0, 0, meta); break; + case GDK_KEY_End: case GDK_KEY_KP_End: gcmap_char_table_select_cell(this, INT32_MAX, 1, meta); break; + case GDK_KEY_Return: case GDK_KEY_KP_Enter: + case GDK_KEY_Begin: case GDK_KEY_KP_Begin: + case GDK_KEY_space: + if (this->selection_callback) + (*this->selection_callback)(this->selected, get_codepoint(this, this->selected), meta, 1); + break; + default: + return FALSE; + } + + return TRUE; } + static void gcmap_char_table_init(CharTable *this) { @@ -317,10 +434,15 @@ gcmap_char_table_init(CharTable *this) this->max_h = 1; this->cell_h = 1; this->nchars = 0u; + this->selected = 0u; this->ranges = NULL; this->nranges = 0u; this->viewport_w = 1; this->viewport_h = 1; + this->snap_cols_to_2pow = 0; + this->snap_rows_to_2pow = 0; + this->multiclick_count = 0u; + this->selection_callback = NULL; GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS); gtk_widget_set_sensitive(widget, TRUE); @@ -330,8 +452,8 @@ gcmap_char_table_init(CharTable *this) GDK_KEY_PRESS_MASK | GDK_FOCUS_CHANGE_MASK); - g_signal_connect(widget, "button-press-event", - G_CALLBACK(&gcmap_char_table_button_press), NULL); + g_signal_connect(widget, "button-press-event", G_CALLBACK(&gcmap_char_table_button_press), NULL); + g_signal_connect(widget, "key-press-event", G_CALLBACK(&gcmap_char_table_key_press), NULL); } @@ -421,6 +543,28 @@ gcmap_char_table_set_font_size(CharTable *this, int size) void +gcmap_char_table_set_snap_cols_to_2pow(CharTable *this, int active) +{ + GtkWidget *widget = GTK_WIDGET(this); + this->snap_cols_to_2pow = active; + update_cell_size(widget, 0); + update_content_size(this); + gtk_widget_queue_draw(widget); +} + + +void +gcmap_char_table_set_snap_rows_to_2pow(CharTable *this, int active) +{ + GtkWidget *widget = GTK_WIDGET(this); + this->snap_rows_to_2pow = active; + update_cell_size(widget, 0); + update_content_size(this); + gtk_widget_queue_draw(widget); +} + + +void gcmap_char_table_set_ranges(CharTable *this, const struct libcmap_range *ranges, size_t nranges) { GtkWidget *widget; @@ -428,9 +572,12 @@ gcmap_char_table_set_ranges(CharTable *this, const struct libcmap_range *ranges, return; this->ranges = ranges; this->nranges = nranges; + this->selected = 0u; widget = GTK_WIDGET(this); update_cell_size(widget, 1); update_content_size(this); + if (this->selection_callback) + (*this->selection_callback)(this->selected, get_codepoint(this, this->selected), 0, 0); gtk_widget_queue_draw(widget); } @@ -469,3 +616,87 @@ gcmap_char_table_new(const char *font_family, int font_size, PangoWeight font_we return widget; } + + +void +gcmap_char_table_select_cell(CharTable *this, int32_t selected, int clamp, int meta) +{ + GtkWidget *widget = GTK_WIDGET(this); + LogicalScrollPane *scrolls = LOGICAL_SCROLL_PANE(gtk_widget_get_parent(widget)); + GtkAdjustment *vadjustment = logical_scroll_pane_get_vadjustment(scrolls); + double yadj = round(vadjustment->value); + int r0 = MAX((int)yadj, 0); + int r = r0; + int32_t first, last; + + if (selected < 0) { + if (!clamp || !this->nchars) + return; + selected = 0; + } else if ((uint32_t)selected >= this->nchars) { + if (!clamp) + return; + selected = (int32_t)(this->nchars - 1u); + } + + if ((uint32_t)selected == this->selected) + return; + + if (selected == 0) { + r = 0; + } else if (selected == (int32_t)this->nchars - 1) { + goto scroll_down; + } else if ((uint32_t)selected < this->selected) { + first = (int32_t)r0 * (int32_t)this->ncols; + if (selected < first) + r = (int)((uint32_t)selected / (uint32_t)this->ncols); + } else { + last = ((int32_t)r0 + (int32_t)this->nrows) * (int32_t)this->ncols - 1; + if (selected > last) { + scroll_down: + r = (int)((uint32_t)selected / (uint32_t)this->ncols); + r -= this->nrows - 1; + r = MAX(r, 0); + } + } + + this->selected = (uint32_t)selected; + if (this->selection_callback) + (*this->selection_callback)(this->selected, get_codepoint(this, this->selected), meta, 0); + + if (r == r0) { + gtk_widget_queue_draw(widget); /* XXX just redraw the affected cells */ + } else { + yadj = (double)r; + gtk_adjustment_set_value(vadjustment, yadj); + } +} + + +void +gcmap_char_table_adjust_cell_selection(CharTable *this, int32_t adjustment, int clamp, int meta) +{ + int32_t selected = (int32_t)this->selected; + gcmap_char_table_select_cell(this, selected + adjustment, clamp, meta); +} + + +int +gcmap_char_table_select_codepoint(CharTable *this, uint32_t codepoint) +{ + size_t i = 0u; + uint32_t index = 0u; + + while (i < this->nranges && codepoint > this->ranges[i].last) { + index += (uint32_t)LIBCMAP_RANGE_SIZE(&this->ranges[i]); + i += 1u; + } + + if (i >= this->nranges || codepoint < this->ranges[i].first) + return 0; + + index += codepoint - this->ranges[i].first; + + gcmap_char_table_select_cell(this, (int32_t)index, 0, 0); + return 1; +} diff --git a/char-table.h b/char-table.h index 1663c9c..6976156 100644 --- a/char-table.h +++ b/char-table.h @@ -15,15 +15,19 @@ typedef struct _CharTable { int nrows, ncols; int max_w, max_h; int cell_h; - uint32_t nchars; + uint32_t nchars, selected; int viewport_w, viewport_h; PangoFontDescription *font; PangoLayout *layout; int font_size; + int snap_cols_to_2pow; + int snap_rows_to_2pow; + unsigned multiclick_count; PangoWeight font_weight; PangoStyle font_style; const struct libcmap_range *ranges; size_t nranges; + void (*selection_callback)(uint32_t index, uint32_t codepoint, int meta, int copy_to_text_field); } CharTable; typedef struct _CharTableClass { @@ -38,5 +42,10 @@ 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_snap_cols_to_2pow(CharTable *this, int active); +void gcmap_char_table_set_snap_rows_to_2pow(CharTable *this, int active); 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); +void gcmap_char_table_select_cell(CharTable *this, int32_t selected, int clamp, int meta); +void gcmap_char_table_adjust_cell_selection(CharTable *this, int32_t adjustment, int clamp, int meta); +int gcmap_char_table_select_codepoint(CharTable *this, uint32_t codepoint); @@ -44,11 +44,16 @@ static GtkWidget *nextgroup; static GtkWidget *prevgroup; static GtkWidget *bylisting[NLISTINGS]; static GtkWidget *vtabtext; +static GtkWidget *snap2_cols; +static GtkWidget *snap2_rows; static GtkWidget *chartable; static GtkListStore *fontcombo_store; static GtkAdjustment *fontsize_adjustment; static GtkAccelGroup *accelgroup; +static uint32_t selected_codepoint = 0u; +static int switching_groups = 0; + #ifdef HAVE_ITEM_TOOLTIPS /* relying on initialisation to NULL and 0 */ static const char **group_tooltips[NLISTINGS]; @@ -58,6 +63,76 @@ static size_t ngroups_tooltips; #endif +static size_t +format_statusbar_message(char *buffer, size_t size) +{ + const struct libcmap_codepoint_data *data; + int r; + size_t len = 0u; + + r = snprintf(buffer, size, "U+%04"PRIX32, selected_codepoint); + if (r < 0) + eprintf("snprintf"); + len += (size_t)r; + buffer = &buffer[MIN(size, (size_t)r)]; + size -= MIN(size, (size_t)r); + + data = libcmap_find_codepoint_data(selected_codepoint); + if (!data) + return len; + + r = snprintf(buffer, size, " %s", data->name); + if (r < 0) + eprintf("snprintf"); + len += (size_t)r; + buffer = &buffer[MIN(size, (size_t)r)]; + size -= MIN(size, (size_t)r); + + return len; +} + + +static void +update_statusbar(void) +{ + size_t len = format_statusbar_message(NULL, 0u); + char *message = emalloc(++len); + format_statusbar_message(message, len); + gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 0u); + gtk_statusbar_push(GTK_STATUSBAR(statusbar), 0u, message); + free(message); +} + + +static void +character_cell_selected(uint32_t index, uint32_t codepoint, int meta, int copy_to_text_field) +{ + GtkEditable *editable; + char text[16]; + int len, pos; + + (void) index; + + text[len = g_unichar_to_utf8(codepoint, text)] = '\0'; + selected_codepoint = codepoint; + + if (copy_to_text_field) { + editable = GTK_EDITABLE(copytext); + pos = gtk_editable_get_position(editable); + gtk_editable_insert_text(editable, text, len, &pos); + gtk_editable_set_position(editable, pos); + } else if (meta) { + gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_SECONDARY), text, len); + /* XXX add setting to swap SECONDARY and PRIMARY */ + } else { + gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), text, len); + /* XXX add setting to disable */ + } + + update_statusbar(); +} + + static int populate_font_families(GtkWidget *widget, GtkListStore *store, const char **selectedp) { @@ -100,6 +175,18 @@ populate_font_families(GtkWidget *widget, GtkListStore *store, const char **sele } +static void +select_group(int index) +{ + GtkTreeView *treeview = GTK_TREE_VIEW(grouplist); + GtkTreePath *path = gtk_tree_path_new_from_indices(index, -1); + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + gtk_tree_selection_select_path(selection, path); + gtk_tree_view_set_cursor(treeview, path, NULL, FALSE); + gtk_tree_path_free(path); +} + + #ifdef HAVE_ITEM_TOOLTIPS @@ -226,6 +313,9 @@ grouplist_selection_changed(GtkTreeSelection *selection, void *user_data) (void) user_data; + if (switching_groups) + return; + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; @@ -388,8 +478,17 @@ static void listcombo_changed(GtkComboBox *combo, GtkListStore *store) { static int recursion_guard = 0; + GtkWidget *label; int listing; + int all_selected = 1; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + const struct libcmap_block *block; + const struct libcmap_script *script; + uint32_t codepoint = selected_codepoint; if (recursion_guard) return; @@ -397,6 +496,15 @@ listcombo_changed(GtkComboBox *combo, GtkListStore *store) listing = gtk_combo_box_get_active(combo); + switching_groups++; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(grouplist)); + if (gtk_tree_selection_get_selected(selection, &model, &iter)) { + path = gtk_tree_model_get_path(model, &iter); + all_selected = !gtk_tree_path_get_indices(path)[0u]; + gtk_tree_path_free(path); + } + switch (listing) { #define X(ENUM, TITLE, TYPE, SELFUN, POPFUN, ACCEL)\ case ENUM:\ @@ -416,7 +524,24 @@ listcombo_changed(GtkComboBox *combo, GtkListStore *store) if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(bylisting[listing]))) gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(bylisting[listing]), TRUE); - /* TODO select appropriate list item to keep select character */ + switching_groups--; + + if (all_selected) { + select_group(0); + } else { + switch ((enum listing)listing) { + case BY_BLOCK: + block = libcmap_find_block(codepoint, NULL); + select_group((block ? (int)(block - libcmap_block_list) : (int)libcmap_block_list_size) + 1); + break; + case BY_SCRIPT: + script = libcmap_find_script(codepoint, NULL, NULL); + select_group((script ? (int)(script - libcmap_script_list) : (int)libcmap_script_list_size) + 1); + break; + default: + abort(); + } + } recursion_guard--; } @@ -544,6 +669,24 @@ zoom_original(GtkWidget *menu_item, void *user_data) } +static void +snap2_cols_changed(GtkWidget *menu_item, void *user_data) +{ + (void) user_data; + gcmap_char_table_set_snap_cols_to_2pow(GCMAP_CHAR_TABLE(chartable), + gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))); +} + + +static void +snap2_rows_changed(GtkWidget *menu_item, void *user_data) +{ + (void) user_data; + gcmap_char_table_set_snap_rows_to_2pow(GCMAP_CHAR_TABLE(chartable), + gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_item))); +} + + static int zoom_original_accel(GtkAccelGroup *accel_group, GObject *acceleratable, unsigned int keyval, GdkModifierType modifier, void *user_data) @@ -557,18 +700,20 @@ zoom_original_accel(GtkAccelGroup *accel_group, GObject *acceleratable, unsigned } static void -go_next(GtkWidget *menu_item, void *user_data) /* TODO */ +go_next(GtkWidget *menu_item, void *user_data) { (void) menu_item; (void) user_data; + gcmap_char_table_adjust_cell_selection(GCMAP_CHAR_TABLE(chartable), +1, 0, 0); } static void -go_prev(GtkWidget *menu_item, void *user_data) /* TODO */ +go_prev(GtkWidget *menu_item, void *user_data) { (void) menu_item; (void) user_data; + gcmap_char_table_adjust_cell_selection(GCMAP_CHAR_TABLE(chartable), -1, 0, 0); } @@ -778,8 +923,8 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); vtabtext = add_check_menu_item(menu, "_Vertical tab text", 1, 0, 0, &vtabtext_changed); gtk_widget_set_sensitive(vtabtext, FALSE); - /* TODO add options to put some tabs in side-pane on the right */ - /* TODO add option for shorter tab texts */ + /* XXX add options to put some tabs in a side-pane on the right */ + /* XXX add option for shorter tab texts */ menu = add_menu(menubar, "_View"); group = NULL; @@ -787,7 +932,7 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d bylisting[ENUM] = add_radio_menu_item(menu, TITLE, &group, ACCEL, GDK_CONTROL_MASK, &SELFUN) LIST_LISTINGS(X, ;); #undef X - /* TODO add option to use character list (show glyphs with names in rows) instead of character grid */ + /* XXX add option to use character list (show glyphs with names in rows) instead of character grid */ gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); add_menu_item(menu, "_Larger glyphs", "zoom-in", GDK_plus, GDK_CONTROL_MASK, &zoom_in); add_menu_item(menu, "S_maller glyphs", "zoom-out", GDK_minus, GDK_CONTROL_MASK, &zoom_out); @@ -796,6 +941,9 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d g_cclosure_new(G_CALLBACK(&zoom_original_accel), NULL, NULL)); gtk_accel_group_connect(accelgroup, GDK_1, GDK_CONTROL_MASK, 0, g_cclosure_new(G_CALLBACK(&zoom_original_accel), NULL, NULL)); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); + snap2_cols = add_check_menu_item(menu, "Snap _columns to power of 2", 0, GDK_KEY_2, GDK_CONTROL_MASK, &snap2_cols_changed); + snap2_rows = add_check_menu_item(menu, "Snap _rows to power of 2", 0, GDK_KEY_3, GDK_CONTROL_MASK, &snap2_rows_changed); menu = add_menu(menubar, "_Go"); add_menu_item(menu, "_Next character", "go-next", GDK_n, GDK_CONTROL_MASK, &go_next); @@ -844,7 +992,7 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d small_font_size_increment, big_font_size_increment, 0); fontsize_adjustment = GTK_ADJUSTMENT(obj); sizespinner = gtk_spin_button_new(fontsize_adjustment, 0, 0); - g_signal_connect(fontsize_adjustment, "value-changed", G_CALLBACK(fontsize_changed), NULL); + g_signal_connect(fontsize_adjustment, "value-changed", G_CALLBACK(&fontsize_changed), NULL); gtk_box_pack_start(GTK_BOX(hbox), sizespinner, FALSE, FALSE, 0); accessible = gtk_widget_get_accessible(sizespinner); atk_object_set_name(accessible, "Font size"); @@ -880,7 +1028,6 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); - /* TODO character map tab pane (should have focus: gtk_widget_grab_focus(GTK_WIDGET(...)) */ scrolled = logical_scroll_pane_new(); logical_scroll_pane_set_hscrollbar_visible(LOGICAL_SCROLL_PANE(scrolled), FALSE); chartable = gcmap_char_table_new(default_font, (int)default_font_size, default_weight, default_style); @@ -892,7 +1039,7 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d 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_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Character _details")); #endif @@ -900,7 +1047,7 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d 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_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Glyph v_ariants")); #endif @@ -908,7 +1055,7 @@ create_window(const char *default_font, PangoWeight default_weight, PangoStyle d 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_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, gtk_label_new_with_mnemonic("Font c_omparison")); #endif @@ -1017,6 +1164,9 @@ main(int argc, char *argv[]) int min_font_size_set = 0; int max_font_size_set = 0; const char *font_family = DEFAULT_FONT_FAMILY; + const struct libcmap_block *block; + const struct libcmap_script *script; + char *message; ARGBEGIN { case 'B': @@ -1100,8 +1250,30 @@ main(int argc, char *argv[]) groups_tooltips = group_tooltips[listing]; ngroups_tooltips = ngroup_tooltips[listing]; - /* TODO select character (U+0000) and group (locate the one containing it, go to All if not found) */ + switch (listing) { + case BY_BLOCK: + block = libcmap_find_block(selected_codepoint, NULL); + select_group(block ? (int)(block - libcmap_block_list) + 1 : 0); + break; + case BY_SCRIPT: + script = libcmap_find_script(selected_codepoint, NULL, NULL); + select_group(script ? (int)(script - libcmap_script_list) + 1 : 0); + break; + default: + abort(); + } + GCMAP_CHAR_TABLE(chartable)->selection_callback = &character_cell_selected; + gcmap_char_table_select_codepoint(GCMAP_CHAR_TABLE(chartable), selected_codepoint); + + if (libsimple_asprintf(&message, "Using Unicode %s", libcmap_unicode_version) >= 0 && message) { + gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 0u); + gtk_statusbar_push(GTK_STATUSBAR(statusbar), 0u, message); + free(message); + } else { + update_statusbar(); + } gtk_window_present(GTK_WINDOW(window)); + gtk_widget_grab_focus(GTK_WIDGET(chartable)); gtk_main(); } diff --git a/logical-scroll-pane.c b/logical-scroll-pane.c index 207d34e..dd856a6 100644 --- a/logical-scroll-pane.c +++ b/logical-scroll-pane.c @@ -5,25 +5,9 @@ G_DEFINE_TYPE(LogicalScrollPane, logical_scroll_pane, GTK_TYPE_BIN) static void logical_scroll_pane_adjustment_value_changed(GtkAdjustment *adjustment, LogicalScrollPane *this) { -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - - double value; - if (this->viewport_size_is_logical) { - value = round(adjustment->value); - if (value != adjustment->value) { - gtk_adjustment_set_value(adjustment, value); - return; - } - } + (void) adjustment; if (this->child) gtk_widget_queue_draw(this->child); - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif } static void @@ -33,7 +17,7 @@ logical_scroll_pane_configure_adjustment(LogicalScrollPane *this, GtkAdjustment page_size = MAX(page_size, 1); pg = (double)page_size; upper = (double)MAX(content_size - page_size, 0); - value = this->viewport_size_is_logical ? round(adjustment->value) : adjustment->value; + value = adjustment->value; value = MAX(value, 0.0); value = MIN(value, upper); upper = (double)MAX(content_size, page_size); @@ -203,7 +187,7 @@ logical_scroll_pane_child_scroll(GtkWidget *widget, GdkEventScroll *event, Logic (void) widget; - switch (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_META_MASK)) { + switch (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) { case 0: switch (event->direction) { case GDK_SCROLL_LEFT: @@ -244,7 +228,7 @@ logical_scroll_pane_child_key_press(GtkWidget *widget, GdkEventKey *event, Logic (void) widget; - switch (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_META_MASK)) { + switch (event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) { case 0: break; case GDK_SHIFT_MASK: |
