aboutsummaryrefslogtreecommitdiff
path: root/render.f90
blob: 29135075d30dca1e64667d117f17a7d1ab8d88aa (plain)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
module render
implicit none

    type, abstract :: renderer
    
        integer::y
        integer::max_width
        
        contains
        
        procedure::render_proportional
        
        procedure(initialize), deferred::initialize
        
        procedure(calculate_width), deferred::text_width
        procedure(calculate_height), deferred::text_height
        procedure(calculate_visibility), deferred::is_text_visible
        procedure(draw_text), deferred::draw_porportional

        procedure(calculate_width), deferred::preformatted_width
        procedure(calculate_height), deferred::preformatted_height
        procedure(calculate_visibility), deferred::is_preformatted_visible
        procedure(draw_text), deferred::draw_preformatted

    end type renderer

    abstract interface
        subroutine initialize(self)
        import::renderer
        class(renderer)::self
        end subroutine initialize
    end interface

    abstract interface
        function calculate_width(self, text)
        import::renderer
        class(renderer)::self
        character(*), intent(in)::text
        integer::calculate_width
        end function calculate_width
    end interface
    
    abstract interface
        function calculate_height(self, text)
        import::renderer
        class(renderer)::self
        character(*), intent(in)::text
        integer::calculate_height
        end function calculate_height
    end interface
    
    abstract interface
        subroutine draw_text(self, text)
        import::renderer
        class(renderer)::self
        character(*), intent(in)::text
        end subroutine draw_text
    end interface
    
    abstract interface
        function calculate_visibility(self, text)
        import::renderer
        class(renderer)::self
        character(*), intent(in)::text
        logical::calculate_visibility
        end function calculate_visibility
    end interface

contains
 
    function width_of_line(r, text, startpos, endpos)
    implicit none
    
        class(renderer)::r
        character(*), intent(in)::text
        integer, intent(in)::startpos, endpos
        integer::width_of_line
        
        integer::my_start, my_end
        
        my_end = endpos
        if(endpos <= 0) then
            my_end = len_trim(text)
        end if
        
        my_start = startpos
        if(startpos <= 0) then
            my_start = 1
        end if
        
        if(my_end <= my_start) then
            width_of_line = 0
        else
            width_of_line = r%text_width(text(my_start:my_end))
        end if
    
    end function width_of_line

    function wrap_line(r, text, startpos) result(endpos)
    implicit none

        class(renderer)::r
        character(*), intent(in)::text
        integer, intent(in)::startpos
        integer::endpos
        integer::my_start
        integer::w
        
        my_start = startpos
        if(startpos == 0) then
            my_start = 1
        end if
        
        endpos = len_trim(text)
        w = width_of_line(r, text, my_start, endpos)
        do while(w > r%max_width)
        
            endpos = endpos - 1
            do while(text(endpos:endpos) /= ' ' .and. text(endpos:endpos) /= '-')
                endpos = endpos - 1
            end do
            
            w = width_of_line(r, text, my_start, endpos)
        end do
        
    end function wrap_line
    
    subroutine render_proportional(r, text)
    implicit none
    
        class(renderer)::r
        character(*)::text
        
        integer::startpos, endpos
        
        if(len_trim(text) == 0) then 
            if(r%is_text_visible(" ")) then
                call r%draw_porportional("")
            end if
            r%y = r%y + r%text_height(" ")
        else
            startpos = 1
            endpos = wrap_line(r, text, startpos)
            do while(endpos > startpos)
                if(r%is_text_visible(text(startpos:endpos))) then
                    call r%draw_porportional(text(startpos:endpos))
                end if
                r%y = r%y + r%text_height(text(startpos:endpos))
                
                ! Advance string positions
                startpos = endpos+1
                do while(text(startpos:startpos) == ' ')
                    startpos = startpos + 1
                end do
                endpos = wrap_line(r, text, startpos)
            end do
        end if
    
    end subroutine render_proportional
    
    subroutine render_preformatted(r, text)
    implicit none
    
        class(renderer)::r
        character(*)::text
        
        if(r%is_preformatted_visible(text)) then
            call r%draw_preformatted(text)
        end if
        r%y = r%y + r%preformatted_height(text)
    
    end subroutine render_preformatted
end module render