Compare commits
No commits in common. "26a3c0c8251fd060b515aafe588dea844a20096c" and "33e98881ad787a93cc2fc2770c1c993d5bb65081" have entirely different histories.
26a3c0c825
...
33e98881ad
@ -79,7 +79,7 @@ if (WITH_X11)
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
pkg_check_modules (gtk gtk+-3.0)
|
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})
|
link_directories (${dependencies_LIBRARY_DIRS})
|
||||||
include_directories (${ZLIB_INCLUDE_DIRS} ${icu_INCLUDE_DIRS}
|
include_directories (${ZLIB_INCLUDE_DIRS} ${icu_INCLUDE_DIRS}
|
||||||
|
@ -81,9 +81,8 @@ and general undesirability of terminal UIs, it might be better to start anew.
|
|||||||
|
|
||||||
Graphical UI
|
Graphical UI
|
||||||
------------
|
------------
|
||||||
With GTK+ 3 development packages installed, an alternative frontend will be
|
With GTK+ 3 development packages installed, an alternative, work-in-progress
|
||||||
built and installed. It shares the default dictionary list with 'sdtui',
|
frontend will be built and installed.
|
||||||
but styling will follow your theme, and has to be customized from 'gtk.css'.
|
|
||||||
|
|
||||||
Contributing and Support
|
Contributing and Support
|
||||||
------------------------
|
------------------------
|
||||||
|
29
src/sdgui.c
29
src/sdgui.c
@ -246,30 +246,8 @@ main (int argc, char *argv[])
|
|||||||
if (!load_dictionaries (g.dictionaries, &error))
|
if (!load_dictionaries (g.dictionaries, &error))
|
||||||
die_with_dialog (error->message);
|
die_with_dialog (error->message);
|
||||||
|
|
||||||
// Some Adwaita stupidity, plus defaults for our own widget.
|
// Some Adwaita stupidity
|
||||||
// All the named colours have been there since GNOME 3.4
|
const char *style = "notebook header tab { padding: 2px 8px; margin: 0; }";
|
||||||
// (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' */ }";
|
|
||||||
|
|
||||||
GdkScreen *screen = gdk_screen_get_default ();
|
GdkScreen *screen = gdk_screen_get_default ();
|
||||||
GtkCssProvider *provider = gtk_css_provider_new ();
|
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
|
// FIXME: when the clear icon shows, the widget changes in height
|
||||||
g.entry = gtk_search_entry_new ();
|
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);
|
g_signal_connect (g.entry, "changed", G_CALLBACK (on_changed), g.view);
|
||||||
// TODO: make the entry have a background colour, rather than transparency
|
// TODO: make the entry have a background colour, rather than transparency
|
||||||
gtk_entry_set_has_frame (GTK_ENTRY (g.entry), FALSE);
|
gtk_entry_set_has_frame (GTK_ENTRY (g.entry), FALSE);
|
||||||
|
@ -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);
|
return MAX (word_y + word_h, defn_y + defn_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkBorder
|
#define PADDING 5
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width,
|
view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width, gboolean even)
|
||||||
GtkStyleContext *style)
|
|
||||||
{
|
{
|
||||||
|
// TODO: this shouldn't be hardcoded, read it out from somewhere
|
||||||
|
gdouble g = even ? 1. : .95;
|
||||||
|
|
||||||
gint word_y = 0, defn_y = 0,
|
gint word_y = 0, defn_y = 0,
|
||||||
height = view_entry_height (ve, &word_y, &defn_y);
|
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);
|
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||||
gtk_render_frame (style, cr, 0, 0, full_width, height);
|
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);
|
PangoLayoutIter *iter = pango_layout_get_iter (ve->definition_layout);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -174,43 +162,36 @@ view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width,
|
|||||||
|
|
||||||
PangoRectangle logical = {};
|
PangoRectangle logical = {};
|
||||||
pango_layout_iter_get_line_extents (iter, NULL, &logical);
|
pango_layout_iter_get_line_extents (iter, NULL, &logical);
|
||||||
gtk_render_layout (style, cr,
|
cairo_move_to (cr, PADDING, word_y + PANGO_PIXELS (logical.y));
|
||||||
padding.left, word_y + PANGO_PIXELS (logical.y), ve->word_layout);
|
pango_cairo_show_layout (cr, ve->word_layout);
|
||||||
}
|
}
|
||||||
while (pango_layout_iter_next_line (iter));
|
while (pango_layout_iter_next_line (iter));
|
||||||
pango_layout_iter_free (iter);
|
pango_layout_iter_free (iter);
|
||||||
gtk_style_context_restore (style);
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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->word_layout);
|
||||||
g_clear_object (&ve->definition_layout);
|
g_clear_object (&ve->definition_layout);
|
||||||
|
|
||||||
GtkBorder padding = view_entry_get_padding (style);
|
int left_width = width / 2 - 2 * PADDING;
|
||||||
gint part_width = full_width / 2 - padding.left - padding.right;
|
int right_width = width - left_width - 2 * PADDING;
|
||||||
if (part_width < 1)
|
if (left_width < 1 || right_width < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Left/right-dependent fonts aren't supported (GTK_STYLE_PROPERTY_FONT)
|
|
||||||
// TODO: preferably pre-validate the layouts with pango_parse_markup(),
|
// TODO: preferably pre-validate the layouts with pango_parse_markup(),
|
||||||
// so that it doesn't warn without indication on the frontend
|
// so that it doesn't warn without indication on the frontend
|
||||||
ve->word_layout = pango_layout_new (pc);
|
ve->word_layout = pango_layout_new (pc);
|
||||||
pango_layout_set_markup (ve->word_layout, ve->word, -1);
|
pango_layout_set_markup (ve->word_layout, ve->word, -1);
|
||||||
pango_layout_set_ellipsize (ve->word_layout, PANGO_ELLIPSIZE_END);
|
pango_layout_set_ellipsize (ve->word_layout, PANGO_ELLIPSIZE_END);
|
||||||
pango_layout_set_single_paragraph_mode (ve->word_layout, TRUE);
|
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);
|
ve->definition_layout = pango_layout_new (pc);
|
||||||
pango_layout_set_markup (ve->definition_layout, ve->definition, -1);
|
pango_layout_set_markup (ve->definition_layout, ve->definition, -1);
|
||||||
pango_layout_set_width (ve->definition_layout, PANGO_SCALE * part_width);
|
pango_layout_set_width (ve->definition_layout, PANGO_SCALE * right_width);
|
||||||
pango_layout_set_wrap (ve->definition_layout, PANGO_WRAP_WORD_CHAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Widget ------------------------------------------------------------------
|
// --- Widget ------------------------------------------------------------------
|
||||||
@ -233,9 +214,12 @@ struct _StardictView
|
|||||||
static ViewEntry *
|
static ViewEntry *
|
||||||
make_entry (StardictView *self, StardictIterator *iterator)
|
make_entry (StardictView *self, StardictIterator *iterator)
|
||||||
{
|
{
|
||||||
const gchar *matched = self->matched ? self->matched : "";
|
ViewEntry *ve =
|
||||||
ViewEntry *ve = view_entry_new (iterator, matched);
|
view_entry_new (iterator, self->matched ? self->matched : "");
|
||||||
view_entry_rebuild_layouts (ve, GTK_WIDGET (self));
|
|
||||||
|
GtkWidget *widget = GTK_WIDGET (self);
|
||||||
|
view_entry_rebuild_layout (ve, gtk_widget_get_pango_context (widget),
|
||||||
|
gtk_widget_get_allocated_width (widget));
|
||||||
return ve;
|
return ve;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,12 +354,10 @@ stardict_view_get_preferred_height (GtkWidget *widget,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stardict_view_get_preferred_width (GtkWidget *widget,
|
stardict_view_get_preferred_width (GtkWidget *widget G_GNUC_UNUSED,
|
||||||
gint *minimum, gint *natural)
|
gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
GtkStyleContext *style = gtk_widget_get_style_context (widget);
|
*natural = *minimum = 4 * PADDING;
|
||||||
GtkBorder padding = view_entry_get_padding (style);
|
|
||||||
*natural = *minimum = 2 * (padding.left + 1 * padding.right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -405,7 +387,9 @@ stardict_view_realize (GtkWidget *widget)
|
|||||||
GdkWindow *window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
GdkWindow *window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
||||||
&attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL);
|
&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_register_window (widget, window);
|
||||||
gtk_widget_set_window (widget, window);
|
gtk_widget_set_window (widget, window);
|
||||||
gtk_widget_set_realized (widget, TRUE);
|
gtk_widget_set_realized (widget, TRUE);
|
||||||
@ -419,33 +403,15 @@ stardict_view_draw (GtkWidget *widget, cairo_t *cr)
|
|||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
gtk_widget_get_allocation (widget, &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 offset = -self->top_offset;
|
||||||
gint i = self->top_position;
|
gint i = self->top_position;
|
||||||
for (GList *iter = self->entries; iter; iter = iter->next)
|
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_save (cr);
|
||||||
cairo_translate (cr, 0, offset);
|
cairo_translate (cr, 0, offset);
|
||||||
// TODO: later exclude clipped entries, but it's not that important
|
// 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);
|
cairo_restore (cr);
|
||||||
|
|
||||||
gtk_style_context_restore (style);
|
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -510,8 +476,6 @@ stardict_view_class_init (StardictViewClass *klass)
|
|||||||
widget_class->size_allocate = stardict_view_size_allocate;
|
widget_class->size_allocate = stardict_view_size_allocate;
|
||||||
widget_class->screen_changed = stardict_view_screen_changed;
|
widget_class->screen_changed = stardict_view_screen_changed;
|
||||||
widget_class->scroll_event = stardict_view_scroll_event;
|
widget_class->scroll_event = stardict_view_scroll_event;
|
||||||
|
|
||||||
gtk_widget_class_set_css_name (widget_class, "stardict-view");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
x
Reference in New Issue
Block a user