Feature: Add configurable remote-desktop quality levels menu
Add an "高级 (Advanced)" menu after "其他 (Other)" whose "远程桌面质量等级 (Remote Desktop Quality Levels)" item opens a dialog to edit the six preset QualityProfile levels (max FPS, max width, codec algorithm, bitrate). The dialog edits a working copy in a full grid with per-field validation and a restore-defaults button; on OK it persists the values to the [quality] INI section. The server stays authoritative: LoadQualityProfilesFromCfg loads the saved levels at startup (falling back to GetQualityProfile defaults), and ScreenSpyDlg now sends CMD_QUALITY_PROFILES from GetQualityProfileCfg so new remote-desktop sessions transmit with the configured parameters. Added en_US/de_DE/zh_TW translations for the menu and dialog strings. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
1 parent
0416dadbba
commit
033ff077ef
9 files changed
+294
-3
No files matched your search
@@ -0,0 +1,156 @@
|
||||
// QualityLevelsDlg.h
|
||||
// 远程桌面质量等级配置对话框:编辑 6 档 QualityProfile(帧率/宽度/算法/码率)。
|
||||
// 纯主控端 UI 偏好,持久化由 CMy2015RemoteDlg::SaveQualityProfilesToCfg() 负责。
|
||||
// 仅在 2015RemoteDlg.cpp 中 include 一次(头文件内联实现,勿多处包含)。
|
||||
#pragma once
|
||||
|
||||
#include "LangManager.h"
|
||||
|
||||
class CQualityLevelsDlg : public CDialog
|
||||
{
|
||||
public:
|
||||
enum { IDD = IDD_QUALITY_LEVELS };
|
||||
|
||||
// profiles: 指向 6 元素 QualityProfile 数组,确认后写回
|
||||
CQualityLevelsDlg(QualityProfile* profiles, CWnd* pParent = NULL)
|
||||
: CDialog(CQualityLevelsDlg::IDD, pParent), m_profiles(profiles)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
QualityProfile* m_profiles;
|
||||
QualityProfile m_working[QUALITY_COUNT];
|
||||
|
||||
static const char* AlgorithmName(int algo)
|
||||
{
|
||||
switch (algo) {
|
||||
case ALGORITHM_GRAY: return "GRAY";
|
||||
case ALGORITHM_DIFF: return "DIFF";
|
||||
case ALGORITHM_H264: return "H264";
|
||||
case ALGORITHM_RGB565: return "RGB565";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static const char* LevelName(int i)
|
||||
{
|
||||
static const char* names[QUALITY_COUNT] = {
|
||||
"Ultra", "High", "Good", "Medium", "Low", "Minimal"
|
||||
};
|
||||
return (i >= 0 && i < QUALITY_COUNT) ? names[i] : "?";
|
||||
}
|
||||
|
||||
void FillAlgoCombo(int i)
|
||||
{
|
||||
CComboBox* cb = (CComboBox*)GetDlgItem(IDC_QLEVEL_ALGO + i);
|
||||
if (!cb) return;
|
||||
for (int a = 0; a < 4; a++) {
|
||||
cb->AddString(CString(AlgorithmName(a)));
|
||||
}
|
||||
cb->SetCurSel(m_working[i].algorithm);
|
||||
}
|
||||
|
||||
void LoadToControls()
|
||||
{
|
||||
CString s;
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
s.Format(_T("%d"), m_working[i].maxFPS);
|
||||
SetDlgItemText(IDC_QLEVEL_FPS + i, s);
|
||||
s.Format(_T("%d"), m_working[i].maxWidth);
|
||||
SetDlgItemText(IDC_QLEVEL_WIDTH + i, s);
|
||||
s.Format(_T("%d"), m_working[i].bitRate);
|
||||
SetDlgItemText(IDC_QLEVEL_BITRATE + i, s);
|
||||
FillAlgoCombo(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool ReadInt(int id, int& out)
|
||||
{
|
||||
CString s;
|
||||
GetDlgItemText(id, s);
|
||||
s.Trim();
|
||||
if (s.IsEmpty()) return false;
|
||||
|
||||
int v = 0;
|
||||
for (int k = 0; k < s.GetLength(); k++) {
|
||||
TCHAR ch = s[k];
|
||||
if (ch < _T('0') || ch > _T('9')) return false;
|
||||
v = v * 10 + (ch - _T('0'));
|
||||
}
|
||||
out = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFromControls(CString& err)
|
||||
{
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
int fps, w, br;
|
||||
if (!ReadInt(IDC_QLEVEL_FPS + i, fps))
|
||||
{ err.Format(_T("等级 %s 的帧率不是有效数字"), LevelName(i)); return false; }
|
||||
if (!ReadInt(IDC_QLEVEL_WIDTH + i, w))
|
||||
{ err.Format(_T("等级 %s 的最大宽度不是有效数字"), LevelName(i)); return false; }
|
||||
if (!ReadInt(IDC_QLEVEL_BITRATE + i, br))
|
||||
{ err.Format(_T("等级 %s 的码率不是有效数字"), LevelName(i)); return false; }
|
||||
|
||||
if (fps < 1 || fps > 60)
|
||||
{ err.Format(_T("等级 %s 的帧率需在 1~60 之间"), LevelName(i)); return false; }
|
||||
if (w < 0 || w > 8192)
|
||||
{ err.Format(_T("等级 %s 的最大宽度需在 0~8192 之间(0=原始分辨率)"), LevelName(i)); return false; }
|
||||
if (br < 0 || br > 50000)
|
||||
{ err.Format(_T("等级 %s 的码率需在 0~50000 之间"), LevelName(i)); return false; }
|
||||
|
||||
CComboBox* cb = (CComboBox*)GetDlgItem(IDC_QLEVEL_ALGO + i);
|
||||
int algo = cb ? cb->GetCurSel() : -1;
|
||||
if (algo < 0 || algo > 3)
|
||||
{ err.Format(_T("等级 %s 的编码算法未选择"), LevelName(i)); return false; }
|
||||
|
||||
m_working[i].maxFPS = fps;
|
||||
m_working[i].maxWidth = w;
|
||||
m_working[i].bitRate = br;
|
||||
m_working[i].algorithm = algo;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetToDefaults()
|
||||
{
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_working[i] = GetQualityProfile(i);
|
||||
}
|
||||
LoadToControls();
|
||||
}
|
||||
|
||||
virtual BOOL OnInitDialog() override
|
||||
{
|
||||
CDialog::OnInitDialog();
|
||||
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_working[i] = m_profiles[i];
|
||||
}
|
||||
LoadToControls();
|
||||
TranslateDialog(this);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
virtual void OnOK() override
|
||||
{
|
||||
CString err;
|
||||
if (!ReadFromControls(err)) {
|
||||
MessageBox(err, _TR("提示"), MB_ICONWARNING);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < QUALITY_COUNT; i++) {
|
||||
m_profiles[i] = m_working[i];
|
||||
}
|
||||
CDialog::OnOK();
|
||||
}
|
||||
|
||||
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam) override
|
||||
{
|
||||
if (LOWORD(wParam) == IDC_QLEVEL_RESET && HIWORD(wParam) == BN_CLICKED) {
|
||||
ResetToDefaults();
|
||||
return TRUE;
|
||||
}
|
||||
return CDialog::OnCommand(wParam, lParam);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user