media:cpp --uinext win32xx 2/2
This commit is contained in:
parent
c18f4878e8
commit
3a1ac7ff00
BIN
packages/media/cpp/dist/pm-image.exe
vendored
BIN
packages/media/cpp/dist/pm-image.exe
vendored
Binary file not shown.
BIN
packages/media/cpp/dist/pm-image.pdb
vendored
BIN
packages/media/cpp/dist/pm-image.pdb
vendored
Binary file not shown.
@ -2,6 +2,7 @@
|
||||
#include "Mainfrm.h"
|
||||
#include "Resource.h"
|
||||
#include "core/resize.hpp"
|
||||
#include "core/transform.hpp"
|
||||
#include <shlobj.h>
|
||||
#include <filesystem>
|
||||
|
||||
@ -36,6 +37,7 @@ STDMETHODIMP CMainFrame::Execute(UINT32 cmdID, UI_EXECUTIONVERB verb,
|
||||
case IDC_CMD_ADD_FOLDER: OnAddFolder(); break;
|
||||
case IDC_CMD_CLEAR: OnClearQueue(); break;
|
||||
case IDC_CMD_RESIZE: OnResize(); break;
|
||||
case IDC_CMD_TRANSFORM: OnTransform(); break;
|
||||
case IDC_CMD_ABOUT: OnHelp(); break;
|
||||
case IDC_CMD_EXIT: OnExit(); break;
|
||||
case IDC_RIBBONHELP: OnHelp(); break;
|
||||
@ -256,6 +258,201 @@ void CMainFrame::OnResize()
|
||||
GetStatusBar().SetPartText(0, L"Resizing\u2026");
|
||||
}
|
||||
|
||||
std::vector<int> CMainFrame::GetSelectedQueueItems()
|
||||
{
|
||||
std::vector<int> sel;
|
||||
if (!m_pDockQueue) return sel;
|
||||
auto& lv = m_pDockQueue->GetQueueContainer().GetListView();
|
||||
int idx = -1;
|
||||
while ((idx = lv.GetNextItem(idx, LVNI_SELECTED)) != -1)
|
||||
sel.push_back(idx);
|
||||
if (sel.empty()) {
|
||||
int total = lv.QueueCount();
|
||||
for (int i = 0; i < total; ++i) sel.push_back(i);
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK PromptDlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
|
||||
{
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG: {
|
||||
::SetWindowLongPtr(hwnd, GWLP_USERDATA, lp);
|
||||
auto* prompt = reinterpret_cast<std::wstring*>(lp);
|
||||
if (!prompt->empty())
|
||||
::SetDlgItemTextW(hwnd, IDC_EDIT_PROMPT, prompt->c_str());
|
||||
|
||||
RECT rc;
|
||||
::GetClientRect(hwnd, &rc);
|
||||
int w = rc.right - rc.left, h = rc.bottom - rc.top;
|
||||
int margin = 10;
|
||||
|
||||
HWND hLabel = ::GetDlgItem(hwnd, IDC_STATIC_PROMPT_LABEL);
|
||||
::SetWindowPos(hLabel, nullptr, margin, margin, w - 2*margin, 20, SWP_NOZORDER);
|
||||
|
||||
HWND hEdit = ::GetDlgItem(hwnd, IDC_EDIT_PROMPT);
|
||||
::SetWindowPos(hEdit, nullptr, margin, 35, w - 2*margin, h - 80, SWP_NOZORDER);
|
||||
|
||||
HWND hOk = ::GetDlgItem(hwnd, IDOK);
|
||||
HWND hCancel = ::GetDlgItem(hwnd, IDCANCEL);
|
||||
int btnW = 80, btnH = 28;
|
||||
::SetWindowPos(hOk, nullptr, w - 2*(btnW + margin), h - btnH - margin, btnW, btnH, SWP_NOZORDER);
|
||||
::SetWindowPos(hCancel, nullptr, w - btnW - margin, h - btnH - margin, btnW, btnH, SWP_NOZORDER);
|
||||
|
||||
HFONT hFont = static_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
|
||||
::SendMessage(hLabel, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||||
::SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||||
::SendMessage(hOk, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||||
::SendMessage(hCancel, WM_SETFONT, (WPARAM)hFont, TRUE);
|
||||
|
||||
::SetFocus(hEdit);
|
||||
return FALSE;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wp) == IDOK) {
|
||||
auto* prompt = reinterpret_cast<std::wstring*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
wchar_t buf[4096]{};
|
||||
::GetDlgItemTextW(hwnd, IDC_EDIT_PROMPT, buf, 4095);
|
||||
*prompt = buf;
|
||||
::EndDialog(hwnd, IDOK);
|
||||
return TRUE;
|
||||
}
|
||||
if (LOWORD(wp) == IDCANCEL) {
|
||||
::EndDialog(hwnd, IDCANCEL);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
::EndDialog(hwnd, IDCANCEL);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static HWND CreatePromptDialog(HWND parent, std::wstring& prompt)
|
||||
{
|
||||
// Build a dialog template in memory
|
||||
alignas(DWORD) BYTE buf[2048]{};
|
||||
DLGTEMPLATE* dlg = reinterpret_cast<DLGTEMPLATE*>(buf);
|
||||
dlg->style = DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE;
|
||||
dlg->cdit = 4; // label, edit, OK, Cancel
|
||||
dlg->cx = 280; dlg->cy = 160;
|
||||
|
||||
WORD* p = reinterpret_cast<WORD*>(dlg + 1);
|
||||
*p++ = 0; // menu
|
||||
*p++ = 0; // class
|
||||
// title "AI Transform - Enter Prompt"
|
||||
const wchar_t title[] = L"AI Transform - Enter Prompt";
|
||||
memcpy(p, title, sizeof(title));
|
||||
p += (sizeof(title) / sizeof(WORD));
|
||||
|
||||
// Align to DWORD
|
||||
if (reinterpret_cast<uintptr_t>(p) % 4) p++;
|
||||
|
||||
auto addItem = [&](DWORD style, short x, short y, short cx, short cy, WORD id, const wchar_t* cls, const wchar_t* text) {
|
||||
if (reinterpret_cast<uintptr_t>(p) % 4) p++;
|
||||
DLGITEMTEMPLATE* item = reinterpret_cast<DLGITEMTEMPLATE*>(p);
|
||||
item->style = style | WS_CHILD | WS_VISIBLE;
|
||||
item->x = x; item->y = y; item->cx = cx; item->cy = cy;
|
||||
item->id = id;
|
||||
p = reinterpret_cast<WORD*>(item + 1);
|
||||
// class
|
||||
size_t clen = wcslen(cls) + 1;
|
||||
memcpy(p, cls, clen * 2); p += clen;
|
||||
// text
|
||||
size_t tlen = wcslen(text) + 1;
|
||||
memcpy(p, text, tlen * 2); p += tlen;
|
||||
*p++ = 0; // extra
|
||||
};
|
||||
|
||||
// Label
|
||||
addItem(SS_LEFT, 6, 4, 268, 10, IDC_STATIC_PROMPT_LABEL,
|
||||
L"Static", L"Describe the transformation:");
|
||||
// Multiline edit
|
||||
addItem(ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_BORDER | WS_VSCROLL | WS_TABSTOP,
|
||||
6, 18, 268, 110, IDC_EDIT_PROMPT, L"Edit", L"");
|
||||
// OK button
|
||||
addItem(BS_DEFPUSHBUTTON | WS_TABSTOP, 150, 134, 56, 18, IDOK, L"Button", L"Transform");
|
||||
// Cancel button
|
||||
addItem(WS_TABSTOP, 212, 134, 56, 18, IDCANCEL, L"Button", L"Cancel");
|
||||
|
||||
INT_PTR result = ::DialogBoxIndirectParam(
|
||||
::GetModuleHandle(nullptr),
|
||||
dlg, parent, PromptDlgProc,
|
||||
reinterpret_cast<LPARAM>(&prompt));
|
||||
|
||||
return (result == IDOK) ? parent : nullptr;
|
||||
}
|
||||
|
||||
void CMainFrame::OnTransform()
|
||||
{
|
||||
if (m_processing) {
|
||||
::MessageBox(GetHwnd(), L"Already processing.", L"pm-image", MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
if (!m_pDockQueue) return;
|
||||
|
||||
auto indices = GetSelectedQueueItems();
|
||||
if (indices.empty()) {
|
||||
::MessageBox(GetHwnd(), L"Queue is empty \u2014 drop files first.", L"pm-image", MB_ICONINFORMATION);
|
||||
return;
|
||||
}
|
||||
|
||||
std::wstring prompt = m_lastPrompt;
|
||||
if (!CreatePromptDialog(GetHwnd(), prompt))
|
||||
return;
|
||||
if (prompt.empty()) {
|
||||
::MessageBox(GetHwnd(), L"Prompt cannot be empty.", L"pm-image", MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
m_lastPrompt = prompt;
|
||||
|
||||
std::string promptUtf8 = wide_to_utf8(prompt);
|
||||
|
||||
// Resolve API key
|
||||
std::string api_key;
|
||||
const char* env_key = std::getenv("IMAGE_TRANSFORM_GOOGLE_API_KEY");
|
||||
if (env_key && env_key[0] != '\0') api_key = env_key;
|
||||
|
||||
if (api_key.empty()) {
|
||||
::MessageBox(GetHwnd(),
|
||||
L"API key not found.\nSet IMAGE_TRANSFORM_GOOGLE_API_KEY in your .env file.",
|
||||
L"pm-image", MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
auto& lv = m_pDockQueue->GetQueueContainer().GetListView();
|
||||
std::vector<std::pair<int, std::string>> items;
|
||||
for (int idx : indices) {
|
||||
CString p = lv.GetItemPath(idx);
|
||||
items.emplace_back(idx, wide_to_utf8(std::wstring(p.c_str())));
|
||||
}
|
||||
|
||||
m_processing = true;
|
||||
HWND hwnd = GetHwnd();
|
||||
|
||||
m_worker = std::thread([items = std::move(items), promptUtf8, api_key, hwnd]() {
|
||||
int ok = 0, fail = 0;
|
||||
for (auto& [idx, input] : items) {
|
||||
::PostMessage(hwnd, UWM_TRANSFORM_PROGRESS, (WPARAM)idx, 1);
|
||||
|
||||
media::TransformOptions topts;
|
||||
topts.prompt = promptUtf8;
|
||||
topts.api_key = api_key;
|
||||
|
||||
std::string output = media::default_transform_output(input, promptUtf8);
|
||||
auto result = media::transform_image(input, output, topts, nullptr);
|
||||
|
||||
::PostMessage(hwnd, UWM_TRANSFORM_PROGRESS, (WPARAM)idx, result.ok ? 2 : 3);
|
||||
if (result.ok) ++ok; else ++fail;
|
||||
}
|
||||
::PostMessage(hwnd, UWM_TRANSFORM_DONE, (WPARAM)ok, (LPARAM)fail);
|
||||
});
|
||||
m_worker.detach();
|
||||
|
||||
GetStatusBar().SetPartText(0, L"Transforming\u2026");
|
||||
}
|
||||
|
||||
void CMainFrame::OnExit()
|
||||
{
|
||||
Close();
|
||||
@ -298,13 +495,43 @@ LRESULT CMainFrame::OnQueueDone(WPARAM wparam, LPARAM lparam)
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CMainFrame::OnTransformProgress(WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
if (!m_pDockQueue) return 0;
|
||||
auto& lv = m_pDockQueue->GetQueueContainer().GetListView();
|
||||
int idx = static_cast<int>(wparam);
|
||||
int state = static_cast<int>(lparam);
|
||||
if (state == 1)
|
||||
lv.SetItemStatus(idx, L"Transforming\u2026");
|
||||
else if (state == 2)
|
||||
lv.SetItemStatus(idx, L"\u2713 Transformed");
|
||||
else
|
||||
lv.SetItemStatus(idx, L"\u2717 AI Error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CMainFrame::OnTransformDone(WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
m_processing = false;
|
||||
int ok = static_cast<int>(wparam);
|
||||
int fail = static_cast<int>(lparam);
|
||||
CString s;
|
||||
s.Format(L"Transform done: %d succeeded, %d failed", ok, fail);
|
||||
GetStatusBar().SetPartText(0, s);
|
||||
if (fail > 0)
|
||||
::MessageBox(GetHwnd(), s, L"pm-image", MB_ICONWARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CMainFrame::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try {
|
||||
switch (msg) {
|
||||
case WM_GETMINMAXINFO: return OnGetMinMaxInfo(msg, wparam, lparam);
|
||||
case UWM_QUEUE_PROGRESS: return OnQueueProgress(wparam, lparam);
|
||||
case UWM_QUEUE_PROGRESS: return OnQueueProgress(wparam, lparam);
|
||||
case UWM_QUEUE_DONE: return OnQueueDone(wparam, lparam);
|
||||
case UWM_TRANSFORM_PROGRESS: return OnTransformProgress(wparam, lparam);
|
||||
case UWM_TRANSFORM_DONE: return OnTransformDone(wparam, lparam);
|
||||
case UWM_QUEUE_ITEM_CLICKED: {
|
||||
int idx = static_cast<int>(wparam);
|
||||
if (m_pDockQueue) {
|
||||
|
||||
@ -32,11 +32,16 @@ private:
|
||||
void OnAddFolder();
|
||||
void OnClearQueue();
|
||||
void OnResize();
|
||||
void OnTransform();
|
||||
void OnExit();
|
||||
|
||||
LRESULT OnGetMinMaxInfo(UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
LRESULT OnQueueProgress(WPARAM wparam, LPARAM lparam);
|
||||
LRESULT OnQueueDone(WPARAM wparam, LPARAM lparam);
|
||||
LRESULT OnTransformProgress(WPARAM wparam, LPARAM lparam);
|
||||
LRESULT OnTransformDone(WPARAM wparam, LPARAM lparam);
|
||||
|
||||
std::vector<int> GetSelectedQueueItems();
|
||||
|
||||
CImagePreview m_view;
|
||||
IUIRibbon* m_pIUIRibbon = nullptr;
|
||||
@ -45,6 +50,7 @@ private:
|
||||
|
||||
std::thread m_worker;
|
||||
bool m_processing = false;
|
||||
std::wstring m_lastPrompt;
|
||||
};
|
||||
|
||||
#endif // PM_UI_MAINFRM_H
|
||||
|
||||
@ -25,10 +25,17 @@
|
||||
#define IDC_CHK_AUTOROT 608
|
||||
#define IDC_CHK_STRIP 609
|
||||
|
||||
// AI Transform dialog controls
|
||||
#define IDD_TRANSFORM_PROMPT 700
|
||||
#define IDC_EDIT_PROMPT 701
|
||||
#define IDC_STATIC_PROMPT_LABEL 702
|
||||
|
||||
// User messages
|
||||
#define UWM_QUEUE_PROGRESS (WM_USER + 100)
|
||||
#define UWM_QUEUE_DONE (WM_USER + 101)
|
||||
#define UWM_IMAGELOADED (WM_USER + 102)
|
||||
#define UWM_QUEUE_ITEM_CLICKED (WM_USER + 103)
|
||||
#define UWM_TRANSFORM_PROGRESS (WM_USER + 104)
|
||||
#define UWM_TRANSFORM_DONE (WM_USER + 105)
|
||||
|
||||
#endif // PM_UI_RESOURCE_H
|
||||
|
||||
BIN
packages/media/cpp/src/win/ui_next/RibbonUI.bml
Normal file
BIN
packages/media/cpp/src/win/ui_next/RibbonUI.bml
Normal file
Binary file not shown.
@ -30,6 +30,14 @@
|
||||
#define IDC_CMD_EXIT_LabelTitle_RESID 3041
|
||||
#define IDC_CMD_ABOUT 305
|
||||
#define IDC_CMD_ABOUT_LabelTitle_RESID 3051
|
||||
#define cmdTabAI 410
|
||||
#define cmdTabAI_LabelTitle_RESID 4101
|
||||
#define cmdGroupTransform 411
|
||||
#define cmdGroupTransform_LabelTitle_RESID 4111
|
||||
#define IDC_CMD_TRANSFORM 310
|
||||
#define IDC_CMD_TRANSFORM_LabelTitle_RESID 3101
|
||||
#define IDC_CMD_TRANSFORM_SmallImages_RESID 3103
|
||||
#define IDC_CMD_TRANSFORM_LargeImages_RESID 3102
|
||||
#define cmdAppMenu 710
|
||||
#define IDC_RIBBONHELP 700
|
||||
#define IDC_QAT 701
|
||||
|
||||
@ -57,4 +57,21 @@ BEGIN
|
||||
IDC_CMD_ABOUT_LabelTitle_RESID L"About" /* LabelTitle IDC_CMD_ABOUT_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
APPLICATION_RIBBON UIFILE "C:/Users/zx/Desktop/polymech/polymech-mono/packages/media/cpp/src/win/ui_next/Ribbon.bml"
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
cmdTabAI_LabelTitle_RESID L"AI Transform" /* LabelTitle cmdTabAI_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
cmdGroupTransform_LabelTitle_RESID L"Transform" /* LabelTitle cmdGroupTransform_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDC_CMD_TRANSFORM_LabelTitle_RESID L"Transform" /* LabelTitle IDC_CMD_TRANSFORM_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
IDC_CMD_TRANSFORM_SmallImages_RESID BITMAP "res\\TransformS.bmp" /* SmallImages IDC_CMD_TRANSFORM_SmallImages_RESID: (null) */
|
||||
IDC_CMD_TRANSFORM_LargeImages_RESID BITMAP "res\\TransformL.bmp" /* LargeImages IDC_CMD_TRANSFORM_LargeImages_RESID: (null) */
|
||||
APPLICATION_RIBBON UIFILE "C:\\Users\\zx\\Desktop\\polymech\\polymech-mono\\packages\\media\\cpp\\src\\win\\ui_next\\RibbonUI.bml"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 300 KiB After Width: | Height: | Size: 266 KiB |
Loading…
Reference in New Issue
Block a user