|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /****************************** Module Header ******************************* ! 13: * Module Name: BAR.C ! 14: * ! 15: * This module contains functions for bar window ! 16: * graphically showing two lists of sections and showing ! 17: * colored vertical bars for the sections of text, ! 18: * with linking lines for the sections that are the same. ! 19: * ! 20: * Functions: ! 21: * ! 22: * BarWndProc() ! 23: * BarPaint() ! 24: * DrawSection() ! 25: * DrawLink() ! 26: * BarClick() ! 27: * InitBarClass() ! 28: * BarDrawPosition() ! 29: * ! 30: * Comments: ! 31: * ! 32: ****************************************************************************/ ! 33: ! 34: #include <windows.h> ! 35: #include <commdlg.h> ! 36: ! 37: #include "gutils.h" ! 38: #include "table.h" ! 39: #include "state.h" ! 40: #include "wdiffrc.h" ! 41: #include "windiff.h" ! 42: #include "list.h" ! 43: #include "line.h" ! 44: #include "scandir.h" ! 45: #include "file.h" ! 46: #include "section.h" ! 47: #include "compitem.h" ! 48: #include "complist.h" ! 49: #include "view.h" ! 50: ! 51: ! 52: long APIENTRY BarWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam); ! 53: void BarPaint(HWND hwnd); ! 54: void DrawSection(HDC hdc, int cx, int cy, int lines, SECTION sec, int sidecode); ! 55: void DrawLink(HDC hdc, int cx, int cy, int lines, SECTION sec); ! 56: void BarClick(HWND hwnd, int x, int y); ! 57: ! 58: ! 59: HPEN hpenSame, hpenLeft, hpenRight; ! 60: HBRUSH hbrSame, hbrLeft, hbrRight; ! 61: HBRUSH hbrSideBar; ! 62: ! 63: ! 64: /*************************************************************************** ! 65: * Function: InitBarClass ! 66: * ! 67: * Purpose: ! 68: * ! 69: * Create bar window class ! 70: */ ! 71: BOOL ! 72: InitBarClass(HINSTANCE hInstance) ! 73: { ! 74: WNDCLASS wc; ! 75: BOOL resp; ! 76: ! 77: ! 78: ! 79: wc.style = CS_HREDRAW | CS_VREDRAW; ! 80: wc.lpfnWndProc = BarWndProc; ! 81: wc.cbClsExtra = 0; ! 82: wc.cbWndExtra = 0; ! 83: wc.hInstance = hInstance; ! 84: wc.hIcon = NULL; ! 85: wc.hCursor = LoadCursor(NULL, IDC_ARROW); ! 86: wc.hbrBackground = GetStockObject(WHITE_BRUSH); ! 87: wc.lpszClassName = "BarClass"; ! 88: wc.lpszMenuName = NULL; ! 89: ! 90: resp = RegisterClass(&wc); ! 91: ! 92: return(resp); ! 93: } ! 94: ! 95: ! 96: ! 97: /*************************************************************************** ! 98: * Function: BarWndProc ! 99: * ! 100: * Purpose: ! 101: * ! 102: * Window procedure supporting bar window ! 103: * ! 104: */ ! 105: ! 106: long APIENTRY ! 107: BarWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam) ! 108: { ! 109: ! 110: switch(message) { ! 111: ! 112: ! 113: case WM_CREATE: ! 114: ! 115: hpenSame = CreatePen(PS_SOLID, 1, RGB(0,0,0)); ! 116: hbrSame = CreateSolidBrush(RGB(255,255,255)); ! 117: ! 118: hpenLeft = CreatePen(PS_SOLID, 1, rgb_barleft); ! 119: hbrLeft = CreateSolidBrush(rgb_barleft); ! 120: ! 121: hpenRight = CreatePen(PS_SOLID, 1, rgb_barright); ! 122: hbrRight = CreateSolidBrush(rgb_barright); ! 123: ! 124: hbrSideBar = CreateSolidBrush(rgb_barcurrent); ! 125: break; ! 126: ! 127: case WM_DESTROY: ! 128: DeleteObject(hpenSame); ! 129: DeleteObject(hpenLeft); ! 130: DeleteObject(hpenRight); ! 131: DeleteObject(hbrSame); ! 132: DeleteObject(hbrLeft); ! 133: DeleteObject(hbrRight); ! 134: DeleteObject(hbrSideBar); ! 135: break; ! 136: ! 137: case WM_PAINT: ! 138: BarPaint(hWnd); ! 139: break; ! 140: ! 141: case WM_LBUTTONDOWN: ! 142: BarClick(hWnd, LOWORD(lParam), HIWORD(lParam)); ! 143: break; ! 144: ! 145: default: ! 146: return(DefWindowProc(hWnd, message, wParam, lParam)); ! 147: } ! 148: return 0; ! 149: } ! 150: ! 151: /*************************************************************************** ! 152: * Function: BarDrawPosition ! 153: * ! 154: * Purpose: ! 155: * ! 156: * Draw the current position as side-bars down the bar window, ! 157: * showing which lines from each file are currently in view. HDC can be ! 158: * NULL (we get one ourselves if so). If bErase is true, we clear ! 159: * the previous side-bars first. ! 160: * ! 161: * This is called from BarPaint when we paint the whole window, and ! 162: * from TableServer() whenever it receives a TQ_SCROLL notification that ! 163: * the table window has been scrolled. ! 164: */ ! 165: void ! 166: BarDrawPosition(HWND hwndBar, HDC hdcIn, BOOL bErase) ! 167: { ! 168: HDC hdc; ! 169: int total_lines, cy, cx; ! 170: RECT rc, rcLeft, rcRight; ! 171: VIEW view; ! 172: COMPITEM item; ! 173: LIST listleft, listright; ! 174: long toprow, endrow, i; ! 175: int left_first, left_last, right_first, right_last, linenr; ! 176: ! 177: ! 178: /* get a hdc if we weren't given one */ ! 179: if (hdcIn == NULL) { ! 180: hdc = GetDC(hwndBar); ! 181: } else { ! 182: hdc = hdcIn; ! 183: } ! 184: ! 185: /* set horz position of bars */ ! 186: GetClientRect(hwndBar, &rc); ! 187: cx = (int)(rc.right - rc.left); ! 188: cy = (int)(rc.bottom - rc.top); ! 189: ! 190: /* layout constants are defined as percentages of window width */ ! 191: rcLeft.left = cx * L_POS_START / 100; ! 192: rcRight.left = cx * R_POS_START / 100; ! 193: rcLeft.right = rcLeft.left + (cx * L_POS_WIDTH / 100); ! 194: rcRight.right = rcRight.left + (cx * R_POS_WIDTH / 100); ! 195: ! 196: /* erase the whole marker section if requested */ ! 197: if (bErase) { ! 198: rcLeft.top = rc.top; ! 199: rcLeft.bottom = rc.bottom; ! 200: rcRight.top = rc.top; ! 201: rcRight.bottom = rc.bottom; ! 202: ! 203: FillRect(hdc, &rcLeft, GetStockObject(WHITE_BRUSH)); ! 204: ! 205: FillRect(hdc, &rcRight, GetStockObject(WHITE_BRUSH)); ! 206: } ! 207: ! 208: ! 209: /* ! 210: * calculate the vertical scaling - depends on the ! 211: * total number of lines shown ! 212: */ ! 213: ! 214: /* get the handles to the two lists of sections */ ! 215: view = (VIEW) SendMessage(hwndClient, TM_CURRENTVIEW, 0, 0); ! 216: /* make sure we are in expand mode */ ! 217: if (view_isexpanded(view) == FALSE) { ! 218: /* get rid of the dc if we made it ourselves */ ! 219: if (hdcIn == NULL) { ! 220: ReleaseDC(hwndBar, hdc); ! 221: } ! 222: return; ! 223: } ! 224: ! 225: item = view_getitem(view, 0); ! 226: ! 227: listleft = compitem_getleftsections(item); ! 228: listright = compitem_getrightsections(item); ! 229: ! 230: /* if there is only one list of sections, draw nothing. The ! 231: * picture for a single file is not very exciting. ! 232: */ ! 233: ! 234: if ((listleft == NULL) || (listright == NULL)) { ! 235: /* get rid of the dc if we made it ourselves */ ! 236: if (hdcIn == NULL) { ! 237: ReleaseDC(hwndBar, hdc); ! 238: } ! 239: return; ! 240: } ! 241: ! 242: /* take the longest of the two files and use this ! 243: * for vertical scaling. the scale is such that the longest file ! 244: * *just fits*. ! 245: */ ! 246: total_lines = line_getlinenr(section_getlastline(List_Last(listleft))); ! 247: total_lines = max(total_lines, ! 248: (int) line_getlinenr(section_getlastline(List_Last(listright)))); ! 249: ! 250: ! 251: /* get the current top row and nr of rows visible */ ! 252: toprow = SendMessage(hwndRCD, TM_TOPROW, FALSE, 0); ! 253: endrow = SendMessage(hwndRCD, TM_ENDROW, FALSE, 0); ! 254: endrow = min(endrow, view_getrowcount(view)-1); ! 255: ! 256: ! 257: ! 258: /* ! 259: * find the first and last line nrs from each file currently visible. ! 260: * ! 261: */ ! 262: left_first = left_last = right_first = right_last = 0; ! 263: ! 264: for (i = toprow; i <= endrow; i++) { ! 265: linenr = view_getlinenr_left(view, i); ! 266: ! 267: if (linenr > 0) { ! 268: ! 269: if (left_first == 0) { ! 270: left_first = linenr; ! 271: } ! 272: left_first = min(left_first, linenr); ! 273: left_last = max(left_last, linenr); ! 274: } ! 275: ! 276: linenr = view_getlinenr_right(view, i); ! 277: if (linenr > 0) { ! 278: if (right_first == 0) { ! 279: right_first = linenr; ! 280: } ! 281: right_first = min(right_first, linenr); ! 282: right_last = max(right_last, linenr); ! 283: } ! 284: ! 285: } ! 286: ! 287: /* draw the two markers as thick bars -> elongated rectangles */ ! 288: rcLeft.top = MulDiv(left_first-1, cy, total_lines); ! 289: rcLeft.bottom = MulDiv(left_last, cy, total_lines); ! 290: FillRect(hdc, &rcLeft, hbrSideBar); ! 291: ! 292: rcRight.top = MulDiv(right_first-1, cy, total_lines); ! 293: rcRight.bottom = MulDiv(right_last, cy, total_lines); ! 294: FillRect(hdc, &rcRight, hbrSideBar); ! 295: ! 296: /* get rid of the dc if we made it ourselves */ ! 297: if (hdcIn == NULL) { ! 298: ReleaseDC(hwndBar, hdc); ! 299: } ! 300: ! 301: } ! 302: ! 303: ! 304: /*************************************************************************** ! 305: * Function: BarPaint ! 306: * ! 307: * Purpose: ! 308: * ! 309: * Paint the bar window ! 310: */ ! 311: void ! 312: BarPaint(HWND hwnd) ! 313: { ! 314: PAINTSTRUCT ps; ! 315: HDC hdc; ! 316: VIEW view; ! 317: COMPITEM item; ! 318: LIST listleft, listright; ! 319: SECTION sec; ! 320: int total_lines, cx, cy; ! 321: RECT rc; ! 322: ! 323: hdc = BeginPaint(hwnd, &ps); ! 324: ! 325: /* draw a separator line at the very edge of the window */ ! 326: GetClientRect(hwnd, &rc); ! 327: MoveToEx(hdc, (int)(rc.right-1), rc.top, NULL); ! 328: LineTo(hdc, (int)(rc.right-1), rc.bottom); ! 329: ! 330: ! 331: /* first gather information about what is to be displayed */ ! 332: ! 333: /* find the total lines (for horz. scaling) */ ! 334: ! 335: /* get the handles to the two lists of sections */ ! 336: view = (VIEW) SendMessage(hwndClient, TM_CURRENTVIEW, 0, 0); ! 337: ! 338: /* make sure we are in expand mode */ ! 339: if (view_isexpanded(view) == FALSE) { ! 340: return; ! 341: } ! 342: ! 343: item = view_getitem(view, 0); ! 344: ! 345: listleft = compitem_getleftsections(item); ! 346: listright = compitem_getrightsections(item); ! 347: ! 348: /* ! 349: * don't bother if there is only one list - not very interesting ! 350: */ ! 351: if ((listleft == NULL) || (listright == NULL)) { ! 352: EndPaint(hwnd, &ps); ! 353: return; ! 354: } ! 355: ! 356: /* take the longest of the two files and use this ! 357: * for vertical scaling. the scale is such that the longest file ! 358: * *just fits*. ! 359: */ ! 360: total_lines = (int) line_getlinenr(section_getlastline(List_Last(listleft))); ! 361: total_lines = max(total_lines, ! 362: (int) line_getlinenr(section_getlastline(List_Last(listright)))); ! 363: ! 364: ! 365: ! 366: /* horizontal spacing: ! 367: * ! 368: * there are two columns, for the left and right files, and a gap ! 369: * between them criss-crossed by lines marking the links. ! 370: * ! 371: * Each of the columns then has three sections, for the ! 372: * position marker, the different sections ! 373: * and the linked sections. The width and positions of these items ! 374: * are defined (in windiff.h) as percentages of the window width. ! 375: */ ! 376: ! 377: cx = (int)(rc.right - rc.left); ! 378: cy = (int)(rc.bottom - rc.top); ! 379: ! 380: ! 381: /* draw all the left sections and links */ ! 382: List_TRAVERSE(listleft, sec) { ! 383: DrawSection(hdc, cx, cy, total_lines, sec, STATE_LEFTONLY); ! 384: ! 385: if (section_getlink(sec) != NULL) { ! 386: DrawLink(hdc, cx, cy, total_lines, sec); ! 387: } ! 388: } ! 389: ! 390: /* draw all the right sections */ ! 391: List_TRAVERSE(listright, sec) { ! 392: DrawSection(hdc, cx, cy, total_lines, sec, STATE_RIGHTONLY); ! 393: } ! 394: ! 395: ! 396: ! 397: /* now draw current position markers */ ! 398: BarDrawPosition(hwnd, hdc, FALSE); ! 399: ! 400: EndPaint(hwnd, &ps); ! 401: } ! 402: ! 403: /*************************************************************************** ! 404: * Function: DrawSection ! 405: * ! 406: * Purpose: ! 407: * ! 408: * Paint a single section ! 409: */ ! 410: void ! 411: DrawSection(HDC hdc, int cx, int cy, int lines, SECTION sec, int sidecode) ! 412: { ! 413: int x1, y1, x2, y2; ! 414: HPEN hpenOld; ! 415: HBRUSH hbrOld; ! 416: ! 417: /* calculate the vertical position from the scaling. the scaling ! 418: * is such that the longest file just fits ! 419: */ ! 420: y1 = MulDiv(line_getlinenr(section_getfirstline(sec))- 1, cy, lines); ! 421: y2 = MulDiv(line_getlinenr(section_getlastline(sec)), cy, lines); ! 422: ! 423: ! 424: /* left or right - set bar position and width*/ ! 425: if (sidecode == STATE_LEFTONLY) { ! 426: if (section_getlink(sec) != NULL) { ! 427: x1 = L_MATCH_START; ! 428: x2 = L_MATCH_WIDTH; ! 429: } else { ! 430: x1 = L_UNMATCH_START; ! 431: x2 = L_UNMATCH_WIDTH; ! 432: } ! 433: } else { ! 434: if (section_getlink(sec) != NULL) { ! 435: x1 = R_MATCH_START; ! 436: x2 = R_MATCH_WIDTH; ! 437: } else { ! 438: x1 = R_UNMATCH_START; ! 439: x2 = R_UNMATCH_WIDTH; ! 440: } ! 441: } ! 442: /* bar position defines are in percentages of the win width (cx) */ ! 443: x1 = cx * x1 / 100; ! 444: x2 = (cx * x2 / 100) + x1; ! 445: ! 446: ! 447: /* select pens and brushes */ ! 448: if (section_getlink(sec) != NULL) { ! 449: hpenOld = SelectObject(hdc, hpenSame); ! 450: hbrOld = SelectObject(hdc, hbrSame); ! 451: } else if (sidecode == STATE_LEFTONLY) { ! 452: hpenOld = SelectObject(hdc, hpenLeft); ! 453: hbrOld = SelectObject(hdc, hbrLeft); ! 454: } else { ! 455: hpenOld = SelectObject(hdc, hpenRight); ! 456: hbrOld = SelectObject(hdc, hbrRight); ! 457: } ! 458: ! 459: /* draw the section as a coloured elongated rectangle */ ! 460: Rectangle(hdc, x1, y1, x2, y2); ! 461: ! 462: /* de-select the pen and brush in favour of the default */ ! 463: SelectObject(hdc, hpenOld); ! 464: SelectObject(hdc, hbrOld); ! 465: ! 466: } ! 467: ! 468: /*************************************************************************** ! 469: * Function: DrawLink ! 470: * ! 471: * Purpose: ! 472: * ! 473: * Draw a line linking two sections. Indicates a section from each ! 474: * file that match each other. psec points to the section in the ! 475: * left file. ! 476: */ ! 477: void ! 478: DrawLink(HDC hdc, int cx, int cy, int lines, SECTION sec) ! 479: { ! 480: int x1, y1, x2, y2; ! 481: int ybase, yrange; ! 482: SECTION other; ! 483: ! 484: other = section_getlink(sec); ! 485: ! 486: /* position the link line halfway down the section ! 487: * - allow for the case where ! 488: * the section is one line (ie halve the co-ords, not the line nr) ! 489: */ ! 490: ybase = MulDiv(line_getlinenr(section_getfirstline(sec)) - 1, cy, lines); ! 491: yrange = MulDiv(line_getlinenr(section_getlastline(sec)), cy, lines); ! 492: y1 = ((yrange - ybase) / 2) + ybase; ! 493: ! 494: ybase = MulDiv(line_getlinenr(section_getfirstline(other)) - 1, cy, lines); ! 495: yrange = MulDiv(line_getlinenr(section_getlastline(other)), cy, lines); ! 496: y2 = ((yrange - ybase) / 2) + ybase; ! 497: ! 498: /* horizontal layout constants are defined as percentages of the ! 499: * window width ! 500: */ ! 501: x1 = cx * (L_MATCH_START + L_MATCH_WIDTH) / 100; ! 502: x2 = cx * R_UNMATCH_START / 100; ! 503: ! 504: MoveToEx(hdc, x1, y1, NULL); ! 505: LineTo(hdc, x2, y2); ! 506: } ! 507: ! 508: ! 509: /*************************************************************************** ! 510: * Function: BarClick ! 511: * ! 512: * Purpose: ! 513: * ! 514: * The user has clicked on the bar window. Translate the clicked position into ! 515: * a line in one of the files if possible, and scroll the table window to ! 516: * show that line. ! 517: */ ! 518: void ! 519: BarClick(HWND hwnd, int x, int y) ! 520: { ! 521: RECT rc; ! 522: int xleft, xright; ! 523: int linenr, i, this; ! 524: BOOL bIsLeft; ! 525: int tot_left, tot_right, total_lines; ! 526: LIST listleft, listright; ! 527: VIEW view; ! 528: COMPITEM item; ! 529: TableSelection select; ! 530: ! 531: ! 532: /* find size of the window to get horz scaling, and see ! 533: * where click was ! 534: */ ! 535: GetClientRect(hwnd, &rc); ! 536: ! 537: /* was it near either of the bars ? */ ! 538: ! 539: /* horz positioning is in percentages of window width */ ! 540: xleft = max(L_UNMATCH_START + L_UNMATCH_WIDTH, ! 541: L_MATCH_START + L_MATCH_WIDTH); ! 542: xright = min(R_UNMATCH_START, R_MATCH_START); ! 543: xleft = xleft * (rc.right - rc.left) / 100; ! 544: xright = xright * (rc.right - rc.left) / 100; ! 545: ! 546: ! 547: if (x < xleft) { ! 548: bIsLeft = TRUE; ! 549: } else if (x > xright) { ! 550: bIsLeft = FALSE; ! 551: } else { ! 552: /* click was between the two bars - ignore it */ ! 553: return; ! 554: } ! 555: ! 556: ! 557: /* calculate the vertical scaling (based on total lines displayed) ! 558: * so that we can convert the y position into a line nr ! 559: */ ! 560: ! 561: /* get the handles to the two lists of sections */ ! 562: view = (VIEW) SendMessage(hwndClient, TM_CURRENTVIEW, 0, 0); ! 563: ! 564: /* make sure we are in expand mode */ ! 565: if (view_isexpanded(view) == FALSE) { ! 566: return; ! 567: } ! 568: ! 569: item = view_getitem(view, 0); ! 570: ! 571: listleft = compitem_getleftsections(item); ! 572: listright = compitem_getrightsections(item); ! 573: ! 574: /* ignore the click if only one list of sections, since in ! 575: * this case there is nothing drawn for him to click on. ! 576: */ ! 577: if ((listleft == NULL) || (listright == NULL)) { ! 578: return; ! 579: } ! 580: ! 581: /* take the longest of the two files and use this ! 582: * for vertical scaling. the scale is such that the longest file ! 583: * *just fits*. ! 584: */ ! 585: tot_left = line_getlinenr(section_getlastline(List_Last(listleft))); ! 586: tot_right = line_getlinenr(section_getlastline(List_Last(listright))); ! 587: ! 588: total_lines = max(tot_left, tot_right); ! 589: ! 590: ! 591: /* convert vertical position into a line nr. The vertical scaling ! 592: * can be calculated from knowing that the longest list of ! 593: * lines just fits in the window. ! 594: */ ! 595: linenr = (int) (((long) total_lines * y) / (rc.bottom - rc.top)) + 1; ! 596: ! 597: /* check that the line is valid */ ! 598: if (bIsLeft) { ! 599: if (linenr > tot_left) { ! 600: return; ! 601: } ! 602: } else { ! 603: if (linenr > tot_right) { ! 604: return; ! 605: } ! 606: } ! 607: ! 608: /* search the current view, looking for a row with this ! 609: * line nr on the correct side ! 610: */ ! 611: for (i = 0; i < view_getrowcount(view); i++) { ! 612: if (bIsLeft) { ! 613: this = view_getlinenr_left(view,i); ! 614: } else { ! 615: this = view_getlinenr_right(view,i); ! 616: } ! 617: ! 618: if (linenr == this) { ! 619: /* found the matching line- select it in the ! 620: * table window ! 621: */ ! 622: select.startrow = i; ! 623: select.startcell = 0; ! 624: select.nrows = 1; ! 625: select.ncells = 1; ! 626: SendMessage(hwndRCD, TM_SELECT, 0, (long) (LPSTR)&select); ! 627: return; ! 628: } ! 629: } ! 630: ! 631: windiff_UI(TRUE); ! 632: MessageBox(hwndClient, "Line not visible in this view", ! 633: "WinDiff", MB_ICONSTOP|MB_OK); ! 634: windiff_UI(FALSE); ! 635: } ! 636: ! 637:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.