]> gitweb.factorcode.org Git - factor.git/blob - basis/ui/baseline-alignment/baseline-alignment.factor
ui.baseline-alignment: fix float shift on retina.
[factor.git] / basis / ui / baseline-alignment / baseline-alignment.factor
1 ! Copyright (C) 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays kernel locals math math.functions math.order math.vectors
4 sequences ui.gadgets accessors combinators ;
5 IN: ui.baseline-alignment
6
7 SYMBOL: +baseline+
8
9
10 TUPLE: aligned-gadget < gadget baseline cap-height ;
11
12 GENERIC: baseline* ( gadget -- y )
13
14 GENERIC: baseline ( gadget -- y )
15
16 M: gadget baseline drop f ;
17
18 M: aligned-gadget baseline
19     dup baseline>>
20     [ ] [
21         [ baseline* ] [ ] [ layout-state>> ] tri
22         [ drop ] [ dupd baseline<< ] if
23     ] ?if ;
24
25 GENERIC: cap-height* ( gadget -- y )
26
27 GENERIC: cap-height ( gadget -- y )
28
29 M: gadget cap-height drop f ;
30
31 M: aligned-gadget cap-height
32     dup cap-height>>
33     [ ] [
34         [ cap-height* ] [ ] [ layout-state>> ] tri
35         [ drop ] [ dupd cap-height<< ] if
36     ] ?if ;
37
38 <PRIVATE
39
40 ! Text has ascent/descent/cap-height slots, graphics does not.
41 TUPLE: gadget-metrics height ascent descent cap-height ;
42
43 : <gadget-metrics> ( gadget dim -- metrics )
44     second swap [ baseline ] [ cap-height ] bi
45     [ dup [ 2dup - ] [ f ] if ] dip
46     gadget-metrics boa ; inline
47
48 : ?supremum ( seq -- n/f )
49     sift [ f ] [ supremum ] if-empty ;
50
51 : max-ascent ( seq -- n )
52     [ ascent>> ] map ?supremum ;
53
54 : max-cap-height ( seq -- n )
55     [ cap-height>> ] map ?supremum ;
56
57 : max-descent ( seq -- n )
58     [ descent>> ] map ?supremum ;
59
60 : max-graphics-height ( seq -- y )
61     [ ascent>> not ] filter [ height>> ] map ?supremum 0 or ;
62
63 :: combine-metrics ( graphics-height ascent descent cap-height -- ascent' descent' )
64     ascent [
65         cap-height 2 / :> mid-line 
66         graphics-height 2 /
67         [ ascent mid-line - max mid-line + floor >integer ]
68         [ descent mid-line + max mid-line - ceiling >integer ] bi
69     ] [ f f ] if ;
70
71 : (measure-metrics) ( children sizes -- graphics-height ascent descent cap-height )
72     [ <gadget-metrics> ] 2map
73     {
74         [ max-graphics-height ]
75         [ max-ascent ]
76         [ max-descent ]
77         [ max-cap-height ]
78     } cleave ;
79
80 PRIVATE>
81
82 :: align-baselines ( gadgets -- ys )
83     gadgets [ dup pref-dim <gadget-metrics> ] map
84     dup max-ascent 0 or :> max-ascent
85     dup max-cap-height 0 or :> max-cap-height
86     dup max-graphics-height :> max-graphics-height
87
88     max-cap-height max-graphics-height + 2 /i :> critical-line
89     critical-line max-ascent [-] :> text-leading
90     max-ascent critical-line [-] :> graphics-leading
91
92     [
93         dup ascent>>
94         [ ascent>> max-ascent swap - text-leading ]
95         [ height>> max-graphics-height swap - 2 /i graphics-leading ] if +
96     ] map ;
97
98 : measure-metrics ( children sizes -- ascent descent )
99     (measure-metrics) combine-metrics ;
100
101 : measure-height ( children sizes -- height )
102     (measure-metrics) dup [ combine-metrics + ] [ 3drop ] if ;