Fortran · 6116 bytes Raw Blame History
1 ! UI display for Fortress navigator (simplified for fac)
2
3 module fortress_display_module
4 use iso_fortran_env, only: output_unit
5 use fortress_fs_module, only: MAX_PATH, MAX_FILES
6 implicit none
7 private
8
9 public :: draw_fortress_interface
10
11 ! ANSI escape codes
12 character(len=*), parameter :: ESC = char(27)
13 character(len=*), parameter :: BOLD = ESC // "[1m"
14 character(len=*), parameter :: DIM = ESC // "[2m"
15 character(len=*), parameter :: UNDERLINE = ESC // "[4m"
16 character(len=*), parameter :: RESET = ESC // "[0m"
17 character(len=*), parameter :: BLUE = ESC // "[34m"
18 character(len=*), parameter :: GREEN = ESC // "[32m"
19 character(len=*), parameter :: GREY = ESC // "[90m"
20 character(len=*), parameter :: WHITE = ESC // "[37m"
21
22 contains
23
24 subroutine draw_fortress_interface(r, c, current_dir, current_files, current_is_dir, current_is_exec, &
25 current_count, parent_files, parent_is_dir, parent_count, &
26 selected, parent_selected, scroll_offset, parent_scroll_offset, first_draw)
27 integer, intent(in) :: r, c, current_count, parent_count, selected, parent_selected
28 integer, intent(in) :: scroll_offset, parent_scroll_offset
29 character(len=*), intent(in) :: current_dir
30 character(len=*), dimension(*), intent(in) :: current_files, parent_files
31 logical, dimension(*), intent(in) :: current_is_dir, parent_is_dir
32 logical, dimension(*), intent(in) :: current_is_exec
33 logical, intent(in), optional :: first_draw
34 integer :: left_w, i, j, parent_idx, current_idx, vis_h
35 character(len=256) :: parent_name, current_name
36 character(len=256) :: line
37 logical :: do_clear
38
39 ! Calculate layout
40 left_w = c * 3 / 10
41 vis_h = r - 3
42
43 ! Check if we should do full clear (only on first draw)
44 do_clear = .false.
45 if (present(first_draw)) do_clear = first_draw
46
47 ! Hide cursor and optionally clear screen
48 if (do_clear) then
49 write(output_unit, '(a)', advance='no') ESC // "[?25l" // ESC // "[2J" // ESC // "[H"
50 else
51 write(output_unit, '(a)', advance='no') ESC // "[?25l" // ESC // "[H"
52 end if
53
54 ! Header - clear line then write
55 write(output_unit, '(a)', advance='no') ESC // "[K"
56 write(output_unit, '(a)') BOLD // "FORTRESS" // RESET // " - " // trim(current_dir)
57 write(output_unit, '(a)', advance='no') ESC // "[K"
58 write(output_unit, '(a)') ""
59
60 ! Render each line - write complete lines at once
61 do i = 1, vis_h
62 parent_idx = i + parent_scroll_offset
63 current_idx = i + scroll_offset
64
65 ! Move to absolute row position (row 3 + i) and clear line
66 write(line, '(a,i0,a)') ESC // "[", 2 + i, ";1H" // ESC // "[K"
67 write(output_unit, '(a)', advance='no') trim(line)
68
69 ! === Parent pane (left 30%) ===
70 if (parent_idx >= 1 .and. parent_idx <= parent_count) then
71 ! Clean the filename - remove any control characters
72 parent_name = trim(adjustl(parent_files(parent_idx)))
73
74 ! Remove any newlines or carriage returns
75 j = scan(parent_name, char(10)//char(13))
76 if (j > 0) then
77 parent_name = parent_name(1:j-1)
78 end if
79
80 if (parent_is_dir(parent_idx)) parent_name = trim(parent_name) // "/"
81
82 ! Truncate if too long
83 if (len_trim(parent_name) > left_w) then
84 parent_name = parent_name(1:left_w)
85 end if
86
87 ! Write parent item with color
88 if (parent_idx == parent_selected) then
89 write(output_unit, '(a)', advance='no') DIM // BOLD // BLUE // trim(parent_name) // RESET
90 else
91 write(output_unit, '(a)', advance='no') DIM // GREY // trim(parent_name) // RESET
92 end if
93 end if
94
95 ! Use explicit cursor positioning for separator - build the position string
96 write(line, '(a,i0,a)') ESC // "[", left_w + 1, "G"
97 write(output_unit, '(a)', advance='no') trim(line) // " │ "
98
99 ! === Current pane (right) ===
100 if (current_idx >= 1 .and. current_idx <= current_count) then
101 ! Clean the filename - remove any control characters
102 current_name = trim(adjustl(current_files(current_idx)))
103
104 ! Remove any newlines or carriage returns by finding first occurrence
105 j = scan(current_name, char(10)//char(13))
106 if (j > 0) then
107 current_name = current_name(1:j-1)
108 end if
109
110 if (current_is_dir(current_idx)) current_name = trim(current_name) // "/"
111
112 if (current_idx == selected) then
113 write(output_unit, '(a)', advance='no') BOLD // UNDERLINE // WHITE // trim(current_name) // RESET
114 else if (current_is_dir(current_idx)) then
115 write(output_unit, '(a)', advance='no') BLUE // trim(current_name) // RESET
116 else if (current_is_exec(current_idx)) then
117 write(output_unit, '(a)', advance='no') GREEN // trim(current_name) // RESET
118 else
119 write(output_unit, '(a)', advance='no') trim(current_name) // RESET
120 end if
121 end if
122 ! No else needed - line is already cleared
123 end do
124
125 ! Footer - position at last row and clear line
126 write(line, '(a,i0,a)') ESC // "[", r, ";1H" // ESC // "[K"
127 write(output_unit, '(a)', advance='no') trim(line)
128 write(output_unit, '(a)', advance='no') DIM // "arrows:nav enter:open f:favorite esc:quit" // RESET
129
130 ! Show cursor again
131 write(output_unit, '(a)', advance='no') ESC // "[?25h"
132 flush(output_unit)
133 end subroutine draw_fortress_interface
134
135 end module fortress_display_module
136