diff --git a/win32/CShaderParamDlg.cpp b/win32/CShaderParamDlg.cpp index 4c93c15f..887e23b4 100644 --- a/win32/CShaderParamDlg.cpp +++ b/win32/CShaderParamDlg.cpp @@ -13,6 +13,7 @@ #define IDC_PARAMS_START_STATIC 5000 #define IDC_PARAMS_START_EDIT 5500 #define IDC_PARAMS_START_UPDOWN 6000 +#define IDC_PARAMS_START_TRACKBAR 6500 INT_PTR CALLBACK CShaderParamDlg::DlgShaderParams(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -25,6 +26,10 @@ INT_PTR CALLBACK CShaderParamDlg::DlgShaderParams(HWND hDlg, UINT msg, WPARAM wP dlg->createContent(hDlg); return TRUE; + case WM_SIZE: + dlg->resize(hDlg); + return TRUE; + case WM_COMMAND: switch(LOWORD(wParam)) { @@ -100,11 +105,12 @@ INT_PTR CALLBACK CShaderParamDlg::DlgShaderParams(HWND hDlg, UINT msg, WPARAM wP INT_PTR CALLBACK CShaderParamDlg::WndProcContainerStatic(HWND hStatic, UINT msg, WPARAM wParam, LPARAM lParam) { + UINT nCode; CShaderParamDlg* dlg = (CShaderParamDlg*)GetWindowLongPtr(hStatic, GWLP_USERDATA); switch (msg) { case WM_NOTIFY: - UINT nCode = ((LPNMHDR)lParam)->code; + nCode = ((LPNMHDR)lParam)->code; switch (nCode) { case UDN_DELTAPOS: @@ -113,10 +119,30 @@ INT_PTR CALLBACK CShaderParamDlg::WndProcContainerStatic(HWND hStatic, UINT msg, dlg->apply_changes(GetParent(hStatic)); return TRUE; // return true so the up/down pos does not change } + break; + case WM_HSCROLL: + dlg->trackbar_changed((HWND)lParam); + dlg->apply_changes(GetParent(hStatic)); + break; } + return dlg->oldStaticProc(hStatic, msg, wParam, lParam); } +void CShaderParamDlg::trackbar_changed(HWND trackbar) +{ + LONG i = GetWindowLongPtr(trackbar, GWLP_USERDATA); + + auto& p = parameter_widgets[i]; + int pos = SendMessage(trackbar, TBM_GETPOS, 0, 0); + float value = parameters[i].step * pos; + + TCHAR val[256]; + _stprintf(val, TEXT("%g"), value); + + SetWindowText(p.entry, val); +} + CShaderParamDlg::CShaderParamDlg(std::vector& parameters_, std::function save_function_) : parameters(parameters_), save_function(save_function_) @@ -185,6 +211,52 @@ bool CShaderParamDlg::show() return false; } +static int fromDialogUnits(HWND dialog, int value) +{ + RECT rect = { value, value, value, value }; + MapDialogRect(dialog, &rect); + return rect.left; +}; + + +void CShaderParamDlg::resize(HWND hDlg) +{ + const int MARGIN = fromDialogUnits(hDlg, 5); + RECT buttonRect; + GetClientRect(GetDlgItem(hDlg, IDOK), &buttonRect); + const int BUTTON_WIDTH = buttonRect.right - buttonRect.left; + const int BUTTON_HEIGHT = buttonRect.bottom - buttonRect.top; + const int SCROLLBAR_WIDTH = fromDialogUnits(hDlg, 12); + const int edit_width = avgCharWidth * 12; + + RECT dialogRect; + GetClientRect(hDlg, &dialogRect); + HWND parent = GetDlgItem(hDlg, IDC_STATIC_CONTAINER); + RECT crect; + GetClientRect(parent, &crect); + SetWindowPos(parent, 0, MARGIN, MARGIN, dialogRect.right - MARGIN * 2 - SCROLLBAR_WIDTH, dialogRect.bottom - MARGIN * 3 - BUTTON_HEIGHT, SWP_NOZORDER); + + SetWindowPos(GetDlgItem(hDlg, IDAPPLY ), 0, dialogRect.right - (MARGIN + BUTTON_WIDTH) * 1, dialogRect.bottom - MARGIN - BUTTON_HEIGHT, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + SetWindowPos(GetDlgItem(hDlg, IDCANCEL), 0, dialogRect.right - (MARGIN + BUTTON_WIDTH) * 2, dialogRect.bottom - MARGIN - BUTTON_HEIGHT, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + SetWindowPos(GetDlgItem(hDlg, IDOK ), 0, dialogRect.right - (MARGIN + BUTTON_WIDTH) * 3, dialogRect.bottom - MARGIN - BUTTON_HEIGHT, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + SetWindowPos(GetDlgItem(hDlg, IDC_SCROLLBAR_PARAMS), 0, dialogRect.right - MARGIN - SCROLLBAR_WIDTH, MARGIN, SCROLLBAR_WIDTH, dialogRect.bottom - MARGIN * 3 - BUTTON_HEIGHT, SWP_NOZORDER); + + HWND scrollbar = GetDlgItem(hDlg, IDC_SCROLLBAR_PARAMS); + SCROLLINFO si = { 0 }; + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_PAGE; + si.nPage = crect.bottom; + SetScrollInfo(scrollbar, SB_CTL, &si, TRUE); + + for (size_t i = 0; i < parameter_widgets.size(); i++) + { + auto& p = parameter_widgets[i]; + SetWindowPos(p.trackbar, 0, 0, 0, crect.right - MARGIN * 4 - maxDescriptionWidth - edit_width, avgCharHeight * 1.7, SWP_NOMOVE | SWP_NOZORDER); + SetWindowPos(p.entry, 0, crect.right - MARGIN - edit_width, -1 * scrollpos + MARGIN + i * ((int)(avgCharHeight * 1.7) + MARGIN), edit_width, avgCharHeight * 1.7, SWP_NOZORDER); + SendMessage(p.updown, UDM_SETBUDDY, (WPARAM)p.entry, 0); + } +} + void CShaderParamDlg::createContent(HWND hDlg) { HWND parent = GetDlgItem(hDlg, IDC_STATIC_CONTAINER); @@ -196,32 +268,67 @@ void CShaderParamDlg::createContent(HWND hDlg) RECT clientRect; GetClientRect(parent, &clientRect); - const int HORIZONTAL_MARGIN = 10; - const int VERTICAL_MARGIN = 10; - const int HORIZONTAL_SPACE = 20; - const int VERTICAL_SPACE = 5; + maxDescriptionWidth = 30; + for (auto& p : parameters) + { + SIZE size; + Utf8ToWide wcsname(p.name.c_str()); + GetTextExtentPoint32(GetDC(hDlg), wcsname, wcslen(wcsname), &size); + if (size.cx > maxDescriptionWidth) + maxDescriptionWidth = size.cx; + } + maxDescriptionWidth += 5; - unsigned int desc_left = HORIZONTAL_MARGIN; - unsigned int desc_width = (clientRect.right - clientRect.left) * 3 / 4 - desc_left - HORIZONTAL_SPACE / 2; - unsigned int edit_left = desc_left + desc_width + HORIZONTAL_SPACE; - unsigned int edit_width = clientRect.right - clientRect.left - edit_left - HORIZONTAL_MARGIN; - unsigned int top = VERTICAL_MARGIN; + const int MARGIN = fromDialogUnits(hDlg, 5); + unsigned int desc_width = maxDescriptionWidth; + unsigned int edit_width = avgCharWidth * 12; + unsigned int edit_left = clientRect.right - MARGIN - edit_width; + unsigned int top = MARGIN; + parameter_widgets.clear(); for(int i = 0; i < parameters.size(); i++) { + ParameterWidgetSet widgets; GLSLParam &p = parameters[i]; TCHAR desc[270]; _stprintf(desc, TEXT("%s [%g-%g]"), (TCHAR*)_tFromChar(p.name.c_str()), p.min, p.max); - HWND item = CreateWindow(TEXT("STATIC"), desc, SS_LEFTNOWORDWRAP | WS_VISIBLE | WS_CHILD, desc_left, (INT)(top + avgCharHeight * 0.3), desc_width, avgCharHeight, parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_STATIC + i), GUI.hInstance, NULL); + HWND item = CreateWindow(TEXT("STATIC"), desc, SS_LEFTNOWORDWRAP | WS_VISIBLE | WS_CHILD, MARGIN, (INT)(top + avgCharHeight * 0.3), desc_width, avgCharHeight, parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_STATIC + i), GUI.hInstance, NULL); SendMessage(item, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(FALSE, 0)); + widgets.label = item; + + item = CreateWindowExW( + 0, + TRACKBAR_CLASS, + L"", + WS_CHILD | + WS_VISIBLE | + TBS_NOTICKS, + desc_width + MARGIN * 2, top, + clientRect.right - desc_width - edit_width - MARGIN * 4, avgCharHeight * 1.7, + parent, + (HMENU)(IDC_PARAMS_START_TRACKBAR + i), + GUI.hInstance, + NULL + ); + SendMessage(item, TBM_SETRANGEMIN, false, 0); + SendMessage(item, TBM_SETRANGEMAX, false, (int)round((p.max - p.min) / p.step)); + SendMessage(item, TBM_SETPOS, true, (int)round(p.val / p.step)); + SetWindowLongPtr(item, GWLP_USERDATA, i); + widgets.trackbar = item; + TCHAR val[100]; _stprintf(val, TEXT("%g"), p.val); item = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), val, ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_TABSTOP, edit_left , top, edit_width, (INT)(avgCharHeight * 1.7), parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_EDIT + i), GUI.hInstance, NULL); SendMessage(item, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(FALSE, 0)); + widgets.entry = item; - item = CreateWindow(UPDOWN_CLASS, NULL, WS_CHILDWINDOW | WS_VISIBLE | UDS_AUTOBUDDY | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_HOTTRACK, 0, 0, 0, 0, parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_UPDOWN + i), GUI.hInstance, NULL); + item = CreateWindow(UPDOWN_CLASS, NULL, WS_CHILDWINDOW | WS_VISIBLE | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_HOTTRACK, 0, 0, 0, 0, parent, (HMENU)(UINT_PTR)(IDC_PARAMS_START_UPDOWN + i), GUI.hInstance, NULL); SendMessage(item, UDM_SETRANGE, 0, MAKELONG(10, -10)); // we don't use this range, simply set it so the up arrow is positive and down arrow negative + widgets.updown = item; + SendMessage(item, UDM_SETBUDDY, (WPARAM)widgets.entry, 0); - top += (INT)(avgCharHeight * 1.7 + VERTICAL_SPACE); + top += (INT)(avgCharHeight * 1.7 + MARGIN); + + parameter_widgets.push_back(widgets); } RECT windowRect; @@ -236,6 +343,8 @@ void CShaderParamDlg::createContent(HWND hDlg) si.nPos = 0; scrollpos = 0; SetScrollInfo(scrollbar, SB_CTL, &si, TRUE); + + resize(hDlg); } void CShaderParamDlg::handle_up_down(HWND hStatic, int id, int change) @@ -246,13 +355,16 @@ void CShaderParamDlg::handle_up_down(HWND hStatic, int id, int change) TCHAR val[100]; GetWindowText(hEdit, val, 100); p.val = _ttof(val); - p.val += change > 0 ? p.step : -p.step; + int step = round(p.val / p.step); + step += change > 0 ? 1 : -1; + p.val = step * p.step; if (p.val < p.min) p.val = p.min; if (p.val > p.max) p.val = p.max; _stprintf(val, TEXT("%g"), p.val); SetWindowText(hEdit, val); + SendMessage(parameter_widgets[param_id].trackbar, TBM_SETPOS, true, step); } void CShaderParamDlg::get_changed_parameters(HWND hDlg) diff --git a/win32/CShaderParamDlg.h b/win32/CShaderParamDlg.h index 842486a5..8bdfbfae 100644 --- a/win32/CShaderParamDlg.h +++ b/win32/CShaderParamDlg.h @@ -17,19 +17,31 @@ private: static INT_PTR CALLBACK DlgShaderParams(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); static INT_PTR CALLBACK WndProcContainerStatic(HWND hStatic, UINT msg, WPARAM wParam, LPARAM lParam); void createContent(HWND hDlg); + void resize(HWND hDlg); void get_changed_parameters(HWND hDlg); void handle_up_down(HWND hStatic, int id, int change); void save_custom_shader(); void apply_changes(HWND hDlg); + void trackbar_changed(HWND trackbar); HFONT hFont; unsigned int avgCharWidth; unsigned int avgCharHeight; + unsigned int maxDescriptionWidth; int scrollpos; std::vector& parameters; std::vector saved_parameters; std::function save_function; + struct ParameterWidgetSet + { + HWND label; + HWND trackbar; + HWND entry; + HWND updown; + }; + std::vector parameter_widgets; + WNDPROC oldStaticProc; public: diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index 1252e96c..8ff3c879 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -560,7 +560,7 @@ BEGIN END IDD_DIALOG_SHADER_PARAMS DIALOGEX 0, 0, 308, 206 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME CAPTION "Shader Parameters" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN