| 1 | /* | 
|---|
| 2 | * synergy -- mouse and keyboard sharing utility | 
|---|
| 3 | * Copyright (C) 2002 Chris Schoeneman | 
|---|
| 4 | * | 
|---|
| 5 | * This package is free software; you can redistribute it and/or | 
|---|
| 6 | * modify it under the terms of the GNU General Public License | 
|---|
| 7 | * found in the file COPYING that should have accompanied this file. | 
|---|
| 8 | * | 
|---|
| 9 | * This package is distributed in the hope that it will be useful, | 
|---|
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 12 | * GNU General Public License for more details. | 
|---|
| 13 | */ | 
|---|
| 14 |  | 
|---|
| 15 | #include "CConfig.h" | 
|---|
| 16 | #include "ProtocolTypes.h" | 
|---|
| 17 | #include "CStringUtil.h" | 
|---|
| 18 | #include "CArch.h" | 
|---|
| 19 | #include "CScreensLinks.h" | 
|---|
| 20 | #include "CAddScreen.h" | 
|---|
| 21 | #include "LaunchUtil.h" | 
|---|
| 22 | #include "resource.h" | 
|---|
| 23 |  | 
|---|
| 24 | // | 
|---|
| 25 | // CScreensLinks | 
|---|
| 26 | // | 
|---|
| 27 |  | 
|---|
| 28 | CScreensLinks*          CScreensLinks::s_singleton = NULL; | 
|---|
| 29 |  | 
|---|
| 30 | CScreensLinks::CScreensLinks(HWND parent, CConfig* config) : | 
|---|
| 31 | m_parent(parent), | 
|---|
| 32 | m_mainConfig(config), | 
|---|
| 33 | m_config(&m_scratchConfig) | 
|---|
| 34 | { | 
|---|
| 35 | assert(s_singleton == NULL); | 
|---|
| 36 | s_singleton = this; | 
|---|
| 37 |  | 
|---|
| 38 | // get formatting strings | 
|---|
| 39 | m_linkFormat     = getString(IDS_LINK_FORMAT); | 
|---|
| 40 | m_intervalFormat = getString(IDS_LINK_INTERVAL_FORMAT); | 
|---|
| 41 | m_newLinkLabel   = getString(IDS_NEW_LINK); | 
|---|
| 42 | m_sideLabel[kLeft   - kFirstDirection] = getString(IDS_SIDE_LEFT); | 
|---|
| 43 | m_sideLabel[kRight  - kFirstDirection] = getString(IDS_SIDE_RIGHT); | 
|---|
| 44 | m_sideLabel[kTop    - kFirstDirection] = getString(IDS_SIDE_TOP); | 
|---|
| 45 | m_sideLabel[kBottom - kFirstDirection] = getString(IDS_SIDE_BOTTOM); | 
|---|
| 46 |  | 
|---|
| 47 | // GDI objects | 
|---|
| 48 | m_redPen = CreatePen(PS_INSIDEFRAME, 1, RGB(255, 0, 0)); | 
|---|
| 49 | } | 
|---|
| 50 |  | 
|---|
| 51 | CScreensLinks::~CScreensLinks() | 
|---|
| 52 | { | 
|---|
| 53 | DeleteObject(m_redPen); | 
|---|
| 54 | s_singleton = NULL; | 
|---|
| 55 | } | 
|---|
| 56 |  | 
|---|
| 57 | void | 
|---|
| 58 | CScreensLinks::doModal() | 
|---|
| 59 | { | 
|---|
| 60 | // do dialog | 
|---|
| 61 | DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_SCREENS_LINKS), | 
|---|
| 62 | m_parent, dlgProc, (LPARAM)this); | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | void | 
|---|
| 66 | CScreensLinks::init(HWND hwnd) | 
|---|
| 67 | { | 
|---|
| 68 | // get initial config | 
|---|
| 69 | m_scratchConfig = *m_mainConfig; | 
|---|
| 70 |  | 
|---|
| 71 | // fill side list box (in EDirection order) | 
|---|
| 72 | HWND child = getItem(hwnd, IDC_SCREENS_SRC_SIDE); | 
|---|
| 73 | SendMessage(child, CB_ADDSTRING, 0, (LPARAM)TEXT("---")); | 
|---|
| 74 | SendMessage(child, CB_ADDSTRING, 0, | 
|---|
| 75 | (LPARAM)getString(IDS_EDGE_LEFT).c_str()); | 
|---|
| 76 | SendMessage(child, CB_ADDSTRING, 0, | 
|---|
| 77 | (LPARAM)getString(IDS_EDGE_RIGHT).c_str()); | 
|---|
| 78 | SendMessage(child, CB_ADDSTRING, 0, | 
|---|
| 79 | (LPARAM)getString(IDS_EDGE_TOP).c_str()); | 
|---|
| 80 | SendMessage(child, CB_ADDSTRING, 0, | 
|---|
| 81 | (LPARAM)getString(IDS_EDGE_BOTTOM).c_str()); | 
|---|
| 82 |  | 
|---|
| 83 | // create error boxes | 
|---|
| 84 | m_srcSideError   = createErrorBox(hwnd); | 
|---|
| 85 | m_srcScreenError = createErrorBox(hwnd); | 
|---|
| 86 | m_dstScreenError = createErrorBox(hwnd); | 
|---|
| 87 | resizeErrorBoxes(); | 
|---|
| 88 |  | 
|---|
| 89 | m_selectedLink = -1; | 
|---|
| 90 | m_editedLink   = CEdgeLink(); | 
|---|
| 91 | m_edgeLinks.clear(); | 
|---|
| 92 | updateScreens(hwnd, ""); | 
|---|
| 93 | updateScreensControls(hwnd); | 
|---|
| 94 | updateLinks(hwnd); | 
|---|
| 95 | updateLinksControls(hwnd); | 
|---|
| 96 | } | 
|---|
| 97 |  | 
|---|
| 98 | bool | 
|---|
| 99 | CScreensLinks::save(HWND /*hwnd*/) | 
|---|
| 100 | { | 
|---|
| 101 | *m_mainConfig = m_scratchConfig; | 
|---|
| 102 | return true; | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | BOOL | 
|---|
| 106 | CScreensLinks::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | 
|---|
| 107 | { | 
|---|
| 108 | switch (message) { | 
|---|
| 109 | case WM_INITDIALOG: | 
|---|
| 110 | init(hwnd); | 
|---|
| 111 | return TRUE; | 
|---|
| 112 |  | 
|---|
| 113 | case WM_SIZE: | 
|---|
| 114 | resizeErrorBoxes(); | 
|---|
| 115 | break; | 
|---|
| 116 |  | 
|---|
| 117 | case WM_COMMAND: | 
|---|
| 118 | switch (LOWORD(wParam)) { | 
|---|
| 119 | case IDOK: | 
|---|
| 120 | SetFocus(getItem(hwnd, IDOK)); | 
|---|
| 121 | if (save(hwnd)) { | 
|---|
| 122 | EndDialog(hwnd, 0); | 
|---|
| 123 | } | 
|---|
| 124 | return TRUE; | 
|---|
| 125 |  | 
|---|
| 126 | case IDCANCEL: | 
|---|
| 127 | EndDialog(hwnd, 0); | 
|---|
| 128 | return TRUE; | 
|---|
| 129 |  | 
|---|
| 130 | case IDC_SCREENS_SCREENS: | 
|---|
| 131 | switch (HIWORD(wParam)) { | 
|---|
| 132 | case LBN_DBLCLK: | 
|---|
| 133 | editScreen(hwnd); | 
|---|
| 134 | return TRUE; | 
|---|
| 135 |  | 
|---|
| 136 | case LBN_SELCHANGE: | 
|---|
| 137 | updateScreensControls(hwnd); | 
|---|
| 138 | updateLinkView(hwnd); | 
|---|
| 139 | return TRUE; | 
|---|
| 140 |  | 
|---|
| 141 | case LBN_SELCANCEL: | 
|---|
| 142 | updateScreensControls(hwnd); | 
|---|
| 143 | updateLinkView(hwnd); | 
|---|
| 144 | return TRUE; | 
|---|
| 145 | } | 
|---|
| 146 | break; | 
|---|
| 147 |  | 
|---|
| 148 | case IDC_SCREENS_ADD_SCREEN: | 
|---|
| 149 | addScreen(hwnd); | 
|---|
| 150 | return TRUE; | 
|---|
| 151 |  | 
|---|
| 152 | case IDC_SCREENS_REMOVE_SCREEN: | 
|---|
| 153 | removeScreen(hwnd); | 
|---|
| 154 | return TRUE; | 
|---|
| 155 |  | 
|---|
| 156 | case IDC_SCREENS_EDIT_SCREEN: | 
|---|
| 157 | editScreen(hwnd); | 
|---|
| 158 | return TRUE; | 
|---|
| 159 |  | 
|---|
| 160 | case IDC_SCREENS_LINKS: | 
|---|
| 161 | switch (HIWORD(wParam)) { | 
|---|
| 162 | case LBN_SELCHANGE: | 
|---|
| 163 | editLink(hwnd); | 
|---|
| 164 | return TRUE; | 
|---|
| 165 |  | 
|---|
| 166 | case LBN_SELCANCEL: | 
|---|
| 167 | editLink(hwnd); | 
|---|
| 168 | return TRUE; | 
|---|
| 169 | } | 
|---|
| 170 | break; | 
|---|
| 171 |  | 
|---|
| 172 | case IDC_SCREENS_ADD_LINK: | 
|---|
| 173 | addLink(hwnd); | 
|---|
| 174 | return TRUE; | 
|---|
| 175 |  | 
|---|
| 176 | case IDC_SCREENS_REMOVE_LINK: | 
|---|
| 177 | removeLink(hwnd); | 
|---|
| 178 | return TRUE; | 
|---|
| 179 |  | 
|---|
| 180 | case IDC_SCREENS_SRC_SIDE: | 
|---|
| 181 | switch (HIWORD(wParam)) { | 
|---|
| 182 | case CBN_SELCHANGE: | 
|---|
| 183 | changeSrcSide(hwnd); | 
|---|
| 184 | break; | 
|---|
| 185 | } | 
|---|
| 186 | break; | 
|---|
| 187 |  | 
|---|
| 188 | case IDC_SCREENS_SRC_SCREEN: | 
|---|
| 189 | switch (HIWORD(wParam)) { | 
|---|
| 190 | case CBN_SELCHANGE: | 
|---|
| 191 | changeSrcScreen(hwnd); | 
|---|
| 192 | break; | 
|---|
| 193 | } | 
|---|
| 194 | break; | 
|---|
| 195 |  | 
|---|
| 196 | case IDC_SCREENS_DST_SCREEN: | 
|---|
| 197 | switch (HIWORD(wParam)) { | 
|---|
| 198 | case CBN_SELCHANGE: | 
|---|
| 199 | changeDstScreen(hwnd); | 
|---|
| 200 | break; | 
|---|
| 201 | } | 
|---|
| 202 | break; | 
|---|
| 203 |  | 
|---|
| 204 | case IDC_SCREENS_SRC_START: | 
|---|
| 205 | switch (HIWORD(wParam)) { | 
|---|
| 206 | case EN_KILLFOCUS: | 
|---|
| 207 | changeIntervalStart(hwnd, LOWORD(wParam), | 
|---|
| 208 | m_editedLink.m_srcInterval); | 
|---|
| 209 | break; | 
|---|
| 210 | } | 
|---|
| 211 | break; | 
|---|
| 212 |  | 
|---|
| 213 | case IDC_SCREENS_SRC_END: | 
|---|
| 214 | switch (HIWORD(wParam)) { | 
|---|
| 215 | case EN_KILLFOCUS: | 
|---|
| 216 | changeIntervalEnd(hwnd, LOWORD(wParam), | 
|---|
| 217 | m_editedLink.m_srcInterval); | 
|---|
| 218 | break; | 
|---|
| 219 | } | 
|---|
| 220 | break; | 
|---|
| 221 |  | 
|---|
| 222 | case IDC_SCREENS_DST_START: | 
|---|
| 223 | switch (HIWORD(wParam)) { | 
|---|
| 224 | case EN_KILLFOCUS: | 
|---|
| 225 | changeIntervalStart(hwnd, LOWORD(wParam), | 
|---|
| 226 | m_editedLink.m_dstInterval); | 
|---|
| 227 | break; | 
|---|
| 228 | } | 
|---|
| 229 | break; | 
|---|
| 230 |  | 
|---|
| 231 | case IDC_SCREENS_DST_END: | 
|---|
| 232 | switch (HIWORD(wParam)) { | 
|---|
| 233 | case EN_KILLFOCUS: | 
|---|
| 234 | changeIntervalEnd(hwnd, LOWORD(wParam), | 
|---|
| 235 | m_editedLink.m_dstInterval); | 
|---|
| 236 | break; | 
|---|
| 237 | } | 
|---|
| 238 | break; | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | break; | 
|---|
| 242 |  | 
|---|
| 243 | case WM_CTLCOLORSTATIC: | 
|---|
| 244 | switch (GetDlgCtrlID((HWND)lParam)) { | 
|---|
| 245 | case IDC_SCREENS_OVERLAP_ERROR: | 
|---|
| 246 | SetBkColor((HDC)wParam, GetSysColor(COLOR_3DFACE)); | 
|---|
| 247 | SetTextColor((HDC)wParam, RGB(255, 0, 0)); | 
|---|
| 248 | return (BOOL)GetSysColorBrush(COLOR_3DFACE); | 
|---|
| 249 | } | 
|---|
| 250 | break; | 
|---|
| 251 |  | 
|---|
| 252 | // error outlines | 
|---|
| 253 | case WM_DRAWITEM: { | 
|---|
| 254 | DRAWITEMSTRUCT* di = (DRAWITEMSTRUCT*)lParam; | 
|---|
| 255 | if (di->CtlType == ODT_STATIC) { | 
|---|
| 256 | HGDIOBJ oldPen   = SelectObject(di->hDC, m_redPen); | 
|---|
| 257 | HGDIOBJ oldBrush = SelectObject(di->hDC, | 
|---|
| 258 | GetStockObject(NULL_BRUSH)); | 
|---|
| 259 | Rectangle(di->hDC, di->rcItem.left, di->rcItem.top, | 
|---|
| 260 | di->rcItem.right, di->rcItem.bottom); | 
|---|
| 261 | SelectObject(di->hDC, oldPen); | 
|---|
| 262 | SelectObject(di->hDC, oldBrush); | 
|---|
| 263 | return TRUE; | 
|---|
| 264 | } | 
|---|
| 265 | break; | 
|---|
| 266 | } | 
|---|
| 267 |  | 
|---|
| 268 | default: | 
|---|
| 269 | break; | 
|---|
| 270 | } | 
|---|
| 271 |  | 
|---|
| 272 | return FALSE; | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | BOOL CALLBACK | 
|---|
| 276 | CScreensLinks::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | 
|---|
| 277 | { | 
|---|
| 278 | return s_singleton->doDlgProc(hwnd, message, wParam, lParam); | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | CString | 
|---|
| 282 | CScreensLinks::getSelectedScreen(HWND hwnd) const | 
|---|
| 283 | { | 
|---|
| 284 | HWND child    = getItem(hwnd, IDC_SCREENS_SCREENS); | 
|---|
| 285 | LRESULT index = SendMessage(child, LB_GETCURSEL, 0, 0); | 
|---|
| 286 | if (index == LB_ERR) { | 
|---|
| 287 | return CString(); | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | LRESULT size = SendMessage(child, LB_GETTEXTLEN, index, 0); | 
|---|
| 291 | char* buffer = new char[size + 1]; | 
|---|
| 292 | SendMessage(child, LB_GETTEXT, index, (LPARAM)buffer); | 
|---|
| 293 | buffer[size] = '\0'; | 
|---|
| 294 | CString result(buffer); | 
|---|
| 295 | delete[] buffer; | 
|---|
| 296 | return result; | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | void | 
|---|
| 300 | CScreensLinks::addScreen(HWND hwnd) | 
|---|
| 301 | { | 
|---|
| 302 | CAddScreen dialog(hwnd, m_config, ""); | 
|---|
| 303 | if (dialog.doModal()) { | 
|---|
| 304 | updateScreens(hwnd, dialog.getName()); | 
|---|
| 305 | updateScreensControls(hwnd); | 
|---|
| 306 | updateLinks(hwnd); | 
|---|
| 307 | updateLinksControls(hwnd); | 
|---|
| 308 | } | 
|---|
| 309 | } | 
|---|
| 310 |  | 
|---|
| 311 | void | 
|---|
| 312 | CScreensLinks::editScreen(HWND hwnd) | 
|---|
| 313 | { | 
|---|
| 314 | CString oldName = getSelectedScreen(hwnd); | 
|---|
| 315 | CAddScreen dialog(hwnd, m_config, oldName); | 
|---|
| 316 | if (dialog.doModal()) { | 
|---|
| 317 | CString newName = dialog.getName(); | 
|---|
| 318 |  | 
|---|
| 319 | // rename screens in the edge list | 
|---|
| 320 | if (newName != oldName) { | 
|---|
| 321 | for (size_t i = 0; i < m_edgeLinks.size(); ++i) { | 
|---|
| 322 | m_edgeLinks[i].rename(oldName, newName); | 
|---|
| 323 | } | 
|---|
| 324 | m_editedLink.rename(oldName, newName); | 
|---|
| 325 | } | 
|---|
| 326 |  | 
|---|
| 327 | updateScreens(hwnd, newName); | 
|---|
| 328 | updateScreensControls(hwnd); | 
|---|
| 329 | updateLinks(hwnd); | 
|---|
| 330 | updateLinksControls(hwnd); | 
|---|
| 331 | } | 
|---|
| 332 | } | 
|---|
| 333 |  | 
|---|
| 334 | void | 
|---|
| 335 | CScreensLinks::removeScreen(HWND hwnd) | 
|---|
| 336 | { | 
|---|
| 337 | // remove screen from config (this also removes aliases) | 
|---|
| 338 | m_config->removeScreen(getSelectedScreen(hwnd)); | 
|---|
| 339 |  | 
|---|
| 340 | // update dialog | 
|---|
| 341 | updateScreens(hwnd, ""); | 
|---|
| 342 | updateScreensControls(hwnd); | 
|---|
| 343 | updateLinks(hwnd); | 
|---|
| 344 | updateLinksControls(hwnd); | 
|---|
| 345 | } | 
|---|
| 346 |  | 
|---|
| 347 | void | 
|---|
| 348 | CScreensLinks::addLink(HWND hwnd) | 
|---|
| 349 | { | 
|---|
| 350 | if (m_editedLink.connect(m_config)) { | 
|---|
| 351 | m_editedLink = CEdgeLink(); | 
|---|
| 352 | updateLinks(hwnd); | 
|---|
| 353 | updateLinksControls(hwnd); | 
|---|
| 354 | } | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | void | 
|---|
| 358 | CScreensLinks::editLink(HWND hwnd) | 
|---|
| 359 | { | 
|---|
| 360 | // get selection | 
|---|
| 361 | HWND child = getItem(hwnd, IDC_SCREENS_LINKS); | 
|---|
| 362 | DWORD i = SendMessage(child, LB_GETCURSEL, 0, 0); | 
|---|
| 363 | if (i != LB_ERR && i != (DWORD)m_edgeLinks.size()) { | 
|---|
| 364 | // existing link | 
|---|
| 365 | m_selectedLink = (SInt32)SendMessage(child, LB_GETITEMDATA, i, 0); | 
|---|
| 366 | m_editedLink   = m_edgeLinks[m_selectedLink]; | 
|---|
| 367 | } | 
|---|
| 368 | else { | 
|---|
| 369 | // new link | 
|---|
| 370 | m_selectedLink = -1; | 
|---|
| 371 | m_editedLink   = CEdgeLink(); | 
|---|
| 372 | } | 
|---|
| 373 | updateLinksControls(hwnd); | 
|---|
| 374 | } | 
|---|
| 375 |  | 
|---|
| 376 | void | 
|---|
| 377 | CScreensLinks::removeLink(HWND hwnd) | 
|---|
| 378 | { | 
|---|
| 379 | if (m_editedLink.disconnect(m_config)) { | 
|---|
| 380 | updateLinks(hwnd); | 
|---|
| 381 | updateLinksControls(hwnd); | 
|---|
| 382 | } | 
|---|
| 383 | } | 
|---|
| 384 |  | 
|---|
| 385 | void | 
|---|
| 386 | CScreensLinks::updateScreens(HWND hwnd, const CString& selectName) | 
|---|
| 387 | { | 
|---|
| 388 | HWND child; | 
|---|
| 389 |  | 
|---|
| 390 | // set screen list | 
|---|
| 391 | child = getItem(hwnd, IDC_SCREENS_SCREENS); | 
|---|
| 392 | SendMessage(child, LB_RESETCONTENT, 0, 0); | 
|---|
| 393 | for (CConfig::const_iterator index = m_config->begin(); | 
|---|
| 394 | index != m_config->end(); ) { | 
|---|
| 395 | const CString& name = *index; | 
|---|
| 396 | ++index; | 
|---|
| 397 | if (index != m_config->end()) { | 
|---|
| 398 | SendMessage(child, LB_INSERTSTRING, | 
|---|
| 399 | (WPARAM)-1, (LPARAM)name.c_str()); | 
|---|
| 400 | } | 
|---|
| 401 | else { | 
|---|
| 402 | SendMessage(child, LB_ADDSTRING, 0, (LPARAM)name.c_str()); | 
|---|
| 403 | } | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 | // find the named screen | 
|---|
| 407 | if (!selectName.empty()) { | 
|---|
| 408 | DWORD i = SendMessage(child, LB_FINDSTRINGEXACT, | 
|---|
| 409 | (UINT)-1, (LPARAM)selectName.c_str()); | 
|---|
| 410 | if (i != LB_ERR) { | 
|---|
| 411 | SendMessage(child, LB_SETSEL, TRUE, i); | 
|---|
| 412 | } | 
|---|
| 413 | } | 
|---|
| 414 | } | 
|---|
| 415 |  | 
|---|
| 416 | void | 
|---|
| 417 | CScreensLinks::updateScreensControls(HWND hwnd) | 
|---|
| 418 | { | 
|---|
| 419 | HWND child    = getItem(hwnd, IDC_SCREENS_SCREENS); | 
|---|
| 420 | bool screenSelected = (SendMessage(child, LB_GETCURSEL, 0, 0) != LB_ERR); | 
|---|
| 421 |  | 
|---|
| 422 | enableItem(hwnd, IDC_SCREENS_ADD_SCREEN, TRUE); | 
|---|
| 423 | enableItem(hwnd, IDC_SCREENS_EDIT_SCREEN, screenSelected); | 
|---|
| 424 | enableItem(hwnd, IDC_SCREENS_REMOVE_SCREEN, screenSelected); | 
|---|
| 425 | } | 
|---|
| 426 |  | 
|---|
| 427 | void | 
|---|
| 428 | CScreensLinks::updateLinks(HWND hwnd) | 
|---|
| 429 | { | 
|---|
| 430 | HWND links      = getItem(hwnd, IDC_SCREENS_LINKS); | 
|---|
| 431 | HWND srcScreens = getItem(hwnd, IDC_SCREENS_SRC_SCREEN); | 
|---|
| 432 | HWND dstScreens = getItem(hwnd, IDC_SCREENS_DST_SCREEN); | 
|---|
| 433 |  | 
|---|
| 434 | // get old selection | 
|---|
| 435 | CEdgeLink oldLink; | 
|---|
| 436 | if (m_selectedLink != -1) { | 
|---|
| 437 | oldLink = m_edgeLinks[m_selectedLink]; | 
|---|
| 438 | } | 
|---|
| 439 |  | 
|---|
| 440 | // clear links and screens | 
|---|
| 441 | SendMessage(links, LB_RESETCONTENT, 0, 0); | 
|---|
| 442 | SendMessage(srcScreens, CB_RESETCONTENT, 0, 0); | 
|---|
| 443 | SendMessage(dstScreens, CB_RESETCONTENT, 0, 0); | 
|---|
| 444 | m_edgeLinks.clear(); | 
|---|
| 445 |  | 
|---|
| 446 | // add "no screen" items | 
|---|
| 447 | SendMessage(srcScreens, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)TEXT("----")); | 
|---|
| 448 | SendMessage(dstScreens, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)TEXT("----")); | 
|---|
| 449 |  | 
|---|
| 450 | // add links and screens | 
|---|
| 451 | for (CConfig::const_iterator i = m_config->begin(); | 
|---|
| 452 | i != m_config->end(); ++i) { | 
|---|
| 453 | const CString& name = *i; | 
|---|
| 454 |  | 
|---|
| 455 | // add screen | 
|---|
| 456 | SendMessage(srcScreens, CB_INSERTSTRING, (WPARAM)-1, | 
|---|
| 457 | (LPARAM)name.c_str()); | 
|---|
| 458 | SendMessage(dstScreens, CB_INSERTSTRING, (WPARAM)-1, | 
|---|
| 459 | (LPARAM)name.c_str()); | 
|---|
| 460 |  | 
|---|
| 461 | // add links for screen | 
|---|
| 462 | for (CConfig::link_const_iterator j = m_config->beginNeighbor(name), | 
|---|
| 463 | n = m_config->endNeighbor(name); | 
|---|
| 464 | j != n; ++j) { | 
|---|
| 465 | DWORD k = m_edgeLinks.size(); | 
|---|
| 466 | m_edgeLinks.push_back(CEdgeLink(name, *j)); | 
|---|
| 467 | SendMessage(links, LB_INSERTSTRING, (WPARAM)-1, | 
|---|
| 468 | (LPARAM)formatLink(m_edgeLinks.back()).c_str()); | 
|---|
| 469 | SendMessage(links, LB_SETITEMDATA, (WPARAM)k, (LPARAM)k); | 
|---|
| 470 | } | 
|---|
| 471 | } | 
|---|
| 472 |  | 
|---|
| 473 | // add "new link" item to sort | 
|---|
| 474 | SendMessage(links, LB_ADDSTRING, 0, (LPARAM)m_newLinkLabel.c_str()); | 
|---|
| 475 |  | 
|---|
| 476 | // remove the "new link" item then insert it on the end | 
|---|
| 477 | DWORD i = SendMessage(links, LB_FINDSTRINGEXACT, | 
|---|
| 478 | (UINT)-1, (LPARAM)m_newLinkLabel.c_str()); | 
|---|
| 479 | if (i != LB_ERR) { | 
|---|
| 480 | SendMessage(links, LB_DELETESTRING, i, 0); | 
|---|
| 481 | } | 
|---|
| 482 | SendMessage(links, LB_INSERTSTRING, (WPARAM)-1, | 
|---|
| 483 | (LPARAM)getString(IDS_NEW_LINK).c_str()); | 
|---|
| 484 | SendMessage(links, LB_SETITEMDATA, (WPARAM)m_edgeLinks.size(), | 
|---|
| 485 | (LPARAM)-1); | 
|---|
| 486 |  | 
|---|
| 487 | // select the same link as before | 
|---|
| 488 | SendMessage(links, LB_SETCURSEL, (WPARAM)m_edgeLinks.size(), 0); | 
|---|
| 489 | if (m_selectedLink != -1) { | 
|---|
| 490 | m_selectedLink = -1; | 
|---|
| 491 | for (size_t j = 0; j < m_edgeLinks.size(); ++j) { | 
|---|
| 492 | if (m_edgeLinks[j] == oldLink) { | 
|---|
| 493 | // found matching link | 
|---|
| 494 | m_selectedLink = j; | 
|---|
| 495 | for (size_t k = 0; k < m_edgeLinks.size(); ++k) { | 
|---|
| 496 | if (SendMessage(links, LB_GETITEMDATA, k, 0) == (int)j) { | 
|---|
| 497 | SendMessage(links, LB_SETCURSEL, k, 0); | 
|---|
| 498 | break; | 
|---|
| 499 | } | 
|---|
| 500 | } | 
|---|
| 501 | break; | 
|---|
| 502 | } | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 | // if we can't find the link anymore then reset edited link | 
|---|
| 506 | if (m_selectedLink == -1) { | 
|---|
| 507 | m_editedLink = CEdgeLink(); | 
|---|
| 508 | } | 
|---|
| 509 | } | 
|---|
| 510 | } | 
|---|
| 511 |  | 
|---|
| 512 | void | 
|---|
| 513 | CScreensLinks::updateLinksControls(HWND hwnd) | 
|---|
| 514 | { | 
|---|
| 515 | // get selection.  select "new link" if nothing is selected. | 
|---|
| 516 | HWND child = getItem(hwnd, IDC_SCREENS_LINKS); | 
|---|
| 517 | if (m_selectedLink == -1) { | 
|---|
| 518 | SendMessage(child, LB_SETCURSEL, m_edgeLinks.size(), 0); | 
|---|
| 519 | } | 
|---|
| 520 |  | 
|---|
| 521 | // enable/disable remove button | 
|---|
| 522 | enableItem(hwnd, IDC_SCREENS_REMOVE_LINK, m_selectedLink != -1); | 
|---|
| 523 |  | 
|---|
| 524 | // fill link entry controls from m_editedLink | 
|---|
| 525 | updateLinkEditControls(hwnd, m_editedLink); | 
|---|
| 526 | updateLinkValid(hwnd, m_editedLink); | 
|---|
| 527 | updateLinkView(hwnd); | 
|---|
| 528 | } | 
|---|
| 529 |  | 
|---|
| 530 | void | 
|---|
| 531 | CScreensLinks::changeSrcSide(HWND hwnd) | 
|---|
| 532 | { | 
|---|
| 533 | HWND child = getItem(hwnd, IDC_SCREENS_SRC_SIDE); | 
|---|
| 534 | m_editedLink.m_srcSide = (EDirection)SendMessage(child, CB_GETCURSEL, 0, 0); | 
|---|
| 535 | updateLink(hwnd); | 
|---|
| 536 | } | 
|---|
| 537 |  | 
|---|
| 538 | void | 
|---|
| 539 | CScreensLinks::changeSrcScreen(HWND hwnd) | 
|---|
| 540 | { | 
|---|
| 541 | HWND child = getItem(hwnd, IDC_SCREENS_SRC_SCREEN); | 
|---|
| 542 | m_editedLink.m_srcName = getWindowText(child); | 
|---|
| 543 | updateLink(hwnd); | 
|---|
| 544 | } | 
|---|
| 545 |  | 
|---|
| 546 | void | 
|---|
| 547 | CScreensLinks::changeDstScreen(HWND hwnd) | 
|---|
| 548 | { | 
|---|
| 549 | HWND child = getItem(hwnd, IDC_SCREENS_DST_SCREEN); | 
|---|
| 550 | m_editedLink.m_dstName = getWindowText(child); | 
|---|
| 551 | updateLink(hwnd); | 
|---|
| 552 | } | 
|---|
| 553 |  | 
|---|
| 554 | void | 
|---|
| 555 | CScreensLinks::changeIntervalStart(HWND hwnd, int id, CConfig::CInterval& i) | 
|---|
| 556 | { | 
|---|
| 557 | int x = (int)GetDlgItemInt(hwnd, id, NULL, FALSE); | 
|---|
| 558 | if (x < 0) { | 
|---|
| 559 | x = 0; | 
|---|
| 560 | } | 
|---|
| 561 | else if (x > 99) { | 
|---|
| 562 | x = 99; | 
|---|
| 563 | } | 
|---|
| 564 |  | 
|---|
| 565 | i.first = 0.01f * (float)x; | 
|---|
| 566 | if (i.first >= i.second) { | 
|---|
| 567 | i.second = 0.01f * (float)(x + 1); | 
|---|
| 568 | } | 
|---|
| 569 |  | 
|---|
| 570 | updateLinkIntervalControls(hwnd, m_editedLink); | 
|---|
| 571 | updateLink(hwnd); | 
|---|
| 572 | } | 
|---|
| 573 |  | 
|---|
| 574 | void | 
|---|
| 575 | CScreensLinks::changeIntervalEnd(HWND hwnd, int id, CConfig::CInterval& i) | 
|---|
| 576 | { | 
|---|
| 577 | int x = (int)GetDlgItemInt(hwnd, id, NULL, FALSE); | 
|---|
| 578 | if (x < 1) { | 
|---|
| 579 | x = 1; | 
|---|
| 580 | } | 
|---|
| 581 | else if (x > 100) { | 
|---|
| 582 | x = 100; | 
|---|
| 583 | } | 
|---|
| 584 |  | 
|---|
| 585 | i.second = 0.01f * (float)x; | 
|---|
| 586 | if (i.first >= i.second) { | 
|---|
| 587 | i.first = 0.01f * (float)(x - 1); | 
|---|
| 588 | } | 
|---|
| 589 |  | 
|---|
| 590 | updateLinkIntervalControls(hwnd, m_editedLink); | 
|---|
| 591 | updateLink(hwnd); | 
|---|
| 592 | } | 
|---|
| 593 |  | 
|---|
| 594 | void | 
|---|
| 595 | CScreensLinks::selectScreen(HWND hwnd, int id, const CString& name) | 
|---|
| 596 | { | 
|---|
| 597 | HWND child = getItem(hwnd, id); | 
|---|
| 598 | DWORD i = SendMessage(child, CB_FINDSTRINGEXACT, (WPARAM)-1, | 
|---|
| 599 | (LPARAM)name.c_str()); | 
|---|
| 600 | if (i == CB_ERR) { | 
|---|
| 601 | // no match, select no screen | 
|---|
| 602 | SendMessage(child, CB_SETCURSEL, 0, 0); | 
|---|
| 603 | } | 
|---|
| 604 | else { | 
|---|
| 605 | SendMessage(child, CB_SETCURSEL, i, 0); | 
|---|
| 606 | } | 
|---|
| 607 | } | 
|---|
| 608 |  | 
|---|
| 609 | void | 
|---|
| 610 | CScreensLinks::updateLinkEditControls(HWND hwnd, const CEdgeLink& link) | 
|---|
| 611 | { | 
|---|
| 612 | // fill link entry controls from link | 
|---|
| 613 | HWND child = getItem(hwnd, IDC_SCREENS_SRC_SIDE); | 
|---|
| 614 | SendMessage(child, CB_SETCURSEL, link.m_srcSide, 0); | 
|---|
| 615 | selectScreen(hwnd, IDC_SCREENS_SRC_SCREEN, link.m_srcName); | 
|---|
| 616 | selectScreen(hwnd, IDC_SCREENS_DST_SCREEN, link.m_dstName); | 
|---|
| 617 | updateLinkIntervalControls(hwnd, link); | 
|---|
| 618 | } | 
|---|
| 619 |  | 
|---|
| 620 | void | 
|---|
| 621 | CScreensLinks::updateLinkIntervalControls(HWND hwnd, const CEdgeLink& link) | 
|---|
| 622 | { | 
|---|
| 623 | HWND child; | 
|---|
| 624 |  | 
|---|
| 625 | // src interval | 
|---|
| 626 | child = getItem(hwnd, IDC_SCREENS_SRC_START); | 
|---|
| 627 | setWindowText(child, formatIntervalValue(link.m_srcInterval.first)); | 
|---|
| 628 | child = getItem(hwnd, IDC_SCREENS_SRC_END); | 
|---|
| 629 | setWindowText(child, formatIntervalValue(link.m_srcInterval.second)); | 
|---|
| 630 |  | 
|---|
| 631 | // dst interval | 
|---|
| 632 | child = getItem(hwnd, IDC_SCREENS_DST_START); | 
|---|
| 633 | setWindowText(child, formatIntervalValue(link.m_dstInterval.first)); | 
|---|
| 634 | child = getItem(hwnd, IDC_SCREENS_DST_END); | 
|---|
| 635 | setWindowText(child, formatIntervalValue(link.m_dstInterval.second)); | 
|---|
| 636 | } | 
|---|
| 637 |  | 
|---|
| 638 | void | 
|---|
| 639 | CScreensLinks::updateLink(HWND hwnd) | 
|---|
| 640 | { | 
|---|
| 641 | updateLinkValid(hwnd, m_editedLink); | 
|---|
| 642 |  | 
|---|
| 643 | // update link in config | 
|---|
| 644 | if (m_selectedLink != -1 && m_editedLinkIsValid) { | 
|---|
| 645 | // editing an existing link and entry is valid | 
|---|
| 646 | if (m_edgeLinks[m_selectedLink].disconnect(m_config)) { | 
|---|
| 647 | // successfully removed old link | 
|---|
| 648 | if (!m_editedLink.connect(m_config)) { | 
|---|
| 649 | // couldn't set new link so restore old link | 
|---|
| 650 | m_edgeLinks[m_selectedLink].connect(m_config); | 
|---|
| 651 | } | 
|---|
| 652 | else { | 
|---|
| 653 | m_edgeLinks[m_selectedLink] = m_editedLink; | 
|---|
| 654 | updateLinks(hwnd); | 
|---|
| 655 | updateLinkEditControls(hwnd, m_editedLink); | 
|---|
| 656 | } | 
|---|
| 657 | } | 
|---|
| 658 | } | 
|---|
| 659 |  | 
|---|
| 660 | updateLinkView(hwnd); | 
|---|
| 661 | } | 
|---|
| 662 |  | 
|---|
| 663 | void | 
|---|
| 664 | CScreensLinks::updateLinkValid(HWND hwnd, const CEdgeLink& link) | 
|---|
| 665 | { | 
|---|
| 666 | m_editedLinkIsValid = true; | 
|---|
| 667 |  | 
|---|
| 668 | // check source side and screen | 
|---|
| 669 | if (link.m_srcSide == kNoDirection) { | 
|---|
| 670 | m_editedLinkIsValid = false; | 
|---|
| 671 | ShowWindow(m_srcSideError, SW_SHOWNA); | 
|---|
| 672 | } | 
|---|
| 673 | else { | 
|---|
| 674 | ShowWindow(m_srcSideError, SW_HIDE); | 
|---|
| 675 | } | 
|---|
| 676 | if (!m_config->isCanonicalName(link.m_srcName)) { | 
|---|
| 677 | m_editedLinkIsValid = false; | 
|---|
| 678 | ShowWindow(m_srcScreenError, SW_SHOWNA); | 
|---|
| 679 | } | 
|---|
| 680 | else { | 
|---|
| 681 | ShowWindow(m_srcScreenError, SW_HIDE); | 
|---|
| 682 | } | 
|---|
| 683 |  | 
|---|
| 684 | // check for overlap.  if editing a link we must remove it, then | 
|---|
| 685 | // check for overlap and restore the old link. | 
|---|
| 686 | bool overlap = false; | 
|---|
| 687 | if (m_editedLinkIsValid) { | 
|---|
| 688 | if (m_selectedLink == -1) { | 
|---|
| 689 | if (link.overlaps(m_config)) { | 
|---|
| 690 | m_editedLinkIsValid = false; | 
|---|
| 691 | overlap = true; | 
|---|
| 692 | } | 
|---|
| 693 | } | 
|---|
| 694 | else { | 
|---|
| 695 | if (m_edgeLinks[m_selectedLink].disconnect(m_config)) { | 
|---|
| 696 | overlap = link.overlaps(m_config); | 
|---|
| 697 | m_edgeLinks[m_selectedLink].connect(m_config); | 
|---|
| 698 | if (overlap) { | 
|---|
| 699 | m_editedLinkIsValid = false; | 
|---|
| 700 | } | 
|---|
| 701 | } | 
|---|
| 702 | } | 
|---|
| 703 | } | 
|---|
| 704 | ShowWindow(getItem(hwnd, IDC_SCREENS_OVERLAP_ERROR), | 
|---|
| 705 | overlap ? SW_SHOWNA : SW_HIDE); | 
|---|
| 706 |  | 
|---|
| 707 | // check dst screen | 
|---|
| 708 | if (!m_config->isCanonicalName(link.m_dstName)) { | 
|---|
| 709 | m_editedLinkIsValid = false; | 
|---|
| 710 | ShowWindow(m_dstScreenError, SW_SHOWNA); | 
|---|
| 711 | } | 
|---|
| 712 | else { | 
|---|
| 713 | ShowWindow(m_dstScreenError, SW_HIDE); | 
|---|
| 714 | } | 
|---|
| 715 |  | 
|---|
| 716 | // update add link button | 
|---|
| 717 | enableItem(hwnd, IDC_SCREENS_ADD_LINK, | 
|---|
| 718 | m_selectedLink == -1 && m_editedLinkIsValid); | 
|---|
| 719 | } | 
|---|
| 720 |  | 
|---|
| 721 | void | 
|---|
| 722 | CScreensLinks::updateLinkView(HWND /*hwnd*/) | 
|---|
| 723 | { | 
|---|
| 724 | // XXX -- draw visual of selected screen, highlighting selected link | 
|---|
| 725 | } | 
|---|
| 726 |  | 
|---|
| 727 | HWND | 
|---|
| 728 | CScreensLinks::createErrorBox(HWND parent) | 
|---|
| 729 | { | 
|---|
| 730 | return CreateWindow(TEXT("STATIC"), TEXT(""), | 
|---|
| 731 | WS_CHILD | SS_OWNERDRAW, | 
|---|
| 732 | 0, 0, 1, 1, | 
|---|
| 733 | parent, (HMENU)-1, | 
|---|
| 734 | s_instance, NULL); | 
|---|
| 735 | } | 
|---|
| 736 |  | 
|---|
| 737 | void | 
|---|
| 738 | CScreensLinks::resizeErrorBoxes() | 
|---|
| 739 | { | 
|---|
| 740 | HWND hwnd = GetParent(m_srcSideError); | 
|---|
| 741 | resizeErrorBox(m_srcSideError,   getItem(hwnd, IDC_SCREENS_SRC_SIDE)); | 
|---|
| 742 | resizeErrorBox(m_srcScreenError, getItem(hwnd, IDC_SCREENS_SRC_SCREEN)); | 
|---|
| 743 | resizeErrorBox(m_dstScreenError, getItem(hwnd, IDC_SCREENS_DST_SCREEN)); | 
|---|
| 744 | } | 
|---|
| 745 |  | 
|---|
| 746 | void | 
|---|
| 747 | CScreensLinks::resizeErrorBox(HWND box, HWND assoc) | 
|---|
| 748 | { | 
|---|
| 749 | RECT rect; | 
|---|
| 750 | GetWindowRect(assoc, &rect); | 
|---|
| 751 | MapWindowPoints(NULL, GetParent(box), (POINT*)&rect, 2); | 
|---|
| 752 | SetWindowPos(box, HWND_TOP, rect.left - 1, rect.top - 1, | 
|---|
| 753 | rect.right - rect.left + 2, | 
|---|
| 754 | rect.bottom - rect.top + 2, SWP_NOACTIVATE); | 
|---|
| 755 | } | 
|---|
| 756 |  | 
|---|
| 757 | CString | 
|---|
| 758 | CScreensLinks::formatIntervalValue(float x) const | 
|---|
| 759 | { | 
|---|
| 760 | return CStringUtil::print("%d", (int)(x * 100.0f + 0.5f)); | 
|---|
| 761 | } | 
|---|
| 762 |  | 
|---|
| 763 | CString | 
|---|
| 764 | CScreensLinks::formatInterval(const CConfig::CInterval& i) const | 
|---|
| 765 | { | 
|---|
| 766 | if (i.first == 0.0f && i.second == 1.0f) { | 
|---|
| 767 | return ""; | 
|---|
| 768 | } | 
|---|
| 769 | else { | 
|---|
| 770 | CString start = formatIntervalValue(i.first); | 
|---|
| 771 | CString end   = formatIntervalValue(i.second); | 
|---|
| 772 | return CStringUtil::format(m_intervalFormat.c_str(), | 
|---|
| 773 | start.c_str(), end.c_str()); | 
|---|
| 774 | } | 
|---|
| 775 | } | 
|---|
| 776 |  | 
|---|
| 777 | CString | 
|---|
| 778 | CScreensLinks::formatLink(const CEdgeLink& link) const | 
|---|
| 779 | { | 
|---|
| 780 | CString srcInterval = formatInterval(link.m_srcInterval); | 
|---|
| 781 | CString dstInterval = formatInterval(link.m_dstInterval); | 
|---|
| 782 | return CStringUtil::format(m_linkFormat.c_str(), | 
|---|
| 783 | link.m_srcName.c_str(), srcInterval.c_str(), | 
|---|
| 784 | m_sideLabel[link.m_srcSide - kFirstDirection].c_str(), | 
|---|
| 785 | link.m_dstName.c_str(), dstInterval.c_str()); | 
|---|
| 786 | } | 
|---|
| 787 |  | 
|---|
| 788 | // | 
|---|
| 789 | // CScreensLinks::CEdgeLink | 
|---|
| 790 | // | 
|---|
| 791 |  | 
|---|
| 792 | CScreensLinks::CEdgeLink::CEdgeLink() : | 
|---|
| 793 | m_srcName(), | 
|---|
| 794 | m_srcSide(kNoDirection), | 
|---|
| 795 | m_srcInterval(0.0f, 1.0f), | 
|---|
| 796 | m_dstName(), | 
|---|
| 797 | m_dstInterval(0.0f, 1.0f) | 
|---|
| 798 | { | 
|---|
| 799 | // do nothing | 
|---|
| 800 | } | 
|---|
| 801 |  | 
|---|
| 802 | CScreensLinks::CEdgeLink::CEdgeLink(const CString& name, | 
|---|
| 803 | const CConfigLink& link) : | 
|---|
| 804 | m_srcName(name), | 
|---|
| 805 | m_srcSide(link.first.getSide()), | 
|---|
| 806 | m_srcInterval(link.first.getInterval()), | 
|---|
| 807 | m_dstName(link.second.getName()), | 
|---|
| 808 | m_dstInterval(link.second.getInterval()) | 
|---|
| 809 | { | 
|---|
| 810 | // do nothing | 
|---|
| 811 | } | 
|---|
| 812 |  | 
|---|
| 813 | bool | 
|---|
| 814 | CScreensLinks::CEdgeLink::connect(CConfig* config) | 
|---|
| 815 | { | 
|---|
| 816 | return config->connect(m_srcName, m_srcSide, | 
|---|
| 817 | m_srcInterval.first, m_srcInterval.second, | 
|---|
| 818 | m_dstName, | 
|---|
| 819 | m_dstInterval.first, m_dstInterval.second); | 
|---|
| 820 | } | 
|---|
| 821 |  | 
|---|
| 822 | bool | 
|---|
| 823 | CScreensLinks::CEdgeLink::disconnect(CConfig* config) | 
|---|
| 824 | { | 
|---|
| 825 | return config->disconnect(m_srcName, m_srcSide, 0.5f * | 
|---|
| 826 | (m_srcInterval.first + m_srcInterval.second)); | 
|---|
| 827 | } | 
|---|
| 828 |  | 
|---|
| 829 | void | 
|---|
| 830 | CScreensLinks::CEdgeLink::rename(const CString& oldName, const CString& newName) | 
|---|
| 831 | { | 
|---|
| 832 | if (m_srcName == oldName) { | 
|---|
| 833 | m_srcName = newName; | 
|---|
| 834 | } | 
|---|
| 835 | if (m_dstName == oldName) { | 
|---|
| 836 | m_dstName = newName; | 
|---|
| 837 | } | 
|---|
| 838 | } | 
|---|
| 839 |  | 
|---|
| 840 | bool | 
|---|
| 841 | CScreensLinks::CEdgeLink::overlaps(const CConfig* config) const | 
|---|
| 842 | { | 
|---|
| 843 | return config->hasNeighbor(m_srcName, m_srcSide, | 
|---|
| 844 | m_srcInterval.first, m_srcInterval.second); | 
|---|
| 845 | } | 
|---|
| 846 |  | 
|---|
| 847 | bool | 
|---|
| 848 | CScreensLinks::CEdgeLink::operator==(const CEdgeLink& x) const | 
|---|
| 849 | { | 
|---|
| 850 | return (m_srcName == x.m_srcName && | 
|---|
| 851 | m_srcSide == x.m_srcSide && | 
|---|
| 852 | m_srcInterval == x.m_srcInterval && | 
|---|
| 853 | m_dstName == x.m_dstName && | 
|---|
| 854 | m_dstInterval == x.m_dstInterval); | 
|---|
| 855 | } | 
|---|