Fortran · 5642 bytes Raw Blame History
1 module screen_mod
2 use cell_mod
3 implicit none
4 private
5
6 public :: screen_t
7 public :: screen_init, screen_destroy, screen_resize
8 public :: screen_clear, screen_clear_line, screen_clear_region
9 public :: screen_set_cell, screen_get_cell
10 public :: screen_mark_dirty, screen_mark_all_dirty
11 public :: screen_clear_dirty, screen_is_dirty
12
13 type :: screen_t
14 integer :: rows = 0
15 integer :: cols = 0
16 type(cell_t), allocatable :: cells(:,:) ! (row, col)
17 logical, allocatable :: dirty(:) ! Per-line dirty flags
18 end type screen_t
19
20 contains
21
22 ! Initialize screen buffer
23 subroutine screen_init(scr, rows, cols)
24 type(screen_t), intent(inout) :: scr
25 integer, intent(in) :: rows, cols
26 integer :: r, c
27
28 scr%rows = rows
29 scr%cols = cols
30
31 allocate(scr%cells(rows, cols))
32 allocate(scr%dirty(rows))
33
34 ! Initialize all cells to spaces with default colors
35 do r = 1, rows
36 do c = 1, cols
37 scr%cells(r, c) = cell_t(32, default_fg, default_bg, 0)
38 end do
39 end do
40
41 ! Mark all lines as dirty initially
42 scr%dirty = .true.
43 end subroutine screen_init
44
45 ! Destroy screen buffer
46 subroutine screen_destroy(scr)
47 type(screen_t), intent(inout) :: scr
48
49 if (allocated(scr%cells)) deallocate(scr%cells)
50 if (allocated(scr%dirty)) deallocate(scr%dirty)
51 scr%rows = 0
52 scr%cols = 0
53 end subroutine screen_destroy
54
55 ! Resize screen buffer (preserves content where possible)
56 subroutine screen_resize(scr, new_rows, new_cols)
57 type(screen_t), intent(inout) :: scr
58 integer, intent(in) :: new_rows, new_cols
59 type(cell_t), allocatable :: new_cells(:,:)
60 logical, allocatable :: new_dirty(:)
61 integer :: min_rows, min_cols, r, c
62
63 if (new_rows == scr%rows .and. new_cols == scr%cols) return
64
65 allocate(new_cells(new_rows, new_cols))
66 allocate(new_dirty(new_rows))
67
68 ! Initialize new buffer with spaces
69 do r = 1, new_rows
70 do c = 1, new_cols
71 new_cells(r, c) = cell_t(32, default_fg, default_bg, 0)
72 end do
73 end do
74
75 ! Copy existing content
76 min_rows = min(scr%rows, new_rows)
77 min_cols = min(scr%cols, new_cols)
78
79 do r = 1, min_rows
80 do c = 1, min_cols
81 new_cells(r, c) = scr%cells(r, c)
82 end do
83 end do
84
85 ! Replace buffers
86 call move_alloc(new_cells, scr%cells)
87 call move_alloc(new_dirty, scr%dirty)
88
89 scr%rows = new_rows
90 scr%cols = new_cols
91
92 ! Mark all lines dirty after resize
93 scr%dirty = .true.
94 end subroutine screen_resize
95
96 ! Clear entire screen
97 subroutine screen_clear(scr)
98 type(screen_t), intent(inout) :: scr
99 integer :: r, c
100
101 do r = 1, scr%rows
102 do c = 1, scr%cols
103 scr%cells(r, c) = cell_t(32, default_fg, default_bg, 0)
104 end do
105 scr%dirty(r) = .true.
106 end do
107 end subroutine screen_clear
108
109 ! Clear a single line
110 subroutine screen_clear_line(scr, row)
111 type(screen_t), intent(inout) :: scr
112 integer, intent(in) :: row
113 integer :: c
114
115 if (row < 1 .or. row > scr%rows) return
116
117 do c = 1, scr%cols
118 scr%cells(row, c) = cell_t(32, default_fg, default_bg, 0)
119 end do
120 scr%dirty(row) = .true.
121 end subroutine screen_clear_line
122
123 ! Clear a region of the screen
124 subroutine screen_clear_region(scr, r1, c1, r2, c2)
125 type(screen_t), intent(inout) :: scr
126 integer, intent(in) :: r1, c1, r2, c2
127 integer :: r, c, row_start, row_end, col_start, col_end
128
129 row_start = max(1, min(r1, r2))
130 row_end = min(scr%rows, max(r1, r2))
131 col_start = max(1, min(c1, c2))
132 col_end = min(scr%cols, max(c1, c2))
133
134 do r = row_start, row_end
135 do c = col_start, col_end
136 scr%cells(r, c) = cell_t(32, default_fg, default_bg, 0)
137 end do
138 scr%dirty(r) = .true.
139 end do
140 end subroutine screen_clear_region
141
142 ! Set a cell at given position
143 subroutine screen_set_cell(scr, row, col, cell)
144 type(screen_t), intent(inout) :: scr
145 integer, intent(in) :: row, col
146 type(cell_t), intent(in) :: cell
147
148 if (row < 1 .or. row > scr%rows) return
149 if (col < 1 .or. col > scr%cols) return
150
151 scr%cells(row, col) = cell
152 scr%dirty(row) = .true.
153 end subroutine screen_set_cell
154
155 ! Get a cell at given position
156 function screen_get_cell(scr, row, col) result(cell)
157 type(screen_t), intent(in) :: scr
158 integer, intent(in) :: row, col
159 type(cell_t) :: cell
160
161 if (row < 1 .or. row > scr%rows .or. col < 1 .or. col > scr%cols) then
162 cell = cell_t(32, default_fg, default_bg, 0)
163 return
164 end if
165
166 cell = scr%cells(row, col)
167 end function screen_get_cell
168
169 ! Mark a line as dirty
170 subroutine screen_mark_dirty(scr, row)
171 type(screen_t), intent(inout) :: scr
172 integer, intent(in) :: row
173
174 if (row >= 1 .and. row <= scr%rows) then
175 scr%dirty(row) = .true.
176 end if
177 end subroutine screen_mark_dirty
178
179 ! Mark all lines as dirty
180 subroutine screen_mark_all_dirty(scr)
181 type(screen_t), intent(inout) :: scr
182
183 scr%dirty = .true.
184 end subroutine screen_mark_all_dirty
185
186 ! Clear dirty flag for a line
187 subroutine screen_clear_dirty(scr, row)
188 type(screen_t), intent(inout) :: scr
189 integer, intent(in) :: row
190
191 if (row >= 1 .and. row <= scr%rows) then
192 scr%dirty(row) = .false.
193 end if
194 end subroutine screen_clear_dirty
195
196 ! Check if a line is dirty
197 function screen_is_dirty(scr, row) result(is_dirty)
198 type(screen_t), intent(in) :: scr
199 integer, intent(in) :: row
200 logical :: is_dirty
201
202 if (row < 1 .or. row > scr%rows) then
203 is_dirty = .false.
204 return
205 end if
206
207 is_dirty = scr%dirty(row)
208 end function screen_is_dirty
209
210 end module screen_mod
211