|
|
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.