JeVois  1.21
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
GUIconsole.C
Go to the documentation of this file.
1// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2//
3// JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2020 by Laurent Itti, the University of Southern
4// California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5//
6// This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7// redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8// Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10// License for more details. You should have received a copy of the GNU General Public License along with this program;
11// if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12//
13// Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14// Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16/*! \file */
17
18
19#ifdef JEVOIS_PRO
20
22#include <imgui.h>
23#include <imgui_internal.h>
24
25// ##############################################################################################################
26jevois::GUIconsole::GUIconsole(std::string const & instance) :
27 jevois::UserInterface(instance)
28{
29 itsInputBuf[0] = '\0';
30 /*
31 // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
32 Commands.push_back("HELP");
33 Commands.push_back("HISTORY");
34 Commands.push_back("CLEAR");
35 Commands.push_back("CLASSIFY");
36 */
37}
38
39// ##############################################################################################################
42
43// ##############################################################################################################
46
47// ##############################################################################################################
49{
50 std::lock_guard<std::mutex> _(itsDataMtx);
51 itsData.clear();
52}
53
54// ##############################################################################################################
55bool jevois::GUIconsole::readSome(std::string & str)
56{
57 std::lock_guard<std::mutex> _(itsDataMtx);
58 if (itsLastInput.empty()) return false;
59 str = itsLastInput;
60 itsLastInput.clear();
61
62 // Also keep a copy of the input for our display:
63 itsData.push_back(std::make_pair(true, str));
64
65 return true;
66}
67
68// ##############################################################################################################
69void jevois::GUIconsole::writeString(std::string const & str)
70{
71 std::lock_guard<std::mutex> _(itsDataMtx);
72 itsData.push_back(std::make_pair(false, str));
73 while (itsData.size() > 10000) itsData.pop_front();
74}
75
76// ##############################################################################################################
77static int TextEditCallbackStub(ImGuiInputTextCallbackData * data)
78{
79 jevois::GUIconsole * console = (jevois::GUIconsole *)data->UserData;
80 return console->callback(data);
81}
82
83// ##############################################################################################################
85{
86 // Keep this in sync with GUIserial::draw() for aesthetic consistency
87
88 // Reserve enough left-over height for 1 separator + 1 input text
89 const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
90 ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false,
91 ImGuiWindowFlags_HorizontalScrollbar);
92
93 // Right click on the log to get a popup menu that can clear it:
94 if (ImGui::BeginPopupContextWindow())
95 {
96 if (ImGui::Selectable("Clear")) clear();
97 ImGui::EndPopup();
98 }
99
100 // Tighten spacing:
101 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1));
102
103 // Colorize and draw each data line:
104 std::lock_guard<std::mutex> _(itsDataMtx);
105 for (auto const & p : itsData)
106 {
107 ImVec4 color; bool has_color = false;
108 auto const & s = p.second;
109
110 if (p.first)
111 { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
112 else
113 {
114 if (s == "OK") { color = ImVec4(0.2f, 1.0f, 0.2f, 1.0f); has_color = true; }
115 else if (jevois::stringStartsWith(s, "DBG ")) { color = ImVec4(0.2f, 0.2f, 1.0f, 1.0f); has_color = true; }
116 else if (jevois::stringStartsWith(s, "INF ")) { color = ImVec4(0.4f, 0.7f, 0.4f, 1.0f); has_color = true; }
117 else if (jevois::stringStartsWith(s, "ERR ")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
118 else if (jevois::stringStartsWith(s, "FTL ")) { color = ImVec4(1.0f, 0.0f, 0.0f, 1.0f); has_color = true; }
119 }
120 if (has_color) ImGui::PushStyleColor(ImGuiCol_Text, color);
121 ImGui::TextUnformatted(s.c_str());
122 if (has_color) ImGui::PopStyleColor();
123 }
124
125 static bool autoScroll = true;
126 static bool scrollToBottom = true;
127
128 if (scrollToBottom || (autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) ImGui::SetScrollHereY(1.0f);
129 scrollToBottom = false;
130
131 ImGui::PopStyleVar();
132 ImGui::EndChild();
133 ImGui::Separator();
134
135 // Command-line input:
136 bool reclaim_focus = false;
137 ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackHistory;
138 // | ImGuiInputTextFlags_CallbackCompletion
139
140 if (ImGui::InputTextWithHint("Input", "Type JeVois commands here...",
141 itsInputBuf, IM_ARRAYSIZE(itsInputBuf), input_text_flags,
142 &TextEditCallbackStub, this))
143 {
144 itsLastInput = itsInputBuf;
145 itsInputBuf[0] = '\0';
146 reclaim_focus = true;
147
148 // On command input, we scroll to bottom even if AutoScroll==false
149 scrollToBottom = true;
150
151 // Delete from history if we already had this command:
152 itsHistoryPos = -1;
153 if (itsHistory.empty() == false)
154 for (int i = int(itsHistory.size()) - 1; i >= 0; --i)
155 if (itsHistory[i] == itsLastInput) { itsHistory.erase(itsHistory.begin() + i); break; }
156
157 // Insert into history:
158 itsHistory.push_back(itsLastInput);
159 while (itsHistory.size() > 100) itsHistory.erase(itsHistory.begin());
160 }
161
162 // Auto-focus on window apparition
163 ImGui::SetItemDefaultFocus();
164 if (reclaim_focus) ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
165}
166
167// ##############################################################################################################
168int jevois::GUIconsole::callback(ImGuiInputTextCallbackData * data)
169{
170 switch (data->EventFlag)
171 {
172 /*
173 case ImGuiInputTextFlags_CallbackCompletion:
174 {
175 // Example of TEXT COMPLETION
176
177 // Locate beginning of current word
178 const char* word_end = data->Buf + data->CursorPos;
179 const char* word_start = word_end;
180 while (word_start > data->Buf)
181 {
182 const char c = word_start[-1];
183 if (c == ' ' || c == '\t' || c == ',' || c == ';')
184 break;
185 word_start--;
186 }
187
188 // Build a list of candidates
189 ImVector<const char*> candidates;
190 for (int i = 0; i < Commands.Size; i++)
191 if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
192 candidates.push_back(Commands[i]);
193
194 if (candidates.Size == 0)
195 {
196 // No match
197 AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
198 }
199 else if (candidates.Size == 1)
200 {
201 // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
202 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
203 data->InsertChars(data->CursorPos, candidates[0]);
204 data->InsertChars(data->CursorPos, " ");
205 }
206 else
207 {
208 // Multiple matches. Complete as much as we can..
209 // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
210 int match_len = (int)(word_end - word_start);
211 for (;;)
212 {
213 int c = 0;
214 bool all_candidates_matches = true;
215 for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
216 if (i == 0)
217 c = toupper(candidates[i][match_len]);
218 else if (c == 0 || c != toupper(candidates[i][match_len]))
219 all_candidates_matches = false;
220 if (!all_candidates_matches)
221 break;
222 match_len++;
223 }
224
225 if (match_len > 0)
226 {
227 data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
228 data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
229 }
230
231 // List matches
232 AddLog("Possible matches:\n");
233 for (int i = 0; i < candidates.Size; i++)
234 AddLog("- %s\n", candidates[i]);
235 }
236
237 break;
238 }
239 */
240 case ImGuiInputTextFlags_CallbackHistory:
241 {
242 // Example of HISTORY
243 const int prev_history_pos = itsHistoryPos;
244 if (data->EventKey == ImGuiKey_UpArrow)
245 {
246 if (itsHistoryPos == -1) itsHistoryPos = int(itsHistory.size()) - 1;
247 else if (itsHistoryPos > 0) --itsHistoryPos;
248 }
249 else if (data->EventKey == ImGuiKey_DownArrow)
250 {
251 if (itsHistoryPos != -1 && ++itsHistoryPos >= int(itsHistory.size())) itsHistoryPos = -1;
252 }
253
254 // A better implementation would preserve the data on the current input line along with cursor position.
255 if (prev_history_pos != itsHistoryPos)
256 {
257 std::string const & history_str = (itsHistoryPos >= 0) ? itsHistory[itsHistoryPos] : "";
258 data->DeleteChars(0, data->BufTextLen);
259 data->InsertChars(0, history_str.c_str());
260 }
261 }
262 }
263 return 0;
264}
265
266#endif // JEVOIS_PRO
Simple console with coloring and completion.
Definition GUIconsole.H:32
virtual ~GUIconsole()
Destructor.
Definition GUIconsole.C:40
void writeString(std::string const &str) override
Write a string.
Definition GUIconsole.C:69
bool readSome(std::string &str) override
Read some bytes if available, and return true and a string when one is complete (RETURN pressed)
Definition GUIconsole.C:55
void clear()
Clear the contents of the window.
Definition GUIconsole.C:48
GUIconsole(std::string const &instance)
Constructor.
Definition GUIconsole.C:26
void draw()
Render into ImGui.
Definition GUIconsole.C:84
int callback(ImGuiInputTextCallbackData *data)
Definition GUIconsole.C:168
Type type() const override
Our type is: GUI.
Definition GUIconsole.C:44
Abstract base class for a string-based user interface.
Type
Enum for the interface type.
bool stringStartsWith(std::string const &str, std::string const &prefix)
Return true if str starts with prefix (including if both strings are equal)
Definition Utils.C:294
Main namespace for all JeVois classes and functions.
Definition Concepts.dox:2