a76ec74338
C++ ImGui kanban for steering LLM agents. Six panels (Board, Calendar, Dashboard, Agent runs, Worktrees, DoD inspector) wired to registry functions http_request, kpi_card, sparkline, agent_runs_timeline, dod_evidence_panel. Backend Go on :8403 (independent operations.db from kanban_web).
98 lines
3.2 KiB
C++
98 lines
3.2 KiB
C++
// panel_calendar.cpp — MVP monthly calendar view.
|
|
//
|
|
// Renders a simple 7-column grid for the current month with cards bucketed
|
|
// by `due_date`. No navigation, no editing — that's tracked as TODO in
|
|
// app.md ## Gotchas.
|
|
#include "panels.h"
|
|
#include "core/icons_tabler.h"
|
|
|
|
#include <imgui.h>
|
|
#include <ctime>
|
|
|
|
namespace kanban_cpp {
|
|
|
|
void draw_calendar(AppState& s, bool* p_open) {
|
|
if (!ImGui::Begin(TI_CALENDAR " Calendar", p_open)) {
|
|
ImGui::End();
|
|
return;
|
|
}
|
|
|
|
std::time_t now = std::time(nullptr);
|
|
std::tm tm_now;
|
|
#ifdef _WIN32
|
|
localtime_s(&tm_now, &now);
|
|
#else
|
|
localtime_r(&now, &tm_now);
|
|
#endif
|
|
|
|
// Heading
|
|
static const char* months[] = {"Enero","Febrero","Marzo","Abril","Mayo","Junio",
|
|
"Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"};
|
|
ImGui::Text("%s %d", months[tm_now.tm_mon], tm_now.tm_year + 1900);
|
|
ImGui::TextDisabled("(MVP estatico — TODO: navegacion + filtros)");
|
|
ImGui::Separator();
|
|
|
|
// First day of current month + days in month
|
|
std::tm tm_first = tm_now;
|
|
tm_first.tm_mday = 1;
|
|
std::mktime(&tm_first);
|
|
int first_wday = tm_first.tm_wday; // 0 = Sunday
|
|
int first_wday_mon = (first_wday + 6) % 7; // 0 = Monday (ES convention)
|
|
|
|
int days_in_month = 31;
|
|
{
|
|
std::tm tm_test = tm_now;
|
|
tm_test.tm_mday = 32;
|
|
std::mktime(&tm_test);
|
|
days_in_month = 32 - tm_test.tm_mday;
|
|
}
|
|
|
|
// Grid 7 cols
|
|
if (ImGui::BeginTable("##cal", 7, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame)) {
|
|
const char* wdays[] = {"L","M","X","J","V","S","D"};
|
|
for (int i = 0; i < 7; ++i) ImGui::TableSetupColumn(wdays[i]);
|
|
ImGui::TableHeadersRow();
|
|
|
|
int day = 1;
|
|
int total_cells = first_wday_mon + days_in_month;
|
|
int rows = (total_cells + 6) / 7;
|
|
int cell_index = 0;
|
|
|
|
for (int r = 0; r < rows; ++r) {
|
|
ImGui::TableNextRow();
|
|
for (int c = 0; c < 7; ++c) {
|
|
ImGui::TableSetColumnIndex(c);
|
|
if (cell_index < first_wday_mon || day > days_in_month) {
|
|
ImGui::TextDisabled(" ");
|
|
} else {
|
|
ImGui::Text("%d", day);
|
|
// Count cards whose due_date falls in this day.
|
|
int hits = 0;
|
|
for (const auto& card : s.cards) {
|
|
if (card.due_date == 0) continue;
|
|
std::time_t cd = (std::time_t)card.due_date;
|
|
std::tm tmc;
|
|
#ifdef _WIN32
|
|
localtime_s(&tmc, &cd);
|
|
#else
|
|
localtime_r(&cd, &tmc);
|
|
#endif
|
|
if (tmc.tm_year == tm_now.tm_year && tmc.tm_mon == tm_now.tm_mon
|
|
&& tmc.tm_mday == day) ++hits;
|
|
}
|
|
if (hits > 0)
|
|
ImGui::TextColored(ImVec4(0.6f, 0.55f, 0.95f, 1.0f),
|
|
TI_FLAG " %d", hits);
|
|
++day;
|
|
}
|
|
++cell_index;
|
|
}
|
|
}
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
} // namespace kanban_cpp
|