|
|
|
|
@@ -136,24 +136,36 @@ view_entry_height (ViewEntry *ve, gint *word_offset, gint *defn_offset)
|
|
|
|
|
return MAX (word_y + word_h, defn_y + defn_h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define PADDING 5
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width, gboolean even)
|
|
|
|
|
view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width,
|
|
|
|
|
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,
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
gtk_render_background (style, cr, 0, 0, full_width, height);
|
|
|
|
|
gtk_render_frame (style, cr, 0, 0, full_width, height);
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
{
|
|
|
|
|
@@ -162,36 +174,43 @@ view_entry_draw (ViewEntry *ve, cairo_t *cr, gint full_width, gboolean even)
|
|
|
|
|
|
|
|
|
|
PangoRectangle logical = {};
|
|
|
|
|
pango_layout_iter_get_line_extents (iter, NULL, &logical);
|
|
|
|
|
cairo_move_to (cr, PADDING, word_y + PANGO_PIXELS (logical.y));
|
|
|
|
|
pango_cairo_show_layout (cr, ve->word_layout);
|
|
|
|
|
gtk_render_layout (style, cr,
|
|
|
|
|
padding.left, word_y + PANGO_PIXELS (logical.y), 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_layout (ViewEntry *ve, PangoContext *pc, gint width)
|
|
|
|
|
view_entry_rebuild_layouts (ViewEntry *ve, GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
int left_width = width / 2 - 2 * PADDING;
|
|
|
|
|
int right_width = width - left_width - 2 * PADDING;
|
|
|
|
|
if (left_width < 1 || right_width < 1)
|
|
|
|
|
GtkBorder padding = view_entry_get_padding (style);
|
|
|
|
|
gint part_width = full_width / 2 - padding.left - padding.right;
|
|
|
|
|
if (part_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 * left_width);
|
|
|
|
|
pango_layout_set_width (ve->word_layout, PANGO_SCALE * part_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 * right_width);
|
|
|
|
|
pango_layout_set_width (ve->definition_layout, PANGO_SCALE * part_width);
|
|
|
|
|
pango_layout_set_wrap (ve->definition_layout, PANGO_WRAP_WORD_CHAR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Widget ------------------------------------------------------------------
|
|
|
|
|
@@ -214,12 +233,9 @@ struct _StardictView
|
|
|
|
|
static ViewEntry *
|
|
|
|
|
make_entry (StardictView *self, StardictIterator *iterator)
|
|
|
|
|
{
|
|
|
|
|
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));
|
|
|
|
|
const gchar *matched = self->matched ? self->matched : "";
|
|
|
|
|
ViewEntry *ve = view_entry_new (iterator, matched);
|
|
|
|
|
view_entry_rebuild_layouts (ve, GTK_WIDGET (self));
|
|
|
|
|
return ve;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -354,10 +370,12 @@ stardict_view_get_preferred_height (GtkWidget *widget,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
stardict_view_get_preferred_width (GtkWidget *widget G_GNUC_UNUSED,
|
|
|
|
|
stardict_view_get_preferred_width (GtkWidget *widget,
|
|
|
|
|
gint *minimum, gint *natural)
|
|
|
|
|
{
|
|
|
|
|
*natural = *minimum = 4 * PADDING;
|
|
|
|
|
GtkStyleContext *style = gtk_widget_get_style_context (widget);
|
|
|
|
|
GtkBorder padding = view_entry_get_padding (style);
|
|
|
|
|
*natural = *minimum = 2 * (padding.left + 1 * padding.right);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
@@ -387,9 +405,7 @@ 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,
|
|
|
|
|
// we'll keep it that way, rather than apply the style context.
|
|
|
|
|
|
|
|
|
|
// The default background colour of the GDK window is transparent
|
|
|
|
|
gtk_widget_register_window (widget, window);
|
|
|
|
|
gtk_widget_set_window (widget, window);
|
|
|
|
|
gtk_widget_set_realized (widget, TRUE);
|
|
|
|
|
@@ -403,15 +419,33 @@ 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, i++ & 1);
|
|
|
|
|
offset += view_entry_draw (iter->data, cr, allocation.width, style);
|
|
|
|
|
cairo_restore (cr);
|
|
|
|
|
|
|
|
|
|
gtk_style_context_restore (style);
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
@@ -476,6 +510,8 @@ 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
|
|
|
|
|
|