aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/util/scaling_image.vala
blob: d6ca31fdb62c0865066aad0db0546279555bcb3b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using Gdk;
using Gtk;

namespace Dino.Ui {

class FixedRatioLayout : Gtk.LayoutManager {
    public int min_width { get; set; default = 0; }
    public int target_width { get; set; default = -1; }
    public int max_width { get; set; default = int.MAX; }
    public int min_height { get; set; default = 0; }
    public int target_height { get; set; default = -1; }
    public int max_height { get; set; default = int.MAX; }

    public FixedRatioLayout() {
        this.notify.connect(layout_changed);
    }

    private void measure_target_size(Gtk.Widget widget, out int width, out int height) {
        if (target_width != -1 && target_height != -1) {
            width = target_width;
            height = target_height;
            return;
        }
        Widget child;
        width = min_width;
        height = min_height;

        child = widget.get_first_child();
        while (child != null) {
            if (child.should_layout()) {
                int child_min = 0;
                int child_nat = 0;
                int child_min_baseline = -1;
                int child_nat_baseline = -1;
                child.measure(Orientation.HORIZONTAL, -1, out child_min, out child_nat, out child_min_baseline, out child_nat_baseline);
                width = int.max(child_nat, width);
            }
            child = child.get_next_sibling();
        }
        width = int.min(width, max_width);

        child = widget.get_first_child();
        while (child != null) {
            if (child.should_layout()) {
                int child_min = 0;
                int child_nat = 0;
                int child_min_baseline = -1;
                int child_nat_baseline = -1;
                child.measure(Orientation.VERTICAL, width, out child_min, out child_nat, out child_min_baseline, out child_nat_baseline);
                height = int.max(child_nat, height);
            }
            child = child.get_next_sibling();
        }

        if (height > max_height) {
            height = max_height;
            width = min_width;

            child = widget.get_first_child();
            while (child != null) {
                if (child.should_layout()) {
                    int child_min = 0;
                    int child_nat = 0;
                    int child_min_baseline = -1;
                    int child_nat_baseline = -1;
                    child.measure(Orientation.HORIZONTAL, max_height, out child_min, out child_nat, out child_min_baseline, out child_nat_baseline);
                    width = int.max(child_nat, width);
                }
                child = child.get_next_sibling();
            }
            width = int.min(width, max_width);
        }
    }

    public override void measure(Gtk.Widget widget, Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) {
        minimum_baseline = -1;
        natural_baseline = -1;
        int width, height;
        measure_target_size(widget, out width, out height);
        if (orientation == Orientation.HORIZONTAL) {
            minimum = min_width;
            natural = width;
        } else if (for_size == -1) {
            minimum = min_height;
            natural = height;
        } else {
            minimum = natural = height * for_size / width;
        }
    }

    public override void allocate(Gtk.Widget widget, int width, int height, int baseline) {
        Widget child = widget.get_first_child();
        while (child != null) {
            if (child.should_layout()) {
                child.allocate(width, height, baseline, null);
            }
            child = child.get_next_sibling();
        }
    }

    public override SizeRequestMode get_request_mode(Gtk.Widget widget) {
        return SizeRequestMode.HEIGHT_FOR_WIDTH;
    }
}

class FixedRatioPicture : Gtk.Widget {
    public int min_width { get { return layout.min_width; } set { layout.min_width = value; } }
    public int target_width { get { return layout.target_width; } set { layout.target_width = value; } }
    public int max_width { get { return layout.max_width; } set { layout.max_width = value; } }
    public int min_height { get { return layout.min_height; } set { layout.min_height = value; } }
    public int target_height { get { return layout.target_height; } set { layout.target_height = value; } }
    public int max_height { get { return layout.max_height; } set { layout.max_height = value; } }
    public File file { get { return inner.file; } set { inner.file = value; } }
    public Gdk.Paintable paintable { get { return inner.paintable; } set { inner.paintable = value; } }
#if GTK_4_8 && VALA_0_58
    public Gtk.ContentFit content_fit { get { return inner.content_fit; } set { inner.content_fit = value; } }
#endif
    private Gtk.Picture inner = new Gtk.Picture();
    private FixedRatioLayout layout = new FixedRatioLayout();

    public FixedRatioPicture() {
        layout_manager = layout;
        inner.insert_after(this, null);
    }

    public override void dispose() {
        inner.unparent();
        base.dispose();
    }
}
}