|
1 /* |
|
2 Copyright 2014 Teemu Piippo |
|
3 All rights reserved. |
|
4 |
|
5 Redistribution and use in source and binary forms, with or without |
|
6 modification, are permitted provided that the following conditions |
|
7 are met: |
|
8 |
|
9 1. Redistributions of source code must retain the above copyright |
|
10 notice, this list of conditions and the following disclaimer. |
|
11 2. Redistributions in binary form must reproduce the above copyright |
|
12 notice, this list of conditions and the following disclaimer in the |
|
13 documentation and/or other materials provided with the distribution. |
|
14 3. Neither the name of the copyright holder nor the names of its |
|
15 contributors may be used to endorse or promote products derived from |
|
16 this software without specific prior written permission. |
|
17 |
|
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
20 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
21 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER |
|
22 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
23 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
24 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
25 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
26 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
29 */ |
|
30 |
|
31 #include <string.h> |
|
32 #include "interface.h" |
|
33 |
|
34 static String g_input; |
|
35 static int g_cursor = 0; |
|
36 static int g_pan = 0; |
|
37 static bool g_needRefresh = false; |
|
38 |
|
39 // ------------------------------------------------------------------------------------------------- |
|
40 // |
|
41 static FUNCTION |
|
42 interface_sessions_width() -> int |
|
43 { |
|
44 return COLS / 3; |
|
45 } |
|
46 |
|
47 // ------------------------------------------------------------------------------------------------- |
|
48 // |
|
49 static FUNCTION |
|
50 interface_render_titlebar() -> void |
|
51 { |
|
52 String versionText = format (APPNAME " %1 (%2)", |
|
53 full_version_string(), changeset_date_string()); |
|
54 |
|
55 if (versionText.length() <= COLS) |
|
56 mvprintw (0, (COLS - versionText.length()) / 2, "%s", versionText.chars()); |
|
57 } |
|
58 |
|
59 // ------------------------------------------------------------------------------------------------- |
|
60 // |
|
61 static FUNCTION |
|
62 interface_render_log_area() -> void |
|
63 { |
|
64 |
|
65 } |
|
66 |
|
67 // ------------------------------------------------------------------------------------------------- |
|
68 // |
|
69 static FUNCTION |
|
70 interface_render_input() -> void |
|
71 { |
|
72 static char prompt[] = "> "; |
|
73 int displaylength = COLS - strlen (prompt) - 1; |
|
74 int y = LINES - 2; |
|
75 |
|
76 // Ensure that the cursor is always in view, adjust panning if this is not the case |
|
77 if (g_cursor > g_pan + displaylength) |
|
78 g_pan = g_cursor - displaylength; // cursor went too far right |
|
79 else if (g_cursor < g_pan) |
|
80 g_pan = g_cursor; // cursor went past the pan value to the left |
|
81 |
|
82 int start = g_pan; |
|
83 int end = min<int> (g_input.length(), start + displaylength); |
|
84 assert (g_cursor >= start and g_cursor <= end); |
|
85 String displayTextBegin = g_input.mid (start, g_cursor); |
|
86 String displayTextEnd = g_input.mid (g_cursor, end); |
|
87 |
|
88 // Clear, but only as much as is necessary. I want to avoid clearing the entire line to save |
|
89 // bandwidth over SSH connections. Perhaps needlessly? I'm paranoid. |
|
90 int renderLength = strlen (prompt) + displayTextBegin.length() + displayTextEnd.length(); |
|
91 static int lastRenderLength = 0; |
|
92 |
|
93 if (lastRenderLength > renderLength) |
|
94 mvhline (y, renderLength, ' ', lastRenderLength - renderLength); |
|
95 |
|
96 lastRenderLength = renderLength; |
|
97 |
|
98 // Render the input line, with the part of the input string that's before the cursor written |
|
99 // AFTER the part that comes afterwards. This is to ensure that the cursor is placed at the |
|
100 // position where our cursor is. It looks nice like that. :) |
|
101 mvprintw (y, 0, "%s", prompt); |
|
102 mvprintw (y, strlen (prompt) + displayTextBegin.length(), "%s", displayTextEnd.chars()); |
|
103 mvprintw (y, strlen (prompt), "%s", displayTextBegin.chars()); |
|
104 g_needRefresh = true; |
|
105 } |
|
106 |
|
107 // ------------------------------------------------------------------------------------------------- |
|
108 // |
|
109 static FUNCTION |
|
110 interface_render_statusbar() -> void |
|
111 { |
|
112 |
|
113 } |
|
114 |
|
115 // ------------------------------------------------------------------------------------------------- |
|
116 // |
|
117 static FUNCTION |
|
118 interface_render_full() -> void |
|
119 { |
|
120 interface_render_titlebar(); |
|
121 interface_render_log_area(); |
|
122 interface_render_statusbar(); |
|
123 interface_render_input(); |
|
124 g_needRefresh = true; |
|
125 } |
|
126 |
|
127 // ------------------------------------------------------------------------------------------------- |
|
128 // |
|
129 FUNCTION |
|
130 Interface::initialize() -> void |
|
131 { |
|
132 ::initscr(); |
|
133 ::start_color(); |
|
134 ::raw(); |
|
135 ::keypad (stdscr, true); |
|
136 ::noecho(); |
|
137 ::refresh(); |
|
138 ::timeout (0); |
|
139 interface_render_full(); |
|
140 refresh(); |
|
141 g_needRefresh = false; |
|
142 } |
|
143 |
|
144 // ------------------------------------------------------------------------------------------------- |
|
145 // |
|
146 FUNCTION |
|
147 Interface::handle_input() -> void |
|
148 { |
|
149 int ch = ::getch(); |
|
150 |
|
151 if (ch == KEY_F(1)) |
|
152 { |
|
153 endwin(); |
|
154 exit (EXIT_SUCCESS); |
|
155 } |
|
156 else if (ch >= 0x20 and ch <= 0x7E) |
|
157 { |
|
158 g_input.insert (g_cursor++, char (ch)); |
|
159 interface_render_input(); |
|
160 refresh(); |
|
161 } |
|
162 else if (ch == KEY_LEFT) |
|
163 { |
|
164 if (g_cursor > 0) |
|
165 { |
|
166 g_cursor--; |
|
167 interface_render_input(); |
|
168 } |
|
169 } |
|
170 else if (ch == KEY_RIGHT) |
|
171 { |
|
172 if (g_cursor < g_input.length()) |
|
173 { |
|
174 g_cursor++; |
|
175 interface_render_input(); |
|
176 } |
|
177 } |
|
178 else if (ch == KEY_HOME) |
|
179 { |
|
180 if (g_cursor != 0) |
|
181 { |
|
182 g_cursor = 0; |
|
183 interface_render_input(); |
|
184 } |
|
185 } |
|
186 else if (ch == KEY_END) |
|
187 { |
|
188 if (g_cursor != g_input.length()) |
|
189 { |
|
190 g_cursor = g_input.length(); |
|
191 interface_render_input(); |
|
192 } |
|
193 } |
|
194 else if (ch == KEY_BACKSPACE) |
|
195 { |
|
196 if (not g_input.is_empty() and g_cursor > 0) |
|
197 { |
|
198 g_input.remove_at (--g_cursor); |
|
199 interface_render_input(); |
|
200 } |
|
201 } |
|
202 |
|
203 if (g_needRefresh) |
|
204 { |
|
205 refresh(); |
|
206 g_needRefresh = false; |
|
207 } |
|
208 } |
|
209 |
|
210 FUNCTION print_to_console (const String& a) -> void |
|
211 { |
|
212 |
|
213 } |