/******************************************************************************** Copyright (C) 2013 Christophe Jeannin Eric Bataille 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; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ********************************************************************************/ #include "scenesw.h" SceneSwitcherSettings::SceneSwitcherSettings(SceneSwitcher *thePlugin, OBSHOTKEYPROC ToggleHotkeyProc): SettingsPane(), thePlugin(thePlugin), ToggleHotkeyProc(ToggleHotkeyProc) { pChange = false; } SceneSwitcherSettings::~SceneSwitcherSettings() { } CTSTR SceneSwitcherSettings::GetCategory() const { return PluginStr("Plugin.SettingsName"); } HWND SceneSwitcherSettings::CreatePane(HWND parentHwnd) { hwnd = CreateDialogParam(thePlugin->hinstDll, MAKEINTRESOURCE(IDD_SETTINGS_SCENESW), parentHwnd, (DLGPROC)DialogProc, (LPARAM)this); //EM_SETCUEBANNER HWND hwndAppList = GetDlgItem(hwnd, IDC_APPLIST); HWND hwndMainScn = GetDlgItem(hwnd, IDC_MAINSCN); ComboBox_SetCueBannerText(hwndMainScn, PluginStr("Settings.Scene")); ComboBox_SetCueBannerText(hwndAppList, PluginStr("Settings.WindowTitle")); return hwnd; } void SceneSwitcherSettings::DestroyPane() { DestroyWindow(hwnd); hwnd = NULL; } INT_PTR SceneSwitcherSettings::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: MsgInitDialog(); return TRUE; case WM_COMMAND: return MsgClicked(LOWORD(wParam), HIWORD(wParam), (HWND)lParam); case WM_CTLCOLORSTATIC: if(GetWindowLong((HWND)lParam, GWL_ID) == IDC_RUN) { HDC hdc = (HDC)wParam; SetTextColor(hdc, thePlugin->IsRunning() ? RGB(0,255,0) : RGB(255,0,0)); SetBkColor(hdc, GetSysColor(COLOR_3DFACE)); return (INT_PTR)GetSysColorBrush(COLOR_3DFACE); } break; case WM_NOTIFY: switch (LOWORD(wParam)) { case IDC_WSMAP: { const NMITEMACTIVATE* lpnmitem = (LPNMITEMACTIVATE)lParam; if(lpnmitem->hdr.idFrom == IDC_WSMAP && lpnmitem->hdr.code == NM_CLICK) { const int sel = lpnmitem->iItem; if(sel >= 0) { HWND wsMap = GetDlgItem(hwnd, IDC_WSMAP); HWND hwndAppList = GetDlgItem(hwnd, IDC_APPLIST); HWND hwndMainScn = GetDlgItem(hwnd, IDC_MAINSCN); // Get the text from the item String wnd; wnd.SetLength(256); ListView_GetItemText(wsMap, sel, 0, wnd, 256); String scn; scn.SetLength(256); ListView_GetItemText(wsMap, sel, 1, scn, 256); // Set the combos SetWindowText(hwndAppList, wnd); SendMessage(hwndMainScn, CB_SETCURSEL, SendMessage(hwndMainScn, CB_FINDSTRINGEXACT, -1, (LPARAM)scn.Array()), 0); } } return TRUE; } break; } } return FALSE; } void SceneSwitcherSettings::MsgInitDialog() { LocalizeWindow(hwnd, thePlugin->pluginLocale); HWND hwndAppList = GetDlgItem(hwnd, IDC_APPLIST); HWND hwndMainScn = GetDlgItem(hwnd, IDC_MAINSCN); HWND hwndAltScn = GetDlgItem(hwnd, IDC_ALTSCN); HWND hwndWSMap = GetDlgItem(hwnd, IDC_WSMAP); HWND hwndSwButton = GetDlgItem(hwnd, IDC_ALTSWITCH); HWND hwndNoswButton = GetDlgItem(hwnd, IDC_ALTNOSWITCH); HWND hwndCurrent = GetWindow(GetDesktopWindow(), GW_CHILD); // The top child of the desktop // let's fill the listcontrol SendMessage(hwndWSMap, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP, LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP); LVCOLUMN col1; col1.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; col1.fmt = LVCFMT_RIGHT | LVCFMT_FIXED_WIDTH; col1.cx = 204+205; col1.pszText = (LPWSTR)PluginStr("Settings.WindowTitle"); LVCOLUMN col2; col2.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; col2.fmt = LVCFMT_LEFT | LVCFMT_FIXED_WIDTH; col2.cx = 205; col2.pszText = (LPWSTR)PluginStr("Settings.Scene"); SendMessage(hwndWSMap, LVM_INSERTCOLUMN, 0, (LPARAM) (LPLVCOLUMN) &col1); SendMessage(hwndWSMap, LVM_INSERTCOLUMN, 1, (LPARAM) (LPLVCOLUMN) &col2); // Add the items for (int i = 0; i < thePlugin->GetnWindowsDefined(); i++) { String window = thePlugin->GetWindow(i); String scene = thePlugin->GetScene(i); LVITEM item; item.iItem = 0; item.iSubItem = 0; item.mask = LVIF_TEXT; item.pszText = window; LVITEM subItem; subItem.iItem = 0; subItem.iSubItem = 1; subItem.mask = LVIF_TEXT; subItem.pszText = scene; SendMessage(hwndWSMap, LVM_INSERTITEM, 0, (LPARAM) &item); SendMessage(hwndWSMap, LVM_SETITEM, 0, (LPARAM) &subItem); } // Set the radio buttons and alt scene combo state SendMessage(hwndSwButton, BM_SETCHECK, (thePlugin->IsAltDoSwitch() ? BST_CHECKED : BST_UNCHECKED), 0); SendMessage(hwndNoswButton, BM_SETCHECK, (thePlugin->IsAltDoSwitch() ? BST_UNCHECKED : BST_CHECKED), 0); EnableWindow(hwndAltScn, thePlugin->IsAltDoSwitch()); do { if(IsWindowVisible(hwndCurrent)) { // Get the styles for the window DWORD exStyles = (DWORD)GetWindowLongPtr(hwndCurrent, GWL_EXSTYLE); DWORD styles = (DWORD)GetWindowLongPtr(hwndCurrent, GWL_STYLE); if( (exStyles & WS_EX_TOOLWINDOW) == 0 && (styles & WS_CHILD) == 0) { // The window is not a toolwindow, and not a child window String strWindowName; // Get the name of the window strWindowName.SetLength(GetWindowTextLength(hwndCurrent)); GetWindowText(hwndCurrent, strWindowName, strWindowName.Length()+1); // Add the Name of the window to the appList const int id = (int)SendMessage(hwndAppList, CB_ADDSTRING, 0, (LPARAM)strWindowName.Array()); // Set the data for the added item to be the window handle SendMessage(hwndAppList, CB_SETITEMDATA, id, (LPARAM)hwndCurrent); } } } // Move down the windows in z-order while (hwndCurrent = GetNextWindow(hwndCurrent, GW_HWNDNEXT)); // Get the list of scenes from OBS XElement* scnList = OBSGetSceneListElement(); if(scnList) { const DWORD numScn = scnList->NumElements(); for(DWORD i=0; iGetElementByID(i))->GetName(); // Add the scene name to both scene lists SendMessage(hwndMainScn, CB_ADDSTRING, 0, (LPARAM)sceneName); SendMessage(hwndAltScn, CB_ADDSTRING, 0, (LPARAM)sceneName); } } // Set the selected list items to be the ones from settings SendMessage(hwndMainScn, CB_SETCURSEL, SendMessage(hwndMainScn, CB_FINDSTRINGEXACT, -1, (LPARAM)thePlugin->GetmainSceneName()), 0); SendMessage(hwndAltScn, CB_SETCURSEL, SendMessage(hwndAltScn, CB_FINDSTRINGEXACT, -1, (LPARAM)thePlugin->GetaltSceneName()), 0); SendMessage(hwndAppList, CB_SETCURSEL, SendMessage(hwndAppList, CB_FINDSTRINGEXACT, -1, (LPARAM)thePlugin->GetmainWndName()), 0); // Set the frequency from the settings SetDlgItemInt(hwnd, IDC_FREQ, thePlugin->GettimeToSleep(), FALSE); // Set the autostart checkbox value from the settings if(thePlugin->IsStartAuto()) CheckDlgButton(hwnd, IDC_STARTAUTO, BST_CHECKED); // Set the toggle hotkey control SendMessage(GetDlgItem(hwnd, IDC_TOGGLEHOTKEY), HKM_SETHOTKEY, thePlugin->GetToggleHotkey(), 0); // If the plugin is running, update the text values if(thePlugin->IsRunning()) { SetWindowText(GetDlgItem(hwnd, IDC_RUN), PluginStr("Settings.Running")); SetWindowText(GetDlgItem(hwnd, IDC_STOP), PluginStr("Settings.Stop")); } } INT_PTR SceneSwitcherSettings::MsgClicked(int controlId, int code, HWND controlHwnd) { switch(controlId) { case IDC_CLEAR_HOTKEY: if(code == BN_CLICKED) { SendMessage(GetDlgItem(hwnd, IDC_TOGGLEHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(pChange = true); return TRUE; } break; case IDC_STOP: if(code == BN_CLICKED) // Stop button clicked { if(thePlugin->IsRunning()) thePlugin->StopThread(hwnd); else { ApplyConfig(hwnd); pChange = false; thePlugin->StartThread(hwnd); } SetChangedSettings(pChange); return TRUE; } break; case IDUP: { HWND wsMap = GetDlgItem(hwnd, IDC_WSMAP); const int sel = SendMessage(wsMap, LVM_GETSELECTIONMARK, 0, 0); if (sel > 0) { // Get the text from the item String wnd; wnd.SetLength(256); ListView_GetItemText(wsMap, sel, 0, wnd, 256); String scn; scn.SetLength(256); ListView_GetItemText(wsMap, sel, 1, scn, 256); // Delete it SendMessage(wsMap, LVM_DELETEITEM, sel, 0); // Add it above LVITEM lv1; lv1.mask = LVIF_TEXT; lv1.iItem = sel - 1; lv1.iSubItem = 0; lv1.pszText = wnd; LVITEM lv2; lv2.mask = LVIF_TEXT; lv2.iItem = sel - 1; lv2.iSubItem = 1; lv2.pszText = scn; SendMessage(wsMap, LVM_INSERTITEM, sel - 1, (LPARAM) &lv1); SendMessage(wsMap, LVM_SETITEM, sel - 1, (LPARAM) &lv2); // Update the selection mark SendMessage(wsMap, LVM_SETSELECTIONMARK, 0, sel - 1); SetChangedSettings(pChange = true); return TRUE; } break; } case IDDOWN: { HWND wsMap = GetDlgItem(hwnd, IDC_WSMAP); const int sel = SendMessage(wsMap, LVM_GETSELECTIONMARK, 0, 0); const int max = SendMessage(wsMap, LVM_GETITEMCOUNT, 0, 0) - 1; if (sel > -1 && sel < max) { // Get the text from the item String wnd; wnd.SetLength(256); ListView_GetItemText(wsMap, sel, 0, wnd, 256); String scn; scn.SetLength(256); ListView_GetItemText(wsMap, sel, 1, scn, 256); // Delete it SendMessage(wsMap, LVM_DELETEITEM, sel, 0); // Add it below LVITEM lv1; lv1.mask = LVIF_TEXT; lv1.iItem = sel + 1; lv1.iSubItem = 0; lv1.pszText = wnd; LVITEM lv2; lv2.mask = LVIF_TEXT; lv2.iItem = sel + 1; lv2.iSubItem = 1; lv2.pszText = scn; SendMessage(wsMap, LVM_INSERTITEM, sel + 1, (LPARAM) &lv1); SendMessage(wsMap, LVM_SETITEM, sel + 1, (LPARAM) &lv2); // Update the selection mark SendMessage(wsMap, LVM_SETSELECTIONMARK, 0, sel + 1); SetChangedSettings(pChange = true); return TRUE; } break; } case IDADD: { HWND wsMap = GetDlgItem(hwnd, IDC_WSMAP); HWND appList = GetDlgItem(hwnd, IDC_APPLIST); HWND scnList = GetDlgItem(hwnd, IDC_MAINSCN); String wnd = GetEditText(appList); // First column LVITEM lv1; lv1.mask = LVIF_TEXT; lv1.iItem = 0; lv1.iSubItem = 0; lv1.pszText = wnd; // Second column String scn = GetCBText(scnList, CB_ERR); LVITEM lv2; lv2.mask = LVIF_TEXT; lv2.iItem = 0; lv2.iSubItem = 1; lv2.pszText = scn; // Add first column then set second SendMessage(wsMap, LVM_INSERTITEM, 0, (LPARAM)&lv1); SendMessage(wsMap, LVM_SETITEM, 0, (LPARAM)&lv2); SetChangedSettings(pChange = true); return TRUE; } break; case IDREM: { // Remove the item HWND wsMap = GetDlgItem(hwnd, IDC_WSMAP); const int sel = SendMessage(wsMap, LVM_GETSELECTIONMARK, 0, 0); if (sel > -1) SendMessage(wsMap, LVM_DELETEITEM, sel, 0); SetChangedSettings(pChange = true); return TRUE; } break; case IDC_ALTSWITCH: case IDC_ALTNOSWITCH: if (code == BN_CLICKED) { HWND swButton = GetDlgItem(hwnd, IDC_ALTSWITCH); HWND altCombo = GetDlgItem(hwnd, IDC_ALTSCN); const bool swChecked = (SendMessage(swButton, BM_GETSTATE, 0, 0) & BST_CHECKED) != 0; EnableWindow(altCombo, swChecked); pChange = pChange || (swChecked != thePlugin->IsAltDoSwitch()); SetChangedSettings(pChange); return TRUE; } break; case IDC_STARTAUTO: { HWND control = GetDlgItem(hwnd, IDC_STARTAUTO); bool newState = (SendMessage(control, BM_GETSTATE, 0, 0) & BST_CHECKED) != 0; pChange = pChange || (newState != thePlugin->IsStartAuto()); SetChangedSettings(pChange); return TRUE; } break; case IDC_TOGGLEHOTKEY: if (code == EN_CHANGE) { SetChangedSettings(pChange = true); return TRUE; } break; case IDC_FREQ: if(code == EN_CHANGE) { DWORD newFreq = GetDlgItemInt(hwnd, IDC_FREQ, NULL, FALSE); DWORD oldFreq = thePlugin->GettimeToSleep(); pChange = pChange || newFreq != oldFreq; SetChangedSettings(pChange); return TRUE; } break; case IDC_APPLIST: case IDC_MAINSCN: if (code == CBN_SELCHANGE || code == CBN_EDITCHANGE) { EditItem(code == CBN_SELCHANGE && controlId == IDC_APPLIST); return TRUE; } break; case IDC_ALTSCN: if (code == CBN_SELCHANGE) { SetChangedSettings(pChange = true); return TRUE; } break; } return FALSE; } void SceneSwitcherSettings::EditItem(bool selChange) { HWND wsMap = GetDlgItem(hwnd, IDC_WSMAP); HWND appList = GetDlgItem(hwnd, IDC_APPLIST); HWND scnList = GetDlgItem(hwnd, IDC_MAINSCN); const int sel = SendMessage(wsMap, LVM_GETSELECTIONMARK, 0, 0); if (sel < 0) return; String wnd = selChange ? GetCBText(appList, CB_ERR) : GetEditText(appList); // First column LVITEM lv1; lv1.mask = LVIF_TEXT; lv1.iItem = sel; lv1.iSubItem = 0; lv1.pszText = wnd; String scn = GetCBText(scnList, CB_ERR); // Second column LVITEM lv2; lv2.mask = LVIF_TEXT; lv2.iItem = sel; lv2.iSubItem = 1; lv2.pszText = scn; // Set the text SendMessage(wsMap, LVM_SETITEM, 0, (LPARAM)&lv1); SendMessage(wsMap, LVM_SETITEM, 0, (LPARAM)&lv2); SetChangedSettings(pChange = true); } void SceneSwitcherSettings::ApplyConfig(HWND hWnd) { thePlugin->ApplyConfig(hWnd); // Redefine the hotkey if (hotkeyID) OBSDeleteHotkey(hotkeyID); if (thePlugin->GetToggleHotkey() != 0) hotkeyID = OBSCreateHotkey((DWORD)thePlugin->GetToggleHotkey(), ToggleHotkeyProc, 0); } void SceneSwitcherSettings::ApplySettings() { pChange = false; ApplyConfig(hwnd); } void SceneSwitcherSettings::CancelSettings() { pChange = false; } bool SceneSwitcherSettings::HasDefaults() const { return false; }