37 if (!ctx || !ctx->buf)
41 if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
43 ctx->
buf->resize(
static_cast<size_t>(data->BufTextLen));
44 data->Buf = ctx->buf->data();
48 if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
51 const int len = data->BufTextLen;
52 int cur = data->CursorPos;
54 while (start > 0 && data->Buf[start - 1] !=
'\n')
57 while (end < len && data->Buf[end] !=
'\n')
60 const char* line_start = data->Buf + start;
61 const char* line_end = data->Buf + end;
64 ImVec2 sz = ImGui::CalcTextSize(line_start, line_end,
false, FLT_MAX);
65 if (sz.x <= ctx->max_px || ctx->max_px <= 0.0f)
70 for (
int i = cur - 1; i >= start; --i)
72 char c = data->Buf[i];
73 if (c ==
' ' || c ==
'\t' || c ==
'-' || c ==
'/')
76 ImVec2 sz2 = ImGui::CalcTextSize(line_start, data->Buf + i,
false, FLT_MAX);
77 if (sz2.x <= ctx->max_px)
85 if (break_pos >= start)
88 data->DeleteChars(break_pos, 1);
89 data->InsertChars(break_pos,
"\n");
96 data->InsertChars(cur,
"\n");
97 data->CursorPos = cur + 1;
108 ImGuiInputTextFlags flags = 0)
111 if (str->capacity() == 0)
116 ctx.max_px = std::max(0.0f, max_px_line);
118 flags |= ImGuiInputTextFlags_CallbackResize;
119 flags |= ImGuiInputTextFlags_CallbackEdit;
120 flags |= ImGuiInputTextFlags_NoHorizontalScroll;
122 return ImGui::InputTextMultiline(label,
144 const ImU32 winBg = IM_COL32(16, 16, 18, 255);
145 ImGui::PushStyleColor(ImGuiCol_WindowBg, winBg);
146 ImGui::SetNextWindowSizeConstraints(ImVec2(800, 600), ImVec2(FLT_MAX, FLT_MAX));
148 ImGui::Begin(
"Notes", &open);
150 const float fullW = ImGui::GetContentRegionAvail().x;
151 const float fullH = ImGui::GetContentRegionAvail().y;
153 ImGui::BeginChild(
"##Dir", ImVec2(
leftWidth_, fullH),
true);
158 ImGui::InvisibleButton(
"##splitter", ImVec2(6, fullH));
159 if (ImGui::IsItemActive())
167 ImGui::BeginChild(
"##Tabs", ImVec2(0.f, fullH),
true,
168 ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
173 ImGui::PopStyleColor(1);
180 ImGui::OpenPopup(
"Create Note");
182 bool createOpen =
true;
183 if (ImGui::BeginPopupModal(
"Create Note", &createOpen, ImGuiWindowFlags_AlwaysAutoResize))
190 if (ImGui::Button(
"Create"))
199 ImGui::CloseCurrentPopup();
202 if (ImGui::Button(
"Cancel"))
205 ImGui::CloseCurrentPopup();
218 ImGui::OpenPopup(
"Delete Note?");
221 if (ImGui::BeginPopupModal(
"Delete Note?", &delOpen, ImGuiWindowFlags_AlwaysAutoResize))
223 static bool alsoDisk =
false;
224 ImGui::Checkbox(
"Also delete from disk", &alsoDisk);
226 if (ImGui::Button(
"Delete"))
234 int idx = (int)std::distance(
openTabs_.begin(), it);
241 ImGui::CloseCurrentPopup();
244 if (ImGui::Button(
"Cancel"))
248 ImGui::CloseCurrentPopup();
265 if (ImGui::Button(
"New"))
270 if (ImGui::Button(
"Reload"))
276 ImGui::SetNextItemWidth(-1);
277 ImGui::InputTextWithHint(
"##search",
"Search title/author/text...",
searchBuf_,
sizeof(
searchBuf_));
281 if (ImGui::CollapsingHeader(
"My Notes", ImGuiTreeNodeFlags_DefaultOpen))
286 ImGui::TextDisabled(
"(none)");
294 ImGui::PushID(n->uuid.c_str());
297 const std::string label = n->title.empty() ? n->uuid : n->title;
298 if (ImGui::Selectable(label.c_str(), selected))
342 ImGui::TextDisabled(
"No notes open. Select a note on the left or create a new one.");
346 if (ImGui::BeginTabBar(
"##NoteTabs",
347 ImGuiTabBarFlags_AutoSelectNewTabs |
348 ImGuiTabBarFlags_Reorderable))
350 for (
int i = 0; i < (int)
openTabs_.size(); ++i)
364 const std::string visible = n->title.empty() ? n->uuid : n->title;
365 const std::string label = visible +
"###" + uuid;
367 ImGuiTabItemFlags tif = 0;
369 tif |= ImGuiTabItemFlags_UnsavedDocument;
372 if (ImGui::BeginTabItem(label.c_str(), &open, tif))
376 const float availW = ImGui::GetContentRegionAvail().x;
377 const float availH = ImGui::GetContentRegionAvail().y;
400 ImGuiIO& io = ImGui::GetIO();
401 const bool windowFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootAndChildWindows);
402 if (windowFocused && io.KeyCtrl && ImGui::IsKeyPressed(ImGuiKey_S,
false))
405 if (ImGui::Button(n->open_editor ?
"Hide Editor" :
"Show Editor"))
408 if (ImGui::Button(
"Save"))
411 if (ImGui::Button(
"Delete"))
418 ImGui::TextDisabled(
"%s", n->saved_locally ? n->file_path.filename().string().c_str() :
"(unsaved)");
421 const float spacing = ImGui::GetStyle().ItemSpacing.x;
422 const float splitterW = 6.f;
424 float editorW = 0.f, viewerW = 0.f;
427 const float shared = availW - splitterW - spacing;
428 editorW = floorf(shared * 0.5f);
429 viewerW = shared - editorW;
439 ImGui::BeginChild(
"##editor", ImVec2(editorW, 0.f),
true);
443 ts.editBuffer = n->markdown_text;
444 ts.bufferInit =
true;
447 ImVec2 editorSize = ImGui::GetContentRegionAvail();
448 float wrap_px = editorSize.x - ImGui::GetStyle().FramePadding.x * 2.0f;
455 ImGuiInputTextFlags_AllowTabInput);
460 ImGui::InvisibleButton(
"##split2", ImVec2(splitterW, 0.f));
465 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.f, 8.f));
466 ImGui::BeginChild(
"##viewer", ImVec2(viewerW, 0.f),
true);
469 ImGui::TextDisabled(
"Author: %s", n->author.c_str());
471 ImGui::TextDisabled(
"Created: %lld", (
long long)toMs(n->creation_ts));
473 ImGui::TextDisabled(
"Updated: %lld", (
long long)toMs(n->last_update_ts));
477 md_.
onRoll = [
this](
const std::string& expr)
491 const std::string& md = n->open_editor ?
tabState_[uuid].editBuffer : n->markdown_text;
493 ImGui::PushTextWrapPos(0.f);
495 md_.print(md.c_str(), md.c_str() + md.size());
497 ImGui::TextDisabled(
"(empty)");
498 ImGui::PopTextWrapPos();
501 ImGui::PopStyleVar();
507 if (ts.bufferInit && ts.editBuffer != n->markdown_text)
514 static char titleBuf[128] = {0};
515 static char authorBuf[128] = {0};
516 ImGui::OpenPopup(
"Create Note");
517 if (ImGui::BeginPopupModal(
"Create Note",
nullptr, ImGuiWindowFlags_AlwaysAutoResize))
519 ImGui::InputText(
"Title", titleBuf,
sizeof(titleBuf));
521 ImGui::InputText(
"Author", authorBuf,
sizeof(authorBuf));
523 if (ImGui::Button(
"Create"))
525 std::string title = titleBuf[0] ? titleBuf :
"Untitled";
526 std::string author = authorBuf[0] ? authorBuf :
"unknown";
531 ImGui::CloseCurrentPopup();
534 if (ImGui::Button(
"Cancel"))
536 ImGui::CloseCurrentPopup();
549 ImGui::OpenPopup(
"Delete Note?");
550 if (ImGui::BeginPopupModal(
"Delete Note?",
nullptr, ImGuiWindowFlags_AlwaysAutoResize))
552 static bool alsoDisk =
false;
553 ImGui::Checkbox(
"Also delete from disk", &alsoDisk);
554 if (ImGui::Button(
"Delete"))
560 int idx = (int)std::distance(
openTabs_.begin(), it);
564 ImGui::CloseCurrentPopup();
567 if (ImGui::Button(
"Cancel"))
569 ImGui::CloseCurrentPopup();
640 std::transform(needle.begin(), needle.end(), needle.begin(), ::tolower);
641 auto contains = [&](
const std::string& hay)
643 std::string low = hay;
644 std::transform(low.begin(), low.end(), low.begin(), ::tolower);
645 return low.find(needle) != std::string::npos;
647 return contains(n.title) || contains(n.author) || contains(n.markdown_text);