home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / SAMPLES / SHOWGDI / VIEW.C_ / VIEW.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  11.8 KB  |  350 lines

  1. /****************************************************************************
  2.  View.c
  3.  
  4.  The View module handles the display of the drawing view.
  5.  
  6. ****************************************************************************/
  7.  
  8. #include "windows.h"
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include "MENU.h"
  13.  
  14. #include "util.h"
  15. #include "main.h"
  16. #include "dialogs.h"
  17. #include "dc.h"
  18.  
  19. #include "view.h"
  20.  
  21.  
  22. /****************************************************************************
  23.    Private constants
  24. ****************************************************************************/
  25.  
  26. #define MIN_LABEL_MARGIN   2     /* minimum margin between labels (pixels) */
  27. #define TICK_HEIGHT        4     /* height of tick for grid label (pixels) */
  28. #define TICK_WIDTH         4     /* width of tick for grid label (pixels) */
  29.  
  30.  
  31. /****************************************************************************
  32.    Globals
  33. ****************************************************************************/
  34.  
  35. POINT    drawSize = { 256, 256 };   /* size of off-screen bitmap in pixels */
  36. HDC      drawDC = NULL;             /* the off-screen DC */
  37. BOOL     isBlank = TRUE;            /* TRUE iff drawing is blank */
  38. BOOL     pixGrid = TRUE;            /* TRUE iff pixel grid showing */
  39. int      viewScale = DEFAULT_SCALE; /* scale factor for drawing -> view */
  40.  
  41.  
  42. /****************************************************************************
  43.    Private Data
  44. ****************************************************************************/
  45.  
  46. static HBITMAP  stockBmp = NULL;           /* stock off-screen bitmap */
  47. static HFONT    labelFont = NULL;          /* font for grid labels */
  48. static int      labelFontAscent;           /* ascent of labelFont */
  49. static DWORD    rgbMajorGrid = RGB(0, 0, 255);      /* color of major grid */
  50. static DWORD    rgbMinorGrid = RGB(128, 128, 128);  /* color of minor grid */
  51.  
  52.  
  53. /****************************************************************************
  54.    Functions
  55. ****************************************************************************/
  56.  
  57. int NewView( void )
  58. /* Create a new off-screen drawing (destroy existing one if any). */
  59. {
  60.    HDC         hdcMain = NULL;
  61.    HBITMAP     drawBmp = NULL;
  62.    LOGFONT     lf;
  63.    TEXTMETRIC  tm;
  64.    HFONT       prevFont;
  65.  
  66.    /* Destroy existing DC and bitmap, if any */
  67.    if (drawDC != NULL) {
  68.       drawBmp = SelectObject( drawDC, stockBmp );
  69.       if (drawBmp != NULL) {
  70.          DeleteObject( drawBmp );
  71.       }
  72.       DeleteDC( drawDC );
  73.    }
  74.  
  75.    /* Create a compatible DC and off-screen bitmap */    
  76.    hdcMain = GetDC( hwndMain );
  77.    drawDC = CreateCompatibleDC( hdcMain );
  78.    if (drawDC == NULL)
  79.       goto errorExit;
  80.    drawBmp = CreateCompatibleBitmap( hdcMain, drawSize.x, drawSize.y );
  81.    if (drawBmp == NULL)
  82.       goto errorExit;
  83.    stockBmp = SelectObject( drawDC, drawBmp );
  84.  
  85.    /* Create label font if not already created -- use a small Helv font. */
  86.    if (labelFont == NULL) {
  87.       lf.lfHeight = 10;
  88.       lf.lfWidth = 0;
  89.       lf.lfEscapement = lf.lfOrientation = 0;
  90.       lf.lfWeight = 400;
  91.       lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
  92.       lf.lfCharSet = ANSI_CHARSET;
  93.       lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  94.       lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  95.       lf.lfQuality = PROOF_QUALITY;    /* no stretching */
  96.       lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
  97.       strcpy( lf.lfFaceName, "Helv");
  98.       labelFont = CreateFontIndirect( &lf );
  99.       if (labelFont == NULL) 
  100.          goto errorExit;
  101.       prevFont = SelectObject( hdcMain, labelFont );
  102.       GetTextMetrics( hdcMain, &tm );
  103.       labelFontAscent = tm.tmAscent - tm.tmInternalLeading;
  104.       SelectObject( hdcMain, prevFont );
  105.    }
  106.  
  107.    ReleaseDC( hwndMain, hdcMain );
  108.    ClearView();
  109.    return TRUE;
  110.  
  111. errorExit:
  112.    if (drawBmp != NULL) {
  113.       DeleteObject( drawBmp );
  114.       drawBmp = NULL;
  115.    }
  116.    if (drawDC != NULL) {
  117.       DeleteDC( drawDC );
  118.       drawDC = NULL;
  119.    }
  120.    ReleaseDC( hwndMain, hdcMain );
  121.    return FALSE;
  122. }
  123.  
  124.  
  125. void ClearView( void )
  126. /* Clear the drawing. */
  127. {
  128.    RECT  r;
  129.    
  130.    SetRect( &r, -BIGINT, -BIGINT, BIGINT, BIGINT );
  131.    FillRect( drawDC, &r, (HBRUSH) GetStockObject( WHITE_BRUSH ) );
  132.    isBlank = TRUE;
  133. }
  134.  
  135.  
  136. void PaintView( HDC hdc, RECT r )
  137. /* Repaint the view of the drawing in portion 'r' of 'hdc'. */
  138. {
  139.    RECT     rDraw, rView, rBlt, rGray;
  140.    HPEN     penMajor, penMinor, prevPen;
  141.    HFONT    prevFont;
  142.    int      x, y, xEnd, yEnd;
  143.    int      labelHeight, xLabelWidth, yLabelWidth;
  144.    int      labelStep;
  145.    int      labelValue;
  146.    char     label[8];
  147.    int      shift;
  148.  
  149.    StartWait();
  150.  
  151.    /* Compute drawing view rectangle and needed drawing metrics */
  152.    GetClientRect( hwndMain, &rView );
  153.    if (pixGrid ) {
  154.       /* Create pens for major and minor gridlines and select label font */
  155.       penMajor = CreatePen( PS_SOLID, 0, rgbMajorGrid );
  156.       penMinor = CreatePen( PS_SOLID, 0, rgbMinorGrid );
  157.       prevPen = SelectObject( hdc, penMinor );
  158.       SetTextColor( hdc, rgbMajorGrid );
  159.       prevFont = SelectObject( hdc, labelFont );
  160.  
  161.       /* Compute height for labels */
  162.       labelHeight = HIWORD( GetTextExtent( hdc, "0", 1 ) ) + MIN_LABEL_MARGIN;
  163.  
  164.       /* Compute width for labels on the x scale as approx max of leftmost
  165.          and rightmost label widths plus minimum pixel margin. */
  166.       itoa( -dcv.viewportOrg.x, label, 10 );
  167.       xLabelWidth = LOWORD( GetTextExtent( hdc, label, strlen( label ) ) )
  168.             + MIN_LABEL_MARGIN;
  169.       itoa( -dcv.viewportOrg.x + Width( rView ) / viewScale + 1, label, 10 );
  170.       xLabelWidth = Max( xLabelWidth, LOWORD( GetTextExtent( hdc, label, 
  171.             strlen( label ) ) ) + MIN_LABEL_MARGIN );
  172.  
  173.       /* Compute width for labels on the y scale as approx max of topmost
  174.          and bottommost label widths plus minimum pixel margin. */
  175.       itoa( -dcv.viewportOrg.y, label, 10 );
  176.       yLabelWidth = LOWORD( GetTextExtent( hdc, label, strlen( label ) ) )
  177.             + MIN_LABEL_MARGIN;
  178.       itoa( -dcv.viewportOrg.y + Height( rView ) / viewScale + 1, label, 10 );
  179.       yLabelWidth = Max( yLabelWidth, LOWORD( GetTextExtent( hdc, label, 
  180.             strlen( label ) ) ) + MIN_LABEL_MARGIN );
  181.  
  182.       /* Compute step for label values so that step is a power of 2 and 
  183.          allows at least enough room for the x label width. */
  184.       labelStep = xLabelWidth / viewScale + 1;
  185.       for (shift = 0; labelStep > 1; shift++) {
  186.          labelStep >>= 1;
  187.       }
  188.       labelStep <<= (shift + 1);
  189.  
  190.       /* Allow room for scale area to top and left of viewing rectangle */
  191.       rView.left += yLabelWidth + TICK_WIDTH + MIN_LABEL_MARGIN;
  192.       rView.top += labelHeight + TICK_HEIGHT + MIN_LABEL_MARGIN;
  193.    }
  194.    xEnd = Min( rView.right, 
  195.                ToIntegerPin( rView.left + (long) drawSize.x * viewScale ) );
  196.    yEnd = Min( rView.bottom, 
  197.                ToIntegerPin( rView.top + (long) drawSize.y * viewScale ) );
  198.  
  199.    /* Gray the off-drawing portion of the view rectangle, if any */
  200.    if (xEnd < rView.right ) {
  201.       SetRect( &rGray, xEnd + 1, rView.top, rView.right + 1, rView.bottom + 1 );
  202.       FillRect( hdc, &rGray, GetStockObject( GRAY_BRUSH ) );
  203.    }
  204.    if (yEnd < rView.bottom ) {
  205.       SetRect( &rGray, rView.left, yEnd + 1, rView.right + 1, rView.bottom + 1 );
  206.       FillRect( hdc, &rGray, GetStockObject( GRAY_BRUSH ) );
  207.    }
  208.    
  209.    /* Copy update portion of drawing from off-screen bitmap */
  210.    IntersectRect( &rBlt, &r, &rView );
  211.    rDraw.left = Max( 0, Min( drawSize.x, 
  212.          (rBlt.left - rView.left) / viewScale - 1) );
  213.    rDraw.top = Max( 0, Min( drawSize.y, 
  214.          (rBlt.top - rView.top) / viewScale - 1) );
  215.    rDraw.right = Max( 0, Min( drawSize.x, 
  216.          (rBlt.right - rView.left) / viewScale + 1) );
  217.    rDraw.bottom = Max( 0, Min( drawSize.y, 
  218.          (rBlt.bottom - rView.top) / viewScale + 1) );
  219.    rBlt.left   = rDraw.left * viewScale + rView.left;
  220.    rBlt.top    = rDraw.top * viewScale + rView.top;
  221.    rBlt.right  = rDraw.right * viewScale + rView.left;
  222.    rBlt.bottom = rDraw.bottom * viewScale + rView.top;
  223.    if (isBlank) {
  224.       rBlt.right += 1;
  225.       rBlt.bottom += 1;
  226.       FillRect( hdc, &rBlt, GetStockObject( WHITE_BRUSH ) );
  227.    }else{
  228.       StretchBlt( hdc, rBlt.left, rBlt.top, Width( rBlt ), Height( rBlt ),
  229.                   drawDC, rDraw.left, rDraw.top, Width( rDraw ), 
  230.                   Height( rDraw ), SRCCOPY );
  231.    }
  232.  
  233.    /* Draw pixel grid and scale if showing */
  234.    if (pixGrid) {
  235.       /* Draw major and minor x grid lines, and ticks with labels at each 
  236.          major grid line (each label step) */
  237.       SetTextAlign( hdc, TA_CENTER | TA_BOTTOM );
  238.       for (x = rView.left; x <= xEnd; x += viewScale ) {
  239.          labelValue = (x - rView.left) / viewScale - dcv.viewportOrg.x;
  240.          MoveTo( hdc, x, yEnd );
  241.          if (labelValue % labelStep == 0) {
  242.             /* Major gridline with tick and label */
  243.             SelectObject( hdc, penMajor );
  244.             LineTo( hdc, x, rView.top - TICK_HEIGHT );
  245.             itoa( labelValue, label, 10 );
  246.             TextOut( hdc, x, rView.top - TICK_HEIGHT, label, strlen( label ) );
  247.          }else if (viewScale > 2) {
  248.             /* Minor gridline */
  249.             SelectObject( hdc, penMinor );
  250.             LineTo( hdc, x, rView.top );
  251.          }
  252.       }
  253.  
  254.       /* Draw major and minor y grid lines, and ticks with labels at each 
  255.          major grid line (each label step) */
  256.       SetTextAlign( hdc, TA_RIGHT | TA_BASELINE );
  257.       for (y = rView.top; y <= yEnd; y += viewScale ) {
  258.          labelValue = (y - rView.top) / viewScale - dcv.viewportOrg.y;
  259.          MoveTo( hdc, xEnd, y );
  260.          if (labelValue % labelStep == 0) {
  261.             /* Major gridline with tick and label */
  262.             SelectObject( hdc, penMajor );
  263.             LineTo( hdc, rView.left - TICK_WIDTH, y );
  264.             itoa( labelValue, label, 10 );
  265.             TextOut( hdc, rView.left - TICK_WIDTH - MIN_LABEL_MARGIN, 
  266.                      y + labelFontAscent / 2, label, strlen( label ) );
  267.          }else if (viewScale > 2) {
  268.             /* Minor gridline */
  269.             SelectObject( hdc, penMinor );
  270.             LineTo( hdc, rView.left, y );
  271.          }
  272.       }
  273.  
  274.       /* Clean up */
  275.       SelectObject( hdc, prevPen );
  276.       DeleteObject( penMajor );
  277.       DeleteObject( penMinor );
  278.       SelectObject( hdc, prevFont );
  279.    }
  280.  
  281.    EndWait();
  282. }
  283.  
  284.  
  285. void RefreshView( BOOL erase )
  286. /* Invalidate the screen view for redraw, erasing first iff 'erase'. */
  287. {
  288.    InvalidateRect( hwndMain, NULL, erase );
  289. }
  290.  
  291.  
  292. void ViewCmd( int item )
  293. /* Run the command for menu item 'item' from the View menu. */
  294. {
  295.    switch (item) {
  296.       case IDM_CLEAR:
  297.          ClearView();
  298.          RefreshView( FALSE );
  299.          break;
  300.  
  301.       case IDM_DRAWINGSIZE:
  302.          if (Dlg( DrawingSizeDlg )) {
  303.             NewView();
  304.             RefreshView( TRUE );
  305.          }
  306.          break;
  307.  
  308.       case IDM_NORMALSIZE:
  309.          viewScale = 1;
  310.          RefreshView( TRUE );
  311.          break;
  312.  
  313.       case IDM_ZOOMIN:
  314.          viewScale *= 2;
  315.          if (viewScale > MAX_SCALE ) {
  316.             viewScale = MAX_SCALE;
  317.          }
  318.          RefreshView( TRUE );
  319.          break;
  320.  
  321.       case IDM_ZOOMOUT:
  322.          viewScale /= 2;
  323.          if (viewScale < MIN_SCALE ) {
  324.             viewScale = MIN_SCALE;
  325.          }
  326.          RefreshView( TRUE );
  327.          break;
  328.  
  329.       case IDM_SETSCALE:
  330.          if (Dlg( SetScaleDlg )) {
  331.             RefreshView( TRUE );
  332.          }
  333.          break;
  334.  
  335.       case IDM_PIXGRID:
  336.          pixGrid ^= TRUE;
  337.          RefreshView( TRUE );
  338.          break;
  339.    }
  340. }
  341.  
  342.  
  343. void CheckViewMenuItems( HMENU hMenu )
  344. /* Update enabling and checks on the menus in the View menu. */
  345. {
  346.    EnableMenuCmd( hMenu, IDM_ZOOMIN, (viewScale < MAX_SCALE) );
  347.    EnableMenuCmd( hMenu, IDM_ZOOMOUT, (viewScale > MIN_SCALE) );
  348.    CheckMenuCmd( hMenu, IDM_PIXGRID, pixGrid );
  349. }
  350.