aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-06-07 17:04:14 +0200
committerMattias Andrée <m@maandree.se>2026-06-07 17:04:14 +0200
commitf0e237344af327be7828b6f03a3588a76e867fa3 (patch)
treec8f401428ca767143e68321a366036ae82ea82f5
parentwhitespace fix (diff)
downloadgcmap-f0e237344af327be7828b6f03a3588a76e867fa3.tar.gz
gcmap-f0e237344af327be7828b6f03a3588a76e867fa3.tar.bz2
gcmap-f0e237344af327be7828b6f03a3588a76e867fa3.tar.xz
Misc
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--char-table.c330
-rw-r--r--char-table.h22
-rw-r--r--gcmap.c126
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);
diff --git a/gcmap.c b/gcmap.c
index e134cf4..dbced41 100644
--- a/gcmap.c
+++ b/gcmap.c
@@ -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(&gtk_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();