Compare commits

..

No commits in common. "26a3c0c8251fd060b515aafe588dea844a20096c" and "33e98881ad787a93cc2fc2770c1c993d5bb65081" have entirely different histories.

4 changed files with 39 additions and 95 deletions

View File

@ -79,7 +79,7 @@ if (WITH_X11)
endif ()
pkg_check_modules (gtk gtk+-3.0)
option (WITH_GUI "Build an alternative GTK+ UI" ${gtk_FOUND})
option (WITH_GUI "Build a work-in-progress GTK+ UI" ${gtk_FOUND})
link_directories (${dependencies_LIBRARY_DIRS})
include_directories (${ZLIB_INCLUDE_DIRS} ${icu_INCLUDE_DIRS}

View File

@ -81,9 +81,8 @@ and general undesirability of terminal UIs, it might be better to start anew.
Graphical UI
------------
With GTK+ 3 development packages installed, an alternative frontend will be
built and installed. It shares the default dictionary list with 'sdtui',
but styling will follow your theme, and has to be customized from 'gtk.css'.
With GTK+ 3 development packages installed, an alternative, work-in-progress
frontend will be built and installed.
Contributing and Support
------------------------

View File

@ -246,30 +246,8 @@ main (int argc, char *argv[])
if (!load_dictionaries (g.dictionaries, &error))
die_with_dialog (error->message);
// Some Adwaita stupidity, plus defaults for our own widget.
// All the named colours have been there since GNOME 3.4
// (see gnome-extra-themes git history, Adwaita used to live there).
const char *style = "notebook header tab { padding: 2px 8px; margin: 0; }"
// `gsettings set org.gnome.desktop.interface gtk-key-theme "Emacs"`
// isn't quite what I want, and note that ^U works by default
"@binding-set Readline {"
"bind '<Control>H' { 'delete-from-cursor' (chars, -1) };"
"bind '<Control>W' { 'delete-from-cursor' (word-ends, -1) }; }"
"entry { -gtk-key-bindings: Readline }"
"stardict-view { padding: 0 .25em; }"
"stardict-view.odd {"
"background: @theme_base_color; "
"color: @theme_text_color; }"
"stardict-view.odd:backdrop {"
"background: @theme_unfocused_base_color; "
"color: @theme_fg_color; /* should be more faded than 'text' */ }"
"stardict-view.even {"
"background: mix(@theme_base_color, @theme_text_color, 0.02); "
"color: @theme_text_color; }"
"stardict-view.even:backdrop {"
"background: mix(@theme_unfocused_base_color, "
"@theme_fg_color, 0.02); "
"color: @theme_fg_color; /* should be more faded than 'text' */ }";
// Some Adwaita stupidity
const char *style = "notebook header tab { padding: 2px 8px; margin: 0; }";
GdkScreen *screen = gdk_screen_get_default ();
GtkCssProvider *provider = gtk_css_provider_new ();
@ -305,6 +283,9 @@ main (int argc, char *argv[])
// FIXME: when the clear icon shows, the widget changes in height
g.entry = gtk_search_entry_new ();
// TODO: attach to the "key-press-event" signal and implement ^W at least,
// though ^U is working already! Note that bindings can be done in CSS
// as well, if we have any extra specially for the editor
g_signal_connect (g.entry, "changed", G_CALLBACK (on_changed), g.view);
// TODO: make the entry have a background colour, rather than transparency
gtk_entry_set_has_frame (GTK_ENTRY (g.entry), FALSE);

View File

@ -136,36 +136,24 @@ view_entry_height (ViewEntry *ve, gint *word_offset, gint *defn_offset)
return MAX (word_y + word_h, defn_y + defn_h);
}
static GtkBorder
view_entry_get_padding (GtkStyleContext *style)
{
GtkBorder padding = {};
GtkStateFlags state = gtk_style_context_get_state (style);
gtk_style_context_get_padding (style, state, &padding);
return padding;
}
#define PADDING 5
static gint
view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width,
GtkStyleContext *style)
view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width, gboolean even)
{
// TODO: this shouldn't be hardcoded, read it out from somewhere
gdouble g = even ? 1. : .95;
gint word_y = 0, defn_y = 0,
height = view_entry_height (ve, &word_y, &defn_y);
cairo_rectangle (cr, 0, 0, full_width, height);
cairo_set_source_rgb (cr, g, g, g);
cairo_fill (cr);
gtk_render_background (style, cr, 0, 0, full_width, height);
gtk_render_frame (style, cr, 0, 0, full_width, height);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_move_to (cr, full_width / 2 + PADDING, defn_y);
pango_cairo_show_layout (cr, ve->definition_layout);
// Top/bottom and left/right-dependent padding will not work, too much code
GtkBorder padding = view_entry_get_padding (style);
gtk_style_context_save (style);
gtk_style_context_add_class (style, GTK_STYLE_CLASS_RIGHT);
gtk_render_layout (style, cr,
full_width / 2 + padding.left, defn_y, ve->definition_layout);
gtk_style_context_restore (style);
gtk_style_context_save (style);
gtk_style_context_add_class (style, GTK_STYLE_CLASS_LEFT);
PangoLayoutIter *iter = pango_layout_get_iter (ve->definition_layout);
do
{
@ -174,43 +162,36 @@ view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width,
PangoRectangle logical = {};
pango_layout_iter_get_line_extents (iter, NULL, &logical);
gtk_render_layout (style, cr,
padding.left, word_y + PANGO_PIXELS (logical.y), ve->word_layout);
cairo_move_to (cr, PADDING, word_y + PANGO_PIXELS (logical.y));
pango_cairo_show_layout (cr, ve->word_layout);
}
while (pango_layout_iter_next_line (iter));
pango_layout_iter_free (iter);
gtk_style_context_restore (style);
return height;
}
static void
view_entry_rebuild_layouts (ViewEntry *ve, GtkWidget *widget)
view_entry_rebuild_layout (ViewEntry *ve, PangoContext *pc, gint width)
{
PangoContext *pc = gtk_widget_get_pango_context (widget);
GtkStyleContext *style = gtk_widget_get_style_context (widget);
gint full_width = gtk_widget_get_allocated_width (widget);
g_clear_object (&ve->word_layout);
g_clear_object (&ve->definition_layout);
GtkBorder padding = view_entry_get_padding (style);
gint part_width = full_width / 2 - padding.left - padding.right;
if (part_width < 1)
int left_width = width / 2 - 2 * PADDING;
int right_width = width - left_width - 2 * PADDING;
if (left_width < 1 || right_width < 1)
return;
// Left/right-dependent fonts aren't supported (GTK_STYLE_PROPERTY_FONT)
// TODO: preferably pre-validate the layouts with pango_parse_markup(),
// so that it doesn't warn without indication on the frontend
ve->word_layout = pango_layout_new (pc);
pango_layout_set_markup (ve->word_layout, ve->word, -1);
pango_layout_set_ellipsize (ve->word_layout, PANGO_ELLIPSIZE_END);
pango_layout_set_single_paragraph_mode (ve->word_layout, TRUE);
pango_layout_set_width (ve->word_layout, PANGO_SCALE * part_width);
pango_layout_set_width (ve->word_layout, PANGO_SCALE * left_width);
ve->definition_layout = pango_layout_new (pc);
pango_layout_set_markup (ve->definition_layout, ve->definition, -1);
pango_layout_set_width (ve->definition_layout, PANGO_SCALE * part_width);
pango_layout_set_wrap (ve->definition_layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_width (ve->definition_layout, PANGO_SCALE * right_width);
}
// --- Widget ------------------------------------------------------------------
@ -233,9 +214,12 @@ struct _StardictView
static ViewEntry *
make_entry (StardictView *self, StardictIterator *iterator)
{
const gchar *matched = self->matched ? self->matched : "";
ViewEntry *ve = view_entry_new (iterator, matched);
view_entry_rebuild_layouts (ve, GTK_WIDGET (self));
ViewEntry *ve =
view_entry_new (iterator, self->matched ? self->matched : "");
GtkWidget *widget = GTK_WIDGET (self);
view_entry_rebuild_layout (ve, gtk_widget_get_pango_context (widget),
gtk_widget_get_allocated_width (widget));
return ve;
}
@ -370,12 +354,10 @@ stardict_view_get_preferred_height (GtkWidget *widget,
}
static void
stardict_view_get_preferred_width (GtkWidget *widget,
stardict_view_get_preferred_width (GtkWidget *widget G_GNUC_UNUSED,
gint *minimum, gint *natural)
{
GtkStyleContext *style = gtk_widget_get_style_context (widget);
GtkBorder padding = view_entry_get_padding (style);
*natural = *minimum = 2 * (padding.left + 1 * padding.right);
*natural = *minimum = 4 * PADDING;
}
static void
@ -405,7 +387,9 @@ stardict_view_realize (GtkWidget *widget)
GdkWindow *window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL);
// The default background colour of the GDK window is transparent
// The default background colour of the GDK window is transparent,
// we'll keep it that way, rather than apply the style context.
gtk_widget_register_window (widget, window);
gtk_widget_set_window (widget, window);
gtk_widget_set_realized (widget, TRUE);
@ -419,33 +403,15 @@ stardict_view_draw (GtkWidget *widget, cairo_t *cr)
GtkAllocation allocation;
gtk_widget_get_allocation (widget, &allocation);
GtkStyleContext *style = gtk_widget_get_style_context (widget);
gtk_render_background (style, cr,
0, 0, allocation.width, allocation.height);
gtk_render_frame (style, cr,
0, 0, allocation.width, allocation.height);
gint offset = -self->top_offset;
gint i = self->top_position;
for (GList *iter = self->entries; iter; iter = iter->next)
{
// Style regions would be appropriate, if they weren't deprecated.
// GTK+ CSS gadgets/notes are an internal API. We don't want to turn
// this widget into a container, to avoid needless complexity.
//
// gtk_style_context_{get,set}_path() may be misused by adding the same
// GType with gtk_widget_path_append_type() and changing its name
// using gtk_widget_path_iter_set_name()... but that is ugly.
gtk_style_context_save (style);
gtk_style_context_add_class (style, (i++ & 1) ? "even" : "odd");
cairo_save (cr);
cairo_translate (cr, 0, offset);
// TODO: later exclude clipped entries, but it's not that important
offset += view_entry_draw (iter->data, cr, allocation.width, style);
offset += view_entry_draw (iter->data, cr, allocation.width, i++ & 1);
cairo_restore (cr);
gtk_style_context_restore (style);
}
return TRUE;
}
@ -510,8 +476,6 @@ stardict_view_class_init (StardictViewClass *klass)
widget_class->size_allocate = stardict_view_size_allocate;
widget_class->screen_changed = stardict_view_screen_changed;
widget_class->scroll_event = stardict_view_scroll_event;
gtk_widget_class_set_css_name (widget_class, "stardict-view");
}
static void