/* Weather Protocol plugin for Miranda IM Copyright (c) 2012 Miranda NG team Copyright (c) 2005-2011 Boris Krasnovskiy All Rights Reserved Copyright (c) 2002-2005 Calvin Che This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* This file contain the source related to weather option pages. It also contain code for saving/loading options from the database. */ #include "stdafx.h" static BOOL opt_startup; int RedrawFrame(WPARAM wParam, LPARAM lParam); //============ LOADING AND SAVING OPTIONS =========== const wchar_t* GetDefaultText(int c) { switch (c) { case 'C': return L"%n [%t, %c]"; case 'b': return TranslateT("Weather Condition for %n as of %u"); case 'B': return TranslateT("Feel-Like: %f\\nPressure: %p\\nWind: %i %w\\nHumidity: %m\\nDew Point: %e\\nVisibility: %v\\n\\nSun Rise: %r\\nSun Set: %y\\n\\n5 Days Forecast:\\n%[Forecast Day 1]\\n%[Forecast Day 2]\\n%[Forecast Day 3]\\n%[Forecast Day 4]\\n%[Forecast Day 5]"); case 'X': case 'N': return TranslateT("%c\\nTemperature: %t\\nFeel-Like: %f\\nPressure: %p\\nWind: %i %w\\nHumidity: %m\\nDew Point: %e\\nVisibility: %v\\n\\nSun Rise: %r\\nSun Set: %y\\n\\n5 Days Forecast:\\n%[Forecast Day 1]\\n%[Forecast Day 2]\\n%[Forecast Day 3]\\n%[Forecast Day 4]\\n%[Forecast Day 5]"); case 'E': return TranslateT("%n at %u: %c, %t (feel-like %f) Wind: %i %w Humidity: %m"); case 'H': return TranslateT("%c, %t (feel-like %f) Wind: %i %w Humidity: %m"); case 'S': return TranslateT("Temperature: %[Temperature]"); case 'P': return TranslateT("%n (%u)"); case 'p': return TranslateT("%c, %t\\nToday: High %h, Low %l"); } return L""; } CMStringW GetTextValue(int c) { CMStringW ret; switch (c) { case 'C': ret = g_plugin.getMStringW("DisplayText"); break; case 'b': ret = g_plugin.getMStringW("BriefTextTitle"); break; case 'B': ret = g_plugin.getMStringW("BriefText"); break; case 'N': ret = g_plugin.getMStringW("NoteText"); break; case 'E': ret = g_plugin.getMStringW("ExtText"); break; case 'H': ret = g_plugin.getMStringW("HistoryText"); break; case 'X': ret = g_plugin.getMStringW("ExtraText"); break; case 'S': ret = g_plugin.getMStringW("StatusText"); break; case 'P': ret = g_plugin.getMStringW("PopupTitle"); break; case 'p': ret = g_plugin.getMStringW("PopupText"); break; } return (ret.IsEmpty()) ? GetDefaultText(c) : ret; } // load options from database + set default if the setting does not exist void LoadOptions(void) { memset(&opt, 0, sizeof(opt)); // main options opt.StartupUpdate = g_plugin.getByte("StartupUpdate", true); opt.AutoUpdate = g_plugin.getByte("AutoUpdate", true); opt.UpdateTime = g_plugin.getWord("UpdateTime", 30); opt.NoProtoCondition = g_plugin.getByte("NoStatus", true); opt.UpdateOnlyConditionChanged = g_plugin.getByte("CondChangeAsUpdate", true); opt.RemoveOldData = g_plugin.getByte("RemoveOld", false); opt.MakeItalic = g_plugin.getByte("MakeItalic", true); opt.AvatarSize = g_plugin.getByte("AvatarSize", 128); // units opt.tUnit = g_plugin.getWord("tUnit", 1); opt.wUnit = g_plugin.getWord("wUnit", 2); opt.vUnit = g_plugin.getWord("vUnit", 1); opt.pUnit = g_plugin.getWord("pUnit", 4); opt.dUnit = g_plugin.getWord("dUnit", 1); opt.eUnit = g_plugin.getWord("eUnit", 2); ptrW szValue(g_plugin.getWStringA("DegreeSign")); wcsncpy_s(opt.DegreeSign, (szValue == NULL) ? L"" : szValue, _TRUNCATE); opt.DoNotAppendUnit = g_plugin.getByte("DoNotAppendUnit", 0); opt.NoFrac = g_plugin.getByte("NoFractions", 0); // advanced opt.DisCondIcon = g_plugin.getByte("DisableConditionIcon", false); // popup options opt.UpdatePopup = g_plugin.getByte("UpdatePopup", true); opt.AlertPopup = g_plugin.getByte("AlertPopup", true); opt.PopupOnChange = g_plugin.getByte("PopUpOnChange", true); opt.ShowWarnings = g_plugin.getByte("ShowWarnings", true); // popup colors opt.BGColour = g_plugin.getDword("BackgroundColour", GetSysColor(COLOR_BTNFACE)); opt.TextColour = g_plugin.getDword("TextColour", GetSysColor(COLOR_WINDOWTEXT)); opt.UseWinColors = g_plugin.getByte("UseWinColors", false); // popup actions opt.LeftClickAction = g_plugin.getDword("LeftClickAction", IDM_M2); opt.RightClickAction = g_plugin.getDword("RightClickAction", IDM_M1); // popup delay opt.pDelay = g_plugin.getDword("PopupDelay", 0); // misc if (szValue = g_plugin.getWStringA("Default")) wcsncpy_s(opt.Default, szValue, _TRUNCATE); else opt.Default[0] = 0; } // save the options to database void SaveOptions(void) { // main options g_plugin.setByte("StartupUpdate", (uint8_t)opt.StartupUpdate); g_plugin.setByte("AutoUpdate", (uint8_t)opt.AutoUpdate); g_plugin.setWord("UpdateTime", opt.UpdateTime); g_plugin.setByte("NoStatus", (uint8_t)opt.NoProtoCondition); g_plugin.setByte("CondChangeAsUpdate", (uint8_t)opt.UpdateOnlyConditionChanged); g_plugin.setByte("RemoveOld", (uint8_t)opt.RemoveOldData); g_plugin.setByte("MakeItalic", (uint8_t)opt.MakeItalic); g_plugin.setByte("AvatarSize", (uint8_t)opt.AvatarSize); // units g_plugin.setWord("tUnit", opt.tUnit); g_plugin.setWord("wUnit", opt.wUnit); g_plugin.setWord("vUnit", opt.vUnit); g_plugin.setWord("pUnit", opt.pUnit); g_plugin.setWord("dUnit", opt.dUnit); g_plugin.setWord("eUnit", opt.eUnit); g_plugin.setWString("DegreeSign", opt.DegreeSign); g_plugin.setByte("DoNotAppendUnit", (uint8_t)opt.DoNotAppendUnit); g_plugin.setByte("NoFractions", (uint8_t)opt.NoFrac); // advanced g_plugin.setByte("DisableConditionIcon", (uint8_t)opt.DisCondIcon); // popup options g_plugin.setByte("UpdatePopup", (uint8_t)opt.UpdatePopup); g_plugin.setByte("AlertPopup", (uint8_t)opt.AlertPopup); g_plugin.setByte("PopUpOnChange", (uint8_t)opt.PopupOnChange); g_plugin.setByte("ShowWarnings", (uint8_t)opt.ShowWarnings); // popup colors g_plugin.setDword("BackgroundColour", opt.BGColour); g_plugin.setDword("TextColour", opt.TextColour); g_plugin.setByte("UseWinColors", (uint8_t)opt.UseWinColors); // popup actions g_plugin.setDword("LeftClickAction", opt.LeftClickAction); g_plugin.setDword("RightClickAction", opt.RightClickAction); // popup delay g_plugin.setDword("PopupDelay", opt.pDelay); // misc stuff g_plugin.setWString("Default", opt.Default); } //============ MAIN OPTIONS ============ // weather options static INT_PTR CALLBACK OptionsProc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) { wchar_t str[512]; switch (msg) { case WM_INITDIALOG: opt_startup = TRUE; TranslateDialogDefault(hdlg); // load settings _ltow(opt.UpdateTime, str, 10); SetDlgItemText(hdlg, IDC_UPDATETIME, str); SetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign); SendDlgItemMessage(hdlg, IDC_AVATARSPIN, UDM_SETRANGE32, 0, 999); SendDlgItemMessage(hdlg, IDC_AVATARSPIN, UDM_SETPOS, 0, opt.AvatarSize); SendDlgItemMessage(hdlg, IDC_AVATARSIZE, EM_LIMITTEXT, 3, 0); CheckDlgButton(hdlg, IDC_STARTUPUPD, opt.StartupUpdate ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_UPDATE, opt.AutoUpdate ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_PROTOCOND, !opt.NoProtoCondition ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_UPDCONDCHG, opt.UpdateOnlyConditionChanged ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_REMOVEOLD, opt.RemoveOldData ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_MAKEI, opt.MakeItalic ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_DISCONDICON, opt.DisCondIcon ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_DONOTAPPUNITS, opt.DoNotAppendUnit ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_NOFRAC, opt.NoFrac ? BST_CHECKED : BST_UNCHECKED); // load units switch (opt.tUnit) { // temperature case 1: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T1); break; case 2: CheckRadioButton(hdlg, IDC_T1, IDC_T2, IDC_T2); break; } switch (opt.wUnit) { // wind case 1: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W1); break; case 2: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W2); break; case 3: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W3); break; case 4: CheckRadioButton(hdlg, IDC_W1, IDC_W4, IDC_W4); break; } switch (opt.vUnit) { // visibility case 1: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V1); break; case 2: CheckRadioButton(hdlg, IDC_V1, IDC_V2, IDC_V2); break; } switch (opt.pUnit) { // pressure case 1: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P1); break; case 2: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P2); break; case 3: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P3); break; case 4: CheckRadioButton(hdlg, IDC_P1, IDC_P4, IDC_P4); break; } switch (opt.dUnit) { // pressure case 1: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D1); break; case 2: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D2); break; case 3: CheckRadioButton(hdlg, IDC_D1, IDC_D3, IDC_D3); break; } switch (opt.eUnit) { // elev case 1: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E1); break; case 2: CheckRadioButton(hdlg, IDC_E1, IDC_E2, IDC_E2); break; } opt_startup = FALSE; return 0; case WM_COMMAND: if (HIWORD(wparam) == BN_CLICKED && GetFocus() == (HWND)lparam) if (!opt_startup) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); if (!((LOWORD(wparam) == IDC_UPDATE || LOWORD(wparam) == IDC_DEGREE) && (HIWORD(wparam) != EN_CHANGE || (HWND)lparam != GetFocus()))) if (!opt_startup) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); return 0; case WM_NOTIFY: switch (((LPNMHDR)lparam)->code) { case PSN_APPLY: // change the status for weather protocol if (IsDlgButtonChecked(hdlg, IDC_PROTOCOND) && opt.DefStn != NULL) { old_status = status; status = MapCondToStatus(opt.DefStn); ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, status); } // get update time and remove the old timer GetDlgItemText(hdlg, IDC_UPDATETIME, str, _countof(str)); opt.UpdateTime = (uint16_t)_wtoi(str); if (opt.UpdateTime < 1) opt.UpdateTime = 1; KillTimer(nullptr, timerId); timerId = SetTimer(nullptr, 0, opt.UpdateTime * 60000, timerProc); // other general options GetDlgItemText(hdlg, IDC_DEGREE, opt.DegreeSign, _countof(opt.DegreeSign)); opt.StartupUpdate = IsDlgButtonChecked(hdlg, IDC_STARTUPUPD); opt.AutoUpdate = IsDlgButtonChecked(hdlg, IDC_UPDATE); opt.NoProtoCondition = BST_UNCHECKED == IsDlgButtonChecked(hdlg, IDC_PROTOCOND); opt.DisCondIcon = IsDlgButtonChecked(hdlg, IDC_DISCONDICON); opt.UpdateOnlyConditionChanged = (uint8_t)IsDlgButtonChecked(hdlg, IDC_UPDCONDCHG); opt.RemoveOldData = IsDlgButtonChecked(hdlg, IDC_REMOVEOLD); opt.MakeItalic = IsDlgButtonChecked(hdlg, IDC_MAKEI); opt.AvatarSize = GetDlgItemInt(hdlg, IDC_AVATARSIZE, nullptr, FALSE); opt.DoNotAppendUnit = IsDlgButtonChecked(hdlg, IDC_DONOTAPPUNITS); opt.NoFrac = IsDlgButtonChecked(hdlg, IDC_NOFRAC); UpdateMenu(opt.AutoUpdate); // save the units if (IsDlgButtonChecked(hdlg, IDC_T1)) opt.tUnit = 1; if (IsDlgButtonChecked(hdlg, IDC_T2)) opt.tUnit = 2; if (IsDlgButtonChecked(hdlg, IDC_W1)) opt.wUnit = 1; if (IsDlgButtonChecked(hdlg, IDC_W2)) opt.wUnit = 2; if (IsDlgButtonChecked(hdlg, IDC_W3)) opt.wUnit = 3; if (IsDlgButtonChecked(hdlg, IDC_W4)) opt.wUnit = 4; if (IsDlgButtonChecked(hdlg, IDC_V1)) opt.vUnit = 1; if (IsDlgButtonChecked(hdlg, IDC_V2)) opt.vUnit = 2; if (IsDlgButtonChecked(hdlg, IDC_P1)) opt.pUnit = 1; if (IsDlgButtonChecked(hdlg, IDC_P2)) opt.pUnit = 2; if (IsDlgButtonChecked(hdlg, IDC_P3)) opt.pUnit = 3; if (IsDlgButtonChecked(hdlg, IDC_P4)) opt.pUnit = 4; if (IsDlgButtonChecked(hdlg, IDC_D1)) opt.dUnit = 1; if (IsDlgButtonChecked(hdlg, IDC_D2)) opt.dUnit = 2; if (IsDlgButtonChecked(hdlg, IDC_D3)) opt.dUnit = 3; if (IsDlgButtonChecked(hdlg, IDC_E1)) opt.eUnit = 1; if (IsDlgButtonChecked(hdlg, IDC_E2)) opt.eUnit = 2; // save the new weather options SaveOptions(); RedrawFrame(0, 0); return 1; } break; } return 0; } //============ TEXT OPTION DIALOG ============ // text option dialog struct { wchar_t c; int id; char *setting; } static controls[] = { { 'C', IDC_CTEXT, "DisplayText" }, { 'b', IDC_BTITLE, "BriefTextTitle" }, { 'B', IDC_BTEXT, "BriefText" }, { 'N', IDC_NTEXT, "NoteText" }, { 'X', IDC_XTEXT, "ExtText" }, { 'E', IDC_ETEXT, "HistoryText" }, { 'H', IDC_HTEXT, "ExtraText" }, { 'S', IDC_BTITLE2, "StatusText" }, }; static INT_PTR CALLBACK DlgProcText(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) { RECT rc, pos; HWND button; HMENU hMenu, hMenu1; switch (msg) { case WM_INITDIALOG: opt_startup = TRUE; // set windows position, make it top-most GetWindowRect(hdlg, &rc); SetWindowPos(hdlg, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE); TranslateDialogDefault(hdlg); // generate the display text for variable list SetDlgItemText(hdlg, IDC_VARLIST, VAR_LIST_OPT); for (auto &it : controls) SetDlgItemText(hdlg, it.id, GetTextValue(it.c)); // make the more variable and other buttons flat SendDlgItemMessage(hdlg, IDC_MORE, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM1, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM2, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM3, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM4, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM5, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM6, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM7, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_TM8, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hdlg, IDC_RESET, BUTTONSETASFLATBTN, TRUE, 0); // load the settings opt_startup = FALSE; return TRUE; case WM_COMMAND: if (opt_startup) return TRUE; switch (LOWORD(wParam)) { case IDC_CTEXT: case IDC_BTITLE: case IDC_BTEXT: case IDC_NTEXT: case IDC_XTEXT: case IDC_ETEXT: case IDC_HTEXT: case IDC_BTITLE2: if (HIWORD(wParam) == EN_CHANGE) SendMessage(GetParent(hdlg), PSM_CHANGED, 0, 0); break; case IDC_MORE: // display custom variables list MoreVarList(); break; case IDC_TM1: case IDC_TM2: case IDC_TM3: case IDC_TM4: case IDC_TM5: case IDC_TM6: case IDC_TM7: case IDC_TM8: // display the menu button = GetDlgItem(hdlg, LOWORD(wParam)); GetWindowRect(button, &pos); hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMMENU)); hMenu1 = GetSubMenu(hMenu, 0); TranslateMenu(hMenu1); { auto &var = controls[int(LOWORD(wParam)) - IDC_TM1]; switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr)) { case ID_MPREVIEW: { // show the preview in a message box, using the weather data from the default station WEATHERINFO winfo = LoadWeatherInfo(opt.DefStn); wchar_t buf[2] = { var.c, 0 }, str[4096]; GetDisplay(&winfo, buf, str); MessageBox(nullptr, str, TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST); } break; case ID_MRESET: SetDlgItemText(hdlg, var.id, GetDefaultText(var.c)); break; } DestroyMenu(hMenu); } break; case IDC_RESET: // left click action selection menu button = GetDlgItem(hdlg, IDC_RESET); GetWindowRect(button, &pos); hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMENU)); hMenu1 = GetSubMenu(hMenu, 0); TranslateMenu(hMenu1); switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, hdlg, nullptr)) { case ID_T1: // reset to the strings in memory, discard all changes for (auto &it : controls) SetDlgItemText(hdlg, it.id, GetTextValue(it.c)); break; case ID_T2: // reset to the default setting for (auto &it : controls) SetDlgItemText(hdlg, it.id, GetDefaultText(it.c)); break; } DestroyMenu(hMenu); break; } return TRUE; case WM_NOTIFY: switch (((LPNMHDR)lParam)->code) { case PSN_APPLY: // save the option wchar_t textstr[MAX_TEXT_SIZE]; for (auto &it : controls) { GetDlgItemText(hdlg, it.id, textstr, _countof(textstr)); if (!mir_wstrcmpi(textstr, GetDefaultText(it.c))) g_plugin.delSetting(it.setting); else g_plugin.setWString(it.setting, textstr); } SaveOptions(); UpdateAllInfo(0, 0); break; } break; } return FALSE; } //============ OPTION INITIALIZATION ============ // register the weather option pages int OptInit(WPARAM wParam, LPARAM) { // plugin options OPTIONSDIALOGPAGE odp = {}; odp.position = 95600; odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); odp.pfnDlgProc = OptionsProc; odp.szGroup.a = LPGEN("Network"); odp.szTitle.a = WEATHERPROTOTEXT; odp.szTab.a = LPGEN("General"); odp.flags = ODPF_BOLDGROUPS; g_plugin.addOptions(wParam, &odp); // text options odp.pszTemplate = MAKEINTRESOURCEA(IDD_TEXTOPT); odp.pfnDlgProc = DlgProcText; odp.szTab.a = LPGEN("Display"); g_plugin.addOptions(wParam, &odp); // if popup service exists, load the weather popup options odp.position = 100000000; odp.pszTemplate = MAKEINTRESOURCEA(IDD_POPUP); odp.szGroup.a = LPGEN("Popups"); odp.szTab.a = nullptr; odp.pfnDlgProc = DlgPopupOpts; g_plugin.addOptions(wParam, &odp); return 0; }