27 ImGuiIO& io = ImGui::GetIO();
35 ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
36 ImGui::SetNextWindowSize(ImVec2(
drawer_width_, io.DisplaySize.y), ImGuiCond_Always);
38 ImGuiWindowFlags flags = ImGuiWindowFlags_NoMove |
39 ImGuiWindowFlags_NoResize |
40 ImGuiWindowFlags_NoCollapse |
41 ImGuiWindowFlags_NoTitleBar;
44 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 2.0f);
45 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
49 ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(
50 theme.provider_ollama.x * border_pulse,
51 theme.provider_ollama.y * border_pulse,
52 theme.provider_ollama.z * border_pulse + 0.2f,
56 if (ImGui::Begin(
"##AgentChatPopup", &
visible_, flags)) {
63 float list_height = ImGui::GetContentRegionAvail().y - 220.0f;
66 ImVec4 terminal_bg = theme.code_bg_color;
67 terminal_bg.x *= 0.9f;
68 terminal_bg.y *= 0.9f;
69 terminal_bg.z *= 0.95f;
71 ImGui::PushStyleColor(ImGuiCol_ChildBg, terminal_bg);
72 ImGui::BeginChild(
"MessageList", ImVec2(0, list_height),
true, ImGuiWindowFlags_AlwaysVerticalScrollbar);
75 ImDrawList* draw_list = ImGui::GetWindowDrawList();
76 ImVec2 win_pos = ImGui::GetWindowPos();
77 ImVec2 win_size = ImGui::GetWindowSize();
79 for (
float y = 0; y < win_size.y; y += 3.0f) {
81 if (offset_y < win_size.y) {
83 ImVec2(win_pos.x, win_pos.y + offset_y),
84 ImVec2(win_pos.x + win_size.x, win_pos.y + offset_y),
85 IM_COL32(0, 0, 0, 15));
92 ImGui::SetScrollHereY(1.0f);
97 ImGui::PopStyleColor();
112 ImGui::PopStyleColor();
113 ImGui::PopStyleVar(2);
143 ImGui::PushID(index);
148 ImVec4 header_color = from_user
149 ? ImVec4(1.0f, 0.85f, 0.0f, 1.0f)
150 : ImVec4(0.0f, 1.0f, 0.7f, 1.0f);
152 const char* sender_label = from_user ?
"> USER:" :
"> AGENT:";
155 ImGui::TextColored(header_color,
"%s", sender_label);
158 ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f),
159 "[%s]", absl::FormatTime(
"%H:%M:%S", msg.
timestamp, absl::LocalTimeZone()).c_str());
162 ImGui::Indent(15.0f);
165 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.9f, 1.0f),
168 ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.9f, 1.0f),
172 std::string content = msg.
message;
173 if (content.length() > 200) {
174 content = content.substr(0, 197) +
"...";
176 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.85f, 0.85f, 0.85f, 1.0f));
177 ImGui::TextWrapped(
" %s", content.c_str());
178 ImGui::PopStyleColor();
184 ImGui::TextColored(ImVec4(0.2f, proposal_pulse, 0.4f, 1.0f),
188 ImGui::Unindent(15.0f);
192 ImDrawList* draw_list = ImGui::GetWindowDrawList();
193 ImVec2 line_start = ImGui::GetCursorScreenPos();
194 float line_width = ImGui::GetContentRegionAvail().x;
197 ImVec2(line_start.x + line_width, line_start.y),
198 IM_COL32(60, 60, 70, 100),
202 ImGui::Dummy(ImVec2(0, 2));
209 ImDrawList* draw_list = ImGui::GetWindowDrawList();
210 ImVec2 header_start = ImGui::GetCursorScreenPos();
211 ImVec2 header_size(ImGui::GetContentRegionAvail().x, 55);
215 ImVec4 bg_top = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
216 ImVec4 bg_bottom = ImGui::GetStyleColorVec4(ImGuiCol_ChildBg);
217 bg_top.x += 0.1f * pulse;
218 bg_top.y += 0.1f * pulse;
219 bg_top.z += 0.15f * pulse;
221 ImU32 color_top = ImGui::GetColorU32(bg_top);
222 ImU32 color_bottom = ImGui::GetColorU32(bg_bottom);
223 draw_list->AddRectFilledMultiColor(
225 ImVec2(header_start.x + header_size.x, header_start.y + header_size.y),
226 color_top, color_top, color_bottom, color_bottom);
230 ImU32 accent_color = IM_COL32(
231 static_cast<int>(theme.provider_ollama.x * 255 * line_pulse),
232 static_cast<int>(theme.provider_ollama.y * 255 * line_pulse),
233 static_cast<int>(theme.provider_ollama.z * 255 * line_pulse + 50),
237 ImVec2(header_start.x, header_start.y + header_size.y),
238 ImVec2(header_start.x + header_size.x, header_start.y + header_size.y),
241 ImGui::Dummy(ImVec2(0, 8));
244 ImVec4 title_color = ImVec4(
250 ImGui::PushStyleColor(ImGuiCol_Text, title_color);
252 ImGui::PopStyleColor();
255 ImGui::TextDisabled(
"[v0.4.x]");
258 ImGui::SameLine(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 75.0f);
262 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.4f, 0.6f, 0.7f));
268 ImGui::PopStyleColor();
270 if (ImGui::IsItemHovered()) {
271 ImGui::SetTooltip(
compact_mode_ ?
"Expand view" :
"Compact view");
283 if (ImGui::IsItemHovered()) {
284 ImGui::SetTooltip(
"Open full chat");
293 if (ImGui::IsItemHovered()) {
294 ImGui::SetTooltip(
"Close (Ctrl+H)");
298 int visible_count = 0;
300 if (msg.is_internal)
continue;
309 ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f),
310 "> MESSAGES: [%d]", visible_count);
316 ImGui::TextColored(ImVec4(1.0f, unread_pulse * 0.5f, 0.0f, 1.0f),
320 ImGui::Dummy(ImVec2(0, 5));
325 float button_width = (ImGui::GetContentRegionAvail().x - 15) / 4.0f;
333 if (ImGui::IsItemHovered()) {
334 ImGui::SetTooltip(
"Capture screenshot");
342 if (ImGui::Button(filter_icons[filter_idx], ImVec2(button_width, 30))) {
343 ImGui::OpenPopup(
"FilterPopup");
345 if (ImGui::IsItemHovered()) {
346 const char* filter_names[] = {
"All",
"User only",
"Agent only"};
347 ImGui::SetTooltip(
"Filter: %s", filter_names[filter_idx]);
351 if (ImGui::BeginPopup(
"FilterPopup")) {
367 if (ImGui::Button(
ICON_MD_SAVE, ImVec2(button_width, 30))) {
372 if (ImGui::IsItemHovered()) {
373 ImGui::SetTooltip(
"Save chat session");
382 if (ImGui::IsItemHovered()) {
383 ImGui::SetTooltip(
"Clear popup view");
392 bool send_message =
false;
395 ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CtrlEnterForNewLine)) {
401 ImGui::SetKeyboardFocusHere(-1);
407 float send_button_width = ImGui::GetContentRegionAvail().x;
408 if (ImGui::Button(absl::StrFormat(
"%s Send",
ICON_MD_SEND).c_str(), ImVec2(send_button_width, 32)) || send_message) {
415 if (ImGui::IsItemHovered()) {
416 ImGui::SetTooltip(
"Send message (Enter) • Ctrl+Enter for newline");
421 ImGui::TextDisabled(
ICON_MD_INFO " Enter: send • Ctrl+Enter: newline");