media:cpp --uinext win32xx 1/2
This commit is contained in:
parent
57488b529f
commit
08e690631e
@ -157,6 +157,55 @@ if(WIN32)
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/win/ui_singleton.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/win/media-img-win.manifest"
|
||||
)
|
||||
|
||||
# ── ui_next (Win32++ ribbon + dock UI) ──────────────────────────────
|
||||
set(_UI_NEXT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/win/ui_next")
|
||||
|
||||
# Try to compile Ribbon.xml → Ribbon.bml + RibbonUI.h + RibbonUI.rc via uicc.exe.
|
||||
find_program(UICC_EXE uicc
|
||||
HINTS "C:/Program Files (x86)/Windows Kits/10/bin"
|
||||
"$ENV{WindowsSdkDir}/bin"
|
||||
PATH_SUFFIXES "${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/x64"
|
||||
"${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/x86"
|
||||
"10.0.22621.0/x64" "10.0.22621.0/x86"
|
||||
"10.0.19041.0/x64" "10.0.19041.0/x86"
|
||||
)
|
||||
|
||||
if(UICC_EXE)
|
||||
message(STATUS "uicc found: ${UICC_EXE} — ribbon resources will be compiled")
|
||||
add_custom_command(
|
||||
OUTPUT "${_UI_NEXT_DIR}/Ribbon.bml"
|
||||
"${_UI_NEXT_DIR}/RibbonUI.h"
|
||||
"${_UI_NEXT_DIR}/RibbonUI.rc"
|
||||
COMMAND "${UICC_EXE}"
|
||||
"${_UI_NEXT_DIR}/Ribbon.xml"
|
||||
"${_UI_NEXT_DIR}/Ribbon.bml"
|
||||
"/header:${_UI_NEXT_DIR}/RibbonUI.h"
|
||||
"/res:${_UI_NEXT_DIR}/RibbonUI.rc"
|
||||
DEPENDS "${_UI_NEXT_DIR}/Ribbon.xml"
|
||||
COMMENT "Compiling Ribbon.xml → Ribbon.bml + RibbonUI.h/rc (uicc)"
|
||||
VERBATIM
|
||||
)
|
||||
add_custom_target(pm_image_ribbon DEPENDS
|
||||
"${_UI_NEXT_DIR}/Ribbon.bml"
|
||||
"${_UI_NEXT_DIR}/RibbonUI.h"
|
||||
"${_UI_NEXT_DIR}/RibbonUI.rc"
|
||||
)
|
||||
else()
|
||||
message(STATUS "uicc NOT found — ribbon disabled; classic menu fallback will be used")
|
||||
add_custom_target(pm_image_ribbon)
|
||||
endif()
|
||||
|
||||
target_sources(pm-image PRIVATE
|
||||
"${_UI_NEXT_DIR}/App.cpp"
|
||||
"${_UI_NEXT_DIR}/FileQueue.cpp"
|
||||
"${_UI_NEXT_DIR}/SettingsPanel.cpp"
|
||||
"${_UI_NEXT_DIR}/Mainfrm.cpp"
|
||||
"${_UI_NEXT_DIR}/launch_ui_next.cpp"
|
||||
"${_UI_NEXT_DIR}/Resource.rc"
|
||||
)
|
||||
add_dependencies(pm-image pm_image_ribbon)
|
||||
target_include_directories(pm-image PRIVATE "${_UI_NEXT_DIR}")
|
||||
endif()
|
||||
|
||||
# Win32++ — header-only (vendor tree under packages/Win32xx). See samples e.g.
|
||||
|
||||
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.
@ -35,6 +35,7 @@ std::string join_src_semicolons(const std::vector<std::string> &v) {
|
||||
#include "win/resize_progress_ui.hpp"
|
||||
#include "win/resize_ui.hpp"
|
||||
#include "win/ui_singleton.hpp"
|
||||
#include "win/ui_next/launch_ui_next.h"
|
||||
#endif
|
||||
|
||||
#ifndef MEDIA_IMG_VERSION
|
||||
@ -139,6 +140,9 @@ int main(int argc, char **argv) {
|
||||
bool resize_ui = false;
|
||||
resize_cmd->add_flag("--ui", resize_ui,
|
||||
"Windows: native dialog for paths/options; optional --src/--dst seed the dialog");
|
||||
bool resize_ui_next = false;
|
||||
resize_cmd->add_flag("--ui-next", resize_ui_next,
|
||||
"Windows: new Win32++ ribbon UI with drag-drop queue and settings panel");
|
||||
#endif
|
||||
|
||||
std::string host = "127.0.0.1";
|
||||
@ -217,6 +221,15 @@ int main(int argc, char **argv) {
|
||||
std::string out_path_e;
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (resize_ui_next) {
|
||||
std::vector<std::string> initial;
|
||||
if (!src_list.empty())
|
||||
initial = src_list;
|
||||
else if (!in_path.empty())
|
||||
initial.push_back(in_path);
|
||||
return media::win::launch_ui_next(initial);
|
||||
}
|
||||
|
||||
if (resize_ui) {
|
||||
if (!src_list.empty() && !in_path.empty()) {
|
||||
std::cerr << "resize: use either positional input or --src, not both\n";
|
||||
|
||||
8
packages/media/cpp/src/win/ui_next/App.cpp
Normal file
8
packages/media/cpp/src/win/ui_next/App.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include "stdafx.h"
|
||||
#include "App.h"
|
||||
|
||||
BOOL CPmImageApp::InitInstance()
|
||||
{
|
||||
m_frame.Create();
|
||||
return TRUE;
|
||||
}
|
||||
24
packages/media/cpp/src/win/ui_next/App.h
Normal file
24
packages/media/cpp/src/win/ui_next/App.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef PM_UI_APP_H
|
||||
#define PM_UI_APP_H
|
||||
|
||||
#include "Mainfrm.h"
|
||||
|
||||
class CPmImageApp : public CWinApp
|
||||
{
|
||||
public:
|
||||
CPmImageApp() = default;
|
||||
virtual ~CPmImageApp() override = default;
|
||||
|
||||
CMainFrame& GetMainFrame() { return m_frame; }
|
||||
|
||||
protected:
|
||||
virtual BOOL InitInstance() override;
|
||||
|
||||
private:
|
||||
CPmImageApp(const CPmImageApp&) = delete;
|
||||
CPmImageApp& operator=(const CPmImageApp&) = delete;
|
||||
|
||||
CMainFrame m_frame;
|
||||
};
|
||||
|
||||
#endif // PM_UI_APP_H
|
||||
49
packages/media/cpp/src/win/ui_next/DropView.cpp
Normal file
49
packages/media/cpp/src/win/ui_next/DropView.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "stdafx.h"
|
||||
#include "DropView.h"
|
||||
#include "Resource.h"
|
||||
#include <shellapi.h>
|
||||
|
||||
int CDropView::OnCreate(CREATESTRUCT&)
|
||||
{
|
||||
m_bgBrush.CreateSolidBrush(RGB(245, 245, 245));
|
||||
DragAcceptFiles(TRUE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CDropView::PreCreate(CREATESTRUCT& cs)
|
||||
{
|
||||
cs.dwExStyle = WS_EX_CLIENTEDGE;
|
||||
}
|
||||
|
||||
void CDropView::OnDraw(CDC& dc)
|
||||
{
|
||||
CRect rc = GetClientRect();
|
||||
dc.FillRect(rc, m_bgBrush);
|
||||
|
||||
dc.SetBkMode(TRANSPARENT);
|
||||
dc.SetTextColor(RGB(160, 160, 160));
|
||||
dc.DrawText(L"Drop images here or use Add Files", -1, rc,
|
||||
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||||
}
|
||||
|
||||
LRESULT CDropView::OnDropFiles(WPARAM wparam)
|
||||
{
|
||||
// Forward to parent (CMainFrame) which handles WM_DROPFILES.
|
||||
return GetAncestor().SendMessage(WM_DROPFILES, wparam, 0);
|
||||
}
|
||||
|
||||
LRESULT CDropView::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try {
|
||||
switch (msg) {
|
||||
case WM_DROPFILES: return OnDropFiles(wparam);
|
||||
}
|
||||
return WndProcDefault(msg, wparam, lparam);
|
||||
}
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
27
packages/media/cpp/src/win/ui_next/DropView.h
Normal file
27
packages/media/cpp/src/win/ui_next/DropView.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef PM_UI_DROPVIEW_H
|
||||
#define PM_UI_DROPVIEW_H
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <shellapi.h>
|
||||
|
||||
class CDropView : public CWnd
|
||||
{
|
||||
public:
|
||||
CDropView() = default;
|
||||
virtual ~CDropView() override = default;
|
||||
|
||||
protected:
|
||||
virtual int OnCreate(CREATESTRUCT& cs) override;
|
||||
virtual void OnDraw(CDC& dc) override;
|
||||
virtual void PreCreate(CREATESTRUCT& cs) override;
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CDropView(const CDropView&) = delete;
|
||||
CDropView& operator=(const CDropView&) = delete;
|
||||
|
||||
LRESULT OnDropFiles(WPARAM wparam);
|
||||
CBrush m_bgBrush;
|
||||
};
|
||||
|
||||
#endif // PM_UI_DROPVIEW_H
|
||||
170
packages/media/cpp/src/win/ui_next/FileQueue.cpp
Normal file
170
packages/media/cpp/src/win/ui_next/FileQueue.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#include "stdafx.h"
|
||||
#include "FileQueue.h"
|
||||
#include "Resource.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
//////////////////////////////////////////
|
||||
// CQueueListView
|
||||
//////////////////////////////////////////
|
||||
|
||||
void CQueueListView::OnAttach()
|
||||
{
|
||||
CListView::OnAttach();
|
||||
SetupColumns();
|
||||
DragAcceptFiles(TRUE);
|
||||
|
||||
DWORD exStyle = LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER;
|
||||
SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, exStyle);
|
||||
}
|
||||
|
||||
void CQueueListView::SetupColumns()
|
||||
{
|
||||
LV_COLUMN col{};
|
||||
col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
|
||||
col.fmt = LVCFMT_LEFT;
|
||||
|
||||
WCHAR names[COL_COUNT][16] = { L"Name", L"Status", L"Path" };
|
||||
int widths[COL_COUNT] = { 220, 100, 400 };
|
||||
|
||||
for (int i = 0; i < COL_COUNT; ++i) {
|
||||
col.pszText = names[i];
|
||||
col.cx = DpiScaleInt(widths[i]);
|
||||
col.iSubItem = i;
|
||||
InsertColumn(i, col);
|
||||
}
|
||||
}
|
||||
|
||||
int CQueueListView::AddFile(const CString& path)
|
||||
{
|
||||
// Derive filename from path.
|
||||
fs::path p(std::wstring(path.c_str()));
|
||||
CString name = p.filename().c_str();
|
||||
|
||||
int idx = GetItemCount();
|
||||
int item = InsertItem(idx, name);
|
||||
SetItemText(item, COL_STATUS, L"Queued");
|
||||
SetItemText(item, COL_PATH, path);
|
||||
return item;
|
||||
}
|
||||
|
||||
void CQueueListView::SetItemStatus(int item, LPCWSTR status)
|
||||
{
|
||||
SetItemText(item, COL_STATUS, status);
|
||||
}
|
||||
|
||||
void CQueueListView::ClearAll()
|
||||
{
|
||||
DeleteAllItems();
|
||||
}
|
||||
|
||||
int CQueueListView::QueueCount() const
|
||||
{
|
||||
return GetItemCount();
|
||||
}
|
||||
|
||||
CString CQueueListView::GetItemPath(int item)
|
||||
{
|
||||
wchar_t buf[MAX_PATH * 4]{};
|
||||
LVITEMW lvi{};
|
||||
lvi.iSubItem = COL_PATH;
|
||||
lvi.pszText = buf;
|
||||
lvi.cchTextMax = MAX_PATH * 4;
|
||||
::SendMessageW(GetHwnd(), LVM_GETITEMTEXTW, (WPARAM)item, (LPARAM)&lvi);
|
||||
return CString(buf);
|
||||
}
|
||||
|
||||
LRESULT CQueueListView::OnDropFiles(UINT, WPARAM wparam, LPARAM)
|
||||
{
|
||||
HDROP hDrop = reinterpret_cast<HDROP>(wparam);
|
||||
UINT count = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
|
||||
|
||||
for (UINT i = 0; i < count; ++i) {
|
||||
UINT len = DragQueryFileW(hDrop, i, nullptr, 0);
|
||||
if (len == 0) continue;
|
||||
std::wstring w(static_cast<size_t>(len) + 1, L'\0');
|
||||
DragQueryFileW(hDrop, i, w.data(), len + 1);
|
||||
w.resize(len);
|
||||
|
||||
fs::path p(w);
|
||||
std::error_code ec;
|
||||
if (fs::is_directory(p, ec)) {
|
||||
for (auto& entry : fs::recursive_directory_iterator(p, fs::directory_options::skip_permission_denied, ec)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
std::wstring ext = entry.path().extension().wstring();
|
||||
for (auto& c : ext) c = static_cast<wchar_t>(towlower(c));
|
||||
if (ext == L".jpg" || ext == L".jpeg" || ext == L".png" || ext == L".webp" ||
|
||||
ext == L".tif" || ext == L".tiff" || ext == L".bmp" || ext == L".gif" ||
|
||||
ext == L".avif" || ext == L".heic") {
|
||||
AddFile(CString(entry.path().c_str()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AddFile(CString(w.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
DragFinish(hDrop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CQueueListView::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try {
|
||||
switch (msg) {
|
||||
case WM_DROPFILES: return OnDropFiles(msg, wparam, lparam);
|
||||
}
|
||||
return WndProcDefault(msg, wparam, lparam);
|
||||
}
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// CQueueContainer
|
||||
//////////////////////////////////////////
|
||||
|
||||
CQueueContainer::CQueueContainer()
|
||||
{
|
||||
SetTabText(L"Queue");
|
||||
SetDockCaption(L"File Queue");
|
||||
SetView(m_listView);
|
||||
}
|
||||
|
||||
LRESULT CQueueContainer::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try { return WndProcDefault(msg, wparam, lparam); }
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// CDockQueue
|
||||
//////////////////////////////////////////
|
||||
|
||||
CDockQueue::CDockQueue()
|
||||
{
|
||||
SetView(m_container);
|
||||
SetBarWidth(8);
|
||||
}
|
||||
|
||||
LRESULT CDockQueue::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try { return WndProcDefault(msg, wparam, lparam); }
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
73
packages/media/cpp/src/win/ui_next/FileQueue.h
Normal file
73
packages/media/cpp/src/win/ui_next/FileQueue.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef PM_UI_FILEQUEUE_H
|
||||
#define PM_UI_FILEQUEUE_H
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <shellapi.h>
|
||||
|
||||
// Column indices for the queue list view.
|
||||
enum QueueCol : int { COL_NAME = 0, COL_STATUS, COL_PATH, COL_COUNT };
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// CQueueListView — accepts drag-drop of files/folders,
|
||||
// displays them in a report-style list, tracks status.
|
||||
class CQueueListView : public CListView
|
||||
{
|
||||
public:
|
||||
CQueueListView() = default;
|
||||
virtual ~CQueueListView() override = default;
|
||||
|
||||
int AddFile(const CString& path);
|
||||
void SetItemStatus(int item, LPCWSTR status);
|
||||
void ClearAll();
|
||||
int QueueCount() const;
|
||||
CString GetItemPath(int item);
|
||||
|
||||
protected:
|
||||
virtual void OnAttach() override;
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CQueueListView(const CQueueListView&) = delete;
|
||||
CQueueListView& operator=(const CQueueListView&) = delete;
|
||||
|
||||
LRESULT OnDropFiles(UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
void SetupColumns();
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// CQueueContainer — dock container hosting CQueueListView.
|
||||
class CQueueContainer : public CDockContainer
|
||||
{
|
||||
public:
|
||||
CQueueContainer();
|
||||
virtual ~CQueueContainer() override = default;
|
||||
CQueueListView& GetListView() { return m_listView; }
|
||||
|
||||
protected:
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CQueueContainer(const CQueueContainer&) = delete;
|
||||
CQueueContainer& operator=(const CQueueContainer&) = delete;
|
||||
CQueueListView m_listView;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// CDockQueue — docker wrapping CQueueContainer.
|
||||
class CDockQueue : public CDocker
|
||||
{
|
||||
public:
|
||||
CDockQueue();
|
||||
virtual ~CDockQueue() override = default;
|
||||
CQueueContainer& GetQueueContainer() { return m_container; }
|
||||
|
||||
protected:
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CDockQueue(const CDockQueue&) = delete;
|
||||
CDockQueue& operator=(const CDockQueue&) = delete;
|
||||
CQueueContainer m_container;
|
||||
};
|
||||
|
||||
#endif // PM_UI_FILEQUEUE_H
|
||||
331
packages/media/cpp/src/win/ui_next/Mainfrm.cpp
Normal file
331
packages/media/cpp/src/win/ui_next/Mainfrm.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
#include "stdafx.h"
|
||||
#include "Mainfrm.h"
|
||||
#include "Resource.h"
|
||||
#include "core/resize.hpp"
|
||||
#include <shlobj.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static std::string wide_to_utf8(const std::wstring& w) {
|
||||
if (w.empty()) return {};
|
||||
int n = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), (int)w.size(), nullptr, 0, nullptr, nullptr);
|
||||
if (n <= 0) return {};
|
||||
std::string s(n, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, w.c_str(), (int)w.size(), s.data(), n, nullptr, nullptr);
|
||||
return s;
|
||||
}
|
||||
|
||||
CMainFrame::CMainFrame()
|
||||
{
|
||||
}
|
||||
|
||||
HWND CMainFrame::Create(HWND parent)
|
||||
{
|
||||
SetView(m_view);
|
||||
LoadRegistrySettings(L"Polymech\\pm-image-ui");
|
||||
return CRibbonDockFrame::Create(parent);
|
||||
}
|
||||
|
||||
STDMETHODIMP CMainFrame::Execute(UINT32 cmdID, UI_EXECUTIONVERB verb,
|
||||
const PROPERTYKEY*, const PROPVARIANT*, IUISimplePropertySet*)
|
||||
{
|
||||
if (verb == UI_EXECUTIONVERB_EXECUTE) {
|
||||
switch (cmdID) {
|
||||
case IDC_CMD_ADD_FILES: OnAddFiles(); break;
|
||||
case IDC_CMD_ADD_FOLDER: OnAddFolder(); break;
|
||||
case IDC_CMD_CLEAR: OnClearQueue(); break;
|
||||
case IDC_CMD_PROCESS: OnProcess(); break;
|
||||
case IDC_CMD_ABOUT: OnHelp(); break;
|
||||
case IDC_CMD_EXIT: OnExit(); break;
|
||||
case IDC_RIBBONHELP: OnHelp(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CMainFrame::OnViewChanged(UINT32, UI_VIEWTYPE typeId,
|
||||
IUnknown* pView, UI_VIEWVERB verb, INT32)
|
||||
{
|
||||
if (typeId == UI_VIEWTYPE_RIBBON) {
|
||||
switch (verb) {
|
||||
case UI_VIEWVERB_CREATE:
|
||||
m_pIUIRibbon = reinterpret_cast<IUIRibbon*>(pView);
|
||||
return S_OK;
|
||||
case UI_VIEWVERB_SIZE:
|
||||
RecalcLayout();
|
||||
return S_OK;
|
||||
case UI_VIEWVERB_DESTROY:
|
||||
m_pIUIRibbon = nullptr;
|
||||
return S_OK;
|
||||
case UI_VIEWVERB_ERROR:
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
BOOL CMainFrame::OnCommand(WPARAM wparam, LPARAM)
|
||||
{
|
||||
switch (LOWORD(wparam)) {
|
||||
case IDM_ADD_FILES: OnAddFiles(); return TRUE;
|
||||
case IDM_ADD_FOLDER: OnAddFolder(); return TRUE;
|
||||
case IDM_CLEAR_QUEUE: OnClearQueue(); return TRUE;
|
||||
case IDM_PROCESS: OnProcess(); return TRUE;
|
||||
case IDM_EXIT: OnExit(); return TRUE;
|
||||
case IDM_ABOUT: return OnHelp();
|
||||
case IDW_VIEW_STATUSBAR: return OnViewStatusBar();
|
||||
case IDW_VIEW_TOOLBAR: return OnViewToolBar();
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CMainFrame::OnHelp()
|
||||
{
|
||||
::MessageBox(GetHwnd(), L"pm-image — resize & transform\nWin32++ UI",
|
||||
L"About pm-image", MB_ICONINFORMATION | MB_OK);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CMainFrame::OnInitialUpdate()
|
||||
{
|
||||
DWORD style = DS_CLIENTEDGE;
|
||||
|
||||
auto pDockQ = AddDockedChild(std::make_unique<CDockQueue>(),
|
||||
DS_DOCKED_BOTTOM | style, DpiScaleInt(280));
|
||||
m_pDockQueue = static_cast<CDockQueue*>(pDockQ);
|
||||
m_pDockQueue->GetQueueContainer().SetHideSingleTab(TRUE);
|
||||
|
||||
auto pDockS = AddDockedChild(std::make_unique<CDockSettings>(),
|
||||
DS_DOCKED_RIGHT | style, DpiScaleInt(320));
|
||||
m_pDockSettings = static_cast<CDockSettings*>(pDockS);
|
||||
m_pDockSettings->GetSettingsContainer().SetHideSingleTab(TRUE);
|
||||
|
||||
DragAcceptFiles(TRUE);
|
||||
SetWindowText(L"pm-image");
|
||||
GetStatusBar().SetPartText(0, L"Drop files or use Add Files to begin.");
|
||||
}
|
||||
|
||||
void CMainFrame::SetupToolBar()
|
||||
{
|
||||
AddToolBarButton(IDM_ADD_FILES);
|
||||
AddToolBarButton(IDM_ADD_FOLDER);
|
||||
AddToolBarButton(0);
|
||||
AddToolBarButton(IDM_PROCESS);
|
||||
AddToolBarButton(IDM_CLEAR_QUEUE);
|
||||
}
|
||||
|
||||
void CMainFrame::OnAddFiles()
|
||||
{
|
||||
CFileDialog dlg(TRUE, nullptr, nullptr,
|
||||
OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER,
|
||||
L"Images (*.jpg;*.jpeg;*.png;*.webp;*.tif;*.tiff;*.bmp;*.gif;*.avif;*.heic)\0"
|
||||
L"*.jpg;*.jpeg;*.png;*.webp;*.tif;*.tiff;*.bmp;*.gif;*.avif;*.heic\0"
|
||||
L"All Files (*.*)\0*.*\0\0");
|
||||
dlg.SetTitle(L"Add images to queue");
|
||||
|
||||
if (dlg.DoModal(*this) != IDOK) return;
|
||||
|
||||
std::vector<std::wstring> files;
|
||||
int pos = 0;
|
||||
CString path = dlg.GetNextPathName(pos);
|
||||
while (!path.IsEmpty()) {
|
||||
files.push_back(std::wstring(path.c_str()));
|
||||
if (pos < 0) break;
|
||||
path = dlg.GetNextPathName(pos);
|
||||
}
|
||||
AddFilesToQueue(files);
|
||||
}
|
||||
|
||||
void CMainFrame::OnAddFolder()
|
||||
{
|
||||
BROWSEINFOW bi{};
|
||||
bi.hwndOwner = GetHwnd();
|
||||
bi.lpszTitle = L"Select folder with images";
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
wchar_t dn[MAX_PATH]{};
|
||||
bi.pszDisplayName = dn;
|
||||
PIDLIST_ABSOLUTE pidl = SHBrowseForFolderW(&bi);
|
||||
if (!pidl) return;
|
||||
wchar_t path[MAX_PATH * 4]{};
|
||||
if (SHGetPathFromIDListW(pidl, path)) {
|
||||
std::vector<std::wstring> v = { path };
|
||||
AddFilesToQueue(v);
|
||||
}
|
||||
CoTaskMemFree(pidl);
|
||||
}
|
||||
|
||||
void CMainFrame::AddFilesToQueue(const std::vector<std::wstring>& paths)
|
||||
{
|
||||
if (!m_pDockQueue) return;
|
||||
auto& lv = m_pDockQueue->GetQueueContainer().GetListView();
|
||||
|
||||
for (auto& p : paths) {
|
||||
std::error_code ec;
|
||||
fs::path fp(p);
|
||||
if (fs::is_directory(fp, ec)) {
|
||||
for (auto& entry : fs::recursive_directory_iterator(fp,
|
||||
fs::directory_options::skip_permission_denied, ec)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
std::wstring ext = entry.path().extension().wstring();
|
||||
for (auto& c : ext) c = static_cast<wchar_t>(towlower(c));
|
||||
if (ext == L".jpg" || ext == L".jpeg" || ext == L".png" || ext == L".webp" ||
|
||||
ext == L".tif" || ext == L".tiff" || ext == L".bmp" || ext == L".gif" ||
|
||||
ext == L".avif" || ext == L".heic") {
|
||||
lv.AddFile(CString(entry.path().c_str()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lv.AddFile(CString(fp.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
CString status;
|
||||
status.Format(L"%d file(s) in queue", lv.QueueCount());
|
||||
GetStatusBar().SetPartText(0, status);
|
||||
}
|
||||
|
||||
void CMainFrame::OnClearQueue()
|
||||
{
|
||||
if (m_pDockQueue) {
|
||||
m_pDockQueue->GetQueueContainer().GetListView().ClearAll();
|
||||
GetStatusBar().SetPartText(0, L"Queue cleared.");
|
||||
}
|
||||
}
|
||||
|
||||
void CMainFrame::OnProcess()
|
||||
{
|
||||
if (m_processing) {
|
||||
::MessageBox(GetHwnd(), L"Already processing.", L"pm-image", MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
if (!m_pDockQueue || !m_pDockSettings) return;
|
||||
|
||||
auto& lv = m_pDockQueue->GetQueueContainer().GetListView();
|
||||
int count = lv.QueueCount();
|
||||
if (count == 0) {
|
||||
::MessageBox(GetHwnd(), L"Queue is empty — drop files first.", L"pm-image", MB_ICONINFORMATION);
|
||||
return;
|
||||
}
|
||||
|
||||
media::ResizeOptions opt;
|
||||
std::string out_dir;
|
||||
m_pDockSettings->GetSettingsContainer().GetSettingsView().ReadOptions(opt, out_dir);
|
||||
|
||||
// Gather paths
|
||||
std::vector<std::pair<int, std::string>> items;
|
||||
items.reserve(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
CString p = lv.GetItemPath(i);
|
||||
items.emplace_back(i, wide_to_utf8(std::wstring(p.c_str())));
|
||||
}
|
||||
|
||||
m_processing = true;
|
||||
HWND hwnd = GetHwnd();
|
||||
|
||||
m_worker = std::thread([items = std::move(items), opt, out_dir, hwnd]() mutable {
|
||||
int ok = 0, fail = 0;
|
||||
for (auto& [idx, input] : items) {
|
||||
::PostMessage(hwnd, UWM_QUEUE_PROGRESS, (WPARAM)idx, 1);
|
||||
std::string output_path;
|
||||
if (!out_dir.empty()) {
|
||||
namespace fs2 = std::filesystem;
|
||||
fs2::path op = fs2::path(out_dir) / fs2::path(input).filename();
|
||||
output_path = op.string();
|
||||
std::error_code ec2;
|
||||
fs2::create_directories(fs2::path(out_dir), ec2);
|
||||
} else {
|
||||
output_path = input;
|
||||
}
|
||||
|
||||
std::string err;
|
||||
bool success = media::resize_file(input, output_path, opt, err);
|
||||
::PostMessage(hwnd, UWM_QUEUE_PROGRESS, (WPARAM)idx, success ? 2 : 3);
|
||||
if (success) ++ok; else ++fail;
|
||||
}
|
||||
::PostMessage(hwnd, UWM_QUEUE_DONE, (WPARAM)ok, (LPARAM)fail);
|
||||
});
|
||||
m_worker.detach();
|
||||
|
||||
GetStatusBar().SetPartText(0, L"Processing…");
|
||||
}
|
||||
|
||||
void CMainFrame::OnExit()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
LRESULT CMainFrame::OnGetMinMaxInfo(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
LPMINMAXINFO lpMMI = reinterpret_cast<LPMINMAXINFO>(lparam);
|
||||
const CSize minSz(600, 400);
|
||||
lpMMI->ptMinTrackSize.x = DpiScaleInt(minSz.cx);
|
||||
lpMMI->ptMinTrackSize.y = DpiScaleInt(minSz.cy);
|
||||
return FinalWindowProc(msg, wparam, lparam);
|
||||
}
|
||||
|
||||
LRESULT CMainFrame::OnQueueProgress(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"Processing…");
|
||||
else if (state == 2)
|
||||
lv.SetItemStatus(idx, L"Done");
|
||||
else
|
||||
lv.SetItemStatus(idx, L"Error");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CMainFrame::OnQueueDone(WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
m_processing = false;
|
||||
int ok = static_cast<int>(wparam);
|
||||
int fail = static_cast<int>(lparam);
|
||||
CString s;
|
||||
s.Format(L"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_DONE: return OnQueueDone(wparam, lparam);
|
||||
case WM_DROPFILES: {
|
||||
HDROP hDrop = reinterpret_cast<HDROP>(wparam);
|
||||
UINT count = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
|
||||
std::vector<std::wstring> paths;
|
||||
for (UINT i = 0; i < count; ++i) {
|
||||
UINT len = DragQueryFileW(hDrop, i, nullptr, 0);
|
||||
if (!len) continue;
|
||||
std::wstring w(len + 1, L'\0');
|
||||
DragQueryFileW(hDrop, i, w.data(), len + 1);
|
||||
w.resize(len);
|
||||
paths.push_back(std::move(w));
|
||||
}
|
||||
DragFinish(hDrop);
|
||||
AddFilesToQueue(paths);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return WndProcDefault(msg, wparam, lparam);
|
||||
}
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
::MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
50
packages/media/cpp/src/win/ui_next/Mainfrm.h
Normal file
50
packages/media/cpp/src/win/ui_next/Mainfrm.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef PM_UI_MAINFRM_H
|
||||
#define PM_UI_MAINFRM_H
|
||||
|
||||
#include "DropView.h"
|
||||
#include "FileQueue.h"
|
||||
#include "SettingsPanel.h"
|
||||
|
||||
class CMainFrame : public CRibbonDockFrame
|
||||
{
|
||||
public:
|
||||
CMainFrame();
|
||||
virtual ~CMainFrame() override = default;
|
||||
virtual HWND Create(HWND parent = nullptr) override;
|
||||
|
||||
void AddFilesToQueue(const std::vector<std::wstring>& paths);
|
||||
|
||||
protected:
|
||||
virtual STDMETHODIMP Execute(UINT32, UI_EXECUTIONVERB, const PROPERTYKEY*, const PROPVARIANT*, IUISimplePropertySet*) override;
|
||||
virtual STDMETHODIMP OnViewChanged(UINT32, UI_VIEWTYPE, IUnknown*, UI_VIEWVERB, INT32) override;
|
||||
|
||||
virtual BOOL OnCommand(WPARAM wparam, LPARAM lparam) override;
|
||||
virtual BOOL OnHelp() override;
|
||||
virtual void OnInitialUpdate() override;
|
||||
virtual void SetupToolBar() override;
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CMainFrame(const CMainFrame&) = delete;
|
||||
CMainFrame& operator=(const CMainFrame&) = delete;
|
||||
|
||||
void OnAddFiles();
|
||||
void OnAddFolder();
|
||||
void OnClearQueue();
|
||||
void OnProcess();
|
||||
void OnExit();
|
||||
|
||||
LRESULT OnGetMinMaxInfo(UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
LRESULT OnQueueProgress(WPARAM wparam, LPARAM lparam);
|
||||
LRESULT OnQueueDone(WPARAM wparam, LPARAM lparam);
|
||||
|
||||
CDropView m_view;
|
||||
IUIRibbon* m_pIUIRibbon = nullptr;
|
||||
CDockQueue* m_pDockQueue = nullptr;
|
||||
CDockSettings* m_pDockSettings = nullptr;
|
||||
|
||||
std::thread m_worker;
|
||||
bool m_processing = false;
|
||||
};
|
||||
|
||||
#endif // PM_UI_MAINFRM_H
|
||||
54
packages/media/cpp/src/win/ui_next/Resource.h
Normal file
54
packages/media/cpp/src/win/ui_next/Resource.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef PM_UI_RESOURCE_H
|
||||
#define PM_UI_RESOURCE_H
|
||||
|
||||
#include "default_resource.h"
|
||||
#include "RibbonUI.h"
|
||||
|
||||
// Menu fallback IDs (when ribbon is unavailable)
|
||||
#define IDM_PROCESS 200
|
||||
#define IDM_CLEAR_QUEUE 201
|
||||
#define IDM_ADD_FILES 202
|
||||
#define IDM_ADD_FOLDER 203
|
||||
#define IDM_SETTINGS 204
|
||||
#define IDM_EXIT 205
|
||||
#define IDM_ABOUT 206
|
||||
|
||||
// Ribbon command IDs (must match Ribbon.xml Symbol= values)
|
||||
#define IDC_CMD_PROCESS 300
|
||||
#define IDC_CMD_CLEAR 301
|
||||
#define IDC_CMD_ADD_FILES 302
|
||||
#define IDC_CMD_ADD_FOLDER 303
|
||||
#define IDC_CMD_EXIT 304
|
||||
#define IDC_CMD_ABOUT 305
|
||||
|
||||
// Ribbon tabs/groups
|
||||
#define IDC_TAB_HOME 400
|
||||
#define IDC_GROUP_QUEUE 401
|
||||
#define IDC_GROUP_ACTIONS 402
|
||||
|
||||
// Dock / container
|
||||
#define IDI_QUEUE 500
|
||||
#define IDB_QUEUE 501
|
||||
|
||||
// Settings controls (for settings dock)
|
||||
#define IDC_COMBO_PRESET_OUT 600
|
||||
#define IDC_EDIT_OUT_DIR 601
|
||||
#define IDC_BTN_BROWSE_OUT 602
|
||||
#define IDC_EDIT_MAX_W 603
|
||||
#define IDC_EDIT_MAX_H 604
|
||||
#define IDC_COMBO_FIT 605
|
||||
#define IDC_EDIT_QUALITY 606
|
||||
#define IDC_CHK_ENLARGE 607
|
||||
#define IDC_CHK_AUTOROT 608
|
||||
#define IDC_CHK_STRIP 609
|
||||
|
||||
// Ribbon misc
|
||||
#define IDC_RIBBONHELP 700
|
||||
#define IDC_QAT 701
|
||||
#define IDC_CUSTOMIZE_QAT 702
|
||||
|
||||
// User messages
|
||||
#define UWM_QUEUE_PROGRESS (WM_USER + 100)
|
||||
#define UWM_QUEUE_DONE (WM_USER + 101)
|
||||
|
||||
#endif // PM_UI_RESOURCE_H
|
||||
63
packages/media/cpp/src/win/ui_next/Resource.rc
Normal file
63
packages/media/cpp/src/win/ui_next/Resource.rc
Normal file
@ -0,0 +1,63 @@
|
||||
// pm-image-ui resource script
|
||||
#include "Resource.h"
|
||||
|
||||
#define APSTUDIO_HIDDEN_SYMBOLS
|
||||
#include "windows.h"
|
||||
#undef APSTUDIO_HIDDEN_SYMBOLS
|
||||
|
||||
// Ribbon compiled resources (generated by uicc from Ribbon.xml)
|
||||
#include "RibbonUI.rc"
|
||||
|
||||
// Manifest is provided by media-img-win.manifest (already linked to pm-image).
|
||||
|
||||
// Fallback menu (when ribbon unavailable)
|
||||
IDW_MAIN MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "&Add Files...", IDM_ADD_FILES
|
||||
MENUITEM "Add &Folder...", IDM_ADD_FOLDER
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "E&xit\tAlt+F4", IDM_EXIT
|
||||
END
|
||||
POPUP "&Actions"
|
||||
BEGIN
|
||||
MENUITEM "&Process\tF5", IDM_PROCESS
|
||||
MENUITEM "&Clear Queue", IDM_CLEAR_QUEUE
|
||||
END
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
MENUITEM "&About\tF1", IDM_ABOUT
|
||||
END
|
||||
END
|
||||
|
||||
// Fallback toolbar bitmap (16x15 per button placeholder – tiny 3-button strip)
|
||||
// We can add real bitmaps later; for now the toolbar works without.
|
||||
|
||||
// About dialog
|
||||
IDW_ABOUT DIALOGEX 0, 0, 200, 80
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "About pm-image"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "OK", IDOK, 75, 56, 50, 14
|
||||
CTEXT "pm-image — resize & transform", -1, 10, 12, 180, 10
|
||||
CTEXT "Win32++ UI", -1, 10, 26, 180, 10
|
||||
END
|
||||
|
||||
// Accelerators
|
||||
IDW_MAIN ACCELERATORS
|
||||
BEGIN
|
||||
VK_F5, IDM_PROCESS, VIRTKEY, NOINVERT
|
||||
END
|
||||
|
||||
// String table
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDW_MAIN "pm-image"
|
||||
IDW_READY "Ready"
|
||||
END
|
||||
|
||||
// Docking bitmaps – reuse from Win32xx samples path (or copy to res/)
|
||||
// These are required by the dock framework for the floating dock targeting UI.
|
||||
// If missing, docking still works but without the visual targeting indicators.
|
||||
BIN
packages/media/cpp/src/win/ui_next/Ribbon.bml
Normal file
BIN
packages/media/cpp/src/win/ui_next/Ribbon.bml
Normal file
Binary file not shown.
123
packages/media/cpp/src/win/ui_next/Ribbon.xml
Normal file
123
packages/media/cpp/src/win/ui_next/Ribbon.xml
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Application xmlns='http://schemas.microsoft.com/windows/2009/Ribbon'>
|
||||
<Application.Commands>
|
||||
|
||||
<!-- Tab -->
|
||||
<Command Name="cmdTabHome" Id="400">
|
||||
<Command.LabelTitle>
|
||||
<String Id="4001">Home</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
|
||||
<!-- Groups -->
|
||||
<Command Name="cmdGroupQueue" Id="401">
|
||||
<Command.LabelTitle>
|
||||
<String Id="4011">Queue</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
<Command Name="cmdGroupActions" Id="402">
|
||||
<Command.LabelTitle>
|
||||
<String Id="4021">Actions</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
|
||||
<!-- Buttons -->
|
||||
<Command Name="cmdAddFiles" Symbol="IDC_CMD_ADD_FILES" Id="302">
|
||||
<Command.LabelTitle>
|
||||
<String Id="3021">Add Files</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
<Command Name="cmdAddFolder" Symbol="IDC_CMD_ADD_FOLDER" Id="303">
|
||||
<Command.LabelTitle>
|
||||
<String Id="3031">Add Folder</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
<Command Name="cmdClear" Symbol="IDC_CMD_CLEAR" Id="301">
|
||||
<Command.LabelTitle>
|
||||
<String Id="3011">Clear</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
<Command Name="cmdProcess" Symbol="IDC_CMD_PROCESS" Id="300">
|
||||
<Command.LabelTitle>
|
||||
<String Id="3001">Process</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
<Command Name="cmdExit" Symbol="IDC_CMD_EXIT" Id="304">
|
||||
<Command.LabelTitle>
|
||||
<String Id="3041">Exit</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
<Command Name="cmdAbout" Symbol="IDC_CMD_ABOUT" Id="305">
|
||||
<Command.LabelTitle>
|
||||
<String Id="3051">About</String>
|
||||
</Command.LabelTitle>
|
||||
</Command>
|
||||
|
||||
<!-- Misc -->
|
||||
<Command Name="cmdAppMenu" Id="710" />
|
||||
<Command Name="cmdHelp" Symbol="IDC_RIBBONHELP" Id="700" />
|
||||
<Command Name="cmdQAT" Symbol="IDC_QAT" Id="701" />
|
||||
<Command Name="cmdCustomizeQAT" Symbol="IDC_CUSTOMIZE_QAT" Id="702" />
|
||||
|
||||
</Application.Commands>
|
||||
|
||||
<Application.Views>
|
||||
<Ribbon>
|
||||
|
||||
<!-- Application Menu -->
|
||||
<Ribbon.ApplicationMenu>
|
||||
<ApplicationMenu CommandName="cmdAppMenu">
|
||||
<MenuGroup Class="MajorItems">
|
||||
<Button CommandName="cmdAddFiles" />
|
||||
<Button CommandName="cmdAddFolder" />
|
||||
</MenuGroup>
|
||||
<MenuGroup>
|
||||
<Button CommandName="cmdAbout" />
|
||||
</MenuGroup>
|
||||
<MenuGroup>
|
||||
<Button CommandName="cmdExit" />
|
||||
</MenuGroup>
|
||||
</ApplicationMenu>
|
||||
</Ribbon.ApplicationMenu>
|
||||
|
||||
<!-- Tabs -->
|
||||
<Ribbon.Tabs>
|
||||
<Tab CommandName="cmdTabHome">
|
||||
<Tab.ScalingPolicy>
|
||||
<ScalingPolicy>
|
||||
<ScalingPolicy.IdealSizes>
|
||||
<Scale Group="cmdGroupQueue" Size="Large" />
|
||||
<Scale Group="cmdGroupActions" Size="Large" />
|
||||
</ScalingPolicy.IdealSizes>
|
||||
<Scale Group="cmdGroupQueue" Size="Medium" />
|
||||
<Scale Group="cmdGroupActions" Size="Popup" />
|
||||
</ScalingPolicy>
|
||||
</Tab.ScalingPolicy>
|
||||
<Group CommandName="cmdGroupQueue" SizeDefinition="ThreeButtons">
|
||||
<Button CommandName="cmdAddFiles" />
|
||||
<Button CommandName="cmdAddFolder" />
|
||||
<Button CommandName="cmdClear" />
|
||||
</Group>
|
||||
<Group CommandName="cmdGroupActions" SizeDefinition="OneButton">
|
||||
<Button CommandName="cmdProcess" />
|
||||
</Group>
|
||||
</Tab>
|
||||
</Ribbon.Tabs>
|
||||
|
||||
<!-- Help button -->
|
||||
<Ribbon.HelpButton>
|
||||
<HelpButton CommandName="cmdHelp" />
|
||||
</Ribbon.HelpButton>
|
||||
|
||||
<!-- Quick Access toolbar -->
|
||||
<Ribbon.QuickAccessToolbar>
|
||||
<QuickAccessToolbar CommandName="cmdQAT" CustomizeCommandName="cmdCustomizeQAT">
|
||||
<QuickAccessToolbar.ApplicationDefaults>
|
||||
<Button CommandName="cmdProcess" ApplicationDefaults.IsChecked="true" />
|
||||
</QuickAccessToolbar.ApplicationDefaults>
|
||||
</QuickAccessToolbar>
|
||||
</Ribbon.QuickAccessToolbar>
|
||||
|
||||
</Ribbon>
|
||||
</Application.Views>
|
||||
</Application>
|
||||
29
packages/media/cpp/src/win/ui_next/RibbonUI.h
Normal file
29
packages/media/cpp/src/win/ui_next/RibbonUI.h
Normal file
@ -0,0 +1,29 @@
|
||||
// *****************************************************************************
|
||||
// * This is an automatically generated header file for UI Element definition *
|
||||
// * resource symbols and values. Please do not modify manually. *
|
||||
// *****************************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#define cmdTabHome 400
|
||||
#define cmdTabHome_LabelTitle_RESID 4001
|
||||
#define cmdGroupQueue 401
|
||||
#define cmdGroupQueue_LabelTitle_RESID 4011
|
||||
#define cmdGroupActions 402
|
||||
#define cmdGroupActions_LabelTitle_RESID 4021
|
||||
#define IDC_CMD_ADD_FILES 302
|
||||
#define IDC_CMD_ADD_FILES_LabelTitle_RESID 3021
|
||||
#define IDC_CMD_ADD_FOLDER 303
|
||||
#define IDC_CMD_ADD_FOLDER_LabelTitle_RESID 3031
|
||||
#define IDC_CMD_CLEAR 301
|
||||
#define IDC_CMD_CLEAR_LabelTitle_RESID 3011
|
||||
#define IDC_CMD_PROCESS 300
|
||||
#define IDC_CMD_PROCESS_LabelTitle_RESID 3001
|
||||
#define IDC_CMD_EXIT 304
|
||||
#define IDC_CMD_EXIT_LabelTitle_RESID 3041
|
||||
#define IDC_CMD_ABOUT 305
|
||||
#define IDC_CMD_ABOUT_LabelTitle_RESID 3051
|
||||
#define cmdAppMenu 710
|
||||
#define IDC_RIBBONHELP 700
|
||||
#define IDC_QAT 701
|
||||
#define IDC_CUSTOMIZE_QAT 702
|
||||
53
packages/media/cpp/src/win/ui_next/RibbonUI.rc
Normal file
53
packages/media/cpp/src/win/ui_next/RibbonUI.rc
Normal file
@ -0,0 +1,53 @@
|
||||
// ******************************************************************************
|
||||
// * This is an automatically generated file containing the ribbon resource for *
|
||||
// * your application. *
|
||||
// ******************************************************************************
|
||||
|
||||
#include ".\RibbonUI.h"
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
cmdTabHome_LabelTitle_RESID L"Home" /* LabelTitle cmdTabHome_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
cmdGroupQueue_LabelTitle_RESID L"Queue" /* LabelTitle cmdGroupQueue_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
cmdGroupActions_LabelTitle_RESID L"Actions" /* LabelTitle cmdGroupActions_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDC_CMD_ADD_FILES_LabelTitle_RESID L"Add Files" /* LabelTitle IDC_CMD_ADD_FILES_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDC_CMD_ADD_FOLDER_LabelTitle_RESID L"Add Folder" /* LabelTitle IDC_CMD_ADD_FOLDER_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDC_CMD_CLEAR_LabelTitle_RESID L"Clear" /* LabelTitle IDC_CMD_CLEAR_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDC_CMD_PROCESS_LabelTitle_RESID L"Process" /* LabelTitle IDC_CMD_PROCESS_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDC_CMD_EXIT_LabelTitle_RESID L"Exit" /* LabelTitle IDC_CMD_EXIT_LabelTitle_RESID: (null) */
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
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"
|
||||
254
packages/media/cpp/src/win/ui_next/SettingsPanel.cpp
Normal file
254
packages/media/cpp/src/win/ui_next/SettingsPanel.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
#include "stdafx.h"
|
||||
#include "SettingsPanel.h"
|
||||
#include "Resource.h"
|
||||
#include <shlobj.h>
|
||||
|
||||
static std::string wide_to_utf8(const std::wstring& w) {
|
||||
if (w.empty()) return {};
|
||||
int n = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), (int)w.size(), nullptr, 0, nullptr, nullptr);
|
||||
if (n <= 0) return {};
|
||||
std::string s(n, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, w.c_str(), (int)w.size(), s.data(), n, nullptr, nullptr);
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::wstring utf8_to_wide(const std::string& s) {
|
||||
if (s.empty()) return {};
|
||||
int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0);
|
||||
if (n <= 0) return {};
|
||||
std::wstring w(n, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), w.data(), n);
|
||||
return w;
|
||||
}
|
||||
|
||||
static std::wstring get_edit_text(HWND h) {
|
||||
int n = ::GetWindowTextLengthW(h);
|
||||
if (n <= 0) return {};
|
||||
std::wstring w(n + 1, L'\0');
|
||||
::GetWindowTextW(h, w.data(), n + 1);
|
||||
w.resize(n);
|
||||
return w;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// CSettingsView
|
||||
//////////////////////////////////////////
|
||||
|
||||
int CSettingsView::OnCreate(CREATESTRUCT&)
|
||||
{
|
||||
CreateControls();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSettingsView::CreateControls()
|
||||
{
|
||||
const int x0 = 8, lw = 100, gap = 6;
|
||||
const int ew = 140, eh = 22;
|
||||
int y = 10;
|
||||
HINSTANCE inst = GetModuleHandleW(nullptr);
|
||||
|
||||
auto label = [&](LPCWSTR text, int yoff = 0) {
|
||||
CreateWindowExW(0, L"STATIC", text, WS_CHILD | WS_VISIBLE,
|
||||
x0, y + yoff, lw, 18, GetHwnd(), nullptr, inst, nullptr);
|
||||
};
|
||||
|
||||
// Output preset
|
||||
label(L"Output preset:");
|
||||
m_hPreset = CreateWindowExW(WS_EX_CLIENTEDGE, L"COMBOBOX", L"",
|
||||
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
x0 + lw + gap, y - 2, ew + 40, 140, GetHwnd(), (HMENU)(UINT_PTR)IDC_COMBO_PRESET_OUT, inst, nullptr);
|
||||
::SendMessageW(m_hPreset, CB_ADDSTRING, 0, (LPARAM)L"Next to source");
|
||||
::SendMessageW(m_hPreset, CB_ADDSTRING, 0, (LPARAM)L"Next to source (_resized)");
|
||||
::SendMessageW(m_hPreset, CB_ADDSTRING, 0, (LPARAM)L"Custom folder");
|
||||
::SendMessageW(m_hPreset, CB_SETCURSEL, 0, 0);
|
||||
y += 30;
|
||||
|
||||
// Output directory
|
||||
label(L"Output folder:");
|
||||
m_hOutDir = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"",
|
||||
WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
|
||||
x0 + lw + gap, y, ew, eh, GetHwnd(), (HMENU)(UINT_PTR)IDC_EDIT_OUT_DIR, inst, nullptr);
|
||||
m_hBtnBrowse = CreateWindowExW(0, L"BUTTON", L"...",
|
||||
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
|
||||
x0 + lw + gap + ew + 4, y, 28, eh, GetHwnd(), (HMENU)(UINT_PTR)IDC_BTN_BROWSE_OUT, inst, nullptr);
|
||||
y += 30;
|
||||
|
||||
// Max width / height
|
||||
label(L"Max width:");
|
||||
m_hMaxW = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"0",
|
||||
WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER,
|
||||
x0 + lw + gap, y, 60, eh, GetHwnd(), (HMENU)(UINT_PTR)IDC_EDIT_MAX_W, inst, nullptr);
|
||||
CreateWindowExW(0, L"STATIC", L"Max height:", WS_CHILD | WS_VISIBLE,
|
||||
x0 + lw + gap + 68, y, 80, 18, GetHwnd(), nullptr, inst, nullptr);
|
||||
m_hMaxH = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"0",
|
||||
WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER,
|
||||
x0 + lw + gap + 68 + 84, y, 60, eh, GetHwnd(), (HMENU)(UINT_PTR)IDC_EDIT_MAX_H, inst, nullptr);
|
||||
y += 30;
|
||||
|
||||
// Fit
|
||||
label(L"Fit:");
|
||||
m_hFit = CreateWindowExW(WS_EX_CLIENTEDGE, L"COMBOBOX", L"",
|
||||
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
x0 + lw + gap, y - 2, ew, 140, GetHwnd(), (HMENU)(UINT_PTR)IDC_COMBO_FIT, inst, nullptr);
|
||||
const LPCWSTR fits[] = { L"inside", L"cover", L"contain", L"fill", L"outside" };
|
||||
for (auto f : fits) ::SendMessageW(m_hFit, CB_ADDSTRING, 0, (LPARAM)f);
|
||||
::SendMessageW(m_hFit, CB_SETCURSEL, 0, 0);
|
||||
y += 30;
|
||||
|
||||
// Quality
|
||||
label(L"Quality (1-100):");
|
||||
m_hQuality = CreateWindowExW(WS_EX_CLIENTEDGE, L"EDIT", L"85",
|
||||
WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER,
|
||||
x0 + lw + gap, y, 48, eh, GetHwnd(), (HMENU)(UINT_PTR)IDC_EDIT_QUALITY, inst, nullptr);
|
||||
y += 30;
|
||||
|
||||
// Checkboxes
|
||||
m_hEnlarge = CreateWindowExW(0, L"BUTTON", L"Allow enlargement",
|
||||
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
|
||||
x0, y, 180, 22, GetHwnd(), (HMENU)(UINT_PTR)IDC_CHK_ENLARGE, inst, nullptr);
|
||||
y += 24;
|
||||
|
||||
m_hAutorot = CreateWindowExW(0, L"BUTTON", L"EXIF autorotate",
|
||||
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
|
||||
x0, y, 180, 22, GetHwnd(), (HMENU)(UINT_PTR)IDC_CHK_AUTOROT, inst, nullptr);
|
||||
::SendMessageW(m_hAutorot, BM_SETCHECK, BST_CHECKED, 0);
|
||||
y += 24;
|
||||
|
||||
m_hStrip = CreateWindowExW(0, L"BUTTON", L"Strip metadata on save",
|
||||
WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
|
||||
x0, y, 200, 22, GetHwnd(), (HMENU)(UINT_PTR)IDC_CHK_STRIP, inst, nullptr);
|
||||
::SendMessageW(m_hStrip, BM_SETCHECK, BST_CHECKED, 0);
|
||||
}
|
||||
|
||||
void CSettingsView::ReadOptions(media::ResizeOptions& opt, std::string& out_dir) const
|
||||
{
|
||||
int preset = (int)::SendMessageW(m_hPreset, CB_GETCURSEL, 0, 0);
|
||||
opt.output_stem_suffix.clear();
|
||||
if (preset == 1) opt.output_stem_suffix = "_resized";
|
||||
|
||||
out_dir.clear();
|
||||
if (preset == 2 || !get_edit_text(m_hOutDir).empty())
|
||||
out_dir = wide_to_utf8(get_edit_text(m_hOutDir));
|
||||
|
||||
wchar_t buf[32]{};
|
||||
::GetWindowTextW(m_hMaxW, buf, 32);
|
||||
opt.max_width = _wtoi(buf);
|
||||
if (opt.max_width < 0) opt.max_width = 0;
|
||||
|
||||
::GetWindowTextW(m_hMaxH, buf, 32);
|
||||
opt.max_height = _wtoi(buf);
|
||||
if (opt.max_height < 0) opt.max_height = 0;
|
||||
|
||||
int fi = (int)::SendMessageW(m_hFit, CB_GETCURSEL, 0, 0);
|
||||
const char* fits[] = { "inside", "cover", "contain", "fill", "outside" };
|
||||
if (fi >= 0 && fi < 5) opt.fit = fits[fi];
|
||||
|
||||
::GetWindowTextW(m_hQuality, buf, 32);
|
||||
opt.quality = _wtoi(buf);
|
||||
if (opt.quality < 1) opt.quality = 1;
|
||||
if (opt.quality > 100) opt.quality = 100;
|
||||
|
||||
opt.without_enlargement = ::SendMessageW(m_hEnlarge, BM_GETCHECK, 0, 0) != BST_CHECKED;
|
||||
opt.autorotate = ::SendMessageW(m_hAutorot, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
||||
opt.strip_metadata = ::SendMessageW(m_hStrip, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
||||
}
|
||||
|
||||
void CSettingsView::WriteOptions(const media::ResizeOptions& opt, const std::string& out_dir)
|
||||
{
|
||||
int preset = 0;
|
||||
if (!out_dir.empty()) preset = 2;
|
||||
else if (opt.output_stem_suffix == "_resized") preset = 1;
|
||||
::SendMessageW(m_hPreset, CB_SETCURSEL, preset, 0);
|
||||
|
||||
::SetWindowTextW(m_hOutDir, utf8_to_wide(out_dir).c_str());
|
||||
|
||||
wchar_t buf[32]{};
|
||||
swprintf_s(buf, L"%d", opt.max_width);
|
||||
::SetWindowTextW(m_hMaxW, buf);
|
||||
swprintf_s(buf, L"%d", opt.max_height);
|
||||
::SetWindowTextW(m_hMaxH, buf);
|
||||
swprintf_s(buf, L"%d", opt.quality);
|
||||
::SetWindowTextW(m_hQuality, buf);
|
||||
|
||||
::SendMessageW(m_hEnlarge, BM_SETCHECK, opt.without_enlargement ? BST_UNCHECKED : BST_CHECKED, 0);
|
||||
::SendMessageW(m_hAutorot, BM_SETCHECK, opt.autorotate ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||
::SendMessageW(m_hStrip, BM_SETCHECK, opt.strip_metadata ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||
}
|
||||
|
||||
void CSettingsView::OnBrowseOutput()
|
||||
{
|
||||
BROWSEINFOW bi{};
|
||||
bi.hwndOwner = GetHwnd();
|
||||
bi.lpszTitle = L"Choose output folder";
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
wchar_t dn[MAX_PATH]{};
|
||||
bi.pszDisplayName = dn;
|
||||
PIDLIST_ABSOLUTE pidl = SHBrowseForFolderW(&bi);
|
||||
if (!pidl) return;
|
||||
wchar_t path[MAX_PATH * 4]{};
|
||||
if (SHGetPathFromIDListW(pidl, path))
|
||||
::SetWindowTextW(m_hOutDir, path);
|
||||
CoTaskMemFree(pidl);
|
||||
}
|
||||
|
||||
LRESULT CSettingsView::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try {
|
||||
if (msg == WM_COMMAND) {
|
||||
if (LOWORD(wparam) == IDC_BTN_BROWSE_OUT) {
|
||||
OnBrowseOutput();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return WndProcDefault(msg, wparam, lparam);
|
||||
}
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// CSettingsContainer
|
||||
//////////////////////////////////////////
|
||||
|
||||
CSettingsContainer::CSettingsContainer()
|
||||
{
|
||||
SetTabText(L"Settings");
|
||||
SetDockCaption(L"Resize Settings");
|
||||
SetView(m_view);
|
||||
}
|
||||
|
||||
LRESULT CSettingsContainer::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try { return WndProcDefault(msg, wparam, lparam); }
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// CDockSettings
|
||||
//////////////////////////////////////////
|
||||
|
||||
CDockSettings::CDockSettings()
|
||||
{
|
||||
SetView(m_container);
|
||||
SetBarWidth(8);
|
||||
}
|
||||
|
||||
LRESULT CDockSettings::WndProc(UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
try { return WndProcDefault(msg, wparam, lparam); }
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"Error", MB_ICONERROR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
78
packages/media/cpp/src/win/ui_next/SettingsPanel.h
Normal file
78
packages/media/cpp/src/win/ui_next/SettingsPanel.h
Normal file
@ -0,0 +1,78 @@
|
||||
#ifndef PM_UI_SETTINGSPANEL_H
|
||||
#define PM_UI_SETTINGSPANEL_H
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "core/resize.hpp"
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// CSettingsView — child dialog-like panel for resize options.
|
||||
// Hosted inside a dock container on the right.
|
||||
class CSettingsView : public CWnd
|
||||
{
|
||||
public:
|
||||
CSettingsView() = default;
|
||||
virtual ~CSettingsView() override = default;
|
||||
|
||||
void ReadOptions(media::ResizeOptions& opt, std::string& out_dir) const;
|
||||
void WriteOptions(const media::ResizeOptions& opt, const std::string& out_dir);
|
||||
|
||||
protected:
|
||||
virtual int OnCreate(CREATESTRUCT& cs) override;
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CSettingsView(const CSettingsView&) = delete;
|
||||
CSettingsView& operator=(const CSettingsView&) = delete;
|
||||
|
||||
void OnBrowseOutput();
|
||||
void CreateControls();
|
||||
|
||||
HWND m_hPreset{};
|
||||
HWND m_hOutDir{};
|
||||
HWND m_hBtnBrowse{};
|
||||
HWND m_hMaxW{};
|
||||
HWND m_hMaxH{};
|
||||
HWND m_hFit{};
|
||||
HWND m_hQuality{};
|
||||
HWND m_hEnlarge{};
|
||||
HWND m_hAutorot{};
|
||||
HWND m_hStrip{};
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// CSettingsContainer — dock container hosting CSettingsView.
|
||||
class CSettingsContainer : public CDockContainer
|
||||
{
|
||||
public:
|
||||
CSettingsContainer();
|
||||
virtual ~CSettingsContainer() override = default;
|
||||
CSettingsView& GetSettingsView() { return m_view; }
|
||||
|
||||
protected:
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CSettingsContainer(const CSettingsContainer&) = delete;
|
||||
CSettingsContainer& operator=(const CSettingsContainer&) = delete;
|
||||
CSettingsView m_view;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// CDockSettings — docker wrapping CSettingsContainer.
|
||||
class CDockSettings : public CDocker
|
||||
{
|
||||
public:
|
||||
CDockSettings();
|
||||
virtual ~CDockSettings() override = default;
|
||||
CSettingsContainer& GetSettingsContainer() { return m_container; }
|
||||
|
||||
protected:
|
||||
virtual LRESULT WndProc(UINT msg, WPARAM wparam, LPARAM lparam) override;
|
||||
|
||||
private:
|
||||
CDockSettings(const CDockSettings&) = delete;
|
||||
CDockSettings& operator=(const CDockSettings&) = delete;
|
||||
CSettingsContainer m_container;
|
||||
};
|
||||
|
||||
#endif // PM_UI_SETTINGSPANEL_H
|
||||
49
packages/media/cpp/src/win/ui_next/launch_ui_next.cpp
Normal file
49
packages/media/cpp/src/win/ui_next/launch_ui_next.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "stdafx.h"
|
||||
#include "launch_ui_next.h"
|
||||
#include "App.h"
|
||||
#include <objbase.h>
|
||||
|
||||
static std::wstring utf8_to_wide(const std::string& s) {
|
||||
if (s.empty()) return {};
|
||||
int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0);
|
||||
if (n <= 0) return {};
|
||||
std::wstring w(n, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), w.data(), n);
|
||||
return w;
|
||||
}
|
||||
|
||||
namespace media::win {
|
||||
|
||||
int launch_ui_next(const std::vector<std::string>& initial_files)
|
||||
{
|
||||
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||
|
||||
try {
|
||||
CPmImageApp app;
|
||||
|
||||
if (!initial_files.empty()) {
|
||||
std::vector<std::wstring> wpaths;
|
||||
wpaths.reserve(initial_files.size());
|
||||
for (auto& f : initial_files)
|
||||
wpaths.push_back(utf8_to_wide(f));
|
||||
app.GetMainFrame().AddFilesToQueue(wpaths);
|
||||
}
|
||||
|
||||
int rc = app.Run();
|
||||
CoUninitialize();
|
||||
return rc;
|
||||
}
|
||||
catch (const CException& e) {
|
||||
CString s;
|
||||
s << e.GetText() << L'\n' << e.GetErrorString();
|
||||
::MessageBox(nullptr, s, L"pm-image startup error", MB_ICONERROR);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
::MessageBoxA(nullptr, e.what(), "pm-image startup error", MB_ICONERROR);
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace media::win
|
||||
13
packages/media/cpp/src/win/ui_next/launch_ui_next.h
Normal file
13
packages/media/cpp/src/win/ui_next/launch_ui_next.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace media::win {
|
||||
|
||||
/// Launch the Win32++ "next" UI. Runs the message loop; returns when window is closed.
|
||||
/// @param initial_files Optional pre-seeded file paths to add to the queue on launch.
|
||||
/// @return 0 on normal exit.
|
||||
int launch_ui_next(const std::vector<std::string>& initial_files = {});
|
||||
|
||||
} // namespace media::win
|
||||
17
packages/media/cpp/src/win/ui_next/res/PerMonitorV2.manifest
Normal file
17
packages/media/cpp/src/win/ui_next/res/PerMonitorV2.manifest
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"
|
||||
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0" processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df" language="*" />
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
</assembly>
|
||||
53
packages/media/cpp/src/win/ui_next/stdafx.h
Normal file
53
packages/media/cpp/src/win/ui_next/stdafx.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef PM_UI_STDAFX_H
|
||||
#define PM_UI_STDAFX_H
|
||||
|
||||
// Standard library
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
// Win32++ — full set in the order required by the library.
|
||||
// (mirrors the RibbonDockFrame sample's stdafx.h)
|
||||
#include <wxx_appcore.h>
|
||||
#include <wxx_archive.h>
|
||||
#include <wxx_controls.h>
|
||||
#include <wxx_cstring.h>
|
||||
#include <wxx_dialog.h>
|
||||
#include <wxx_dockframe.h>
|
||||
#include <wxx_docking.h>
|
||||
#include <wxx_exception.h>
|
||||
#include <wxx_file.h>
|
||||
#include <wxx_folderdialog.h>
|
||||
#include <wxx_frame.h>
|
||||
#include <wxx_gdi.h>
|
||||
#include <wxx_imagelist.h>
|
||||
#include <wxx_listview.h>
|
||||
#include <wxx_menu.h>
|
||||
#include <wxx_menubar.h>
|
||||
#include <wxx_propertysheet.h>
|
||||
#include <wxx_rebar.h>
|
||||
#include <wxx_rect.h>
|
||||
#include <wxx_regkey.h>
|
||||
#include <wxx_statusbar.h>
|
||||
#include <wxx_stdcontrols.h>
|
||||
#include <wxx_tab.h>
|
||||
#include <wxx_themes.h>
|
||||
#include <wxx_thread.h>
|
||||
#include <wxx_toolbar.h>
|
||||
#include <wxx_wincore.h>
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#include <wxx_commondlg.h>
|
||||
#include <wxx_taskdialog.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include <wxx_ribbon.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // PM_UI_STDAFX_H
|
||||
0
packages/media/cpp/ui-win32.md
Normal file
0
packages/media/cpp/ui-win32.md
Normal file
Loading…
Reference in New Issue
Block a user