home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / bar.c next >
C/C++ Source or Header  |  1997-10-05  |  20KB  |  637 lines

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