AdvancedConfigDlg.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * AdvancedConfigDlg.cpp
  3. * ---------------------
  4. * Purpose: Implementation of the advanced settings dialog.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Mainfrm.h"
  11. #include "AdvancedConfigDlg.h"
  12. #include "Settings.h"
  13. #include "dlg_misc.h"
  14. OPENMPT_NAMESPACE_BEGIN
  15. BEGIN_MESSAGE_MAP(COptionsAdvanced, CPropertyPage)
  16. ON_NOTIFY(NM_DBLCLK, IDC_LIST1, &COptionsAdvanced::OnOptionDblClick)
  17. #ifndef MPT_MFC_FULL
  18. ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, &COptionsAdvanced::OnCustomDrawList)
  19. #endif
  20. ON_EN_CHANGE(IDC_EDIT1, &COptionsAdvanced::OnFindStringChanged)
  21. ON_COMMAND(IDC_BUTTON1, &COptionsAdvanced::OnSaveNow)
  22. END_MESSAGE_MAP()
  23. void COptionsAdvanced::DoDataExchange(CDataExchange* pDX)
  24. {
  25. CDialog::DoDataExchange(pDX);
  26. //{{AFX_DATA_MAP(CModTypeDlg)
  27. DDX_Control(pDX, IDC_LIST1, m_List);
  28. //}}AFX_DATA_MAP
  29. }
  30. BOOL COptionsAdvanced::PreTranslateMessage(MSG *msg)
  31. {
  32. if(msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN)
  33. {
  34. OnOptionDblClick(nullptr, nullptr);
  35. return TRUE;
  36. }
  37. return FALSE;
  38. }
  39. BOOL COptionsAdvanced::OnInitDialog()
  40. {
  41. CPropertyPage::OnInitDialog();
  42. m_List.SetExtendedStyle(m_List.GetExtendedStyle() | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
  43. ListView_EnableGroupView(m_List.m_hWnd, FALSE); // try to set known state
  44. int enableGroupsResult1 = static_cast<int>(ListView_EnableGroupView(m_List.m_hWnd, TRUE));
  45. int enableGroupsResult2 = static_cast<int>(ListView_EnableGroupView(m_List.m_hWnd, TRUE));
  46. // Looks like we have to check enabling and check that a second enabling does
  47. // not change anything.
  48. // Just checking if enabling fails with -1 does not work for older control
  49. // versions because they just do not know the window message at all and return
  50. // 0, always. At least Wine does behave this way.
  51. if(enableGroupsResult1 == 1 && enableGroupsResult2 == 0)
  52. {
  53. m_listGrouped = true;
  54. } else
  55. {
  56. // Did not behave as documented or expected, the actual state of the
  57. // control is unknown by now.
  58. // Play safe and set and assume the traditional ungrouped mode again.
  59. ListView_EnableGroupView(m_List.m_hWnd, FALSE);
  60. m_listGrouped = false;
  61. }
  62. if(m_listGrouped)
  63. {
  64. static constexpr ListCtrl::Header headers[] =
  65. {
  66. { _T("Setting"), 150, LVCFMT_LEFT },
  67. { _T("Type"), 40, LVCFMT_LEFT },
  68. { _T("Value"), 140, LVCFMT_LEFT },
  69. { _T("Default"), 62, LVCFMT_LEFT },
  70. };
  71. m_List.SetHeaders(headers);
  72. } else
  73. {
  74. static constexpr ListCtrl::Header headers[] =
  75. {
  76. { _T("Setting"), 200, LVCFMT_LEFT },
  77. { _T("Type"), 40, LVCFMT_LEFT },
  78. { _T("Value"), 100, LVCFMT_LEFT },
  79. { _T("Default"), 52, LVCFMT_LEFT },
  80. };
  81. m_List.SetHeaders(headers);
  82. }
  83. ReInit();
  84. return TRUE;
  85. }
  86. void COptionsAdvanced::ReInit()
  87. {
  88. m_List.SetRedraw(FALSE);
  89. m_List.DeleteAllItems();
  90. if(m_listGrouped)
  91. {
  92. ListView_RemoveAllGroups(m_List.m_hWnd);
  93. }
  94. m_List.SetItemCount(static_cast<int>(theApp.GetSettings().size()));
  95. m_indexToPath.clear();
  96. m_indexToPath.reserve(theApp.GetSettings().size());
  97. m_groups.clear();
  98. int numGroups = 0;
  99. mpt::ustring findStr = mpt::ToLowerCase(GetWindowTextUnicode(*GetDlgItem(IDC_EDIT1)));
  100. LVITEMW lvi;
  101. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  102. lvi.mask |= (m_listGrouped ? LVIF_GROUPID : 0);
  103. lvi.iSubItem = 0;
  104. lvi.state = 0;
  105. lvi.stateMask = 0;
  106. lvi.cchTextMax = 0;
  107. lvi.iImage = 0;
  108. lvi.iIndent = 0;
  109. lvi.iGroupId = 0;
  110. int i = 0;
  111. for(const auto &[path, state] : theApp.GetSettings())
  112. {
  113. // In MPT_USTRING_MODE_WIDE mode,
  114. // this loop is heavily optimized to avoid as much string copies as possible
  115. // in order to perform ok-ish in debug builds.
  116. // MPT_USTRING_MODE_UTF8 is not optimized as we (currently) do not build in
  117. // this mode by default.
  118. const mpt::ustring &section = path.GetRefSection();
  119. const mpt::ustring &key = path.GetRefKey();
  120. const SettingValue &value = state.GetRefValue();
  121. const SettingValue &defaultValue = state.GetRefDefault();
  122. if(!findStr.empty())
  123. {
  124. mpt::ustring str = path.FormatAsString() + U_("=") + value.FormatValueAsString();
  125. str = mpt::ToLowerCase(str);
  126. if(str.find(findStr) == mpt::ustring::npos)
  127. {
  128. continue;
  129. }
  130. }
  131. int index;
  132. lvi.iItem = i++;
  133. lvi.lParam = m_indexToPath.size();
  134. if(m_listGrouped)
  135. {
  136. auto gi = m_groups.find(section);
  137. if(gi == m_groups.end())
  138. {
  139. LVGROUP group;
  140. #if _WIN32_WINNT >= 0x0600
  141. group.cbSize = LVGROUP_V5_SIZE;
  142. #else
  143. group.cbSize = sizeof(group);
  144. #endif
  145. group.mask = LVGF_HEADER | LVGF_GROUPID;
  146. #if MPT_USTRING_MODE_WIDE
  147. group.pszHeader = const_cast<wchar_t *>(section.c_str());
  148. #else
  149. const std::wstring wsection = mpt::ToWide(section);
  150. group.pszHeader = const_cast<wchar_t *>(wsection.c_str());
  151. #endif
  152. group.cchHeader = 0;
  153. group.pszFooter = nullptr;
  154. group.cchFooter = 0;
  155. group.iGroupId = lvi.iGroupId = numGroups++;
  156. group.stateMask = LVGS_COLLAPSIBLE;
  157. group.state = LVGS_COLLAPSIBLE;
  158. group.uAlign = LVGA_HEADER_LEFT;
  159. ListView_InsertGroup(m_List.m_hWnd, -1, &group);
  160. m_groups.insert(std::make_pair(section, lvi.iGroupId));
  161. } else
  162. {
  163. lvi.iGroupId = gi->second;
  164. }
  165. #if MPT_USTRING_MODE_WIDE
  166. lvi.pszText = const_cast<wchar_t *>(key.c_str());
  167. #else
  168. const std::wstring wkey = mpt::ToWide(key);
  169. lvi.pszText = const_cast<wchar_t *>(wkey.c_str());
  170. #endif
  171. index = static_cast<int>(m_List.SendMessage(LVM_INSERTITEMW, 0, (LPARAM)(&lvi)));
  172. } else
  173. {
  174. const mpt::ustring sectionAndKey = path.FormatAsString();
  175. #if MPT_USTRING_MODE_WIDE
  176. lvi.pszText = const_cast<wchar_t *>(sectionAndKey.c_str());
  177. #else
  178. const std::wstring wsectionAndKey = mpt::ToWide(sectionAndKey);
  179. lvi.pszText = const_cast<wchar_t *>(wsectionAndKey.c_str());
  180. #endif
  181. index = static_cast<int>(m_List.SendMessage(LVM_INSERTITEMW, 0, (LPARAM)(&lvi)));
  182. }
  183. #if MPT_USTRING_MODE_WIDE
  184. m_List.SetItemText(index, 1, value.FormatTypeAsString().c_str());
  185. m_List.SetItemText(index, 2, value.FormatValueAsString().c_str());
  186. m_List.SetItemText(index, 3, defaultValue.FormatValueAsString().c_str());
  187. #else
  188. m_List.SetItemText(index, 1, mpt::ToCString(value.FormatTypeAsString()));
  189. m_List.SetItemText(index, 2, mpt::ToCString(value.FormatValueAsString()));
  190. m_List.SetItemText(index, 3, mpt::ToCString(defaultValue.FormatValueAsString()));
  191. #endif
  192. m_indexToPath.push_back(path);
  193. }
  194. m_List.SetItemCount(i);
  195. m_List.SetRedraw(TRUE);
  196. m_List.Invalidate(FALSE);
  197. }
  198. void COptionsAdvanced::OnOK()
  199. {
  200. CSoundFile::SetDefaultNoteNames();
  201. CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
  202. if (pMainFrm) pMainFrm->PostMessage(WM_MOD_INVALIDATEPATTERNS, HINT_MPTOPTIONS);
  203. CPropertyPage::OnOK();
  204. }
  205. BOOL COptionsAdvanced::OnSetActive()
  206. {
  207. ReInit();
  208. CMainFrame::m_nLastOptionsPage = OPTIONS_PAGE_ADVANCED;
  209. return CPropertyPage::OnSetActive();
  210. }
  211. #ifdef MPT_MFC_FULL
  212. COLORREF CAdvancedSettingsList::OnGetCellBkColor(int nRow, int /* nColumn */ )
  213. {
  214. const bool isDefault = theApp.GetSettings().GetMap().find(m_indexToPath[GetItemData(nRow)])->second.IsDefault();
  215. COLORREF defColor = GetBkColor();
  216. COLORREF txtColor = GetTextColor();
  217. COLORREF modColor = RGB(GetRValue(defColor) * 0.9 + GetRValue(txtColor) * 0.1, GetGValue(defColor) * 0.9 + GetGValue(txtColor) * 0.1, GetBValue(defColor) * 0.9 + GetBValue(txtColor) * 0.1);
  218. return isDefault ? defColor : modColor;
  219. }
  220. COLORREF CAdvancedSettingsList::OnGetCellTextColor(int nRow, int nColumn)
  221. {
  222. return CMFCListCtrlEx::OnGetCellTextColor(nRow, nColumn);
  223. }
  224. #else // !MPT_MFC_FULL
  225. void COptionsAdvanced::OnCustomDrawList(NMHDR* pNMHDR, LRESULT* pResult)
  226. {
  227. NMLVCUSTOMDRAW *pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
  228. *pResult = CDRF_DODEFAULT;
  229. switch(pLVCD->nmcd.dwDrawStage)
  230. {
  231. case CDDS_PREPAINT:
  232. *pResult = CDRF_NOTIFYITEMDRAW;
  233. break;
  234. case CDDS_ITEMPREPAINT:
  235. {
  236. const bool isDefault = theApp.GetSettings().GetMap().find(m_indexToPath[pLVCD->nmcd.lItemlParam])->second.IsDefault();
  237. COLORREF defColor = m_List.GetBkColor();
  238. COLORREF txtColor = m_List.GetTextColor();
  239. COLORREF modColor = RGB(GetRValue(defColor) * 0.9 + GetRValue(txtColor) * 0.1, GetGValue(defColor) * 0.9 + GetGValue(txtColor) * 0.1, GetBValue(defColor) * 0.9 + GetBValue(txtColor) * 0.1);
  240. pLVCD->clrTextBk = isDefault ? defColor : modColor;
  241. }
  242. break;
  243. }
  244. }
  245. #endif // MPT_MFC_FULL
  246. void COptionsAdvanced::OnOptionDblClick(NMHDR *, LRESULT *)
  247. {
  248. const int index = m_List.GetSelectionMark();
  249. if(index < 0)
  250. return;
  251. const SettingPath path = m_indexToPath[m_List.GetItemData(index)];
  252. SettingValue val = theApp.GetSettings().GetMap().find(path)->second;
  253. if(val.GetType() == SettingTypeBool)
  254. {
  255. val = !val.as<bool>();
  256. } else
  257. {
  258. CInputDlg inputDlg(this, _T("Enter new value for ") + mpt::ToCString(path.FormatAsString()), mpt::ToCString(val.FormatValueAsString()));
  259. if(inputDlg.DoModal() != IDOK)
  260. {
  261. return;
  262. }
  263. val.SetFromString(inputDlg.resultAsString);
  264. }
  265. theApp.GetSettings().Write(path, val);
  266. #if MPT_USTRING_MODE_WIDE
  267. m_List.SetItemText(index, 2, val.FormatValueAsString().c_str());
  268. #else
  269. m_List.SetItemText(index, 2, mpt::ToCString(val.FormatValueAsString()));
  270. #endif
  271. m_List.SetSelectionMark(index);
  272. OnSettingsChanged();
  273. }
  274. void COptionsAdvanced::OnSaveNow()
  275. {
  276. TrackerSettings::Instance().SaveSettings();
  277. theApp.GetSettings().WriteSettings();
  278. }
  279. OPENMPT_NAMESPACE_END