25 #include <imgui-filebrowser/imfilebrowser.h>
32 std::vector<jevois::EditorItem> && fixeditems, std::string
const & scanpath,
33 std::string
const & prefix, std::set<std::string> && extensions) :
34 TextEditor(), itsHelper(helper), itsId(imguiid), itsItems(fixeditems), itsNumFixedItems(fixeditems.size()),
35 itsScanPath(scanpath), itsPrefix(prefix), itsExtensions(extensions),
36 itsBrowser(new
ImGui::FileBrowser(ImGuiFileBrowserFlags_EnterNewFilename | ImGuiFileBrowserFlags_CreateNewDir))
38 TextEditor::SetSaveCallback([
this]() {
saveFile(); } );
40 itsBrowser->SetTitle(
"Select a file to open or create...");
41 itsBrowser->SetPwd(JEVOIS_SHARE_PATH);
53 bool keep_current =
false;
EditorItem current_item;
54 if (itsCurrentItem >=
int(itsNumFixedItems)) { current_item = itsItems[itsCurrentItem]; keep_current =
true; }
57 itsItems.resize(itsNumFixedItems);
60 if (itsItems[0].filename ==
"*")
62 jevois::VideoMapping
const & vm = itsHelper->engine()->getCurrentVideoMapping();
63 if (std::filesystem::exists(vm.cmakepath()))
64 itsItems.emplace_back(
EditorItem {
"#",
"Module's CMakeLists.txt", EditorSaveAction::Compile } );
68 for (
auto const & dent : std::filesystem::recursive_directory_iterator(itsScanPath))
70 if (dent.is_regular_file())
72 std::filesystem::path
const path = dent.path();
75 if (itsExtensions.find(path.extension()) == itsExtensions.end())
continue;
78 itsItems.emplace_back(
EditorItem { path, itsPrefix + path.string(), EditorSaveAction::Reload });
83 if (keep_current) itsItems.emplace_back(std::move(current_item));
86 itsItems.emplace_back(
EditorItem {
"**",
"Browse / Create file...", EditorSaveAction::Reload });
89 bool not_found =
true;
91 for (
int i = 0;
auto const & item : itsItems)
92 if (item.filename == itsFilename)
108 itsOverrideReloadModule = IsEdited();
116 char const * items[itsItems.size()];
117 for (
int i = 0;
EditorItem const & c : itsItems) items[i++] = c.displayname.c_str();
120 if (ImGui::Combo((
"##"+itsId+
"editorcombo").c_str(), &itsNewItem, items, itsItems.size())) itsWantLoad =
true;
123 if (itsWantLoad && itsWantAction ==
false)
127 static int discard_edits_default = 0;
128 int ret = itsHelper->modal(
"Discard edits?",
"File was edited. Discard all edits? This cannot be undone.",
129 &discard_edits_default,
"Discard",
"Save");
132 case 1: itsWantLoad =
false; itsOkToLoad =
true;
break;
133 case 2: saveFile();
break;
147 switch (itsItems[itsCurrentItem].action)
150 case jevois::EditorSaveAction::None:
151 itsWantAction =
false;
155 case jevois::EditorSaveAction::Reload:
159 if (itsOverrideReloadModule)
161 itsOverrideReloadModule =
false;
162 itsWantAction =
false;
163 itsOkToLoad = itsWantLoad;
168 static int reload_default = 0;
169 int ret = itsHelper->modal(
"Reload Module?",
"Reload Machine Vision Module for changes to take effect?",
170 &reload_default,
"Reload",
"Later");
174 itsHelper->engine()->requestSetFormat(-1);
175 itsWantAction =
false;
176 itsOkToLoad = itsWantLoad;
180 itsWantAction =
false;
181 itsOkToLoad = itsWantLoad;
190 case jevois::EditorSaveAction::Reboot:
192 int ret = itsHelper->modal(
"Restart?",
"Restart JeVois-Pro for changes to take effect?",
193 nullptr,
"Restart",
"Later");
197 itsHelper->engine()->reboot();
198 itsWantAction =
false;
202 itsWantAction =
false;
211 case jevois::EditorSaveAction::RefreshMappings:
213 itsHelper->engine()->reloadVideoMappings();
214 itsWantAction =
false;
219 case jevois::EditorSaveAction::Compile:
222 static int compile_default = 0;
223 int ret = itsHelper->modal(
"Compile Module?",
"Compile Machine Vision Module for changes to take effect?",
224 &compile_default,
"Compile",
"Later");
228 itsHelper->startCompilation();
229 itsWantAction =
false;
230 itsOkToLoad = itsWantLoad;
234 itsWantAction =
false;
235 itsOkToLoad = itsWantLoad;
249 if (itsItems[itsNewItem].filename ==
"**")
251 ImGui::PushStyleColor(ImGuiCol_PopupBg, 0xf0ffe0e0);
253 if (itsBrowser->IsOpened() ==
false)
256 itsBrowser->Display();
260 itsBrowser->Display();
262 if (itsBrowser->HasSelected())
264 std::filesystem::path
const fn = itsBrowser->GetSelected();
266 if (std::filesystem::exists(fn))
267 loadFileInternal(fn,
"Could not load " + fn.string());
269 loadFileInternal(fn,
"");
272 itsBrowser->Display();
276 if (itsBrowser->IsOpened() ==
false)
279 itsNewItem = itsCurrentItem;
281 itsBrowser->Display();
284 ImGui::PopStyleColor();
289 itsCurrentItem = itsNewItem;
290 loadFileInternal(itsItems[itsCurrentItem].filename,
"");
295 bool const ro = IsReadOnly();
297 if (ImGui::Button(
"...")) ImGui::OpenPopup(
"editor_actions");
298 if (ImGui::BeginPopup(
"editor_actions"))
300 constexpr
int ok = ImGuiSelectableFlags_None;
301 constexpr
int disa = ImGuiSelectableFlags_Disabled;
303 if (ImGui::Selectable(
"Save [Ctrl-S]",
false, !ro && IsEdited() ? ok : disa)) saveFile();
307 if (ImGui::Selectable(
"Undo [Ctrl-Z]",
false, !ro && CanUndo() ? ok : disa)) Undo();
308 if (ImGui::Selectable(
"Redo [Ctrl-Y]",
false, !ro && CanRedo() ? ok : disa)) Redo();
312 if (ImGui::Selectable(
"Copy [Ctrl-C]",
false, HasSelection() ? ok : disa)) Copy();
313 if (ImGui::Selectable(
"Cut [Ctrl-X]",
false, !ro && HasSelection() ? ok : disa)) Cut();
314 if (ImGui::Selectable(
"Delete [Del]",
false, !ro && HasSelection() ? ok : disa)) Delete();
315 if (ImGui::Selectable(
"Paste [Ctrl-V]",
false, !ro && ImGui::GetClipboardText()!=
nullptr ? ok : disa)) Paste();
319 ImGui::Selectable(
"More shortcuts...",
false, disa);
320 if (ImGui::IsItemHovered())
321 ImGui::SetTooltip(
"[Ctrl-A] Select all\n"
322 "[PgUp/PgDn] Move one page up/down\n"
323 "[Home] Move to start of line\n"
324 "[End] Move to end of line\n"
325 "[Ctrl-Home] Move to start of file\n"
326 "[Ctrl-End] Move to end of file\n"
327 "[Ctrl-Left/Right] Move left/right one word\n"
328 "[Ins] Toggle overwrite mode\n"
329 "[Alt-Bksp] Undo (same as [Ctrl-Z])\n"
330 "[Ctrl-Ins] Copy (same as [Ctrl-C])\n"
331 "[Shift-Ins] Paste (same as [Ctrl-V])\n"
332 "[Shift-Del] Cut (same as [Ctrl-X])\n"
333 "[Shift-Cursor] Select while moving cursor (up, down, left, right, home, end)\n"
334 "[Mouse-Drag] Select with mouse\n"
344 ImGui::TextUnformatted(
" "); ImGui::SameLine();
345 if (ImGui::Button(
"Save")) saveFile();
351 auto cpos = GetCursorPosition();
353 ImGui::Text(
"%6d/%-6d %6d lines | %s | %s | %s", cpos.mLine + 1, cpos.mColumn + 1, GetTotalLines(),
354 IsOverwrite() ?
"Ovr" :
"Ins",
355 IsEdited() ?
"*" :
" ",
356 GetLanguageDefinition().mName.c_str());
358 Render(
"JeVois-Pro Editor");
365 for (
int i = 0;
EditorItem const & item : itsItems)
366 if (item.filename == fn) { itsNewItem = i; itsWantLoad =
true;
return; }
else ++i;
371 if (fn.filename() ==
"CMakeLists.txt")
372 action = EditorSaveAction::Compile;
373 else if (fn.filename() ==
"jevoispro-fan.service")
374 action = EditorSaveAction::Reboot;
377 std::string
const ext = fn.extension().string();
378 if (ext ==
".C" || ext ==
".H" || ext ==
".cpp" || ext ==
".hpp" || ext ==
".c" || ext ==
".h")
379 action = EditorSaveAction::Compile;
381 itsItems.emplace_back(
EditorItem { fn,
"File " + fn.string(), action });
383 itsNewItem = itsItems.size() - 1;
388 void jevois::GUIeditor::loadFileInternal(std::filesystem::path
const & fpath, std::string
const & failt)
390 std::filesystem::path fn = fpath; std::string failtxt = failt;
bool special_path =
false;
395 jevois::VideoMapping
const & vm = itsHelper->engine()->getCurrentVideoMapping();
397 failtxt =
"Could not open Module's source code";
400 else if (fpath ==
"#")
403 jevois::VideoMapping
const & vm = itsHelper->engine()->getCurrentVideoMapping();
405 failtxt =
"Could not open Module's CMakeLists.txt";
408 else if (fpath.is_relative())
411 auto m = itsHelper->engine()->module();
412 if (m) fn = m->absolutePath(fpath);
416 if (fn != fpath)
LINFO(
"Loading " << fn <<
" ... [" << fpath <<
']');
else LINFO(
"Loading " << fn <<
" ...");
419 EditorSaveAction action = EditorSaveAction::Reload;
425 std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
429 for (
int i = 0; EditorItem
const & item : itsItems)
430 if (item.filename == fpath) { itsCurrentItem = i; got_it =
true;
break; }
else ++i;
435 if (fn.filename() ==
"CMakeLists.txt")
437 SetLanguageDefinition(TextEditor::LanguageDefinition::CMake());
439 action = EditorSaveAction::Compile;
443 std::filesystem::path
const ext = fn.extension();
444 std::filesystem::path cmak = fn; cmak.remove_filename(); cmak /=
"CMakeLists.txt";
445 bool has_cmake = std::filesystem::exists(cmak);
449 SetLanguageDefinition(TextEditor::LanguageDefinition::Python());
452 else if (ext ==
".C" || ext ==
".H" || ext ==
".cpp" || ext ==
".hpp")
454 SetLanguageDefinition(TextEditor::LanguageDefinition::CPlusPlus());
455 SetReadOnly(! has_cmake);
456 action = EditorSaveAction::Compile;
458 else if ( ext ==
".c" || ext ==
".h")
460 SetLanguageDefinition(TextEditor::LanguageDefinition::C());
461 SetReadOnly(! has_cmake);
462 action = EditorSaveAction::Compile;
467 SetLanguageDefinition(TextEditor::LanguageDefinition::JeVoisCfg());
476 if (failtxt.empty()) {
LINFO(
"File " << fn <<
" not found -- CREATING NEW"); SetReadOnly(
false); }
477 else {
LINFO(
"File " << fn <<
" not found."); SetReadOnly(
true); }
481 if (got_it ==
false && special_path ==
false)
483 itsItems.emplace_back(EditorItem { fn,
"File " + fn.string(), action });
484 itsCurrentItem = itsItems.size() - 1;
486 else if (fpath ==
"*") itsItems[itsCurrentItem].action = action;
490 itsNewItem = itsCurrentItem;
498 LINFO(
"Saving " << itsFilename <<
" ...");
499 std::ofstream os(itsFilename);
500 if (os.is_open() ==
false) { itsHelper->reportError(
"Cannot write " + itsFilename.string());
return; }
502 std::string
const txt = GetText();
509 std::filesystem::path mi = itsFilename.parent_path() /
"modinfo.html";
510 if (std::filesystem::exists(mi)) std::filesystem::remove(mi);
513 itsWantAction =
true;