43 static bool g_needOutputRender = false; |
43 static bool g_needOutputRender = false; |
44 static String g_statusBarText; |
44 static String g_statusBarText; |
45 static struct { char ch; int x; } g_cursorChar; |
45 static struct { char ch; int x; } g_cursorChar; |
46 static Vector<String> g_output = {""}; |
46 static Vector<String> g_output = {""}; |
47 static int g_outputScroll = 0; |
47 static int g_outputScroll = 0; |
|
48 static String g_title; |
48 |
49 |
49 // ------------------------------------------------------------------------------------------------- |
50 // ------------------------------------------------------------------------------------------------- |
50 // |
51 // |
51 static FUNCTION |
52 static FUNCTION |
52 interface_color_pair (Color fg, Color bg) -> int |
53 interface_color_pair (Color fg, Color bg) -> int |
89 } |
91 } |
90 |
92 |
91 // ------------------------------------------------------------------------------------------------- |
93 // ------------------------------------------------------------------------------------------------- |
92 // |
94 // |
93 static FUNCTION |
95 static FUNCTION |
94 interface_clear_titlebar() -> void |
|
95 { |
|
96 int pair = interface_color_pair (WHITE, BLUE); |
|
97 attron (pair); |
|
98 mvhline (0, 0, ' ', COLS); |
|
99 attroff (pair); |
|
100 } |
|
101 |
|
102 // ------------------------------------------------------------------------------------------------- |
|
103 // |
|
104 static FUNCTION |
|
105 interface_render_titlebar() -> void |
96 interface_render_titlebar() -> void |
106 { |
97 { |
107 String versionText = format (APPNAME " %1 (%2)", |
98 if (g_title.length() <= COLS) |
108 full_version_string(), changeset_date_string()); |
|
109 |
|
110 if (versionText.length() <= COLS) |
|
111 { |
99 { |
112 int pair = interface_color_pair (WHITE, BLUE); |
100 int pair = interface_color_pair (WHITE, BLUE); |
|
101 int startx = (COLS - g_title.length()) / 2; |
|
102 int endx = startx + g_title.length(); |
|
103 print ("startx: %1, endx: %2\n", startx, endx); |
|
104 |
113 attron (pair); |
105 attron (pair); |
114 mvprintw (0, (COLS - versionText.length()) / 2, "%s", versionText.chars()); |
106 mvprintw (0, startx, "%s", g_title.chars()); |
|
107 mvhline (0, 0, ' ', startx); |
|
108 mvhline (0, endx, ' ', COLS - endx); |
115 attroff (pair); |
109 attroff (pair); |
116 } |
110 } |
|
111 |
|
112 g_needRefresh = true; |
|
113 } |
|
114 |
|
115 // ------------------------------------------------------------------------------------------------- |
|
116 // |
|
117 FUNCTION |
|
118 Interface::set_title (const String& title) -> void |
|
119 { |
|
120 g_title = title; |
|
121 interface_render_titlebar(); |
117 } |
122 } |
118 |
123 |
119 // ------------------------------------------------------------------------------------------------- |
124 // ------------------------------------------------------------------------------------------------- |
120 // |
125 // |
121 static FUNCTION |
126 static FUNCTION |
146 // ------------------------------------------------------------------------------------------------- |
151 // ------------------------------------------------------------------------------------------------- |
147 // |
152 // |
148 static FUNCTION |
153 static FUNCTION |
149 interface_render_input() -> void |
154 interface_render_input() -> void |
150 { |
155 { |
151 static char prompt[] = "> "; |
156 static char prompt[] = ">"; |
152 int displaylength = COLS - strlen (prompt) - 1; |
157 int displaylength = COLS - strlen (prompt) - 2; |
153 int y = LINES - 2; |
158 int y = LINES - 2; |
154 |
159 |
155 // Ensure the cursor is within bounds |
160 // Ensure the cursor is within bounds |
156 g_cursor = clamp (g_cursor, 0, g_input.length()); |
161 g_cursor = clamp (g_cursor, 0, g_input.length()); |
157 |
162 |
162 g_pan = g_cursor; // cursor went past the pan value to the left |
167 g_pan = g_cursor; // cursor went past the pan value to the left |
163 |
168 |
164 int start = g_pan; |
169 int start = g_pan; |
165 int end = min<int> (g_input.length(), start + displaylength); |
170 int end = min<int> (g_input.length(), start + displaylength); |
166 assert (g_cursor >= start and g_cursor <= end); |
171 assert (g_cursor >= start and g_cursor <= end); |
167 String displayTextBegin = g_input.mid (start, g_cursor); |
|
168 String displayTextEnd = g_input.mid (g_cursor, end); |
|
169 |
172 |
170 // Clear, but only as much as is necessary. I want to avoid clearing the entire line to save |
173 // Clear, but only as much as is necessary. I want to avoid clearing the entire line to save |
171 // bandwidth over SSH connections. Perhaps needlessly? I'm paranoid. |
174 // bandwidth over SSH connections. Perhaps needlessly? I'm paranoid. |
172 int renderLength = strlen (prompt) + displayTextBegin.length() + displayTextEnd.length(); |
175 int renderLength = strlen (prompt) + 1 + g_input.length(); |
173 static int lastRenderLength = 0; |
176 static int lastRenderLength = 0; |
174 |
177 |
175 if (lastRenderLength > renderLength) |
178 if (lastRenderLength > renderLength) |
176 mvhline (y, renderLength, ' ', lastRenderLength - renderLength); |
179 mvhline (y, renderLength, ' ', lastRenderLength - renderLength); |
177 |
180 |
178 lastRenderLength = renderLength; |
181 lastRenderLength = renderLength; |
179 |
182 |
180 // Render the input line, with the part of the input string that's before the cursor written |
183 // Render the input line, with the part of the input string that's before the cursor written |
181 // AFTER the part that comes afterwards. This is to ensure that the cursor is placed at the |
184 // AFTER the part that comes afterwards. This is to ensure that the cursor is placed at the |
182 // position where our cursor is. It looks nice like that. :) |
185 // position where our cursor is. It looks nice like that. :) |
|
186 |
|
187 int pair = interface_color_pair (WHITE, BLUE); |
|
188 attron (pair); |
183 mvprintw (y, 0, "%s", prompt); |
189 mvprintw (y, 0, "%s", prompt); |
184 mvprintw (y, strlen (prompt) + displayTextBegin.length(), "%s", displayTextEnd.chars()); |
190 attroff (pair); |
185 mvprintw (y, strlen (prompt), "%s", displayTextBegin.chars()); |
191 mvprintw (y, strlen (prompt) + 1, "%s", g_input.chars()); |
186 g_cursorChar.ch = g_cursor != 0 ? g_input[g_cursor - 1] : '\0'; |
192 g_cursorChar.ch = g_cursor != 0 ? g_input[g_cursor - 1] : '\0'; |
187 g_cursorChar.x = strlen (prompt) + displayTextBegin.length() - 1; |
193 g_cursorChar.x = strlen (prompt) + (g_cursor - g_pan); |
188 g_needRefresh = true; |
194 g_needRefresh = true; |
189 g_needInputRender = false; |
195 g_needInputRender = false; |
190 } |
196 } |
191 |
197 |
192 // ------------------------------------------------------------------------------------------------- |
198 // ------------------------------------------------------------------------------------------------- |
213 // ------------------------------------------------------------------------------------------------- |
219 // ------------------------------------------------------------------------------------------------- |
214 // |
220 // |
215 FUNCTION |
221 FUNCTION |
216 Interface::render_full() -> void |
222 Interface::render_full() -> void |
217 { |
223 { |
218 interface_clear_titlebar(); |
|
219 interface_render_titlebar(); |
224 interface_render_titlebar(); |
220 interface_render_output(); |
225 interface_render_output(); |
221 interface_render_statusbar(); |
226 interface_render_statusbar(); |
222 interface_render_input(); |
227 interface_render_input(); |
223 } |
228 } |