Replace history popup with inline dropdown painted on main surface
This commit is contained in:
+93
-8
@@ -153,6 +153,9 @@ RectF g_sBack, g_sSave, g_sCancel;
|
|||||||
RECT g_sContent = {0,0,0,0};
|
RECT g_sContent = {0,0,0,0};
|
||||||
struct CatRowRect { RectF row, btn; };
|
struct CatRowRect { RectF row, btn; };
|
||||||
int g_setHot = -1;
|
int g_setHot = -1;
|
||||||
|
int g_histOpen = -1;
|
||||||
|
int g_histScroll = 0;
|
||||||
|
int g_histHot = -1;
|
||||||
Downloader g_dl;
|
Downloader g_dl;
|
||||||
enum class DlState { NotInstalled, Downloading, Installed };
|
enum class DlState { NotInstalled, Downloading, Installed };
|
||||||
struct CatState { DlState state = DlState::NotInstalled; int pct = 0; };
|
struct CatState { DlState state = DlState::NotInstalled; int pct = 0; };
|
||||||
@@ -651,7 +654,9 @@ LRESULT CALLBACK PopupProc(HWND h, UINT m, WPARAM w, LPARAM l) {
|
|||||||
PostMessageW(g_pop.owner, WM_APP_SELECT, (WPARAM)g_pop.ctrlId, (LPARAM)row);
|
PostMessageW(g_pop.owner, WM_APP_SELECT, (WPARAM)g_pop.ctrlId, (LPARAM)row);
|
||||||
DestroyWindow(h); return 0;
|
DestroyWindow(h); return 0;
|
||||||
}
|
}
|
||||||
case WM_KILLFOCUS: DestroyWindow(h); return 0;
|
case WM_ACTIVATE:
|
||||||
|
if (LOWORD(w) == WA_INACTIVE) DestroyWindow(h);
|
||||||
|
return 0;
|
||||||
case WM_ERASEBKGND: return 1;
|
case WM_ERASEBKGND: return 1;
|
||||||
case WM_PAINT: {
|
case WM_PAINT: {
|
||||||
PAINTSTRUCT ps; HDC hdc = BeginPaint(h, &ps);
|
PAINTSTRUCT ps; HDC hdc = BeginPaint(h, &ps);
|
||||||
@@ -968,6 +973,40 @@ void PaintSurface(HWND hwnd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_histOpen >= 0 && g_view == View::Main) {
|
||||||
|
RectF& anchor = g_w[(int)WK::History].r;
|
||||||
|
float s = g_dpiScale;
|
||||||
|
REAL dropW = (REAL)(int)(anchor.Width);
|
||||||
|
REAL dropX = anchor.X;
|
||||||
|
REAL dropY = anchor.Y + anchor.Height + 2 * s;
|
||||||
|
int maxVis = std::min(g_histOpen, 6);
|
||||||
|
REAL rowH = 30 * s;
|
||||||
|
REAL dropH = maxVis * rowH + 6 * s;
|
||||||
|
|
||||||
|
Rect dropR((int)dropX, (int)dropY, (int)dropW, (int)dropH);
|
||||||
|
FillRound(g, T_CARD, dropR, (int)(10 * s));
|
||||||
|
StrokeRound(g, T_FAINT, dropR, (int)(10 * s), 1.0f);
|
||||||
|
|
||||||
|
int startIdx = g_histScroll;
|
||||||
|
for (int i = 0; i < maxVis && (startIdx + i) < (int)g_history.size(); ++i) {
|
||||||
|
int gi = startIdx + i;
|
||||||
|
Rect rowR((int)(dropX + 3 * s), (int)(dropY + 3 * s + i * rowH),
|
||||||
|
(int)(dropW - 6 * s), (int)(rowH));
|
||||||
|
if (gi == g_histHot)
|
||||||
|
FillRound(g, T_CARD_HI, rowR, (int)(7 * s));
|
||||||
|
RectF tb((REAL)rowR.X + 6 * s, (REAL)rowR.Y, (REAL)rowR.Width - 12 * s, (REAL)rowR.Height);
|
||||||
|
DrawTextC(g, g_history[gi].label.c_str(), *g_gpUI, T_TEXT,
|
||||||
|
tb, StringAlignmentNear, StringAlignmentCenter);
|
||||||
|
}
|
||||||
|
if (g_histOpen > maxVis) {
|
||||||
|
REAL scrollH = dropH - 2 * s;
|
||||||
|
REAL thumbH = scrollH * maxVis / g_histOpen;
|
||||||
|
REAL thumbY = dropY + 1 * s + (scrollH - thumbH) * g_histScroll / (g_histOpen - maxVis);
|
||||||
|
Rect thumb((int)(dropX + dropW - 6 * s), (int)thumbY, (int)(4 * s), (int)thumbH);
|
||||||
|
FillRound(g, T_DIM, thumb, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RECT vr = g_vuRect;
|
RECT vr = g_vuRect;
|
||||||
RectF stripRect((REAL)vr.left, (REAL)vr.top, (REAL)(vr.right - vr.left), (REAL)(vr.bottom - vr.top));
|
RectF stripRect((REAL)vr.left, (REAL)vr.top, (REAL)(vr.right - vr.left), (REAL)(vr.bottom - vr.top));
|
||||||
DrawStatusStrip(g, stripRect);
|
DrawStatusStrip(g, stripRect);
|
||||||
@@ -1018,6 +1057,21 @@ void PaintSurface(HWND hwnd) {
|
|||||||
EndPaint(hwnd, &ps);
|
EndPaint(hwnd, &ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int HistDropHitTest(POINT p) {
|
||||||
|
if (g_histOpen <= 0) return -1;
|
||||||
|
RectF& anchor = g_w[(int)WK::History].r;
|
||||||
|
float s = g_dpiScale;
|
||||||
|
REAL dropX = anchor.X, dropY = anchor.Y + anchor.Height + 2*s;
|
||||||
|
REAL dropW = anchor.Width, rowH = 30*s;
|
||||||
|
REAL dropH = std::min(g_histOpen, 6) * rowH + 6*s;
|
||||||
|
if (p.x < dropX || p.x > dropX + dropW || p.y < dropY || p.y > dropY + dropH)
|
||||||
|
return -1;
|
||||||
|
int idx = (int)((p.y - dropY - 3*s) / rowH);
|
||||||
|
int realIdx = g_histScroll + idx;
|
||||||
|
if (realIdx < 0 || realIdx >= (int)g_history.size()) return -1;
|
||||||
|
return realIdx;
|
||||||
|
}
|
||||||
|
|
||||||
int HitTest(POINT p) {
|
int HitTest(POINT p) {
|
||||||
for (int i = 0; i < (int)std::size(g_w); ++i)
|
for (int i = 0; i < (int)std::size(g_w); ++i)
|
||||||
if (g_w[i].kind != WK::Transcript && g_w[i].r.Contains((REAL)p.x, (REAL)p.y)) return i;
|
if (g_w[i].kind != WK::Transcript && g_w[i].r.Contains((REAL)p.x, (REAL)p.y)) return i;
|
||||||
@@ -1077,13 +1131,11 @@ void OnClick(HWND hWnd, WK kind) {
|
|||||||
ShowSelectPopup(hWnd, ID_SEL_AUDIO, g_audioItems, g_audioSel, g_w[(int)WK::SelAudio].r);
|
ShowSelectPopup(hWnd, ID_SEL_AUDIO, g_audioItems, g_audioSel, g_w[(int)WK::SelAudio].r);
|
||||||
break;
|
break;
|
||||||
case WK::History: {
|
case WK::History: {
|
||||||
wchar_t dbg[64];
|
if (g_histOpen >= 0) { g_histOpen = -1; InvalidateRect(hWnd, nullptr, FALSE); break; }
|
||||||
swprintf_s(dbg, L"History: %d entries", (int)g_history.size());
|
if (g_history.empty()) { SetStatus(hWnd, L"No history yet"); break; }
|
||||||
SetStatus(hWnd, dbg);
|
g_histOpen = (int)g_history.size();
|
||||||
std::vector<std::wstring> items;
|
g_histScroll = 0; g_histHot = -1;
|
||||||
for (auto& e : g_history) items.push_back(e.label);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
if (items.empty()) items.push_back(L"No history yet");
|
|
||||||
ShowSelectPopup(hWnd, ID_SEL_HISTORY, items, -1, g_w[(int)WK::History].r);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WK::SettingsCog: SwitchView(hWnd, View::Settings); break;
|
case WK::SettingsCog: SwitchView(hWnd, View::Settings); break;
|
||||||
@@ -1361,6 +1413,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
|
if (g_histOpen > 0) {
|
||||||
|
int dh = HistDropHitTest(p);
|
||||||
|
if (dh != g_histHot) { g_histHot = dh; InvalidateRect(hWnd, nullptr, FALSE); }
|
||||||
|
}
|
||||||
int hot = HitTest(p);
|
int hot = HitTest(p);
|
||||||
if (hot != g_hot) {
|
if (hot != g_hot) {
|
||||||
if (g_hot >= 0) g_w[g_hot].hover = false;
|
if (g_hot >= 0) g_w[g_hot].hover = false;
|
||||||
@@ -1373,9 +1429,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
}
|
}
|
||||||
case WM_MOUSELEAVE:
|
case WM_MOUSELEAVE:
|
||||||
if (g_hot >= 0) { g_w[g_hot].hover = false; g_hot = -1; EnsureAnimating(hWnd); }
|
if (g_hot >= 0) { g_w[g_hot].hover = false; g_hot = -1; EnsureAnimating(hWnd); }
|
||||||
|
if (g_histHot >= 0) { g_histHot = -1; InvalidateRect(hWnd, nullptr, FALSE); }
|
||||||
return 0;
|
return 0;
|
||||||
case WM_LBUTTONDOWN:
|
case WM_LBUTTONDOWN:
|
||||||
if (g_view == View::Settings) return 0;
|
if (g_view == View::Settings) return 0;
|
||||||
|
if (g_histOpen > 0) {
|
||||||
|
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
|
if (HistDropHitTest(p) < 0) { g_histOpen = -1; g_histHot = -1; g_active = -1; InvalidateRect(hWnd, nullptr, FALSE); return 0; }
|
||||||
|
}
|
||||||
g_active = g_hot;
|
g_active = g_hot;
|
||||||
if (g_active >= 0) { g_w[g_active].pressed = true; SetCapture(hWnd); EnsureAnimating(hWnd); }
|
if (g_active >= 0) { g_w[g_active].pressed = true; SetCapture(hWnd); EnsureAnimating(hWnd); }
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1385,6 +1446,25 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
OnSettingsClick(hWnd, p);
|
OnSettingsClick(hWnd, p);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (g_histOpen > 0) {
|
||||||
|
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
|
int dh = HistDropHitTest(p);
|
||||||
|
if (dh >= 0 && dh < (int)g_history.size()) {
|
||||||
|
std::wstring cur = GetEditText(hWnd);
|
||||||
|
if (!cur.empty() && cur != g_lastLoadedText)
|
||||||
|
ArchiveSession(cur);
|
||||||
|
std::wstring text = ReadFileUtf8(g_history[dh].path);
|
||||||
|
SetWindowTextW(GetDlgItem(hWnd, ID_EDIT_TEXT), text.c_str());
|
||||||
|
g_lastLoadedText = text;
|
||||||
|
g_editDirty = false;
|
||||||
|
g_history = LoadHistoryIndex();
|
||||||
|
UpdatePlaceholder(hWnd);
|
||||||
|
SetStatus(hWnd, L"Loaded from history");
|
||||||
|
}
|
||||||
|
g_histOpen = -1; g_histHot = -1;
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
ReleaseCapture();
|
ReleaseCapture();
|
||||||
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
POINT p{ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
if (g_active >= 0 && HitTest(p) == g_active) OnClick(hWnd, g_w[g_active].kind);
|
if (g_active >= 0 && HitTest(p) == g_active) OnClick(hWnd, g_w[g_active].kind);
|
||||||
@@ -1401,6 +1481,11 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
LayoutSettings(rc.right, rc.bottom);
|
LayoutSettings(rc.right, rc.bottom);
|
||||||
InvalidateRect(hWnd, nullptr, FALSE);
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
}
|
}
|
||||||
|
if (g_histOpen > 6) {
|
||||||
|
g_histScroll -= GET_WHEEL_DELTA_WPARAM(wParam) / 60;
|
||||||
|
g_histScroll = std::max(0, std::min(g_histScroll, g_histOpen - 6));
|
||||||
|
InvalidateRect(hWnd, nullptr, FALSE);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case WM_DPICHANGED: {
|
case WM_DPICHANGED: {
|
||||||
|
|||||||
Reference in New Issue
Block a user