home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / krcls012.zip / KrClass / demo / demo.cpp next >
C/C++ Source or Header  |  1997-02-24  |  25KB  |  504 lines

  1. // Kroni's Classes: Demonstration of many abilities in one guided tour
  2. // (c) 1997 Wolfgang Kronberg
  3. // file: demo.cpp
  4.  
  5.  
  6. // ************************************************************************* //
  7. //                   Demonstration of Kroni's Classes                        //
  8. //                                                                           //
  9. //                               Guided tour                                 //
  10. // ************************************************************************* //
  11.  
  12. #define IC_TRACE_ALL                             // Activate full tracing even in non-critical situations
  13.  
  14. #include "krcto.hpp"                             // Support to re-route cout to a window
  15. #include "krbwin.hpp"                            // Support for bitmap-buffered graphics
  16. #include "krprint.hpp"                           // Support for printing
  17. #include "krgobj.hpp"                            // Support for special graphics objects
  18.                                                  //   includes krcstran.hpp for coordinate systems
  19. #include "krasyncm.hpp"                          // Support for asynchronous main function
  20. #include "krwc.hpp"                              // Support for windowed communication
  21. #include "krtrace.hpp"                           // Support for exception handling
  22.  
  23. #include <isplitcv.hpp>                          // ISplitCanvas
  24. #include <icheckbx.hpp>                          // ICheckBox
  25. #include <ientryfd.hpp>                          // IEntryField
  26. #include <imsgbox.hpp>                           // IMessageBox
  27.  
  28.  
  29. // First, we must derive a class from the virtual class KrAsyncMain in a standard way:
  30.  
  31. class MyMain : public KrAsyncMain
  32. {
  33. public:
  34.   MyMain (IWindow * mainWindow) : KrAsyncMain (mainWindow) {};
  35.                                                  // We must forward the original object's only constructor
  36.   virtual void main (IEvent & event);            // This will be our actual new main function
  37. };
  38.  
  39.  
  40. // All global window objects should be declared static and before all functions.
  41. //   This is the comon UICL way to define a frame window and its childs:
  42.  
  43. static IFrameWindow mainWindow ("Demonstration of Kroni's Classes", 0x1000);
  44.                                                  // Our main window
  45. static ISplitCanvas split (IC_FRAME_CLIENT_ID, &mainWindow, &mainWindow);
  46.                                                  // A canvas to hold the various sub-windows we need for
  47.                                                  //   this demonstration
  48. static KrCommonTextOutput text (0x1001, &split, &split);
  49.                                                  // This window will hold all text output, e.g. for use
  50.                                                  //   with common cout.
  51. static IDrawingCanvas iDraw (0x1002, &split, &split);
  52.                                                  // This window will hold general graphics output. We will
  53.                                                  //   later use it to hold a KrMemoryBitmap object.
  54. static KrDrawingCanvas krDraw (0x1003, &split, &split);
  55.                                                  // Another window, just like the previous one, but we want
  56.                                                  //   to put graphics objects in there associated with an
  57.                                                  //   KrCoordSystemTranslator object.
  58.  
  59. // The following will demonstrate how to prepare any kind of object for user input.
  60. //   This is a little bit sophisticated; skip it on first read  and
  61. //   go on at the definition of MyMain::main ().
  62.  
  63. // This is the object we want to input: a combination of string and boolean,
  64. //   the boolean indicating whether the string has any meaning.
  65.  
  66. class BoolString
  67. {
  68. public:
  69.   BoolString (const IString & s = "", Boolean b = false) {string = s; boolean = b;};
  70.   IString string;
  71.   Boolean boolean;
  72. };
  73.  
  74. // All user defined input is done by a class derived from KrUserDataField:
  75.  
  76. class BoolStringInput : public KrUserDataField
  77. {
  78. public:
  79.  
  80.   BoolStringInput (BoolString & b);              // The constructor (there's no work to do for the
  81.                                                  //   base class)
  82.   ~BoolStringInput ();                           // The same goes for the destructor.
  83.  
  84.   virtual Boolean transform (Boolean doIt);      // These two functions *must* be overwritten.
  85.   virtual int initialize (IMultiCellCanvas & c, int start);
  86.  
  87. private:
  88.  
  89.   BoolString * theVariable;                      // Pointer to the variable we want to input
  90.  
  91.   IMultiCellCanvas * canvas;                     // Some windows we'll need to accept user input
  92.   ICheckBox * checkBox;
  93.   IEntryField * entryField;
  94. };
  95.  
  96. // Now let's define BoolStringInput's member functions.
  97.  
  98. BoolStringInput::BoolStringInput (BoolString & b)
  99. {
  100.   theVariable = &b;
  101.   canvas = 0; checkBox = 0; entryField = 0;      // To indicate that those are not constructed yet.
  102. };
  103.  
  104. BoolStringInput::~BoolStringInput ()
  105. {
  106.   if (canvas) delete canvas;
  107.   if (checkBox) delete checkBox;
  108.   if (entryField) delete entryField;
  109. };
  110.  
  111. Boolean BoolStringInput::transform (Boolean doIt)
  112.                                                  // Here, we transform the data in the windows which
  113.                                                  //   the user typed his input in to the variable itself.
  114. {
  115.   if (!doIt)                                     // No action should take place
  116.      return true;                                // This means that the user input is OK (he couldn't
  117.                                                  //   possibly do anything wrong).
  118.  
  119.   if (canvas && checkBox && entryField)          // If you don't shrew it up yourself, this should
  120.      {                                           //   always be the case.
  121.      theVariable -> boolean = checkBox -> isSelected ();
  122.                                                  // This gives the user input straight to the variable.
  123.      theVariable -> string = entryField -> text ();
  124.      }
  125.   else                                           // This can't happen, but we're careful...
  126.      {
  127.      KRNAMEDTHROW("Windows undefined!","Kroni's Classes Demo");
  128.      };
  129.   return true;                                   // User input is ok (s.a.).
  130. };
  131.  
  132. int BoolStringInput::initialize (IMultiCellCanvas & c, int start)
  133.                                                  // This function draws the windows for user input.
  134. {
  135.   if (canvas) delete canvas;                     // Clean up if neccessary
  136.   if (checkBox) delete checkBox;
  137.   if (entryField) delete entryField;
  138.  
  139.   canvas = new IMultiCellCanvas (
  140.                  0x1000 + 0x40 * start,          // This window ID + the next 0x3f are save to use.
  141.                  &c, &c                          // c must own the top level of windows you're building.
  142.                );
  143.  
  144.   checkBox = new ICheckBox (0x1000, canvas, canvas);
  145.                                                  // You are free to choose any window IDs for windows
  146.                                                  //   on lower levels.
  147.   entryField = new IEntryField (0x1001, canvas, canvas);
  148.  
  149.   checkBox -> select (theVariable->boolean);     // Initialize the check box with the boolean variable
  150.                                                  //   it is meant to represent on input
  151.   entryField -> setText (theVariable->string);   // dto. for the string variable
  152.  
  153.   // The cleanest way to show windows in the dialog is to put them into a canvas (if they are more
  154.   //   than one) and to put this canvas into c at cell (4,start).
  155.  
  156.   canvas->addToCell (checkBox,1,1);
  157.   canvas->addToCell (entryField,2,1);
  158.   c.addToCell (canvas,4,start);
  159.  
  160.   return ++start;                                // Return the first unoccupied line in c.
  161. };
  162.  
  163.  
  164. // Next define the asynchronous main function. Doing calculations here does not block message processing.
  165.  
  166. void MyMain::main (IEvent & event)               // Do in this effective main function whatever you want!
  167. {                                                //   However, please note that this function - unlike the
  168.                                                  //   usual main() - will be left before the program exits.
  169.                                                  //   Make sure to define all variables as static or use
  170.                                                  //   new / delete for objects which must survive the exit
  171.                                                  //   of the function.
  172.  
  173.   switch (event.parameter1())                    // Use this to define the different parts of your program
  174.      {
  175.      case cmdStartUp:                            // This part will be run when the program first comes up.
  176.                                                  //   You may define more commands (e.g. as menu entries or
  177.                                                  //   as subprocedures to be called from here) and add them
  178.                                                  //   to this switch instruction.
  179.  
  180.   // We will use a common UICL message box to guide the user through the demo as he runs it.
  181.  
  182.         IMessageBox msgBox (0);                  // Use desktop as parent to make the box non-modal
  183.         msgBox.setTitle ("Kroni's Classes Demo - Next Action");
  184.         IMessageBox::Style msgBoxStyle =
  185.           IMessageBox::okButton | IMessageBox::informationIcon | IMessageBox::moveable;
  186.  
  187.         msgBox.show ("Welcome to this demo of Kroni's Classes!\n\n"
  188.                      "From left to right, you see:\n"
  189.                      "- a KrCommonTextOutput object\n"
  190.                      "      (used to diplay text on the screen)\n"
  191.                      "- an IDrawingCanvas object\n"
  192.                      "      (the common UICL graphics surface)\n"
  193.                      "- a KrDrawingCanvas object\n"
  194.                      "      (the IDrawingCanvas equivalent in Kroni's Classes)\n"
  195.                      "\nFeel free to rearrange the windows however you like!\n"
  196.                      "To stop this demo at any time, just close its main window.", msgBoxStyle);
  197.  
  198.   // Here the action takes place! Let's have a look at what Kroni's Classes can do.
  199.  
  200.   // Here's how to re-route text output to a GUI window:
  201.  
  202.         cout = text.stream();                    // Assign the KrTextOutput object's stream to cout
  203.         cout.setf (ios::unitbuf);                // Unfortunately, the above line does not copy this property
  204.  
  205.         msgBox.show ("You are able to output text\n"
  206.                      "using common C++ stream operators like <<.", msgBoxStyle);
  207.  
  208.   // Now we can use cout as we would in text mode programs:
  209.  
  210.         cout << "Here's a little test of\nKroni's Class Library!\n";
  211.  
  212.   // Of course, re-routing of cout is not necessary. You can also use the stream directly:
  213.  
  214.         text.stream() << "\nYou may both re-route cout or access the GUI stream directly.\n";
  215.  
  216.   // We draw a cross using common IOCL methods...
  217.  
  218.         static IGLine line1 (IPoint(0,0), IPoint(300,300));
  219.         static IGLine line2 (IPoint(0,300), IPoint(300,0));
  220.         static IGList crossList;
  221.         crossList.addAsFirst (line1);
  222.         crossList.addAsFirst (line2);
  223.  
  224.   // ...and display it on both drawing areas:
  225.  
  226.         msgBox.show ("Kroni's Classes peacefully coexist\n"
  227.                      "with the IBM Open Class Library they're based on.\n\n"
  228.                      "Do demonstrate this, we draw a cross\n"
  229.                      "using the common UICL classes in the middle window.\n"
  230.                      "Try resizing the window to see how the UICL reacts.",
  231.                      msgBoxStyle);
  232.  
  233.         iDraw.setGraphicList (&crossList);
  234.         iDraw.refresh();
  235.  
  236.         msgBox.show ("The drawing canvas from Kroni's Classes (right window)\n"
  237.                      "is completely compatible and shows the same behaviour.",
  238.                      msgBoxStyle);
  239.  
  240.         krDraw.setGraphicList (&crossList);
  241.         krDraw.refresh();
  242.  
  243.   // We now put the cross into a memory bitmap:
  244.  
  245.         static KrMemoryBitmap mbm (300,300);
  246.         mbm.setList (crossList);
  247.  
  248.   // This memory bitmap can be shown using common IOCL methods:
  249.  
  250.         static IGList mbmList;
  251.         mbmList.addAsFirst (mbm);
  252.  
  253.         msgBox.show ("If you draw complex graphics on the screen,\n"
  254.                      "redrawing can take a lot of time.\n"
  255.                      "One solution is to do the complex drawing on a memory bitmap.\n"
  256.                      "When the screen is redrawn, it is then sufficient to do a simple\n"
  257.                      "copy operation from the memory to the screen.\n\n"
  258.                      "The demo will now substitute the cross in the middle window\n"
  259.                      "with a memory bitmap into which the very same cross is drawn.\n"
  260.                      "You won't notice any difference.",
  261.                      msgBoxStyle);
  262.  
  263.         iDraw.setGraphicList (&mbmList);
  264.         iDraw.refresh();
  265.  
  266.         msgBox.show ("Again, we do the same for the right window.\n"
  267.                      "Again, there won't be any difference.",
  268.                      msgBoxStyle);
  269.  
  270.         krDraw.setGraphicList (&mbmList);
  271.         krDraw.refresh();
  272.  
  273.   // Now let's do some graphics with user-friendly scaling methods.
  274.  
  275.   // This defines a coordinate system with a range from -1 to 1 on both axes.
  276.  
  277.         static KrCoordSystemTranslator trans (KrPoint(0,-1),KrPoint(1,1));
  278.  
  279.   // Within this coordinate system, we draw some graphics
  280.  
  281.         static KrGLine mLine1 (trans, KrPoint (0,-1), KrPoint (1,0));
  282.         static KrGLine mLine2 (trans, KrPoint (0,0), KrPoint (1,-1));
  283.         static KrGString mText (trans, "Kroni's Classes", KrPoint(0.5,0.5));
  284.  
  285.   // To collect graphics using a coordinate system, we need a KrGraphicList object instead of IGraphicList.
  286.  
  287.         static KrGraphicList mList (trans);
  288.  
  289.   // We use the common IOCL methods to get our graphics on the screen:
  290.  
  291.         mList.addAsFirst (mLine1);
  292.         mList.addAsFirst (mLine2);
  293.         mList.addAsFirst (mText);
  294.  
  295.         msgBox.show ("With Kroni's Classes, it is possible to draw pictures\n"
  296.                      "using an arbitrary coordinate system instead of pixel units.\n\n"
  297.                      "Try resizing the right window, into which an example is drawn,\n"
  298.                      "and note how the picture is resized automatically\n"
  299.                      "to always fit the new window size.",
  300.                      msgBoxStyle);
  301.  
  302.         krDraw.setGraphicList (&mList);
  303.         krDraw.refresh();
  304.  
  305.   // Now we want a unit on the y-axis to appear exactely as long as a unit on the x-axis.
  306.   //   That means, we want to have an aspect ratio of 1.
  307.  
  308.         msgBox.show ("It is, however, also possible to preserve the aspect ratio.\n"
  309.                      "In this case, the picture will still be as large as possible\n"
  310.                      "*under the condition* that the aspect ratio is preserved.\n\n"
  311.                      "Please note that 'as large as possible' means that the whole\n"
  312.                      "coordinate system must fit in. In the following example, the cross\n"
  313.                      "occupies only the lower half of the coordinate system.\n\n"
  314.                      "If the cross in the right window does not cover the space\n"
  315.                      "of an exakt square, your graphics driver gives wrong\n"
  316.                      "information about the aspect ratio.\n"
  317.                      "This error, however, should not be too large.",
  318.                      msgBoxStyle);
  319.  
  320.         trans.setAspectRatio (1);
  321.         krDraw.refresh();
  322.  
  323.   // All of this also works with memory bitmaps.
  324.  
  325.         msgBox.show ("Of course, you can also draw into memory bitmaps.\n"
  326.                      "using the coordinate system method.\n"
  327.                      "However, the bitmap is generally not automatically resized.\n\n"
  328.                      "Have a look at the middle window to find out\n"
  329.                      "what that means.",
  330.                      msgBoxStyle);
  331.  
  332.         mbm.setList (mList);
  333.         iDraw.refresh ();
  334.  
  335.         msgBox.show ("If you *really* want to resize a memory bitmap\n"
  336.                      "automatically according to the window size, however,\n"
  337.                      "there's a way to do it: assign a coordinate system to it.\n\n"
  338.                      "Note, however, that a resized bitmap is often ugly.\n"
  339.                      "Note also, that drawing in a coordinate system requires a\n"
  340.                      "KrDrawingCanvas, so that the bitmap in this example must be\n"
  341.                      "removed from the middle window; only the right can show it.\n\n"
  342.                      "When writing your own programs, do yourself a favor by\n"
  343.                      "using only KrDrawingCanvas and never IDrawingCanvas,\n"
  344.                      "even if you currently don't use coordinate systems.",
  345.                      msgBoxStyle);
  346.  
  347.         static IGList emptyList;                 // An empty list for the IDrawingCanvas
  348.         iDraw.setGraphicList (&emptyList);
  349.         iDraw.refresh();
  350.  
  351.         static KrCoordSystemTranslator trans2 (KrPoint(0,0),KrPoint(1,1));
  352.         static KrGraphicList m2List (trans2);    // We use a new coordinate system
  353.                                                  //   without fixed aspect ratio for fitting the bitmap
  354.         m2List.addAsFirst (mbm);
  355.         mbm.setCoordSystem (&trans2, KrPoint (0,0), KrPoint (1,1));
  356.                                                  // The bitmap should cover the whole coordinate system
  357.         krDraw.setGraphicList (&m2List);
  358.         krDraw.refresh ();
  359.  
  360.   // Let's have a look at what frames do.
  361.  
  362.         static KrGraphicList fList (trans);
  363.  
  364.         msgBox.show ("The mighty frame concept lets you place arbitrary\n"
  365.                      "complex pictures easily into subsections of the screen.\n\n"
  366.                      "This is especially useful for printing.\n",
  367.                      msgBoxStyle);
  368.  
  369.   // We add a frame in the upper left area, enter our picture there, and remove the frame.
  370.  
  371.         KrFrame frame1 (trans,KrPoint(0.05,0.05),0.4);
  372.         KrAntiFrame aFrame (trans);
  373.         fList.addAsLast (frame1);
  374.         fList.addAsLast (mList);
  375.         fList.addAsLast (aFrame);
  376.  
  377.   // Now we add a frame in the lower right area, enter the same picture there, and remove the frame.
  378.  
  379.         KrFrame frame2 (trans,KrPoint(0.55,-0.95),0.4);
  380.         fList.addAsLast (frame2);
  381.         fList.addAsLast (mList);
  382.         fList.addAsLast (aFrame);
  383.  
  384.   // We draw the whole picture in the KrDrawingCanvas.
  385.  
  386.         krDraw.setGraphicList (&fList);
  387.         krDraw.refresh ();
  388.  
  389.   // Removing all frames is neccessary to leave trans unframed for the next redraw.
  390.   //   It is possible (but not desired for redraw) to have frames in frames.
  391.  
  392.  
  393.   // We will not only look at the above object, but print it. First, create a KrPrinter object.
  394.  
  395.         static KrPrinter printer;
  396.  
  397.   // You can select any IGList (that means, also KrGraphicsList) into the KrPrinter object.
  398.  
  399.         printer.setList (fList);
  400.  
  401.         msgBox.show ("Kroni's Classes let you print everything what you can draw.\n"
  402.                      "It also provides the neccessary dialogs for user interaction.\n\n"
  403.                      "If you press OK in the next dialog, the picture from the\n"
  404.                      "right window will be printed! Press cancel instead of OK\n"
  405.                      "in the next dialog if you don't want this to happen,\n"
  406.                      "but be sure to try the settings button before that!",
  407.                      msgBoxStyle);
  408.  
  409.   // You might want to give the user the chance to chhoses the printer and set its options.
  410.  
  411.         if (printer.printDialog ())
  412.  
  413.   // Then all you have to do ist call the print command. The string parameter is diplayed in the spooler.
  414.  
  415.             printer.print ("KrClasses Demo");
  416.  
  417.   // Now let's have a look at the windowed communication classes.
  418.  
  419.         msgBox.show ("The last part of this demo shows a very easy way\n"
  420.                      "to query for user input using the common >> operator.\n\n"
  421.                      "The KrWinComm class will collect the input variables\n"
  422.                      "and put them all into a dialog window.\n\n"
  423.                      "The user can change the data and press either OK or\n"
  424.                      "Cancel. In the latter case, the variables remain unchanged.",
  425.                      msgBoxStyle);
  426.  
  427.         static KrWinComm kwc ("TestDialog");     // This defines the dialog object itself and sets its title
  428.  
  429.         static IString s = "Test Text";          // We define some arbitrary variables.
  430.         static double d = 38.75;                 //   Since their values are shown to the user, they
  431.         static unsigned long l = 1024;           //   must be initialized.
  432.         static signed long ls = -2048;
  433.  
  434.         static KrBitfield bf;                    // This is how to give the user options (check boxes)
  435.         int bf1 = bf.add ("Option One");
  436.         int bf2 = bf.add ("Option Two");
  437.  
  438.         static KrChoice ch;                      // This is how to offer the user a choice (radio buttons)
  439.         int ch1 = ch.add ("Choice One");
  440.         int ch2 = ch.add ("Choice Two");
  441.         ch.set (ch1);                            // Some choice should be set by default.
  442.  
  443.         static BoolString bs ("Optional string", true);
  444.                                                  // All kind of self-defined variables can be used...
  445.         static BoolStringInput bsi (bs);         // ...but they must be wrapped into a corresponding object
  446.                                                  //   to define the appearence on the screen.
  447.  
  448.         kwc << "Enter a string here:" >> s       // The input is done using the common >> operator.
  449.                                                  //   In addition, the << operator can be used to
  450.                                                  //   put comments for the input variables into the dialog.
  451.             << "Enter a floating point number here:" >> d
  452.             << "Enter an unsigned integer here:" >> l
  453.             << "Enter a signed integer here:" >> ls
  454.             << "Select whatever options you like:" >> bf
  455.             << "Choose one of these:" >> ch
  456.             << "Enter a string or not:" >> bsi
  457.             << display;                          // The "display" manipulator actually displays and
  458.                                                  //   evaluates the dialog. It may be used with both the
  459.                                                  //   >> and the << operator.
  460.  
  461.         cout << "\nResults of your Input:"       // This is to test the success.
  462.              << "\nString: " << s
  463.              << "\nFloating Point: " << d
  464.              << "\nUnsigned int: " << l
  465.              << "\nSigned int: " << ls
  466.              << "\nOption 1: " << bf.isChecked(bf1)
  467.              << "\nOption 2: " << bf.isChecked(bf2)
  468.              << "\nChoice: " << ch.get ()
  469.              << "\nOptional String: " << bs.boolean << " / " << bs.string;
  470.  
  471.  
  472.         msgBox.show ("Thank you for trying Kroni's Classes!\n\n"
  473.                      "To leave the program, close the main window.",
  474.                      msgBoxStyle);
  475.  
  476.         break;                                   // Our effective main program ends here.
  477.      };
  478. };
  479.  
  480.  
  481. int main (int argc, char **argv, char **envv)    // This should include all initial window definitions;
  482. {                                                //   the other stuff should be in MyMain::main().
  483.   IApplication::current().setArgs(argc,argv);    // This is "good style" when using the UICL.
  484.                                                  //   Do always include this line.
  485.   KrTrace::traceTo ();                           // Create log file
  486.   KrTrace::tellUser (KrTrace::full);             // Give the user full information in a popup window
  487.                                                  //   if any exception occurs!
  488.  
  489.   // First, we must make sure that our window is shown on the screen.
  490.   //   This is ordinary UICL code.
  491.  
  492.   mainWindow.setClient (&split);
  493.   mainWindow.sizeTo (ISize(800,500));
  494.   mainWindow.setFocus ();
  495.   mainWindow.show ();
  496.  
  497.   // These should always be the very last statements in the main() function:
  498.  
  499.   MyMain myMain (&mainWindow);                   // initializes the use of the function MyMain::main
  500.   IApplication::current().run();
  501.   return 0;
  502. };
  503.  
  504.