home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / opmsam.zip / GRAPH.CPP < prev    next >
C/C++ Source or Header  |  1993-06-15  |  12KB  |  463 lines

  1. /*  VCS_ID
  2.  *  $Filename:   graph.cxx
  3.  *  $Author  :   John Pompeii
  4.  *  $Revision:   1.1  $
  5.  *  $Date:   28 Dec 1991 14:18:26  $
  6.  */
  7.  
  8. // The Graph Demo Program
  9. // Written by John Pompeii, 1991
  10. //
  11. // The purpose of this program is to demonstrate the ObjectPM
  12. // drawing tools, as well as demonstrate the techniques required
  13. // build WYSIWYG programs.  The graph is rendered using wPen, wTextPen, 
  14. // wFillPattern, and outline wFont objects.  By not using any of the 
  15. // standard bitmap fonts, it is possible to accurately reproduce the
  16. // drawing on all of OS/2's output devices.
  17.  
  18.  
  19. extern "C"
  20. {
  21.     #include <stdio.h>
  22.     #include <stdlib.h>
  23. }
  24.  
  25. #define InclPrinters
  26. #define InclGraphics
  27. #define InclFixedMath
  28. #define InclProfiles
  29. #define InclForms
  30.  
  31.  
  32. #include <ObjectPM.hpp>
  33. #include "graph.hpp"
  34. #include "printdlg.hpp"
  35.  
  36.  
  37. short bMainThread :: Start()        // Program execution starts here
  38. {
  39.     GraphWindow w;                // Contstruct the top level frame window
  40.     Exec();                        // Go to the message loop.
  41.  
  42.     return 0;
  43. }
  44.  
  45. GraphWindow :: GraphWindow()
  46. {
  47.     CreateWindow(OpmStdFrame);                       // Create the frame
  48.     SetCaption("Graph");                              // Set captions
  49.     SetSwitchTitle("Graph Demo Program");
  50.     SetIcon(icon = new wIcon(ResIcon, I_OBJPM));   // Set the app's icon
  51.  
  52.     // This section create a menu bar and then adds items to the
  53.     // sub menu itself.  It is also possible to construct the menu
  54.     // from the resource file if desired
  55.  
  56.     menubar = new wMenu(this, MB_GRAPH, "~Graph\\~Exit\\");
  57.     menubar->SetSubMenuItems(MB_GRAPH, MI_OPTIONS, "~Options...;Printer ~Setup...;-;Print");
  58.     menubar->SetSubMenuItems(MB_EXIT, MI_EXIT, "Exit\tAlt+F4;Continue;");
  59.  
  60.     // Create a temporary system menu object for the purposes of adding
  61.     // a seperator and the "About..." menu item.
  62.  
  63.     wSysMenu sm(this);
  64.     sm.AppendSeparator();
  65.     sm.AppendItem(SC_ABOUT, "~About...");
  66.  
  67.     optionsDialog = new OptionsDialog(this);
  68.  
  69.     // Setup the initial position, scaling, and rotation...
  70.  
  71.     xGraphPos = 25;
  72.     yGraphPos = 25;
  73.     scale = 1.0;
  74.     aRotation = 0;
  75.  
  76.     // Create a device representing the client window
  77.  
  78.     winDC = new wWindowDevice(this);
  79.  
  80.     // Create a PrinterInfo object and construct a default
  81.     // PrinterSetup object...
  82.  
  83.     wPrinterInfo pi;
  84.     prSetup = pi.GetDefaultPrinter();
  85.  
  86.     // Create the initial wPresSpace object and some tools
  87.  
  88.     PrepPS();
  89.     Show();
  90.     ToTop();
  91. }
  92.  
  93. GraphWindow :: ~GraphWindow()
  94. {
  95.     DestroyPS();
  96.     delete icon;
  97.     delete optionsDialog;
  98. }
  99.  
  100.  
  101. void GraphWindow :: PrepPS()
  102. {
  103.     if ( prSetup && (prSetup->GetPort()).Length() )
  104.     {
  105.         // Create a wPresSpace object that has the exact page
  106.         // dimensions of the current print destination.     Although it
  107.         // it is not important in this application, true WYSIWYG apps
  108.         // must do this so that the display and printer are in sync.
  109.  
  110.         wPrinter printer(prSetup);
  111.         WindowPS() = new wPresSpace(&printer, PuLoMetric, PcReAssociate + PcRetain);
  112.         WindowPS()->AssociateDevice(winDC);
  113.     }
  114.     else
  115.         WindowPS() = new wPresSpace(winDC, PuLoMetric, PcReAssociate + PcRetain);
  116.  
  117.     CreateFonts(scFonts);
  118.     fonts = scFonts;
  119.  
  120.     // create a "bracket" wSubPicture
  121.  
  122.     bracket = new wSubPicture(WindowPS());
  123.     DrawBracket(wDimension(370, 50));
  124.     bracket->Close();
  125. }
  126.  
  127. void GraphWindow :: DestroyPS()
  128. {
  129.     delete bracket;
  130.     delete scFonts[0];
  131.     delete scFonts[1];
  132.     WindowPS()->DisAssociateDevice();
  133.     delete WindowPS();
  134.     WindowPS() = NULL;
  135. }
  136.  
  137. void GraphWindow :: CreateFonts(wFont **f)
  138. {
  139.     // Create the fonts using the "painfull" method.  The painfull method
  140.     // includes querying the fonts from the PS and creating the desired
  141.     // fonts using FontDef objects instead of the simple enumerated font
  142.     // types.  This is important because the wFont constructor that uses
  143.     // FontDef objects does not use a machine dependent font metric value
  144.     // called lMatch.
  145.  
  146.     // lMatch values are simply an index that allow the PM to create a
  147.     // font very quickly.  Without it, it must use a "best fit" algorythm
  148.     // to create a font that matches the desired font as much as possible.
  149.     // Although it is slower, the best fit method is independent of
  150.     // lMatches, and thus, when the "Create wFont" orders are stored in a
  151.     // print file or metafile no lMatches are used.  This makes these files
  152.     // conform to SAA standards as well as being machine independent.
  153.  
  154.     wFontDefList *fonts = 0;
  155.  
  156.     for (;;)
  157.     {
  158.         // First check if the PostScript fonts are installed...
  159.  
  160.         fonts = WindowPS()->EnumFonts("Helvetica");
  161.         if (fonts && fonts->First())
  162.         {
  163.             f[0] = new wFont((*fonts)(), WindowPS());
  164.             f[0]->ChangePointSize(8);
  165.             delete fonts;
  166.  
  167.             fonts = WindowPS()->EnumFonts("Helvetica Bold");
  168.             f[1] = new wFont((*fonts)(), WindowPS());
  169.             f[1]->ChangePointSize(10);
  170.             break;
  171.         }
  172.         if (fonts) delete fonts;
  173.  
  174.         // next, try the core Helv font.  Althought this should never
  175.         // fail,  it is possible on the OS/2 1.3 installation to not install
  176.         // this font!  It seems IBM may have gone a bit far in trying to 
  177.         // let users reduce the disk storage required for OS/2.
  178.  
  179.         fonts = WindowPS()->EnumFonts("Helv", FfOutline);
  180.         if (fonts && fonts->First())
  181.         {
  182.             f[0] = new wFont((*fonts)(), WindowPS());
  183.             f[0]->ChangePointSize(8);
  184.  
  185.             (*fonts)()->fsSelection = BoldFont;
  186.             f[1] = new wFont((*fonts)(), WindowPS());
  187.             f[1]->ChangePointSize(10);
  188.             break;
  189.         }
  190.  
  191.         f[0] = new wFont(SysMono10, 0, WindowPS());
  192.         f[1] = new wFont(SysMono12, 0, WindowPS());
  193.         break;
  194.     }
  195.     if (fonts) delete fonts;
  196. }
  197.  
  198.  
  199. // The MenuCommand member is sent a Command message each time
  200. // an item on the menu bar is selected.
  201.  
  202. long GraphWindow :: MenuCommand(wCommandMsg m)
  203. {
  204.     switch(m.usCmd())
  205.     {
  206.         case MI_OPTIONS:
  207.             optionsDialog->FormUp(this);
  208.             if (optionsDialog->GetResult())
  209.                 break;                            // repaint if "OK" pressed
  210.             else
  211.                 return FALSE;
  212.  
  213.  
  214.         case MI_PRINT:
  215.             PrintGraph();
  216.             break;
  217.  
  218.         case MI_SETUP:
  219.             {
  220.                 PrintDlg pd(this, prSetup);
  221.                 prSetup = pd.GetSetup();
  222.                 
  223.                 if (pd.IsChanged())
  224.                 {
  225.                     // re-create the wPresSpace if the printer setup changed.
  226.                     // athough we are being lazy here, a real application 
  227.                     // would most likely verify that either the printer 
  228.                      // or the form changed before going through all this work.
  229.  
  230.                     HourGlass();
  231.                     DestroyPS();    // destroy current PS
  232.                     PrepPS();        // create new PS with updated page size
  233.                     HourGlass();
  234.                     break;
  235.                 }
  236.             }
  237.             return FALSE;
  238.  
  239.         case SC_ABOUT:
  240.             {
  241.                 AboutDialog aboutWin(this);         // Create the "about" box
  242.                 return FALSE;
  243.             }
  244.  
  245.         case MI_EXIT:
  246.             CurrentThread->Quit();
  247.             return FALSE;
  248.  
  249.     }
  250.     RePaint();        // invalidate the client window 
  251.  
  252.     return FALSE;
  253. }
  254.  
  255. void GraphWindow :: PrintGraph()
  256. {
  257.     wFont *prFonts[2];
  258.  
  259.     HourGlass();
  260.     wPrinter printer(prSetup);
  261.     WindowPS()->AssociateDevice(&printer);
  262.  
  263.     printer.StartPrintJob("Hardcopy Graph");
  264.     CreateFonts(prFonts);
  265.     fonts = prFonts;
  266.  
  267.     Paint();
  268.     printer.EndPrintJob();
  269.  
  270.     delete prFonts[0];
  271.     delete prFonts[1];
  272.     fonts = scFonts;
  273.  
  274.     WindowPS()->AssociateDevice(winDC);
  275.     HourGlass();
  276. }
  277.  
  278.  
  279. void GraphWindow :: Paint()
  280. {
  281.  
  282.     static ushort vals[] = { 150, 130, 250, 75, 100, 83, 120, 150, 200, 180, 200, 160 }; 
  283.     char wbuf[40];
  284.     int i;
  285.  
  286.     // Create some drawing tools to work with.  Unlike fonts, pens
  287.     // and textpens are fast to create.     
  288.  
  289.     wPen pen(WindowPS());
  290.     wFillPattern fillPat(WindowPS());
  291.     fillPat.SetBackMix(BmOverPaint);
  292.     wTextPen textPen(WindowPS());
  293.     textPen.SetBufferSize(40);
  294.  
  295.     // Adjust the page orientation 
  296.  
  297.     WindowPS()->Erase();
  298.  
  299.     if (aRotation)
  300.         WindowPS()->SetPageRotation(aRotation);
  301.  
  302.     if (scale != 1)
  303.         WindowPS()->SetPageScale(scale, scale, TransformAdd);
  304.  
  305.     WindowPS()->SetPageOrigin(wPointl(xGraphPos * 10, yGraphPos * 10), TransformAdd);
  306.  
  307.     // Draw the axis of the graph in a wide line (at the page origin)
  308.     // Note that we must use a path to do this since it is the only
  309.     // mechanism available to draw lines wider that 1 pel.
  310.  
  311.     pen.MoveTo(0, 700);
  312.     pen.SetGeomLineWidth(3);
  313.     pen.BeginPath();
  314.     pen.LineTo(0, 0);
  315.     pen.LineTo(1250, 0);
  316.     pen.PaintPath();
  317.  
  318.     // Draw the horizontal grid    lines 
  319.  
  320.     pen.SetColor(ClrPaleGray);
  321.  
  322.     for (i = 1; i < 8; i++)
  323.     {
  324.         pen.MoveTo(2, i * 100);
  325.         pen.LineTo(1250, i * 100);
  326.     }
  327.  
  328.     // Draw the colored bars using a wFillPattern object to 
  329.     // to fill the interior of the boxes drawn with the wPen object
  330.  
  331.     pen.SetColor(ClrBlack);
  332.  
  333.     for (i = 0; i < 12; i++)
  334.     {
  335.         switch (i % 4)
  336.         {
  337.             case 0:
  338.                 fillPat.SetColor(ClrDarkRed);
  339.                 fillPat.SetPattern(PatDense8);
  340.                 break;
  341.             case 1:
  342.                 fillPat.SetColor(ClrDarkBlue);     
  343.                 fillPat.SetPattern(PatDense7);
  344.                 break;
  345.             case 2:
  346.                 fillPat.SetColor(ClrDarkGreen);     
  347.                 fillPat.SetPattern(PatDense6);
  348.                 break;
  349.             case 3:
  350.                 fillPat.SetColor(ClrRed);     
  351.                 fillPat.SetPattern(PatSolid);
  352.                 break;
  353.         }
  354.         pen.Box(wRectl(wPointl(100 * i, 2), wDimension(101, vals[i] * 2)), 
  355.                 DoOutlineFill);
  356.     }
  357.  
  358.     // Now using an 8 point outline font, draw the horizontal units
  359.  
  360.     textPen.PenDown(fonts[0]);     // PenDown causes the wTextPen and the
  361.                                 // wFont to be the current wTextPen and wFont
  362.  
  363.     long yBaseline = -((long)((float)textPen.MaxCharHeight() * 1.5));
  364.  
  365.     for (i = 0; i < 12; i++)
  366.         textPen.Printf((100 * i) + 23, yBaseline, "Q%d", (i % 4) + 1);
  367.     
  368.  
  369.     // draw the brackets and years
  370.  
  371.     for (i = 0; i < 3; i++)
  372.      {
  373.         char year[5];
  374.         wPointl p;
  375.         
  376.         p.x() = (i * 400) + 15;
  377.         p.y() = -((textPen.MaxCharHeight() * 2) + 50);
  378.         bracket->Draw(p, TransformAdd);
  379.  
  380.         sprintf(year, "%d", 1988 + i);
  381.         textPen.Display(p.x() + (185 - (textPen.TextSize(year).xWidth()) / 2),
  382.                         p.y() - 50, year);
  383.     }
  384.  
  385.     // Draw the y-axis units
  386.  
  387.     float o = 0.0;
  388.  
  389.     for (i = 0; i < 8; i++, o += .5)
  390.     {
  391.         char nBuf[8];
  392.  
  393.         sprintf(nBuf, "%.2f", o);
  394.         textPen.Display(-(30 + textPen.TextSize(nBuf).xWidth()),    // x-pos
  395.                        (i * 100) - (textPen.MaxCharHeight() / 2),      // y-pos
  396.                        nBuf);                                          // text
  397.     }
  398.  
  399.     // draw the y-axis title
  400.  
  401.     textPen.PenDown(fonts[1]);
  402.     textPen.SetBaselineAngle(wPointl(0, 10));
  403.     textPen.Display(wPointl(-150, 100), "Earnings per share");
  404.     textPen.SetBaselineAngle(wPointl(1, 0));
  405.  
  406.     // draw the graph's title
  407.  
  408.     textPen.Display(425, 625, "History of Earnings");
  409.     WindowPS()->SetPageOrigin(wPointl(0, 0));
  410. }
  411.  
  412. void GraphWindow :: DrawBracket(wDimension siz)
  413. {
  414.     long basHeight, tailHeight, basArc, tailArc;
  415.     wPen p (WindowPS());
  416.  
  417.      basHeight  = siz.yHeight() / 3;
  418.     tailHeight = siz.yHeight() - basHeight;
  419.  
  420.     siz.xWidth() /= 2;
  421.     basArc  = (long)(((float)basHeight * 0.7) + 0.5);
  422.     tailArc = (long)(((float)tailHeight * 0.7) + 0.5);
  423.  
  424.     WindowPS()->SetModelTransl(wPointl(siz.xWidth(), 0), TransformAdd);
  425.  
  426.     // run through a loop twice.  First to draw the right side of the
  427.     // brace, and then secondly, draw the left side using a reflection
  428.     // transform
  429.  
  430.     for (short i = 0; i < 2; i++)
  431.     {
  432.         p.MoveTo(0,0);
  433.         p.Arc(wPointl(basHeight - basArc, basArc), wPointl(basHeight, basHeight));
  434.         p.LineTo(siz.xWidth() - tailHeight, basHeight);
  435.         p.Arc(wPointl((siz.xWidth() - tailHeight) + tailArc, basHeight + (tailHeight - tailArc)),
  436.              (wPointl&)siz);
  437.  
  438.         if (!i)
  439.             WindowPS()->SetModelScale(-1, 1, wPointl(0, 0), TransformPreempt);
  440.     }
  441. }
  442.  
  443. /* Options Form.... */
  444.  
  445. OptionsDialog :: OptionsDialog(GraphWindow *win) :
  446.     wFormWindow(D_OPTIONS, 4, 0, DlgModal)
  447. {
  448.     // define wEditField objects
  449.  
  450.     AddField( new wEditField(FtLong, 4, E_XPOS, &win->xGraphPos, NULL, FsRequired) );
  451.     AddField( new wEditField(FtLong, 4, E_YPOS, &win->yGraphPos, NULL, FsRequired) );
  452.     AddField( new wEditField(FtDouble, 6, E_SCALE, &win->scale, NULL, FsRequired) );
  453.     AddField( new wEditField(FtShort, 4, E_ROTATE, &win->aRotation, NULL, FsRequired) );
  454.     SetActionButtons(BUT_CANCEL, BUT_OK, 0);
  455. }
  456.  
  457. short OptionsDialog :: Init()
  458. {
  459.     ChangePosition(PosCenter, OwnerWindow());
  460.     return TRUE; 
  461. }
  462.  
  463.