75 dc.SetBackground(wxBrush(wxColour(40, 40, 40)));
81 dc.SetTextForeground(wxColour(150, 150, 150));
82 dc.SetFont(wxFont(11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL));
83 dc.DrawText(
"No blackboards loaded", 20, 20);
90 int contentWidth = panelWidth - 30;
98 m_scrollPanel->CalcUnscrolledPosition(0, 0,
nullptr, &scrollPx);
100 viewY1 = scrollPx +
m_scrollPanel->GetClientSize().GetHeight();
103 auto isVisible = [&](
int top,
int height) {
return top + height >= viewY0 && top <= viewY1; };
106 auto truncate = [&dc](
const wxString &text,
int maxWidth) -> wxString {
109 if (dc.GetTextExtent(text).GetWidth() <= maxWidth)
111 size_t lo = 0, hi = text.Length();
113 size_t mid = (lo + hi + 1) / 2;
114 if (dc.GetTextExtent(text.Left(mid) +
"...").GetWidth() <= maxWidth)
119 return lo > 0 ? text.Left(lo) +
"..." :
"...";
124 int summaryHeight = 60;
125 if (isVisible(y, summaryHeight)) {
127 int totalEntries = 0;
130 totalEntries +=
static_cast<int>(kv.second->GetEntryCount());
133 dc.SetBrush(wxBrush(wxColour(50, 50, 60)));
134 dc.SetPen(wxPen(wxColour(100, 130, 200), 1));
135 dc.DrawRoundedRectangle(x, y, contentWidth, summaryHeight, 5);
137 dc.SetTextForeground(wxColour(130, 180, 255));
138 dc.SetFont(wxFont(11, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
139 dc.DrawText(
"Blackboard Overview", x + 10, y + 8);
141 dc.SetFont(wxFont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
142 dc.SetTextForeground(wxColour(200, 200, 200));
143 dc.DrawText(wxString::Format(
"Total: %d blackboard(s), %d entries", totalBBs, totalEntries), x + 15,
146 y += summaryHeight + 15;
151 int tableWidth = contentWidth - 40;
152 int col1W = tableWidth * 45 / 100;
153 int col2W = tableWidth * 25 / 100;
154 int col3W = tableWidth - col1W - col2W;
157 wxFont headerFont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
158 wxFont incFont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
159 wxFont tableHeaderFont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
160 wxFont monoFont(9, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
168 const auto &bb = bbIt->second;
169 size_t entryCount = bb->GetEntryCount();
174 if (!isCollapsed && entryCount > 0)
175 cardHeight +=
ROW_H +
static_cast<int>(entryCount) *
ROW_H;
185 if (y + cardHeight < viewY0) {
192 dc.SetBrush(wxBrush(wxColour(70, 50, 90)));
193 dc.SetPen(wxPen(wxColour(150, 100, 200), 1));
194 dc.DrawRoundedRectangle(x + 10, y, contentWidth - 20,
CARD_HEADER_H, 3);
198 dc.SetPen(wxPen(wxColour(200, 170, 240), 1));
199 dc.SetBrush(wxBrush(wxColour(200, 170, 240)));
201 wxPoint tri[3] = {wxPoint(triX, triY), wxPoint(triX, triY + 8), wxPoint(triX + 6, triY + 4)};
202 dc.DrawPolygon(3, tri);
204 wxPoint tri[3] = {wxPoint(triX, triY), wxPoint(triX + 8, triY), wxPoint(triX + 4, triY + 6)};
205 dc.DrawPolygon(3, tri);
208 dc.SetTextForeground(wxColour(220, 180, 255));
209 dc.SetFont(headerFont);
210 wxString headerText =
211 wxString::Format(
"[%s] (%zu entr%s)", bbId, entryCount, entryCount == 1 ?
"y" :
"ies");
212 dc.DrawText(headerText, x + 32, y + 4);
215 if (incIt !=
m_includesMap.end() && !incIt->second.empty()) {
216 dc.SetTextForeground(wxColour(180, 150, 200));
218 wxString incText =
"includes: {";
219 for (
size_t i = 0; i < incIt->second.size(); ++i) {
222 incText += wxString::FromUTF8(incIt->second[i]);
225 int maxW = contentWidth - 250;
227 incText = truncate(incText, maxW);
228 int incTextW = dc.GetTextExtent(incText).GetWidth();
229 dc.DrawText(incText, x + contentWidth - 20 - incTextW, y + 6);
236 if (!isCollapsed && entryCount > 0) {
238 if (isVisible(y,
ROW_H)) {
239 dc.SetBrush(wxBrush(wxColour(55, 55, 65)));
240 dc.SetPen(wxPen(wxColour(80, 80, 100), 1));
241 dc.DrawRectangle(tableX, y, col1W,
ROW_H);
242 dc.DrawRectangle(tableX + col1W, y, col2W,
ROW_H);
243 dc.DrawRectangle(tableX + col1W + col2W, y, col3W,
ROW_H);
245 dc.SetTextForeground(wxColour(180, 180, 220));
246 dc.SetFont(tableHeaderFont);
247 dc.DrawText(
"Key", tableX + 5, y + 4);
248 dc.DrawText(
"Type", tableX + col1W + 5, y + 4);
249 dc.DrawText(
"Value", tableX + col1W + col2W + 5, y + 4);
255 for (
const auto &entryPair : bb->GetEntries()) {
256 const auto &entry = entryPair.second;
260 if (isVisible(y,
ROW_H)) {
261 wxColour rowBg = (ei % 2 == 0) ? wxColour(45, 45, 50) : wxColour(50, 50, 55);
262 dc.SetBrush(wxBrush(rowBg));
263 dc.SetPen(wxPen(wxColour(60, 60, 70), 1));
264 dc.DrawRectangle(tableX, y, col1W,
ROW_H);
265 dc.DrawRectangle(tableX + col1W, y, col2W,
ROW_H);
266 dc.DrawRectangle(tableX + col1W + col2W, y, col3W,
ROW_H);
268 dc.SetFont(monoFont);
269 dc.SetTextForeground(wxColour(200, 200, 200));
270 dc.DrawText(truncate(wxString::FromUTF8(entry->GetKey()), col1W - 10), tableX + 5, y + 4);
272 dc.SetTextForeground(wxColour(150, 200, 180));
273 dc.DrawText(truncate(wxString::FromUTF8(entry->GetTypeString()), col2W - 10), tableX + col1W + 5,
276 dc.SetTextForeground(wxColour(180, 180, 150));
277 dc.DrawText(truncate(wxString::FromUTF8(entry->GetValue()), col3W - 10), tableX + col1W + col2W + 5,