diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2023-06-14 20:36:37 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2023-06-14 20:36:37 +0200 |
commit | bb80d3feebdc9acc52e3f4ad24084d8425f043a2 (patch) | |
tree | 2084a84c39f159c6aea254775dc0880d52579d45 /src/CheckerboardLayout.vala | |
parent | b26ff0798252a1a8072dd2c7a67f6205de9fde11 (diff) | |
parent | 31804433d72460cbe0a39f9f8ea5e76058d84cda (diff) |
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'src/CheckerboardLayout.vala')
-rw-r--r-- | src/CheckerboardLayout.vala | 922 |
1 files changed, 28 insertions, 894 deletions
diff --git a/src/CheckerboardLayout.vala b/src/CheckerboardLayout.vala index 70e3b5c..85232f3 100644 --- a/src/CheckerboardLayout.vala +++ b/src/CheckerboardLayout.vala @@ -4,824 +4,6 @@ * See the COPYING file in this distribution. */ -private class CheckerboardItemText { - private static int one_line_height = 0; - - private string text; - private bool marked_up; - private Pango.Alignment alignment; - private Pango.Layout layout = null; - private bool single_line = true; - private int height = 0; - - public Gdk.Rectangle allocation = Gdk.Rectangle(); - - public CheckerboardItemText(string text, Pango.Alignment alignment = Pango.Alignment.LEFT, - bool marked_up = false) { - this.text = text; - this.marked_up = marked_up; - this.alignment = alignment; - - single_line = is_single_line(); - } - - private bool is_single_line() { - return !String.contains_char(text, '\n'); - } - - public bool is_marked_up() { - return marked_up; - } - - public bool is_set_to(string text, bool marked_up, Pango.Alignment alignment) { - return (this.marked_up == marked_up && this.alignment == alignment && this.text == text); - } - - public string get_text() { - return text; - } - - public int get_height() { - if (height == 0) - update_height(); - - return height; - } - - public Pango.Layout get_pango_layout(int max_width = 0) { - if (layout == null) - create_pango(); - - if (max_width > 0) - layout.set_width(max_width * Pango.SCALE); - - return layout; - } - - public void clear_pango_layout() { - layout = null; - } - - private void update_height() { - if (one_line_height != 0 && single_line) - height = one_line_height; - else - create_pango(); - } - - private void create_pango() { - // create layout for this string and ellipsize so it never extends past its laid-down width - layout = AppWindow.get_instance().create_pango_layout(null); - if (!marked_up) - layout.set_text(text, -1); - else - layout.set_markup(text, -1); - - layout.set_ellipsize(Pango.EllipsizeMode.END); - layout.set_alignment(alignment); - - // getting pixel size is expensive, and we only need the height, so use cached values - // whenever possible - if (one_line_height != 0 && single_line) { - height = one_line_height; - } else { - int width; - layout.get_pixel_size(out width, out height); - - // cache first one-line height discovered - if (one_line_height == 0 && single_line) - one_line_height = height; - } - } -} - -public abstract class CheckerboardItem : ThumbnailView { - // Collection properties CheckerboardItem understands - // SHOW_TITLES (bool) - public const string PROP_SHOW_TITLES = "show-titles"; - // SHOW_COMMENTS (bool) - public const string PROP_SHOW_COMMENTS = "show-comments"; - // SHOW_SUBTITLES (bool) - public const string PROP_SHOW_SUBTITLES = "show-subtitles"; - - public const int FRAME_WIDTH = 8; - public const int LABEL_PADDING = 4; - public const int BORDER_WIDTH = 1; - - public const int SHADOW_RADIUS = 4; - public const float SHADOW_INITIAL_ALPHA = 0.5f; - - public const int TRINKET_SCALE = 12; - public const int TRINKET_PADDING = 1; - - public const int BRIGHTEN_SHIFT = 0x18; - - public Dimensions requisition = Dimensions(); - public Gdk.Rectangle allocation = Gdk.Rectangle(); - - private bool exposure = false; - private CheckerboardItemText? title = null; - private bool title_visible = true; - private CheckerboardItemText? comment = null; - private bool comment_visible = true; - private CheckerboardItemText? subtitle = null; - private bool subtitle_visible = false; - private bool is_cursor = false; - private Pango.Alignment tag_alignment = Pango.Alignment.LEFT; - private Gee.List<Tag>? user_visible_tag_list = null; - private Gee.Collection<Tag> tags; - private Gdk.Pixbuf pixbuf = null; - private Gdk.Pixbuf display_pixbuf = null; - private Gdk.Pixbuf brightened = null; - private Dimensions pixbuf_dim = Dimensions(); - private int col = -1; - private int row = -1; - private int horizontal_trinket_offset = 0; - - protected CheckerboardItem(ThumbnailSource source, Dimensions initial_pixbuf_dim, string title, string? comment, - bool marked_up = false, Pango.Alignment alignment = Pango.Alignment.LEFT) { - base(source); - - pixbuf_dim = initial_pixbuf_dim; - this.title = new CheckerboardItemText(title, alignment, marked_up); - // on the checkboard page we display the comment in - // one line, i.e., replacing all newlines with spaces. - // that means that the display will contain "..." if the comment - // is too long. - // warning: changes here have to be done in set_comment, too! - if (comment != null) - this.comment = new CheckerboardItemText(comment.replace("\n", " "), alignment, - marked_up); - - // Don't calculate size here, wait for the item to be assigned to a ViewCollection - // (notify_membership_changed) and calculate when the collection's property settings - // are known - } - - public bool has_tags { get; private set; } - - public override string get_name() { - return (title != null) ? title.get_text() : base.get_name(); - } - - public string get_title() { - return (title != null) ? title.get_text() : ""; - } - - public string get_comment() { - return (comment != null) ? comment.get_text() : ""; - } - - public void set_title(string text, bool marked_up = false, - Pango.Alignment alignment = Pango.Alignment.LEFT) { - if (title != null && title.is_set_to(text, marked_up, alignment)) - return; - - title = new CheckerboardItemText(text, alignment, marked_up); - - if (title_visible) { - recalc_size("set_title"); - notify_view_altered(); - } - } - - public void translate_coordinates(ref int x, ref int y) { - x -= allocation.x + FRAME_WIDTH; - y -= allocation.y + FRAME_WIDTH; - } - - public void clear_title() { - if (title == null) - return; - - title = null; - - if (title_visible) { - recalc_size("clear_title"); - notify_view_altered(); - } - } - - private void set_title_visible(bool visible) { - if (title_visible == visible) - return; - - title_visible = visible; - - recalc_size("set_title_visible"); - notify_view_altered(); - } - - public void set_comment(string text, bool marked_up = false, - Pango.Alignment alignment = Pango.Alignment.LEFT) { - if (comment != null && comment.is_set_to(text, marked_up, alignment)) - return; - - comment = new CheckerboardItemText(text.replace("\n", " "), alignment, marked_up); - - if (comment_visible) { - recalc_size("set_comment"); - notify_view_altered(); - } - } - - public void clear_comment() { - if (comment == null) - return; - - comment = null; - - if (comment_visible) { - recalc_size("clear_comment"); - notify_view_altered(); - } - } - - private void set_comment_visible(bool visible) { - if (comment_visible == visible) - return; - - comment_visible = visible; - - recalc_size("set_comment_visible"); - notify_view_altered(); - } - - public void set_tags(Gee.Collection<Tag>? tags, - Pango.Alignment alignment = Pango.Alignment.LEFT) { - has_tags = (tags != null && tags.size > 0); - tag_alignment = alignment; - string text; - if (has_tags) { - this.tags = tags; - user_visible_tag_list = Tag.make_user_visible_tag_list(tags); - text = Tag.make_tag_markup_string(user_visible_tag_list); - } else { - text = "<small>.</small>"; - } - - if (subtitle != null && subtitle.is_set_to(text, true, alignment)) - return; - subtitle = new CheckerboardItemText(text, alignment, true); - - if (subtitle_visible) { - recalc_size("set_subtitle"); - notify_view_altered(); - } - } - - public void clear_tags() { - clear_subtitle(); - has_tags = false; - user_visible_tag_list = null; - } - - public void highlight_user_visible_tag(int index) - requires (user_visible_tag_list != null) { - string text = Tag.make_tag_markup_string(user_visible_tag_list, index); - subtitle = new CheckerboardItemText(text, tag_alignment, true); - - if (subtitle_visible) - notify_view_altered(); - } - - public Tag get_user_visible_tag(int index) - requires (index >= 0 && index < user_visible_tag_list.size) { - return user_visible_tag_list.get(index); - } - - public Pango.Layout? get_tag_list_layout() { - return has_tags ? subtitle.get_pango_layout() : null; - } - - public Gdk.Rectangle get_subtitle_allocation() { - return subtitle.allocation; - } - - public string get_subtitle() { - return (subtitle != null) ? subtitle.get_text() : ""; - } - - public void set_subtitle(string text, bool marked_up = false, - Pango.Alignment alignment = Pango.Alignment.LEFT) { - if (subtitle != null && subtitle.is_set_to(text, marked_up, alignment)) - return; - - subtitle = new CheckerboardItemText(text, alignment, marked_up); - - if (subtitle_visible) { - recalc_size("set_subtitle"); - notify_view_altered(); - } - } - - public void clear_subtitle() { - if (subtitle == null) - return; - - subtitle = null; - - if (subtitle_visible) { - recalc_size("clear_subtitle"); - notify_view_altered(); - } - } - - private void set_subtitle_visible(bool visible) { - if (subtitle_visible == visible) - return; - - subtitle_visible = visible; - - recalc_size("set_subtitle_visible"); - notify_view_altered(); - } - - public void set_is_cursor(bool is_cursor) { - this.is_cursor = is_cursor; - } - - public bool get_is_cursor() { - return is_cursor; - } - - public virtual void handle_mouse_motion(int x, int y, int height, int width) { - - } - - public virtual void handle_mouse_leave() { - unbrighten(); - } - - public virtual void handle_mouse_enter() { - brighten(); - } - - protected override void notify_membership_changed(DataCollection? collection) { - bool title_visible = (bool) get_collection_property(PROP_SHOW_TITLES, true); - bool comment_visible = (bool) get_collection_property(PROP_SHOW_COMMENTS, true); - bool subtitle_visible = (bool) get_collection_property(PROP_SHOW_SUBTITLES, false); - - bool altered = false; - if (this.title_visible != title_visible) { - this.title_visible = title_visible; - altered = true; - } - - if (this.comment_visible != comment_visible) { - this.comment_visible = comment_visible; - altered = true; - } - - if (this.subtitle_visible != subtitle_visible) { - this.subtitle_visible = subtitle_visible; - altered = true; - } - - if (altered || !requisition.has_area()) { - recalc_size("notify_membership_changed"); - notify_view_altered(); - } - - base.notify_membership_changed(collection); - } - - protected override void notify_collection_property_set(string name, Value? old, Value val) { - switch (name) { - case PROP_SHOW_TITLES: - set_title_visible((bool) val); - break; - - case PROP_SHOW_COMMENTS: - set_comment_visible((bool) val); - break; - - case PROP_SHOW_SUBTITLES: - set_subtitle_visible((bool) val); - break; - } - - base.notify_collection_property_set(name, old, val); - } - - // The alignment point is the coordinate on the y-axis (relative to the top of the - // CheckerboardItem) which this item should be aligned to. This allows for - // bottom-alignment along the bottom edge of the thumbnail. - public int get_alignment_point() { - return FRAME_WIDTH + BORDER_WIDTH + pixbuf_dim.height; - } - - public virtual void exposed() { - exposure = true; - } - - public virtual void unexposed() { - exposure = false; - - if (title != null) - title.clear_pango_layout(); - - if (comment != null) - comment.clear_pango_layout(); - - if (subtitle != null) - subtitle.clear_pango_layout(); - } - - public virtual bool is_exposed() { - return exposure; - } - - public bool has_image() { - return pixbuf != null; - } - - public Gdk.Pixbuf? get_image() { - return pixbuf; - } - - public void set_image(Gdk.Pixbuf pixbuf) { - this.pixbuf = pixbuf; - display_pixbuf = pixbuf; - pixbuf_dim = Dimensions.for_pixbuf(pixbuf); - - recalc_size("set_image"); - notify_view_altered(); - } - - public void clear_image(Dimensions dim) { - bool had_image = pixbuf != null; - - pixbuf = null; - display_pixbuf = null; - pixbuf_dim = dim; - - recalc_size("clear_image"); - - if (had_image) - notify_view_altered(); - } - - public static int get_max_width(int scale) { - // width is frame width (two sides) + frame padding (two sides) + width of pixbuf (text - // never wider) - return (FRAME_WIDTH * 2) + scale; - } - - private void recalc_size(string reason) { - Dimensions old_requisition = requisition; - - // only add in the text heights if they're displayed - int title_height = (title != null && title_visible) - ? title.get_height() + LABEL_PADDING : 0; - int comment_height = (comment != null && comment_visible) - ? comment.get_height() + LABEL_PADDING : 0; - int subtitle_height = (subtitle != null && subtitle_visible) - ? subtitle.get_height() + LABEL_PADDING : 0; - - // width is frame width (two sides) + frame padding (two sides) + width of pixbuf - // (text never wider) - requisition.width = (FRAME_WIDTH * 2) + (BORDER_WIDTH * 2) + pixbuf_dim.width; - - // height is frame width (two sides) + frame padding (two sides) + height of pixbuf - // + height of text + label padding (between pixbuf and text) - requisition.height = (FRAME_WIDTH * 2) + (BORDER_WIDTH * 2) - + pixbuf_dim.height + title_height + comment_height + subtitle_height; - -#if TRACE_REFLOW_ITEMS - debug("recalc_size %s: %s title_height=%d comment_height=%d subtitle_height=%d requisition=%s", - get_source().get_name(), reason, title_height, comment_height, subtitle_height, - requisition.to_string()); -#endif - - if (!requisition.approx_equals(old_requisition)) { -#if TRACE_REFLOW_ITEMS - debug("recalc_size %s: %s notifying geometry altered", get_source().get_name(), reason); -#endif - notify_geometry_altered(); - } - } - - protected static Dimensions get_border_dimensions(Dimensions object_dim, int border_width) { - Dimensions dimensions = Dimensions(); - dimensions.width = object_dim.width + (border_width * 2); - dimensions.height = object_dim.height + (border_width * 2); - return dimensions; - } - - protected static Gdk.Point get_border_origin(Gdk.Point object_origin, int border_width) { - Gdk.Point origin = Gdk.Point(); - origin.x = object_origin.x - border_width; - origin.y = object_origin.y - border_width; - return origin; - } - - protected virtual void paint_shadow(Cairo.Context ctx, Dimensions dimensions, Gdk.Point origin, - int radius, float initial_alpha) { - double rgb_all = 0.0; - - // top right corner - paint_shadow_in_corner(ctx, origin.x + dimensions.width, origin.y + radius, rgb_all, radius, - initial_alpha, -0.5 * Math.PI, 0); - // bottom right corner - paint_shadow_in_corner(ctx, origin.x + dimensions.width, origin.y + dimensions.height, rgb_all, - radius, initial_alpha, 0, 0.5 * Math.PI); - // bottom left corner - paint_shadow_in_corner(ctx, origin.x + radius, origin.y + dimensions.height, rgb_all, radius, - initial_alpha, 0.5 * Math.PI, Math.PI); - - // left right - Cairo.Pattern lr = new Cairo.Pattern.linear(0, origin.y + dimensions.height, - 0, origin.y + dimensions.height + radius); - lr.add_color_stop_rgba(0.0, rgb_all, rgb_all, rgb_all, initial_alpha); - lr.add_color_stop_rgba(1.0, rgb_all, rgb_all, rgb_all, 0.0); - ctx.set_source(lr); - ctx.rectangle(origin.x + radius, origin.y + dimensions.height, dimensions.width - radius, radius); - ctx.fill(); - - // top down - Cairo.Pattern td = new Cairo.Pattern.linear(origin.x + dimensions.width, - 0, origin.x + dimensions.width + radius, 0); - td.add_color_stop_rgba(0.0, rgb_all, rgb_all, rgb_all, initial_alpha); - td.add_color_stop_rgba(1.0, rgb_all, rgb_all, rgb_all, 0.0); - ctx.set_source(td); - ctx.rectangle(origin.x + dimensions.width, origin.y + radius, - radius, dimensions.height - radius); - ctx.fill(); - } - - protected void paint_shadow_in_corner(Cairo.Context ctx, int x, int y, - double rgb_all, float radius, float initial_alpha, double arc1, double arc2) { - Cairo.Pattern p = new Cairo.Pattern.radial(x, y, 0, x, y, radius); - p.add_color_stop_rgba(0.0, rgb_all, rgb_all, rgb_all, initial_alpha); - p.add_color_stop_rgba(1.0, rgb_all, rgb_all, rgb_all, 0); - ctx.set_source(p); - ctx.move_to(x, y); - ctx.arc(x, y, radius, arc1, arc2); - ctx.close_path(); - ctx.fill(); - } - - protected virtual void paint_border(Cairo.Context ctx, Dimensions object_dimensions, - Gdk.Point object_origin, int border_width) { - if (border_width == 1) { - ctx.rectangle(object_origin.x - border_width, object_origin.y - border_width, - object_dimensions.width + (border_width * 2), - object_dimensions.height + (border_width * 2)); - ctx.fill(); - } else { - Dimensions dimensions = get_border_dimensions(object_dimensions, border_width); - Gdk.Point origin = get_border_origin(object_origin, border_width); - - // amount of rounding needed on corners varies by size of object - double scale = int.max(object_dimensions.width, object_dimensions.height); - draw_rounded_corners_filled(ctx, dimensions, origin, 0.25 * scale); - } - } - - protected virtual void paint_image(Cairo.Context ctx, Gdk.Pixbuf pixbuf, Gdk.Point origin) { - paint_pixmap_with_background(ctx, pixbuf, origin.x, origin.y); - } - - private int get_selection_border_width(int scale) { - return ((scale <= ((Thumbnail.MIN_SCALE + Thumbnail.MAX_SCALE) / 3)) ? 5 : 4) - + BORDER_WIDTH; - } - - protected virtual Gdk.Pixbuf? get_top_left_trinket(int scale) { - return null; - } - - protected virtual Gdk.Pixbuf? get_top_right_trinket(int scale) { - return null; - } - - protected virtual Gdk.Pixbuf? get_bottom_left_trinket(int scale) { - return null; - } - - protected virtual Gdk.Pixbuf? get_bottom_right_trinket(int scale) { - return null; - } - - public void paint(Gtk.StyleContext style_context, Cairo.Context ctx, Gdk.RGBA bg_color, Gdk.RGBA selected_color, - Gdk.RGBA? border_color, Gdk.RGBA? focus_color) { - ctx.save(); - ctx.translate(allocation.x + FRAME_WIDTH, - allocation.y + FRAME_WIDTH); - // calc the top-left point of the pixbuf - Gdk.Point pixbuf_origin = Gdk.Point(); - pixbuf_origin.x = BORDER_WIDTH; - pixbuf_origin.y = BORDER_WIDTH; - - ctx.set_line_width(FRAME_WIDTH); - ctx.set_source_rgba(selected_color.red, selected_color.green, selected_color.blue, - selected_color.alpha); - - // draw shadow - if (border_color != null) { - ctx.save(); - Dimensions shadow_dim = Dimensions(); - shadow_dim.width = pixbuf_dim.width + BORDER_WIDTH; - shadow_dim.height = pixbuf_dim.height + BORDER_WIDTH; - paint_shadow(ctx, shadow_dim, pixbuf_origin, SHADOW_RADIUS, SHADOW_INITIAL_ALPHA); - ctx.restore(); - } - - // draw a border for the cursor with the selection width and normal border color - if (is_cursor) { - ctx.save(); - ctx.set_source_rgba(focus_color.red, focus_color.green, focus_color.blue, - focus_color.alpha); - paint_border(ctx, pixbuf_dim, pixbuf_origin, - get_selection_border_width(int.max(pixbuf_dim.width, pixbuf_dim.height))); - ctx.restore(); - } - - // draw selection border - if (is_selected()) { - // border thickness depends on the size of the thumbnail - ctx.save(); - paint_border(ctx, pixbuf_dim, pixbuf_origin, - get_selection_border_width(int.max(pixbuf_dim.width, pixbuf_dim.height))); - ctx.restore(); - } - - if (display_pixbuf != null) { - ctx.save(); - ctx.set_source_rgba(bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha); - paint_image(ctx, display_pixbuf, pixbuf_origin); - ctx.restore(); - } - - // title and subtitles are LABEL_PADDING below bottom of pixbuf - int text_y = pixbuf_dim.height + FRAME_WIDTH + LABEL_PADDING; - if (title != null && title_visible) { - // get the layout sized so its width is no more than the pixbuf's - // resize the text width to be no more than the pixbuf's - title.allocation.x = 0; - title.allocation.y = text_y; - title.allocation.width = pixbuf_dim.width; - title.allocation.height = title.get_height(); - style_context.render_layout(ctx, title.allocation.x, title.allocation.y, - title.get_pango_layout(pixbuf_dim.width)); - - text_y += title.get_height() + LABEL_PADDING; - } - - if (comment != null && comment_visible) { - comment.allocation.x = 0; - comment.allocation.y = text_y; - comment.allocation.width = pixbuf_dim.width; - comment.allocation.height = comment.get_height(); - style_context.render_layout(ctx, comment.allocation.x, comment.allocation.y, - comment.get_pango_layout(pixbuf_dim.width)); - - text_y += comment.get_height() + LABEL_PADDING; - } - - if (subtitle != null && subtitle_visible) { - subtitle.allocation.x = 0; - subtitle.allocation.y = text_y; - subtitle.allocation.width = pixbuf_dim.width; - subtitle.allocation.height = subtitle.get_height(); - - style_context.render_layout(ctx, subtitle.allocation.x, subtitle.allocation.y, - subtitle.get_pango_layout(pixbuf_dim.width)); - - // increment text_y if more text lines follow - } - - ctx.set_source_rgba(selected_color.red, selected_color.green, selected_color.blue, - selected_color.alpha); - - // draw trinkets last - Gdk.Pixbuf? trinket = get_bottom_left_trinket(TRINKET_SCALE); - if (trinket != null) { - int x = pixbuf_origin.x + TRINKET_PADDING + get_horizontal_trinket_offset(); - int y = pixbuf_origin.y + pixbuf_dim.height - trinket.get_height() - - TRINKET_PADDING; - Gdk.cairo_set_source_pixbuf(ctx, trinket, x, y); - ctx.rectangle(x, y, trinket.get_width(), trinket.get_height()); - ctx.fill(); - } - - trinket = get_top_left_trinket(TRINKET_SCALE); - if (trinket != null) { - int x = pixbuf_origin.x + TRINKET_PADDING + get_horizontal_trinket_offset(); - int y = pixbuf_origin.y + TRINKET_PADDING; - Gdk.cairo_set_source_pixbuf(ctx, trinket, x, y); - ctx.rectangle(x, y, trinket.get_width(), trinket.get_height()); - ctx.fill(); - } - - trinket = get_top_right_trinket(TRINKET_SCALE); - if (trinket != null) { - int x = pixbuf_origin.x + pixbuf_dim.width - trinket.width - - get_horizontal_trinket_offset() - TRINKET_PADDING; - int y = pixbuf_origin.y + TRINKET_PADDING; - Gdk.cairo_set_source_pixbuf(ctx, trinket, x, y); - ctx.rectangle(x, y, trinket.get_width(), trinket.get_height()); - ctx.fill(); - } - - trinket = get_bottom_right_trinket(TRINKET_SCALE); - if (trinket != null) { - int x = pixbuf_origin.x + pixbuf_dim.width - trinket.width - - get_horizontal_trinket_offset() - TRINKET_PADDING; - int y = pixbuf_origin.y + pixbuf_dim.height - trinket.height - - TRINKET_PADDING; - Gdk.cairo_set_source_pixbuf(ctx, trinket, x, y); - ctx.rectangle(x, y, trinket.get_width(), trinket.get_height()); - ctx.fill(); - } - ctx.restore(); - } - - protected void set_horizontal_trinket_offset(int horizontal_trinket_offset) { - assert(horizontal_trinket_offset >= 0); - this.horizontal_trinket_offset = horizontal_trinket_offset; - } - - protected int get_horizontal_trinket_offset() { - return horizontal_trinket_offset; - } - - public void set_grid_coordinates(int col, int row) { - this.col = col; - this.row = row; - } - - public int get_column() { - return col; - } - - public int get_row() { - return row; - } - - public void brighten() { - // "should" implies "can" and "didn't already" - if (brightened != null || pixbuf == null) - return; - - // create a new lightened pixbuf to display - brightened = pixbuf.copy(); - shift_colors(brightened, BRIGHTEN_SHIFT, BRIGHTEN_SHIFT, BRIGHTEN_SHIFT, 0); - - display_pixbuf = brightened; - - notify_view_altered(); - } - - - public void unbrighten() { - // "should", "can", "didn't already" - if (brightened == null || pixbuf == null) - return; - - brightened = null; - - // return to the normal image - display_pixbuf = pixbuf; - - notify_view_altered(); - } - - public override void visibility_changed(bool visible) { - // if going from visible to hidden, unbrighten - if (!visible) - unbrighten(); - - base.visibility_changed(visible); - } - - private bool query_tooltip_on_text(CheckerboardItemText text, Gtk.Tooltip tooltip) { - if (!text.get_pango_layout().is_ellipsized()) - return false; - - if (text.is_marked_up()) - tooltip.set_markup(text.get_text()); - else - tooltip.set_text(text.get_text()); - - return true; - } - - public bool query_tooltip(int x, int y, Gtk.Tooltip tooltip) { - if (title != null && title_visible && coord_in_rectangle(x, y, title.allocation)) - return query_tooltip_on_text(title, tooltip); - - if (comment != null && comment_visible && coord_in_rectangle(x, y, comment.allocation)) - return query_tooltip_on_text(comment, tooltip); - - if (subtitle != null && subtitle_visible && coord_in_rectangle(x, y, subtitle.allocation)) - return query_tooltip_on_text(subtitle, tooltip); - - return false; - } -} - public class CheckerboardLayout : Gtk.DrawingArea { public const int TOP_PADDING = 16; public const int BOTTOM_PADDING = 16; @@ -836,7 +18,7 @@ public class CheckerboardLayout : Gtk.DrawingArea { // The number of pixels that the scrollbars of Gtk.ScrolledWindows allocate for themselves // before their final size is computed. This must be taken into account when computing // the width of this widget. This value was 0 in Gtk+ 2.x but is 1 in Gtk+ 3.x. See - // ticket #3870 (http://redmine.yorba.org/issues/3870) for more information + // ticket #3870 (https://bugzilla.gnome.org/show_bug.cgi?id=717754) for more information private const int SCROLLBAR_PLACEHOLDER_WIDTH = 1; private class LayoutRow { @@ -857,7 +39,6 @@ public class CheckerboardLayout : Gtk.DrawingArea { private Gee.HashSet<CheckerboardItem> exposed_items = new Gee.HashSet<CheckerboardItem>(); private Gtk.Adjustment hadjustment = null; private Gtk.Adjustment vadjustment = null; - private string message = null; private Gdk.RGBA selected_color; private Gdk.RGBA unselected_color; private Gdk.RGBA focus_color; @@ -963,23 +144,18 @@ public class CheckerboardLayout : Gtk.DrawingArea { Gtk.Allocation parent_allocation; parent.get_allocation(out parent_allocation); - if (message == null) { - // set the layout's new size to be the same as the parent's width but maintain - // it's own height + // set the layout's new size to be the same as the parent's width but maintain + // it's own height #if TRACE_REFLOW - debug("on_viewport_resized: due_to_reflow=%s set_size_request %dx%d", - size_allocate_due_to_reflow.to_string(), parent_allocation.width, req.height); + debug("on_viewport_resized: due_to_reflow=%s set_size_request %dx%d", + size_allocate_due_to_reflow.to_string(), parent_allocation.width, req.height); #endif - // But if the current height is 0, don't request a size yet. Delay - // it to do_reflow (bgo#766864) - if (req.height != 0) { - set_size_request(parent_allocation.width - SCROLLBAR_PLACEHOLDER_WIDTH, req.height); - } - } else { - // set the layout's width and height to always match the parent's - set_size_request(parent_allocation.width, parent_allocation.height); + // But if the current height is 0, don't request a size yet. Delay + // it to do_reflow (bgo#766864) + if (req.height != 0) { + set_size_request(parent_allocation.width - SCROLLBAR_PLACEHOLDER_WIDTH, req.height); } - + // possible for this widget's size_allocate not to be called, so need to update the page // rect here viewport_resized(); @@ -1070,8 +246,6 @@ public class CheckerboardLayout : Gtk.DrawingArea { private void on_contents_altered(Gee.Iterable<DataObject>? added, Gee.Iterable<DataObject>? removed) { - if (added != null) - message = null; if (removed != null) { foreach (DataObject object in removed) @@ -1142,31 +316,6 @@ public class CheckerboardLayout : Gtk.DrawingArea { queue_draw(); } - public void set_message(string? text) { - if (text == message) - return; - - message = text; - - if (text != null) { - // message is being set, change size to match parent's; if no parent, then the size - // will be set later when added to the parent - if (parent != null) { - Gtk.Allocation parent_allocation; - parent.get_allocation(out parent_allocation); - - set_size_request(parent_allocation.width, parent_allocation.height); - } - } else { - // message is being cleared, layout all the items again - need_reflow("set_message"); - } - } - - public void unset_message() { - set_message(null); - } - private void update_visible_page() { if (hadjustment != null && vadjustment != null) visible_page = get_adjustment_page(hadjustment, vadjustment); @@ -1185,7 +334,7 @@ public class CheckerboardLayout : Gtk.DrawingArea { } public CheckerboardItem? get_item_at_pixel(double xd, double yd) { - if (message != null || item_rows == null) + if (item_rows == null) return null; int x = (int) xd; @@ -1560,10 +709,6 @@ public class CheckerboardLayout : Gtk.DrawingArea { private void reflow(string caller) { reflow_needed = false; - // if set in message mode, nothing to do here - if (message != null) - return; - Gtk.Allocation allocation; get_allocation(out allocation); @@ -1957,35 +1102,17 @@ public class CheckerboardLayout : Gtk.DrawingArea { get_allocation(out allocation); get_style_context().render_background (ctx, 0, 0, allocation.width, allocation.height); - // watch for message mode - if (message == null) { #if TRACE_REFLOW - debug("draw %s: %s", page_name, rectangle_to_string(visible_page)); + debug("draw %s: %s", page_name, rectangle_to_string(visible_page)); #endif - - if (exposure_dirty) - expose_items("draw"); - - // have all items in the exposed area paint themselves - foreach (CheckerboardItem item in intersection(visible_page)) { - item.paint(get_style_context(), ctx, bg_color, item.is_selected() ? selected_color : unselected_color, - border_color, focus_color); - } - } else { - // draw the message in the center of the window - Pango.Layout pango_layout = create_pango_layout(message); - int text_width, text_height; - pango_layout.get_pixel_size(out text_width, out text_height); - - get_allocation(out allocation); - - int x = allocation.width - text_width; - x = (x > 0) ? x / 2 : 0; - - int y = allocation.height - text_height; - y = (y > 0) ? y / 2 : 0; - - get_style_context().render_layout(ctx, x, y, pango_layout); + + if (exposure_dirty) + expose_items("draw"); + + // have all items in the exposed area paint themselves + foreach (CheckerboardItem item in intersection(visible_page)) { + item.paint(get_style_context(), ctx, bg_color, item.is_selected() ? selected_color : unselected_color, + border_color, focus_color); } bool result = (base.draw != null) ? base.draw(ctx) : true; @@ -2025,7 +1152,14 @@ public class CheckerboardLayout : Gtk.DrawingArea { public override bool query_tooltip(int x, int y, bool keyboard_mode, Gtk.Tooltip tooltip) { CheckerboardItem? item = get_item_at_pixel(x, y); - return (item != null) ? item.query_tooltip(x, y, tooltip) : false; + // Note: X & Y allocations are relative to parents, so we need to query the item's tooltip + // relative to its INTERNAL coordinates, otherwise tooltips don't work + if (item != null) { + item.translate_coordinates(ref x, ref y); + return item.query_tooltip(x, y, tooltip); + } else { + return false; + } } private void on_colors_changed() { |