From 306dfc2b3d49ca45445bdfb2164fe1eea45ab321 Mon Sep 17 00:00:00 2001
From: Julian Smart <julian@anthemion.co.uk>
Date: Sun, 7 Feb 1999 23:56:40 +0000
Subject: [PATCH] Removed small OGL glitches; added new sample

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1640 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 utils/ogl/samples/ogledit/ogledit.cpp         |    6 +-
 utils/ogl/samples/studio/bitmaps/alignb.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/alignb.xpm   |   24 +
 utils/ogl/samples/studio/bitmaps/alignl.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/alignl.xpm   |   24 +
 utils/ogl/samples/studio/bitmaps/alignr.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/alignr.xpm   |   24 +
 utils/ogl/samples/studio/bitmaps/alignt.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/alignt.xpm   |   24 +
 utils/ogl/samples/studio/bitmaps/arrow.bmp    |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/bitmaps/arrow.xpm    |   31 +
 utils/ogl/samples/studio/bitmaps/bitmap1.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/bitmap2.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/copy.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/copy.xpm     |   25 +
 utils/ogl/samples/studio/bitmaps/copysize.bmp |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/copysize.xpm |   24 +
 utils/ogl/samples/studio/bitmaps/cut.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/cut.xpm      |   24 +
 utils/ogl/samples/studio/bitmaps/cutpoint.bmp |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/cutpoint.xpm |   25 +
 utils/ogl/samples/studio/bitmaps/file1.ico    |  Bin 0 -> 1078 bytes
 utils/ogl/samples/studio/bitmaps/folder1.ico  |  Bin 0 -> 1078 bytes
 utils/ogl/samples/studio/bitmaps/help.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/help.xpm     |   24 +
 utils/ogl/samples/studio/bitmaps/helpcs.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/helpcs.xpm   |   24 +
 utils/ogl/samples/studio/bitmaps/horiz.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/horiz.xpm    |   24 +
 .../ogl/samples/studio/bitmaps/linearrow.bmp  |  Bin 0 -> 238 bytes
 .../ogl/samples/studio/bitmaps/linearrow.xpm  |   25 +
 utils/ogl/samples/studio/bitmaps/new.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/new.xpm      |   24 +
 utils/ogl/samples/studio/bitmaps/newpoint.bmp |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/newpoint.xpm |   25 +
 utils/ogl/samples/studio/bitmaps/open.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/open.xpm     |   26 +
 utils/ogl/samples/studio/bitmaps/paste.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/paste.xpm    |   27 +
 utils/ogl/samples/studio/bitmaps/preview.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/preview.xpm  |   26 +
 utils/ogl/samples/studio/bitmaps/print.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/print.xpm    |   26 +
 utils/ogl/samples/studio/bitmaps/redo.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/redo.xpm     |   25 +
 utils/ogl/samples/studio/bitmaps/save.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/save.xpm     |   25 +
 utils/ogl/samples/studio/bitmaps/straight.bmp |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/straight.xpm |   24 +
 utils/ogl/samples/studio/bitmaps/texttool.bmp |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/bitmaps/texttool.xpm |   31 +
 utils/ogl/samples/studio/bitmaps/tick.bmp     |  Bin 0 -> 220 bytes
 utils/ogl/samples/studio/bitmaps/tick.xpm     |  Bin 0 -> 6101 bytes
 utils/ogl/samples/studio/bitmaps/toback.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/toback.xpm   |   25 +
 utils/ogl/samples/studio/bitmaps/tofront.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/tofront.xpm  |   25 +
 utils/ogl/samples/studio/bitmaps/undo.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/undo.xpm     |   25 +
 utils/ogl/samples/studio/bitmaps/vert.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/bitmaps/vert.xpm     |   24 +
 utils/ogl/samples/studio/cspalette.cpp        |  153 +++
 utils/ogl/samples/studio/cspalette.h          |   57 +
 utils/ogl/samples/studio/csprint.cpp          |  318 +++++
 utils/ogl/samples/studio/dialogs.cpp          |  525 ++++++++
 utils/ogl/samples/studio/dialogs.h            |  248 ++++
 utils/ogl/samples/studio/doc.cpp              |  598 +++++++++
 utils/ogl/samples/studio/doc.h                |  134 ++
 utils/ogl/samples/studio/mainfrm.cpp          |  256 ++++
 utils/ogl/samples/studio/mainfrm.h            |   55 +
 utils/ogl/samples/studio/makefile.unx         |   39 +
 utils/ogl/samples/studio/makefile.vc          |  143 ++
 utils/ogl/samples/studio/manual/BACK.GIF      |  Bin 0 -> 225 bytes
 utils/ogl/samples/studio/manual/BULLET.BMP    |  Bin 0 -> 138 bytes
 utils/ogl/samples/studio/manual/CONTENTS.GIF  |  Bin 0 -> 231 bytes
 utils/ogl/samples/studio/manual/FORWARD.GIF   |  Bin 0 -> 164 bytes
 utils/ogl/samples/studio/manual/Makefile      |   29 +
 utils/ogl/samples/studio/manual/Tex2rtf.ini   |   20 +
 utils/ogl/samples/studio/manual/UP.GIF        |  Bin 0 -> 137 bytes
 utils/ogl/samples/studio/manual/abacus.bmp    |  Bin 0 -> 566 bytes
 utils/ogl/samples/studio/manual/alignb.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/alignl.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/alignr.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/alignt.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/arrow.bmp     |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/manual/bitmap1.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/bitmap2.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/brush.bmp     |  Bin 0 -> 740 bytes
 utils/ogl/samples/studio/manual/calc.bmp      |  Bin 0 -> 702 bytes
 utils/ogl/samples/studio/manual/chart.bmp     |  Bin 0 -> 600 bytes
 utils/ogl/samples/studio/manual/colour.bmp    |  Bin 0 -> 734 bytes
 utils/ogl/samples/studio/manual/copy.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/copysize.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/cut.bmp       |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/cutpoint.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/files.bmp     |  Bin 0 -> 672 bytes
 utils/ogl/samples/studio/manual/help.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/helpcs.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/horiz.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/linearrow.bmp |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/magnify.bmp   |  Bin 0 -> 722 bytes
 utils/ogl/samples/studio/manual/mike.bmp      |  Bin 0 -> 708 bytes
 utils/ogl/samples/studio/manual/new.bmp       |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/newpoint.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/open.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/page.bmp      |  Bin 0 -> 714 bytes
 utils/ogl/samples/studio/manual/paste.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/pointsize.bmp |  Bin 0 -> 538 bytes
 utils/ogl/samples/studio/manual/preview.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/print.bmp     |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/redo.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/save.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/screw.bmp     |  Bin 0 -> 636 bytes
 utils/ogl/samples/studio/manual/shapes.bmp    |  Bin 0 -> 780 bytes
 utils/ogl/samples/studio/manual/speaker.bmp   |  Bin 0 -> 648 bytes
 utils/ogl/samples/studio/manual/straight.bmp  |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/studio.tex    |  381 ++++++
 utils/ogl/samples/studio/manual/telephon.bmp  |  Bin 0 -> 676 bytes
 utils/ogl/samples/studio/manual/texttool.bmp  |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/manual/therm.bmp     |  Bin 0 -> 812 bytes
 utils/ogl/samples/studio/manual/tick.bmp      |  Bin 0 -> 220 bytes
 utils/ogl/samples/studio/manual/toback.bmp    |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/tofront.bmp   |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/tool1.bmp     |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/manual/tool2.bmp     |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/manual/tool3.bmp     |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/manual/tool4.bmp     |  Bin 0 -> 382 bytes
 utils/ogl/samples/studio/manual/torch.bmp     |  Bin 0 -> 706 bytes
 utils/ogl/samples/studio/manual/undo.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/vert.bmp      |  Bin 0 -> 238 bytes
 utils/ogl/samples/studio/manual/wrench.bmp    |  Bin 0 -> 744 bytes
 utils/ogl/samples/studio/manual/zoom.bmp      |  Bin 0 -> 790 bytes
 utils/ogl/samples/studio/project.cpp          |   89 ++
 utils/ogl/samples/studio/project.h            |   42 +
 utils/ogl/samples/studio/shapes.cpp           | 1185 +++++++++++++++++
 utils/ogl/samples/studio/shapes.h             |  258 ++++
 utils/ogl/samples/studio/studio.cpp           |  510 +++++++
 utils/ogl/samples/studio/studio.h             |  171 +++
 utils/ogl/samples/studio/studio.ico           |  Bin 0 -> 766 bytes
 utils/ogl/samples/studio/studio.rc            |   41 +
 utils/ogl/samples/studio/studio.xpm           |   44 +
 utils/ogl/samples/studio/studio_resources.h   |   44 +
 utils/ogl/samples/studio/studio_resources.wxr |  191 +++
 utils/ogl/samples/studio/symbols.cpp          |  203 +++
 utils/ogl/samples/studio/symbols.h            |   76 ++
 utils/ogl/samples/studio/view.cpp             | 1039 +++++++++++++++
 utils/ogl/samples/studio/view.h               |  141 ++
 utils/ogl/src/mfutils.h                       |    2 +-
 148 files changed, 7673 insertions(+), 5 deletions(-)
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignb.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignb.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignl.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignl.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignr.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignr.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignt.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/alignt.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/arrow.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/arrow.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/bitmap1.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/bitmap2.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/copy.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/copy.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/copysize.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/copysize.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/cut.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/cut.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/cutpoint.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/cutpoint.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/file1.ico
 create mode 100644 utils/ogl/samples/studio/bitmaps/folder1.ico
 create mode 100644 utils/ogl/samples/studio/bitmaps/help.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/help.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/helpcs.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/helpcs.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/horiz.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/horiz.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/linearrow.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/linearrow.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/new.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/new.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/newpoint.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/newpoint.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/open.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/open.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/paste.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/paste.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/preview.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/preview.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/print.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/print.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/redo.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/redo.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/save.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/save.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/straight.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/straight.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/texttool.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/texttool.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/tick.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/tick.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/toback.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/toback.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/tofront.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/tofront.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/undo.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/undo.xpm
 create mode 100644 utils/ogl/samples/studio/bitmaps/vert.bmp
 create mode 100644 utils/ogl/samples/studio/bitmaps/vert.xpm
 create mode 100644 utils/ogl/samples/studio/cspalette.cpp
 create mode 100644 utils/ogl/samples/studio/cspalette.h
 create mode 100644 utils/ogl/samples/studio/csprint.cpp
 create mode 100644 utils/ogl/samples/studio/dialogs.cpp
 create mode 100644 utils/ogl/samples/studio/dialogs.h
 create mode 100644 utils/ogl/samples/studio/doc.cpp
 create mode 100644 utils/ogl/samples/studio/doc.h
 create mode 100644 utils/ogl/samples/studio/mainfrm.cpp
 create mode 100644 utils/ogl/samples/studio/mainfrm.h
 create mode 100644 utils/ogl/samples/studio/makefile.unx
 create mode 100644 utils/ogl/samples/studio/makefile.vc
 create mode 100644 utils/ogl/samples/studio/manual/BACK.GIF
 create mode 100644 utils/ogl/samples/studio/manual/BULLET.BMP
 create mode 100644 utils/ogl/samples/studio/manual/CONTENTS.GIF
 create mode 100644 utils/ogl/samples/studio/manual/FORWARD.GIF
 create mode 100644 utils/ogl/samples/studio/manual/Makefile
 create mode 100644 utils/ogl/samples/studio/manual/Tex2rtf.ini
 create mode 100644 utils/ogl/samples/studio/manual/UP.GIF
 create mode 100644 utils/ogl/samples/studio/manual/abacus.bmp
 create mode 100644 utils/ogl/samples/studio/manual/alignb.bmp
 create mode 100644 utils/ogl/samples/studio/manual/alignl.bmp
 create mode 100644 utils/ogl/samples/studio/manual/alignr.bmp
 create mode 100644 utils/ogl/samples/studio/manual/alignt.bmp
 create mode 100644 utils/ogl/samples/studio/manual/arrow.bmp
 create mode 100644 utils/ogl/samples/studio/manual/bitmap1.bmp
 create mode 100644 utils/ogl/samples/studio/manual/bitmap2.bmp
 create mode 100644 utils/ogl/samples/studio/manual/brush.bmp
 create mode 100644 utils/ogl/samples/studio/manual/calc.bmp
 create mode 100644 utils/ogl/samples/studio/manual/chart.bmp
 create mode 100644 utils/ogl/samples/studio/manual/colour.bmp
 create mode 100644 utils/ogl/samples/studio/manual/copy.bmp
 create mode 100644 utils/ogl/samples/studio/manual/copysize.bmp
 create mode 100644 utils/ogl/samples/studio/manual/cut.bmp
 create mode 100644 utils/ogl/samples/studio/manual/cutpoint.bmp
 create mode 100644 utils/ogl/samples/studio/manual/files.bmp
 create mode 100644 utils/ogl/samples/studio/manual/help.bmp
 create mode 100644 utils/ogl/samples/studio/manual/helpcs.bmp
 create mode 100644 utils/ogl/samples/studio/manual/horiz.bmp
 create mode 100644 utils/ogl/samples/studio/manual/linearrow.bmp
 create mode 100644 utils/ogl/samples/studio/manual/magnify.bmp
 create mode 100644 utils/ogl/samples/studio/manual/mike.bmp
 create mode 100644 utils/ogl/samples/studio/manual/new.bmp
 create mode 100644 utils/ogl/samples/studio/manual/newpoint.bmp
 create mode 100644 utils/ogl/samples/studio/manual/open.bmp
 create mode 100644 utils/ogl/samples/studio/manual/page.bmp
 create mode 100644 utils/ogl/samples/studio/manual/paste.bmp
 create mode 100644 utils/ogl/samples/studio/manual/pointsize.bmp
 create mode 100644 utils/ogl/samples/studio/manual/preview.bmp
 create mode 100644 utils/ogl/samples/studio/manual/print.bmp
 create mode 100644 utils/ogl/samples/studio/manual/redo.bmp
 create mode 100644 utils/ogl/samples/studio/manual/save.bmp
 create mode 100644 utils/ogl/samples/studio/manual/screw.bmp
 create mode 100644 utils/ogl/samples/studio/manual/shapes.bmp
 create mode 100644 utils/ogl/samples/studio/manual/speaker.bmp
 create mode 100644 utils/ogl/samples/studio/manual/straight.bmp
 create mode 100644 utils/ogl/samples/studio/manual/studio.tex
 create mode 100644 utils/ogl/samples/studio/manual/telephon.bmp
 create mode 100644 utils/ogl/samples/studio/manual/texttool.bmp
 create mode 100644 utils/ogl/samples/studio/manual/therm.bmp
 create mode 100644 utils/ogl/samples/studio/manual/tick.bmp
 create mode 100644 utils/ogl/samples/studio/manual/toback.bmp
 create mode 100644 utils/ogl/samples/studio/manual/tofront.bmp
 create mode 100644 utils/ogl/samples/studio/manual/tool1.bmp
 create mode 100644 utils/ogl/samples/studio/manual/tool2.bmp
 create mode 100644 utils/ogl/samples/studio/manual/tool3.bmp
 create mode 100644 utils/ogl/samples/studio/manual/tool4.bmp
 create mode 100644 utils/ogl/samples/studio/manual/torch.bmp
 create mode 100644 utils/ogl/samples/studio/manual/undo.bmp
 create mode 100644 utils/ogl/samples/studio/manual/vert.bmp
 create mode 100644 utils/ogl/samples/studio/manual/wrench.bmp
 create mode 100644 utils/ogl/samples/studio/manual/zoom.bmp
 create mode 100644 utils/ogl/samples/studio/project.cpp
 create mode 100644 utils/ogl/samples/studio/project.h
 create mode 100644 utils/ogl/samples/studio/shapes.cpp
 create mode 100644 utils/ogl/samples/studio/shapes.h
 create mode 100644 utils/ogl/samples/studio/studio.cpp
 create mode 100644 utils/ogl/samples/studio/studio.h
 create mode 100644 utils/ogl/samples/studio/studio.ico
 create mode 100644 utils/ogl/samples/studio/studio.rc
 create mode 100644 utils/ogl/samples/studio/studio.xpm
 create mode 100644 utils/ogl/samples/studio/studio_resources.h
 create mode 100644 utils/ogl/samples/studio/studio_resources.wxr
 create mode 100644 utils/ogl/samples/studio/symbols.cpp
 create mode 100644 utils/ogl/samples/studio/symbols.h
 create mode 100644 utils/ogl/samples/studio/view.cpp
 create mode 100644 utils/ogl/samples/studio/view.h

diff --git a/utils/ogl/samples/ogledit/ogledit.cpp b/utils/ogl/samples/ogledit/ogledit.cpp
index d6172e37db..87f19e6e85 100644
--- a/utils/ogl/samples/ogledit/ogledit.cpp
+++ b/utils/ogl/samples/ogledit/ogledit.cpp
@@ -177,13 +177,11 @@ void MyFrame::OnSize(wxSizeEvent& event)
 
 void MyFrame::OnCloseWindow(wxCloseEvent& event)
 {
-  if (wxDocParentFrame::OnClose())
+  wxDocParentFrame::OnCloseWindow(event);
+  if (!event.GetVeto())
   {
     wxOGLCleanUp();
-    this->Destroy();
   }
-  else
-    event.Veto();
 }
 
 // Intercept menu commands
diff --git a/utils/ogl/samples/studio/bitmaps/alignb.bmp b/utils/ogl/samples/studio/bitmaps/alignb.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6cc2e1dee47c12433ba418577a2e5ad73fab4848
GIT binary patch
literal 238
zcma(~u?>JQ3^NiN1DwGf?EKP+GUlZ2U3w8O1iKLn5)y7~M{(M2`-Q+kTgio-$pIr3
yIJ<@@69WdYU=~JYi`E)lf%k&DI+8~tN`4^$nJY-O<f+#3>D*JU>wjJEKHuH!bxvFW

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/alignb.xpm b/utils/ogl/samples/studio/bitmaps/alignb.xpm
new file mode 100644
index 0000000000..c3b57a5869
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/alignb.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *alignb_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+"        ........",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+" .....  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .....  ........",
+"                ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/alignl.bmp b/utils/ogl/samples/studio/bitmaps/alignl.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..30471101b16de3328c3d7a9ddbb74c95669b30c1
GIT binary patch
literal 238
zcmaKju@QhU3<Jd-ca$&&bI`L(Dxl0r^l35?D};BPbR3E$*^#~Nj~oZK!UfK7(1=P`
yRTs;Qjwn%z(G8_l&Kb9$)KV$dL7sgfXGb6qV@Tls@wV6Rx^q8S&;7TzyzRf`G)$2I

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/alignl.xpm b/utils/ogl/samples/studio/bitmaps/alignl.xpm
new file mode 100644
index 0000000000..6d7def92fb
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/alignl.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *alignl_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+"   ......       ",
+"   .XXXX.       ",
+"   .XXXX.       ",
+"   .XXXX.       ",
+"   ......       ",
+"                ",
+"                ",
+"   ...........  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   ...........  ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/alignr.bmp b/utils/ogl/samples/studio/bitmaps/alignr.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..14a2f85241d5a0f1985c58e88c06b64a606b7764
GIT binary patch
literal 238
zcmaKju@QhU3<Jd-9R-ZR9Q5px3MexYeVR<f3gI1-I|>fPl58tp)=Q2Jo8bgU*r`XQ
zqpFK#Mn{w=#ps68D(8$_P->|Z>mbio$leeL#26AdfBgB^?p|K+nFqW7@RnP41Lmtt
AkpKVy

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/alignr.xpm b/utils/ogl/samples/studio/bitmaps/alignr.xpm
new file mode 100644
index 0000000000..3f873eed4e
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/alignr.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *alignr_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+"        ......  ",
+"        .XXXX.  ",
+"        .XXXX.  ",
+"        .XXXX.  ",
+"        ......  ",
+"                ",
+"                ",
+"   ...........  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   ...........  ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/alignt.bmp b/utils/ogl/samples/studio/bitmaps/alignt.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4505cbab566385942c0912c245668a2567a6e4a9
GIT binary patch
literal 238
zcmaKkF%Ez*3<HhC#sJUY9qjz26EOBk>|OdIzEIAs*ie($j$$j@{;1V~tY85%7&OAt
xRk@Kpqg9j`#n=R9Rn8f;QR=7^Z-Dj*I)92ty-z9KwtE_g+7Cp#O78pXpD*v#PFw&0

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/alignt.xpm b/utils/ogl/samples/studio/bitmaps/alignt.xpm
new file mode 100644
index 0000000000..65fc1b5ccb
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/alignt.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *alignt_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+" .....  ........",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .....  .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        ........",
+"                ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/arrow.bmp b/utils/ogl/samples/studio/bitmaps/arrow.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d406ceb64f017d99bcc2d4913aef75135de357a0
GIT binary patch
literal 382
zcmb7-I}U&#5JZQ>1WPN=;5qEQ3zc?;o59U+Ka+r!5!mH1Gr)e_0X9zQo7Bn*m`tDP
z>tSJ;fdXA9#W(4KsI?;JEJm}1)|8}VswC~|<Acp+X5bX{1r^dYaP*|<cro+>bu-BQ
Vombvu=JhAub(#Nm-N`e*_yJ^>eVzaS

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/arrow.xpm b/utils/ogl/samples/studio/bitmaps/arrow.xpm
new file mode 100644
index 0000000000..e7cab6ae18
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/arrow.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static char *arrow_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    22    22        2            1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+/* pixels */
+"######################",
+"######################",
+"######################",
+"######################",
+"######################",
+"#######.##############",
+"#######..#############",
+"#######...############",
+"#######....###########",
+"#######.....##########",
+"#######......#########",
+"#######.......########",
+"#######........#######",
+"#######.....##########",
+"#######..#..##########",
+"#######.###..#########",
+"###########..#########",
+"############..########",
+"############..########",
+"######################",
+"######################",
+"######################"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/bitmap1.bmp b/utils/ogl/samples/studio/bitmaps/bitmap1.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..13e2170b7369879a97bdd01c57b42af6f4126264
GIT binary patch
literal 238
zcmZup$qj%o3^Ni^o-hV;@Mo922+wZTPQ(hutwBPF)JM*)+X=-^TgaK5$N?i2IJ*8x
z1_<OVqcTM)1t}#CY6og<8OhgLlnA1Qhq=kkUmmbtM;O|i2QpqLp4!xR(~o{Hd|gKu
Dh|EVQ

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/bitmap2.bmp b/utils/ogl/samples/studio/bitmaps/bitmap2.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3d523b2de9cb376db72fd364c6d4cdb7f2e4da9a
GIT binary patch
literal 238
zcmZvW!3{z&3`32C)MFWgIk>Y+Pr$L8wG(}1gYeu+p9^X1)J~P=@jSHSMY)3;sNkY2
zEPWRLqal$RV;7jK=A7!i)5w*|^bK%qLGNEQTGkCeTtf<*)|jz0bZVCKqs&^|_qZ0`
QxOhk{d)WGeIhJR90ll(R-T(jq

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/copy.bmp b/utils/ogl/samples/studio/bitmaps/copy.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4551a06bfa79e0a42c1ffb7cdbb90fd4f699dce2
GIT binary patch
literal 238
zcmZvVK?*`K3`9pLxU9$U91{2|@hV+>tjiv)Cz3AyzP{vxy7<$~OeTT!c7JQf6T89-
z%<!ayO0Uo(X%eN@c0*~^d&hk-qco>?kmn<${;(P#uFN<0A#FuUo(qgT{&F@ekspii
W=d@ZzPG(Cb=QBs}_=7thzxV(viB<;y

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/copy.xpm b/utils/ogl/samples/studio/bitmaps/copy.xpm
new file mode 100644
index 0000000000..47565c1cae
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/copy.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *copy_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 4 1",
+"  c None",
+". c Black",
+"X c Gray100",
+"o c #000080",
+/* pixels */
+"                ",
+" ......         ",
+" .XXXX..        ",
+" .XXXX.X.       ",
+" .X..X.oooooo   ",
+" .XXXXXoXXXXoo  ",
+" .X....oXXXXoXo ",
+" .XXXXXoX..Xoooo",
+" .X....oXXXXXXXo",
+" .XXXXXoX.....Xo",
+" ......oXXXXXXXo",
+"       oX.....Xo",
+"       oXXXXXXXo",
+"       ooooooooo",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/copysize.bmp b/utils/ogl/samples/studio/bitmaps/copysize.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..36060ad72b54ea2be52e4a1ed7b4dda2ca3cf18f
GIT binary patch
literal 238
zcmY*SIS#`x3}b-;8ZxBM=sU9KFPf^3eo}TVeo?>RP?8g%v`FfLyzM^}KD0OaB3JT(
zCl&anmc%SrXaEDPl~I|Z_fC(&$iNtpk$lmjm`TEJhyo%k)jjO4=f?j&&jF^kxcgy{
PbY7_X>Z|3R^1F!>`pH0Q

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/copysize.xpm b/utils/ogl/samples/studio/bitmaps/copysize.xpm
new file mode 100644
index 0000000000..4694bd4083
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/copysize.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *copysize_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+".......... ...  ",
+".XXXXXXXX.   .  ",
+".XXXXXXXX.   .  ",
+".XXXXXXXX. .....",
+".XXXXXXXX.  ... ",
+"..........   .  ",
+"                ",
+"    . . . . . . ",
+"                ",
+"    .  ...... . ",
+"       .XXXX.   ",
+"    .  ...... . ",
+"                ",
+"    . . . . . . "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/cut.bmp b/utils/ogl/samples/studio/bitmaps/cut.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..15554338a01bc4d8f0a501c32237e84200e64583
GIT binary patch
literal 238
zcmZvU!3}^Q5Cqr6gr}Ba8OD(CvKJo2^+{<|WDB@(K8*2TclNjo+kV075Ef~cCTYMZ
z2hQ$)mH}PlY>+FWlp?l4?H9GSB<Zv#8R^+8F{Gd*hV&x6^<?mEPOb*V-jQ$?oH06m
Ls*2CTm$rNZbQeh3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/cut.xpm b/utils/ogl/samples/studio/bitmaps/cut.xpm
new file mode 100644
index 0000000000..bfe7e95cea
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/cut.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *cut_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c #000080",
+/* pixels */
+"                ",
+"     .   .      ",
+"     .   .      ",
+"     .   .      ",
+"     .. ..      ",
+"      . .       ",
+"      ...       ",
+"       .        ",
+"      X.X       ",
+"      X XXX     ",
+"    XXX X  X    ",
+"   X  X X  X    ",
+"   X  X X  X    ",
+"   X  X  XX     ",
+"    XX          "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/cutpoint.bmp b/utils/ogl/samples/studio/bitmaps/cutpoint.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2f7dc780a21ff41a56c536315f5e40034ff1b7b1
GIT binary patch
literal 238
zcmZ9E%MpYy3`3Qfy^|X)Y#rPwW-o+eN=rqw5T4=%W>752pV-TKD6nB)nBfGIKB%-0
z4e`tjREbcnVJN9uYq$q}gnD-dd2S))joA(4hnda^3ME@9IU}4&(EFo)=5zeN_9_1d
HoZL78p=?Bh

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/cutpoint.xpm b/utils/ogl/samples/studio/bitmaps/cutpoint.xpm
new file mode 100644
index 0000000000..597b6b01ee
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/cutpoint.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *cutpoint_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        3            1",
+/* colors */
+". c #000000",
+"# c #800000",
+"a c #c0c0c0",
+/* pixels */
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aa#aaaaaaaaa#aaa",
+"aaa#aaaaaaa#aaaa",
+"aaaa#aaaaa#aaaaa",
+"aaaaa#...#aaaaaa",
+"aaaaaa#.#.aaaaaa",
+".......#........",
+"aaaaaa#.#.aaaaaa",
+"aaaaa#...#aaaaaa",
+"aaaa#aaaaa#aaaaa",
+"aaa#aaaaaaa#aaaa",
+"aa#aaaaaaaaa#aaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/file1.ico b/utils/ogl/samples/studio/bitmaps/file1.ico
new file mode 100644
index 0000000000000000000000000000000000000000..cc828ab4f2c896df378febb8e501332db93e4c54
GIT binary patch
literal 1078
zcmeH`O%B2!6oiLr;?8mdS()BKkM@qnaa{HW_zlFwMHfw6xX>x{{^%n>1}SM$DOtv2
zlCJoiN4_NKe2^Au1>RxO5exWt8zC_iF&vgqwN|_*S|4i75#)2p=8vDg0W|PcSm#!L
zfiIm0@iqdDGlQnP!xDa`^V!E|&DpTupO3!QR@&UZI-tMjuDxNrH}-nkN%m4N@aA_a
FJpqxL*3JL`

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/folder1.ico b/utils/ogl/samples/studio/bitmaps/folder1.ico
new file mode 100644
index 0000000000000000000000000000000000000000..c43de1c07cd64c30413a2c53f521d0e203198a58
GIT binary patch
literal 1078
zcmeH{F%AMD5Jf+$1(o3lRA!Iiy)2xP!~<!`Q7pZIg~j>?vfUP&SZtvm{`_HB2qB-9
zf(GTB<aiF!5lyL&#~>Yc(nu}C6AaoD0pBjeB)ZJH5J^>QMSWswUDM<lq<P81A3uEq
zcwkew&)xYM&OSHtWf&f322VF3l78j$SQ;$8&kl>Pn`8aB-=0Ml-AgfD*@PpCja_E+
T_r_T%*c$R5s2Azc-l_Bfjgso2

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/help.bmp b/utils/ogl/samples/studio/bitmaps/help.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2d9e6922cac0fb0aefa32fd5bae9d460e13484b9
GIT binary patch
literal 238
zcmZuq!3}^g2t1P}{g~(&&f(u(`VyZVjR87~E7Sw@p^<WTP{^@vCn9#rLd?WO3`k_)
zaQ>qTFi~p=nI%+}YJ={H-mN0|?29BK#fUL#erbtT(lh^R?4vYy(d-6AGn1|j$rr}v
KbDqI%Xjd+{i$y;G

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/help.xpm b/utils/ogl/samples/studio/bitmaps/help.xpm
new file mode 100644
index 0000000000..27a87ebb31
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/help.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *help_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c #008080",
+/* pixels */
+"                ",
+"     ......     ",
+"    .XXXXX..    ",
+"   .XX...XX..   ",
+"   .X..  .X..   ",
+"   .X.. .XX..   ",
+"    .. .XX..    ",
+"      .XX..     ",
+"      .X..      ",
+"      .X..      ",
+"      .X..      ",
+"       ..       ",
+"      .XX..     ",
+"      .XX..     ",
+"       ...      "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/helpcs.bmp b/utils/ogl/samples/studio/bitmaps/helpcs.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..88373816814a283aa9ecca7899faf81ce7a15b4e
GIT binary patch
literal 238
zcmZvV!3{z&3`32Clp~D69NgKZC&ICtwG;gn%5(a;k=Ax%E6VeAXxAHgfIGN>i>|Qr
zDgH-8;%kg8Fs<gC>b(=J`dZ5!;MsyQTV&Nwu@o7(Ri`byve-X0yz0?`b73&zHji5?
LZQ&!hb;<MvPm?;n

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/helpcs.xpm b/utils/ogl/samples/studio/bitmaps/helpcs.xpm
new file mode 100644
index 0000000000..4a3e8fcb70
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/helpcs.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *helpcs_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        2            1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+/* pixels */
+"################",
+".########.....##",
+"..######..###..#",
+"...####..####...",
+"....###..####...",
+".....###..###..#",
+"......######..##",
+".......####..###",
+"........##..####",
+".....#####..####",
+"..#..###########",
+".###..####...###",
+"####..####...###",
+"#####..#########",
+"#####..#########"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/horiz.bmp b/utils/ogl/samples/studio/bitmaps/horiz.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..58af34a727e24407124fed67899ae2071dea12e9
GIT binary patch
literal 238
zcmaKjF%Ez*3<HgX#J~X0;2rGzg$Wq@B=!#Ni}*shv{WnzH@1^FotH}m8#cia4zN*+
zN=McrmKh6zL@9(~D6L|Qa?TN?TuRA0$g>r)SF8kLTs=5{{JE?DUYEK&^#0pxo{w%L
C5KP+u

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/horiz.xpm b/utils/ogl/samples/studio/bitmaps/horiz.xpm
new file mode 100644
index 0000000000..381e66fccf
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/horiz.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *horiz_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+"      .....     ",
+"      .XXX.     ",
+"      .XXX.     ",
+"      .XXX.     ",
+"      .....     ",
+"                ",
+"                ",
+"   ...........  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   ...........  ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/linearrow.bmp b/utils/ogl/samples/studio/bitmaps/linearrow.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1fd21fb08ac4a0d07a8b724700eb40c11a276698
GIT binary patch
literal 238
zcmZWjF%p0<2#a^_%H$V(hr5qq5yw8QFY*gDG<K4b1VY>6I3Fl3%1*4rLQI&+z};Dt
zvxK4mOq3!avqY_xnuFF8tz|{<q(zEf_~-bh!fmJww=}qwSzkaJAwPB8``)RI@vqz$
DY>`6V

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/linearrow.xpm b/utils/ogl/samples/studio/bitmaps/linearrow.xpm
new file mode 100644
index 0000000000..ca554f4199
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/linearrow.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *linearrow_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        3            1",
+/* colors */
+". c #000000",
+"# c #800000",
+"a c #c0c0c0",
+/* pixels */
+"aaaaaaaaaaaaaaaa",
+"aaaaa#aaaaaaaaaa",
+"aaaaa##aaaaaaaaa",
+"aaaaa###aaaaaaaa",
+"aaaaa####aaaaaaa",
+"aaaaa#####aaaaaa",
+".....######.....",
+".....######.....",
+"aaaaa#####aaaaaa",
+"aaaaa####aaaaaaa",
+"aaaaa###aaaaaaaa",
+"aaaaa##aaaaaaaaa",
+"aaaaa#aaaaaaaaaa",
+"aaaaaaaaaaaaaaaa",
+"aaaaaaaaaaaaaaaa"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/new.bmp b/utils/ogl/samples/studio/bitmaps/new.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d66feb2384ad4c626a078c995c1a3e49af78ec3c
GIT binary patch
literal 238
zcmbu2yA6Oa5JQcGL>b0l4tjP;1(ew=nJ8j|<6WY3bU0`GK9aK^RUId`!4(ELX-1{H
u>6c`QQqJ8_T9s0iQsQ8(Wab^@`3kuPA_p->w)Xt<krS4l<G*-5<G>4Pkz>06

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/new.xpm b/utils/ogl/samples/studio/bitmaps/new.xpm
new file mode 100644
index 0000000000..754d2d20a2
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/new.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *new_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Gray100",
+/* pixels */
+"                ",
+"   ........     ",
+"   .XXXXXX..    ",
+"   .XXXXXX.X.   ",
+"   .XXXXXX....  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   .XXXXXXXXX.  ",
+"   ...........  ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/newpoint.bmp b/utils/ogl/samples/studio/bitmaps/newpoint.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..cb4f267afca22039f403ed5f92a6c6a0c2978131
GIT binary patch
literal 238
zcma)!u@QhU3<Jd-J&eH|^sEEixye>3XfhEigttvWi5y9eoOs=CC3b9qGo0X{5tYu+
z6rVX0MdGNGG?Z4YHQWb1j(YbFQXV14f9QQ2&YA$<Gry{2*JqoV#jV;=X)MZ<h#!D9
BNYDTP

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/newpoint.xpm b/utils/ogl/samples/studio/bitmaps/newpoint.xpm
new file mode 100644
index 0000000000..c1d9fefcce
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/newpoint.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *newpoint_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        3            1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+"a c #ffff00",
+/* pixels */
+"#######a########",
+"###a###a###a####",
+"####a##a##a#####",
+"#####a#a#a######",
+"################",
+"##aaa#....#aaa##",
+"######....######",
+"................",
+"######....######",
+"######....######",
+"################",
+"################",
+"################",
+"################",
+"################"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/open.bmp b/utils/ogl/samples/studio/bitmaps/open.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..bbf93fe03364e63f3e18a3507a0e85ab8ea2f87d
GIT binary patch
literal 238
zcmXv{u@M3>3=;=;U&0ua+_3>YyQsonW~6N3OvKTr2(k@|B{{YeKb~(CUb3rr5zpcQ
zCn>O}mP9XDa6kd~GO1FGG0<95V`X5i$V8neN$dxz4&8XX3!AZr-;ApY^eS-9oTLj~
Y^Hcc9z2|$wrXTtLH=Rc2n(WoWFRhqJ00000

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/open.xpm b/utils/ogl/samples/studio/bitmaps/open.xpm
new file mode 100644
index 0000000000..54748e910d
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/open.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static char *open_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 5 1",
+"  c None",
+". c Black",
+"X c Yellow",
+"o c Gray100",
+"O c #bfbf00",
+/* pixels */
+"                ",
+"          ...   ",
+"         .   . .",
+"              ..",
+"  ...        ...",
+" .XoX.......    ",
+" .oXoXoXoXo.    ",
+" .XoXoXoXoX.    ",
+" .oXoX..........",
+" .XoX.OOOOOOOOO.",
+" .oo.OOOOOOOOO. ",
+" .X.OOOOOOOOO.  ",
+" ..OOOOOOOOO.   ",
+" ...........    ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/paste.bmp b/utils/ogl/samples/studio/bitmaps/paste.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..564f514e0df7225f0a7adbe8457b41af537813bd
GIT binary patch
literal 238
zcmZvVF%Ci@5Jbns<dazFG5#@(+2mJ-tNhBfq~tjEHk`;S;9I_0IWRN311y*8OB-(3
z3{UU~ciN-Ueds?a5?iHghEl4vhQ~o4TfIjGSrH-bZeUrZOuwXBvsoVg>$83OZ*I;#
co}I%%@f6>ra3+S=gC69}eM%GII+SAI4J;x>B>(^b

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/paste.xpm b/utils/ogl/samples/studio/bitmaps/paste.xpm
new file mode 100644
index 0000000000..69177e9b19
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/paste.xpm
@@ -0,0 +1,27 @@
+/* XPM */
+static char *paste_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 6 1",
+"  c None",
+". c Black",
+"X c Yellow",
+"o c #808080",
+"O c #000080",
+"+ c Gray100",
+/* pixels */
+"                ",
+"     ....       ",
+" .....XX.....   ",
+".ooo.X..X.ooo.  ",
+".oo.      .oo.  ",
+".oo........oo.  ",
+".oooooooooooo.  ",
+".oooooOOOOOOO.  ",
+".oooooO+++++OO  ",
+".oooooO+++++O+O ",
+".oooooO+OOO+OOO ",
+".oooooO+++++++O ",
+".oooooO+OOOOO+O ",
+" .....O+++++++O ",
+"      OOOOOOOOO "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/preview.bmp b/utils/ogl/samples/studio/bitmaps/preview.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..da1f4dbc4be6c2dd8fb9d7cb71cc48a4a7c139ca
GIT binary patch
literal 238
zcmZvVu?@p83<Tdm0IGAw$Q<dji>pv2yNo4mlT?N_pr2ISnd1NHDM5O^cFcMc59&^>
z)PfrwsOeYM05)2ipmU4fJIss+o(=cdQCu+!%TlZiKDH!a!aP2;C|UGpLD9M;zmsLJ
XIp;lzIUm!ckI6HO{IjaYcZ_-fA4^nl

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/preview.xpm b/utils/ogl/samples/studio/bitmaps/preview.xpm
new file mode 100644
index 0000000000..0dfdca46e1
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/preview.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static char *preview_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 5 1",
+"  c Black",
+". c None",
+"X c Gray100",
+"o c #808080",
+"O c Cyan",
+/* pixels */
+"         .......",
+" XXXXXXX  ......",
+" XXXXXXX . .....",
+" XXXXXXX    ....",
+" XXXXXXXXXX ....",
+" XXXXXXX    ....",
+" XXXXXX o..o ...",
+" XXXXX oOO.oo ..",
+" XXXXX .O..o. ..",
+" XXXXX ....o. ..",
+" XXXXX o..Ooo ..",
+" XXXXXX o..o o..",
+" XXXXXXX    o  .",
+" XXXXXXXXXX .   ",
+"            ..  "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/print.bmp b/utils/ogl/samples/studio/bitmaps/print.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..00319b55bb23c3c69cc051144d80e5275747c53e
GIT binary patch
literal 238
zcmZur!3_d23^Ni^o@EUFY`~vgA|YX<`*bfpod|V<Vy9oy#7<f}>izM>j+f}Fx~Q7!
zgtHKM7yg3|DAD^Sp<0YF#C}+nSj(MC$5#Ss27*aN<{l9d<nf^z@_A!K$q=d8y3Dc#
Z*tBKJm=l;@q<LATpSNNQY_h}diXX1oK79ZH

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/print.xpm b/utils/ogl/samples/studio/bitmaps/print.xpm
new file mode 100644
index 0000000000..3c2e2be781
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/print.xpm
@@ -0,0 +1,26 @@
+/* XPM */
+static char *print_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 5 1",
+"  c None",
+". c Black",
+"X c Gray100",
+"o c #808000",
+"O c Yellow",
+/* pixels */
+"                ",
+"     .........  ",
+"    .XXXXXXXX.  ",
+"    .X.....X.   ",
+"   .XXXXXXXX.   ",
+"   .X.....X.... ",
+"  .XXXXXXXX. . .",
+" .......... . ..",
+".          . . .",
+".............  .",
+".      ooo  . . ",
+".      OOO  ... ",
+"............. . ",
+" .         . .  ",
+"  ...........   "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/redo.bmp b/utils/ogl/samples/studio/bitmaps/redo.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5877e34e00515f81b063a0efece347301fcea5b5
GIT binary patch
literal 238
zcmah<u?>JQ3^NitoWUKaQYXHtaK{cvyw!_%p*Ri9bz(b-vmXx}r)(2faS<oXQXqGA
xvCQZwfEuN^Nj0L@Dz~8ZMr$^SDmzIyLc0CqB2x%t)cSk+_9#~#n8<A57%zxBOlSZA

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/redo.xpm b/utils/ogl/samples/studio/bitmaps/redo.xpm
new file mode 100644
index 0000000000..04df64ae54
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/redo.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *redo_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        3            1",
+/* colors */
+". c #000080",
+"# c #c0c0c0",
+"a c #808080",
+/* pixels */
+"################",
+"################",
+"################",
+"################",
+"###a....########",
+"##a.####..###.##",
+"##.#######.#..##",
+"##.########...##",
+"##.#######....##",
+"##a.#####.....##",
+"###.a###########",
+"################",
+"################",
+"################",
+"################"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/save.bmp b/utils/ogl/samples/studio/bitmaps/save.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..56dd10b6e3f05d26ba5a9e4c9a502d6278926a59
GIT binary patch
literal 238
zcmaKlu?>YV3`7rs<PygCB@!FZvr8)S%SbGiiC7^#J1yekyR*+qvLClPPV5I4IKx2`
zD*Z#>q)3!X>4ws(){6V0MX5FKAjcylGXqN-n#XsS=YhW0WogZT{L^_i_GT%*k@+ph
E1NJ~MtpET3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/save.xpm b/utils/ogl/samples/studio/bitmaps/save.xpm
new file mode 100644
index 0000000000..01b18f9340
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/save.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *save_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 4 1",
+"  c None",
+". c Black",
+"X c #808000",
+"o c #808080",
+/* pixels */
+"                ",
+" .............. ",
+" .X.        . . ",
+" .X.        ... ",
+" .X.        .X. ",
+" .X.        .X. ",
+" .X.        .X. ",
+" .X.        .X. ",
+" .XX........oX. ",
+" .XXXXXXXXXXXX. ",
+" .XX.........X. ",
+" .XX......  .X. ",
+" .XX......  .X. ",
+" .XX......  .X. ",
+"  ............. "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/straight.bmp b/utils/ogl/samples/studio/bitmaps/straight.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..529366590b71d7afa1ef14750426a874c8df6c3d
GIT binary patch
literal 238
zcmbu2!3}^Q5Cqr6#HW^F9sccwm-?hMDzXKf<$@OAal3P{0k-{C)B#qspcxGsap`Iv
q=FE!960MvAIHO7_&_QjjT0J3_kFfKrMCAR;DYEp3e$)3m`*#mOwn9e$

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/straight.xpm b/utils/ogl/samples/studio/bitmaps/straight.xpm
new file mode 100644
index 0000000000..12563b4703
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/straight.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *straight_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        2            1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+/* pixels */
+"################",
+".........#######",
+".........#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######..#######",
+"#######.........",
+"#######.........",
+"################"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/texttool.bmp b/utils/ogl/samples/studio/bitmaps/texttool.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..09c989aac1c4833e37cb6b0f96c0c0d0cacfc14d
GIT binary patch
literal 382
zcmbVHF%p0v3=4PO>FDGee22S#VUo?`XYeyjTT}*FEF`2&%fYsv4jKn}C6)?@LF-fX
zC7CPKK!R+fWCxiNIcLNeX%yWkMHIm$B~p0fhX!YOAt?ku5^{&2)nYT(I-4KOfkx}7
W_5`$ATdeLo+T0JezsY;<=;{k{K6#)3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/texttool.xpm b/utils/ogl/samples/studio/bitmaps/texttool.xpm
new file mode 100644
index 0000000000..db6308fcef
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/texttool.xpm
@@ -0,0 +1,31 @@
+/* XPM */
+static char *texttool_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    22    22        2            1",
+/* colors */
+". c #000000",
+"# c #c0c0c0",
+/* pixels */
+"######################",
+"######################",
+"######################",
+"######################",
+"##########..##########",
+"##########..##########",
+"#########....#########",
+"#########....#########",
+"########.....#########",
+"########..#...########",
+"#######..##...########",
+"#######..###...#######",
+"######.........#######",
+"######..####...#######",
+"######.######...######",
+"#####..######...######",
+"####....####......####",
+"######################",
+"######################",
+"######################",
+"######################",
+"######################"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/tick.bmp b/utils/ogl/samples/studio/bitmaps/tick.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..c0d66c94601657fee33b923de9b1791844d7a331
GIT binary patch
literal 220
zcmXv`!4bnS2vd9<&b6P6(K-6>8h!H$UytTNvWqL(DMm;L@cVON#YuV*&l?*Ih5AeU
z<Dd{$G=PcL7O_&I_fFPe%)}T{1fMLHN0y*v8NQS!DqFcF>{bqVO)bKZHuqJq2P$o+
Qrwbl?Kzn<_G@1WzKlk4xlmGw#

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/tick.xpm b/utils/ogl/samples/studio/bitmaps/tick.xpm
new file mode 100644
index 0000000000000000000000000000000000000000..6099b2b8b3c8960d90f2b46bb26681c262577c74
GIT binary patch
literal 6101
zcmeH_-%5l~5XQasDF(fh@K4<Y(M8chLc2*y84+S8DQ&xp8WqvI?W1*OJh}$QU4m|c
z8R0nJ%$e^Te(G2d2UD;dy>8N`%pfb$3M`R5-`&G8eCmz`Z{=fCK#`YEMFWf1mn2)x
zmsL%B>tvNz$*O$M=jdX92+!NBnC;`zg=g%cr?kKk8!|9m3ehu6l$nc9yOqpqayK`D
zTWu-DdmwGw9!Q}El2qFjL#>h$1sRf6ucVdi^#^rF56;EQ82Z<d9{SVZVgdr6A|gd?
zN9oj$0zV${JKQm>XwOb!KNNN4{eFBb#jv78e&U;}{Mvs(F|?&be&QZ~<#+Cf(dE@G
z+*D=L<O_KCfcP2?Y|l-%++w^nnVpR{xx)mQ025#WOn?b60VeQk0@}I{k#<U3YnseO
t(&cSRb?nNz)KpnxP@Srj4@{{o7u?0c1egF5U;<2l2`~XBzy$sofp1=l^ELng

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/toback.bmp b/utils/ogl/samples/studio/bitmaps/toback.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d2e5efffcea17b5340e8c9278186ca5cf16e666e
GIT binary patch
literal 238
zcmZ`yu?>JQ3^NiE0|T7F9qjzl2^cf>9QF?FMZ8d)1PO#h65C0vwDWSpW2H>QNDM@S
zmJIC1PU<N<GQdL4E@ZYSr9ebzR4de~9l_KUX?sPWr(=jw9_7;JJ{@1Br8g;ccJrrz
J`}XGj#|0@HO0NI_

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/toback.xpm b/utils/ogl/samples/studio/bitmaps/toback.xpm
new file mode 100644
index 0000000000..f7a1c46ab8
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/toback.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *toback_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 4 1",
+"  c None",
+". c Black",
+"X c #808080",
+"o c Yellow",
+/* pixels */
+" .......        ",
+" .XXXXX.        ",
+" .XXXXX......   ",
+" .XXXXX.oooo.   ",
+" .XXXXX.oooo.   ",
+" .XXXXX.oooo.   ",
+" .......oooo.   ",
+"    .oooo.......",
+"    .oooo.XXXXX.",
+"    .oooo.XXXXX.",
+"    ......XXXXX.",
+"         .XXXXX.",
+"         .XXXXX.",
+"         .......",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/tofront.bmp b/utils/ogl/samples/studio/bitmaps/tofront.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5b17cc44c86d936cdaba49553685be0719486d34
GIT binary patch
literal 238
zcmZ{cK@Nj33<MVm2_z2m8N7pg|B@5sm?MA6A$bvBNM}i<R!FtIyS7*M`aIQQLl*D=
zGw9UA(tdFxdq#^aQOdaqOsi6gVvHE|D%I)^kX}Krp9pv!!*Rr~ved{trIhX}1$jSk
N^G|(m|MQc{zu(f|NZ|kg

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/tofront.xpm b/utils/ogl/samples/studio/bitmaps/tofront.xpm
new file mode 100644
index 0000000000..f5ce7652a2
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/tofront.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *tofront_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 4 1",
+"  c None",
+". c Black",
+"X c #808080",
+"o c Yellow",
+/* pixels */
+" .......        ",
+" .XXXXX.        ",
+" .XX.........   ",
+" .XX.ooooooo.   ",
+" .XX.ooooooo.   ",
+" .XX.ooooooo.   ",
+" ....ooooooo.   ",
+"    .ooooooo....",
+"    .ooooooo.XX.",
+"    .ooooooo.XX.",
+"    .........XX.",
+"         .XXXXX.",
+"         .XXXXX.",
+"         .......",
+"                "
+};
diff --git a/utils/ogl/samples/studio/bitmaps/undo.bmp b/utils/ogl/samples/studio/bitmaps/undo.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4ad80c772f8f5281500707222f552d634a9c027a
GIT binary patch
literal 238
zcma)zu?>JQ3<MvE9>!n}6e%=pgD_<}*2+Yz5YBOr`1t>vyt3|(LMK@8j3+#3B&Dlo
ygm>;xkr<T{AX!ywg<iBiYRxyy@h8Im=*ng(5u1}A2jtqx?#xC(k5aljzv2a83`_6;

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/undo.xpm b/utils/ogl/samples/studio/bitmaps/undo.xpm
new file mode 100644
index 0000000000..157a623e3c
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/undo.xpm
@@ -0,0 +1,25 @@
+/* XPM */
+static char *undo_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    16    15        3            1",
+/* colors */
+". c #000080",
+"# c #c0c0c0",
+"a c #808080",
+/* pixels */
+"################",
+"################",
+"################",
+"################",
+"########....a###",
+"##.###..####.a##",
+"##..#.#######.##",
+"##...########.##",
+"##....#######.##",
+"##.....#####.a##",
+"###########a.###",
+"################",
+"################",
+"################",
+"################"
+};
diff --git a/utils/ogl/samples/studio/bitmaps/vert.bmp b/utils/ogl/samples/studio/bitmaps/vert.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..dfd7b5cb5339fbffb36ca2113e42e33ea594434b
GIT binary patch
literal 238
zcmaKku?>JQ3<MvEjsnJD4tjQ>0?Ld;pCXxv6~fs8i2~vH|E+&J(|oGdii}_YJ!sUz
z((YWzGDEE-(MqWb%&45RLI?!KTcy|pcxFM{N3r657vo{E>4N2o^{e;ZbNANgU-K?u
CAW)M4

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/bitmaps/vert.xpm b/utils/ogl/samples/studio/bitmaps/vert.xpm
new file mode 100644
index 0000000000..0f85e23920
--- /dev/null
+++ b/utils/ogl/samples/studio/bitmaps/vert.xpm
@@ -0,0 +1,24 @@
+/* XPM */
+static char *vert_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"16 15 3 1",
+"  c None",
+". c Black",
+"X c Yellow",
+/* pixels */
+"                ",
+"        ........",
+"        .XXXXXX.",
+"        .XXXXXX.",
+" .....  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .XXX.  .XXXXXX.",
+" .....  .XXXXXX.",
+"        .XXXXXX.",
+"        .XXXXXX.",
+"        ........",
+"                ",
+"                "
+};
diff --git a/utils/ogl/samples/studio/cspalette.cpp b/utils/ogl/samples/studio/cspalette.cpp
new file mode 100644
index 0000000000..50c5aee777
--- /dev/null
+++ b/utils/ogl/samples/studio/cspalette.cpp
@@ -0,0 +1,153 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        cspalette.cpp
+// Purpose:     OGLEdit palette
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/laywin.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "doc.h"
+#include "view.h"
+#include "studio.h"
+#include "cspalette.h"
+#include "symbols.h"
+
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+#include "bitmaps/arrow.xpm"
+#include "bitmaps/texttool.xpm"
+#endif
+
+/*
+ * Object editor tool palette
+ *
+ */
+
+csEditorToolPalette::csEditorToolPalette(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
+            long style):
+  TOOLPALETTECLASS(parent, id, pos, size, style)
+{
+  m_currentlySelected = -1;
+
+  SetMaxRowsCols(1, 1000);
+}
+
+bool csEditorToolPalette::OnLeftClick(int toolIndex, bool toggled)
+{
+  // BEGIN mutual exclusivity code
+  if (toggled && (m_currentlySelected != -1) && (toolIndex != m_currentlySelected))
+    ToggleTool(m_currentlySelected, FALSE);
+
+  if (toggled)
+    m_currentlySelected = toolIndex;
+  else if (m_currentlySelected == toolIndex)
+    m_currentlySelected = -1;
+  //  END mutual exclusivity code
+
+  return TRUE;
+}
+
+void csEditorToolPalette::OnMouseEnter(int toolIndex)
+{
+    wxString msg("");
+    if (toolIndex == PALETTE_ARROW)
+        msg = "Pointer";
+    else if (toolIndex != -1)
+    {
+        csSymbol* symbol = wxGetApp().GetSymbolDatabase()->FindSymbol(toolIndex);
+        if (symbol)
+            msg = symbol->GetName();
+    }
+    ((wxFrame*) wxGetApp().GetTopWindow())->SetStatusText(msg);
+}
+
+void csEditorToolPalette::SetSize(int x, int y, int width, int height, int sizeFlags)
+{
+  TOOLPALETTECLASS::SetSize(x, y, width, height, sizeFlags);
+}
+
+void csEditorToolPalette::SetSelection(int sel)
+{
+    if ((sel != m_currentlySelected) && (m_currentlySelected != -1))
+    {
+        ToggleTool(m_currentlySelected, FALSE);
+    }
+    m_currentlySelected = sel;
+    ToggleTool(m_currentlySelected, TRUE);
+}
+
+bool csApp::CreatePalette(wxFrame *parent)
+{
+    // First create a layout window
+    wxSashLayoutWindow* win = new wxSashLayoutWindow(parent, ID_LAYOUT_WINDOW_PALETTE, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D|wxCLIP_CHILDREN);
+    win->SetDefaultSize(wxSize(10000, 40));
+    win->SetOrientation(wxLAYOUT_HORIZONTAL);
+    win->SetAlignment(wxLAYOUT_TOP);
+    win->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
+    win->SetSashVisible(wxSASH_BOTTOM, TRUE);
+
+    m_diagramPaletteSashWindow = win;
+
+    m_diagramPaletteSashWindow->Show(FALSE);
+
+  // Load palette bitmaps
+#ifdef __WXMSW__
+    wxBitmap PaletteArrow("arrowtool");
+    wxBitmap TextTool("texttool");
+#elif defined(__WXGTK__) || defined(__WXMOTIF__)
+    wxBitmap PaletteArrow(arrow_xpm);
+    wxBitmap TextTool(texttool_xpm);
+#endif
+
+  csEditorToolPalette *palette = new csEditorToolPalette(m_diagramPaletteSashWindow, ID_DIAGRAM_PALETTE, wxPoint(0, 0), wxSize(-1, -1), wxTB_HORIZONTAL|wxNO_BORDER);
+
+  palette->SetMargins(2, 2);
+
+  palette->SetToolBitmapSize(wxSize(32, 32));
+
+  palette->AddTool(PALETTE_ARROW, PaletteArrow, wxNullBitmap, TRUE, 0, -1, NULL, "Pointer");
+  palette->AddTool(PALETTE_TEXT_TOOL, TextTool, wxNullBitmap, TRUE, 0, -1, NULL, "Text");
+
+  wxNode* node = GetSymbolDatabase()->GetSymbols().First();
+  while (node)
+  {
+    csSymbol* symbol = (csSymbol*) node->Data();
+    wxBitmap* bitmap = GetSymbolDatabase()->CreateToolBitmap(symbol);
+    palette->AddTool(symbol->GetToolId(), *bitmap, wxNullBitmap, TRUE, 0, -1, NULL, symbol->GetName());
+
+    delete bitmap;
+
+    node = node->Next();
+  }
+
+  palette->Realize();
+
+  palette->SetSelection(PALETTE_ARROW);
+  m_diagramPalette = palette;
+
+  return TRUE;
+}
+
diff --git a/utils/ogl/samples/studio/cspalette.h b/utils/ogl/samples/studio/cspalette.h
new file mode 100644
index 0000000000..67a8e63740
--- /dev/null
+++ b/utils/ogl/samples/studio/cspalette.h
@@ -0,0 +1,57 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        cspalette.h
+// Purpose:     OGL sample palette
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_CSPALETTE_H_
+#define _STUDIO_CSPALETTE_H_
+
+#ifdef __GNUG__
+// #pragma interface
+#endif
+
+#include <wx/wx.h>
+#include <wx/string.h>
+#include <wx/tbarsmpl.h>
+
+/*
+ * Object editor tool palette
+ *
+ */
+
+// TODO for wxWin: wxToolBar95 cannot be moved to a non-0,0 position!
+// Needs to have a parent window...
+// So use a simple toolbar at present.
+#define TOOLPALETTECLASS    wxToolBarSimple
+
+class csEditorToolPalette: public TOOLPALETTECLASS
+{
+public:
+
+  csEditorToolPalette(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition,
+    const wxSize& size = wxDefaultSize,
+    long style = wxTB_VERTICAL);
+
+  bool OnLeftClick(int toolIndex, bool toggled);
+  void OnMouseEnter(int toolIndex);
+
+  inline int GetSelection() const { return m_currentlySelected; }
+  void SetSelection(int sel);
+
+  void SetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
+
+protected:
+  int           m_currentlySelected;
+};
+
+#define PALETTE_ARROW           200
+#define PALETTE_TEXT_TOOL       201
+
+#endif
+    // _STUDIO_CSPALETTE_H_
diff --git a/utils/ogl/samples/studio/csprint.cpp b/utils/ogl/samples/studio/csprint.cpp
new file mode 100644
index 0000000000..8006c2717f
--- /dev/null
+++ b/utils/ogl/samples/studio/csprint.cpp
@@ -0,0 +1,318 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        csprint.cpp
+// Purpose:     Printing and clipboard functionality
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/wxexpr.h>
+#include <wx/clipbrd.h>
+
+#ifdef __WXMSW__
+#include <wx/metafile.h>
+#endif
+
+#include "studio.h"
+#include "doc.h"
+#include "shapes.h"
+#include "view.h"
+
+IMPLEMENT_DYNAMIC_CLASS(wxDiagramClipboard, wxDiagram)
+
+// Copy selection
+bool wxDiagramClipboard::Copy(wxDiagram* diagram)
+{
+    DeleteAllShapes();
+
+    return DoCopy(diagram, this, FALSE, NULL);
+}
+
+// Copy contents to the diagram, with new ids.
+
+bool wxDiagramClipboard::Paste(wxDiagram* diagram, wxDC* dc, int offsetX, int offsetY)
+{
+    return DoCopy(this, diagram, TRUE, dc, offsetX, offsetY);
+}
+
+// Universal copy function (to or from clipboard).
+// TODO:
+// Note that this only works for non-composites so far (nested shapes
+// don't have their old-to-new object mappings stored).
+// Also, lines don't yet get their attachment points moved to the new offset position
+// if they have more than 2 points.
+bool wxDiagramClipboard::DoCopy(wxDiagram* diagramFrom, wxDiagram* diagramTo, bool newIds,
+    wxDC* dc, int offsetX, int offsetY)
+{
+    OnStartCopy(diagramTo);
+
+    wxHashTable mapping(wxKEY_INTEGER);
+
+    // First copy all node shapes.
+    wxList* shapeList = diagramFrom->GetShapeList();
+    wxNode* node = shapeList->First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (((diagramFrom == this) || shape->Selected()) && !shape->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxShape* newShape = shape->CreateNewCopy();
+            newShape->GetLines().Clear();
+            if (newIds)
+            {
+                newShape->AssignNewIds();
+            }
+            mapping.Put((long) shape, (wxObject*) newShape);
+
+            newShape->SetX(newShape->GetX() + offsetX);
+            newShape->SetY(newShape->GetY() + offsetY);
+
+            OnAddShape(diagramTo, newShape, dc);
+
+        }
+        node = node->Next();
+    }
+
+    node = shapeList->First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (((diagramFrom == this) || shape->Selected()) && shape->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxLineShape* lineShape = (wxLineShape*) shape;
+            // Only copy a line if its ends are selected too.
+            if ((diagramFrom == this) || (lineShape->GetTo()->Selected() && lineShape->GetFrom()->Selected()))
+            {
+                wxLineShape* newShape = (wxLineShape*) shape->CreateNewCopy();
+                mapping.Put((long) shape, (wxObject*) newShape);
+
+                if (newIds)
+                    newShape->AssignNewIds();
+
+                wxShape* fromShape = (wxShape*) mapping.Get((long) lineShape->GetFrom());
+                wxShape* toShape = (wxShape*) mapping.Get((long) lineShape->GetTo());
+
+                wxASSERT_MSG( (fromShape != NULL), "Could not find 'from' shape");
+                wxASSERT_MSG( (toShape != NULL), "Could not find 'to' shape");
+
+                fromShape->AddLine(newShape, toShape, newShape->GetAttachmentFrom(),
+                  newShape->GetAttachmentTo());
+
+                OnAddShape(diagramTo, newShape, dc);
+
+            }
+        }
+        node = node->Next();
+    }
+
+    // Now make sure line ordering is correct
+    node = shapeList->First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (((diagramFrom == this) || shape->Selected()) && !shape->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxShape* newShape = (wxShape*) mapping.Get((long) shape);
+
+            // Make a list of all the new lines, in the same order as the old lines.
+            // Then apply the list of new lines to the shape.
+            wxList newLines;
+            wxNode* lineNode = shape->GetLines().First();
+            while (lineNode)
+            {
+                wxLineShape* lineShape = (wxLineShape*) lineNode->Data();
+                if ((diagramFrom == this) || (lineShape->GetTo()->Selected() && lineShape->GetFrom()->Selected()))
+                {
+                    wxLineShape* newLineShape = (wxLineShape*) mapping.Get((long) lineShape);
+
+                    wxASSERT_MSG( (newLineShape != NULL), "Could not find new line shape");
+
+                    newLines.Append(newLineShape);
+                }
+
+                lineNode = lineNode->Next();
+            }
+
+            if (newLines.Number() > 0)
+                newShape->ApplyAttachmentOrdering(newLines);
+        }
+        node = node->Next();
+    }
+
+    OnEndCopy(diagramTo);
+
+    return TRUE;
+}
+
+#ifdef __WXMSW__
+// Draw contents to a Windows metafile device context and a bitmap, and copy
+// these to the Windows clipboard
+bool wxDiagramClipboard::CopyToClipboard(double scale)
+{
+  // Make a metafile DC
+  wxMetaFileDC mfDC;
+  if (mfDC.Ok())
+  {
+    mfDC.SetUserScale(scale, scale);
+
+    // Draw on metafile DC
+    Redraw(mfDC);
+
+    int printWidth = mfDC.MaxX() - mfDC.MinX();
+    int printHeight = mfDC.MaxY() - mfDC.MinY();
+    int maxX = (int)mfDC.MaxX();
+    int maxY = (int)mfDC.MaxY();
+    wxMetaFile *mf = mfDC.Close();
+
+    // Set to a bitmap memory DC
+    wxBitmap *newBitmap = new wxBitmap((int)(maxX + 10), (int)(maxY + 10));
+    if (!newBitmap->Ok())
+    {
+      delete newBitmap;
+      
+      char buf[200];
+      sprintf(buf, "Sorry, could not allocate clipboard bitmap (%dx%d)", (maxX+10), (maxY+10));
+      wxMessageBox(buf, "Clipboard copy problem");
+      return FALSE;
+    }
+
+    wxMemoryDC memDC;
+    memDC.SelectObject(*newBitmap);
+    memDC.Clear();
+
+    // Now draw on memory bitmap DC
+    Redraw(memDC);
+
+    memDC.SelectObject(wxNullBitmap);
+
+    // Open clipboard and set the data
+    if (wxOpenClipboard())
+    {
+        wxEmptyClipboard();
+
+        // Copy the bitmap to the clipboard
+        wxSetClipboardData(wxDF_BITMAP, newBitmap, 0, 0);
+
+        if (mf)
+        {
+            // Copy the metafile to the clipboard
+            // Allow a small margin
+            bool success = mf->SetClipboard((int)(mfDC.MaxX() + 15), (int)(mfDC.MaxY() + 15));
+        }
+
+        // Close clipboard
+        wxCloseClipboard();
+    }
+    
+    delete newBitmap;
+    delete mf;
+
+  }
+  return TRUE;
+}
+#endif
+    // __WXMSW__
+
+// Override this to e.g. have the shape added through a Do/Undo command system.
+// By default, we'll just add it directly to the destination diagram.
+bool wxDiagramClipboard::OnAddShape(wxDiagram* diagramTo, wxShape* newShape, wxDC* dc)
+{
+    diagramTo->AddShape(newShape);
+
+    if (dc && (diagramTo != this))
+    {
+        newShape->Select(TRUE, dc);
+    }
+
+    return TRUE;
+}
+
+/*
+ * csDiagramClipboard
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(csDiagramClipboard, wxDiagramClipboard)
+
+// Start/end copying
+bool csDiagramClipboard::OnStartCopy(wxDiagram* diagramTo)
+{
+    // Do nothing if copying to the clipboard
+    if (diagramTo == this)
+        return TRUE;
+
+    // Deselect all objects initially.
+
+    csDiagram* diagram = (csDiagram*) diagramTo;
+    csDiagramDocument* doc = diagram->GetDocument();
+    ((csDiagramView*)doc->GetFirstView())->SelectAll(FALSE);
+
+    m_currentCmd = new csDiagramCommand("Paste", doc);
+
+    return TRUE;
+}
+
+bool csDiagramClipboard::OnEndCopy(wxDiagram* diagramTo)
+{
+    // Do nothing if copying to the clipboard
+    if (diagramTo == this)
+        return TRUE;
+
+    csDiagram* diagram = (csDiagram*) diagramTo;
+    csDiagramDocument* doc = diagram->GetDocument();
+
+    if (m_currentCmd)
+    {
+        if (m_currentCmd->GetStates().Number() == 0)
+        {
+            delete m_currentCmd;
+        }
+        else
+        {
+            doc->GetCommandProcessor()->Submit(m_currentCmd);
+            m_currentCmd = NULL;
+        }
+    }
+    return TRUE;
+}
+
+// Use the command framework to add the shapes, if we're copying to a diagram and
+// not the clipboard.
+bool csDiagramClipboard::OnAddShape(wxDiagram* diagramTo, wxShape* newShape, wxDC* dc)
+{
+    if (diagramTo == this)
+    {
+        diagramTo->AddShape(newShape);
+    }
+    else
+    {
+        csDiagram* diagram = (csDiagram*) diagramTo;
+        csDiagramDocument* doc = diagram->GetDocument();
+
+        if (newShape->IsKindOf(CLASSINFO(wxLineShape)))
+            m_currentCmd->AddState(new csCommandState(ID_CS_ADD_LINE_SELECT, newShape, NULL));
+        else
+            m_currentCmd->AddState(new csCommandState(ID_CS_ADD_SHAPE_SELECT, newShape, NULL));
+    }
+
+    return TRUE;
+}
+
+
diff --git a/utils/ogl/samples/studio/dialogs.cpp b/utils/ogl/samples/studio/dialogs.cpp
new file mode 100644
index 0000000000..9fef6d120f
--- /dev/null
+++ b/utils/ogl/samples/studio/dialogs.cpp
@@ -0,0 +1,525 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dialogs.cpp
+// Purpose:     Implements Studio dialogs
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/resource.h>
+#include "dialogs.h"
+#include "doc.h"
+#include "view.h"
+#include "studio.h"
+#include "studio_resources.h"
+
+IMPLEMENT_CLASS(csLabelEditingDialog, wxDialog)
+
+BEGIN_EVENT_TABLE(csLabelEditingDialog, wxDialog)
+    EVT_BUTTON(wxID_OK, csLabelEditingDialog::OnOK)
+END_EVENT_TABLE()
+
+csLabelEditingDialog::csLabelEditingDialog(wxWindow* parent)
+{
+    LoadFromResource(parent, "shape_label_dialog");
+
+    // Accelerators
+    wxAcceleratorEntry entries[1];
+    entries[0].Set(wxACCEL_CTRL, WXK_RETURN, wxID_OK);
+    wxAcceleratorTable accel(1, entries);
+    SetAcceleratorTable(accel);
+
+    Centre();
+
+    wxTextCtrl* textCtrl = (wxTextCtrl*) FindWindow(ID_LABELTEXT);
+    wxASSERT( (textCtrl != NULL) );
+
+//    textCtrl->SetAcceleratorTable(accel);
+
+    textCtrl->SetFocus();
+}
+
+void csLabelEditingDialog::OnOK(wxCommandEvent& event)
+{
+    wxTextCtrl* textCtrl = (wxTextCtrl*) FindWindow(ID_LABELTEXT);
+    wxASSERT( (textCtrl != NULL) );
+
+    SetShapeLabel(textCtrl->GetValue());
+
+    wxDialog::OnOK(event);
+}
+
+void csLabelEditingDialog::SetShapeLabel(const wxString& label)
+{
+    wxTextCtrl* textCtrl = (wxTextCtrl*) FindWindow(ID_LABELTEXT);
+    wxASSERT( (textCtrl != NULL) );
+
+    m_label = label;
+
+    textCtrl->SetValue(label);
+}
+
+IMPLEMENT_CLASS(csSettingsDialog, wxDialog)
+
+BEGIN_EVENT_TABLE(csSettingsDialog, wxDialog)
+    EVT_BUTTON(wxID_OK, csSettingsDialog::OnOK)
+END_EVENT_TABLE()
+
+#define PROPERTY_DIALOG_WIDTH   400
+#define PROPERTY_DIALOG_HEIGHT  400
+
+// For 400x400 settings dialog, size your panels to about 375x325 in dialog editor
+
+csSettingsDialog::csSettingsDialog(wxWindow* parent):
+    wxDialog(parent, -1, "Settings", wxPoint(0, 0), wxSize(PROPERTY_DIALOG_WIDTH, PROPERTY_DIALOG_HEIGHT))
+{
+    m_generalSettings = NULL;
+    m_diagramSettings = NULL;
+
+    m_notebook = new wxNotebook(this, ID_PROPERTY_NOTEBOOK,
+         wxPoint(2, 2), wxSize(PROPERTY_DIALOG_WIDTH - 4, PROPERTY_DIALOG_HEIGHT - 4));
+
+    m_generalSettings = new wxPanel;
+
+    bool success = m_generalSettings->LoadFromResource(m_notebook, "general_settings_dialog");
+    wxASSERT_MSG( (success), "Could not load general settings panel.");
+    m_notebook->AddPage(m_generalSettings, "General", TRUE);
+
+    m_diagramSettings = new wxPanel;
+
+    success = m_diagramSettings->LoadFromResource(m_notebook, "diagram_settings_dialog");
+    wxASSERT_MSG( (success), "Could not load diagram settings panel.");
+    m_notebook->AddPage(m_diagramSettings, "Diagram");
+
+    int largeButtonWidth = 70;
+    int largeButtonHeight = 22;
+
+    wxButton* okButton = new wxButton(this, wxID_OK, "OK", wxPoint(0, 0), wxSize(largeButtonWidth, largeButtonHeight));
+    wxButton* cancelButton = new wxButton(this, wxID_CANCEL, "Cancel", wxPoint(0, 0), wxSize(largeButtonWidth, largeButtonHeight));
+    wxButton* helpButton = new wxButton(this, wxID_HELP, "Help", wxPoint(0, 0), wxSize(largeButtonWidth, largeButtonHeight));
+
+    // Constraints for the notebook
+    wxLayoutConstraints *c = new wxLayoutConstraints;
+    c->top.SameAs     (this, wxTop, 5);
+    c->left.SameAs    (this, wxLeft, 5);
+    c->right.SameAs   (this, wxRight, 5);
+    c->bottom.SameAs  (cancelButton, wxTop, 5);
+    m_notebook->SetConstraints(c);
+
+    // Constraints for the Help button
+    c = new wxLayoutConstraints;
+    c->width.AsIs();
+    c->height.AsIs();
+    c->right.SameAs    (this, wxRight, 5);
+    c->bottom.SameAs   (this, wxBottom, 5);
+    helpButton->SetConstraints(c);
+
+    // Constraints for the Cancel button
+    c = new wxLayoutConstraints;
+    c->width.AsIs();
+    c->height.AsIs();
+    c->right.SameAs    (helpButton, wxLeft, 5);
+    c->bottom.SameAs   (this, wxBottom, 5);
+    cancelButton->SetConstraints(c);
+
+    // Constraints for the OK button
+    c = new wxLayoutConstraints;
+    c->width.AsIs();
+    c->height.AsIs();
+    c->right.SameAs    (cancelButton, wxLeft, 5);
+    c->bottom.SameAs   (this, wxBottom, 5);
+    okButton->SetConstraints(c);
+
+    okButton->SetDefault();
+    okButton->SetFocus();
+
+    Layout();
+    Centre(wxBOTH);
+}
+
+void csSettingsDialog::OnOK(wxCommandEvent& event)
+{
+    wxDialog::OnOK(event);
+}
+
+bool csSettingsDialog::TransferDataToWindow()
+{
+    wxTextCtrl* gridSpacing = (wxTextCtrl*) m_diagramSettings->FindWindow(ID_GRID_SPACING);
+    wxASSERT_MSG( (gridSpacing != (wxTextCtrl*) NULL), "Could not find grid spacing control.");
+
+    wxChoice* gridStyle = (wxChoice*) m_diagramSettings->FindWindow(ID_GRID_STYLE);
+    wxASSERT_MSG( (gridStyle != (wxChoice*) NULL), "Could not find grid style control.");
+
+    gridStyle->SetSelection(wxGetApp().GetGridStyle());
+
+    wxString str;
+    str.Printf("%d", wxGetApp().GetGridSpacing());
+    gridSpacing->SetValue(str);
+
+    return TRUE;
+}
+
+bool csSettingsDialog::TransferDataFromWindow()
+{
+    wxTextCtrl* gridSpacing = (wxTextCtrl*) m_diagramSettings->FindWindow(ID_GRID_SPACING);
+    wxASSERT_MSG( (gridSpacing != (wxTextCtrl*) NULL), "Could not find grid spacing control.");
+
+    wxChoice* gridStyle = (wxChoice*) m_diagramSettings->FindWindow(ID_GRID_STYLE);
+    wxASSERT_MSG( (gridStyle != (wxChoice*) NULL), "Could not find grid style control.");
+
+    wxGetApp().SetGridStyle(gridStyle->GetSelection());
+    wxGetApp().SetGridSpacing(atoi(gridSpacing->GetValue()));
+
+    if (wxGetApp().GetGridStyle() == csGRID_STYLE_DOTTED)
+    {
+        wxMessageBox("Dotted grid style not yet implemented.", "Studio", wxICON_EXCLAMATION);
+        return FALSE;
+    }
+
+    // Apply settings to all open diagram documents
+    wxNode* node = wxGetApp().GetDocManager()->GetDocuments().First();
+    while (node)
+    {
+        wxDocument* doc = (wxDocument*) node->Data();
+        if (doc->IsKindOf(CLASSINFO(csDiagramDocument)))
+        {
+            csDiagramDocument* diagramDoc = (csDiagramDocument*) doc;
+            wxDiagram* diagram = (wxDiagram*) diagramDoc->GetDiagram();
+
+            diagram->SetGridSpacing((double) wxGetApp().GetGridSpacing());
+            switch (wxGetApp().GetGridStyle())
+            {
+                case csGRID_STYLE_NONE:
+                {
+                    diagram->SetSnapToGrid(FALSE);
+                    break;
+                }
+                case csGRID_STYLE_INVISIBLE:
+                {
+                    diagram->SetSnapToGrid(TRUE);
+                    break;
+                }
+                case csGRID_STYLE_DOTTED:
+                {
+                    // TODO (not implemented in OGL)
+                    break;
+                }
+            }
+        }
+        node = node->Next();
+    }
+
+    return TRUE;
+}
+
+/*
+ * Shape properties dialog (tabbed)
+ */
+
+
+IMPLEMENT_CLASS(csShapePropertiesDialog, wxDialog)
+
+BEGIN_EVENT_TABLE(csShapePropertiesDialog, wxDialog)
+    EVT_BUTTON(wxID_OK, csShapePropertiesDialog::OnOK)
+END_EVENT_TABLE()
+
+#define SHAPE_PROPERTY_DIALOG_WIDTH   400
+#define SHAPE_PROPERTY_DIALOG_HEIGHT  400
+
+// For 400x400 settings dialog, size your panels to about 375x325 in dialog editor
+
+csShapePropertiesDialog::csShapePropertiesDialog(wxWindow* parent, const wxString& title,
+  wxPanel* attributeDialog, const wxString& attributeDialogName):
+    wxDialog(parent, -1, title, wxPoint(0, 0), wxSize(SHAPE_PROPERTY_DIALOG_WIDTH, SHAPE_PROPERTY_DIALOG_HEIGHT))
+{
+    m_attributeDialog = attributeDialog;
+    m_alternativeAttributeDialog = NULL;
+    m_generalPropertiesDialog = NULL;
+
+    m_notebook = new wxNotebook(this, ID_SHAPE_PROPERTY_NOTEBOOK,
+         wxPoint(2, 2), wxSize(SHAPE_PROPERTY_DIALOG_WIDTH - 4, SHAPE_PROPERTY_DIALOG_HEIGHT - 4));
+
+    m_generalPropertiesDialog = new csGeneralShapePropertiesDialog;
+    bool success = m_generalPropertiesDialog->LoadFromResource(m_notebook, "general_shape_properties_dialog");
+    wxASSERT_MSG( (success), "Could not load general properties panel.");
+    m_notebook->AddPage(m_generalPropertiesDialog, "General");
+
+    success = m_attributeDialog->LoadFromResource(m_notebook, attributeDialogName);
+    if (!success)
+    {
+        wxMessageBox("Could not load the attribute dialog for this shape.", "Studio", wxICON_EXCLAMATION);
+        delete m_attributeDialog;
+        m_attributeDialog = NULL;
+    }
+    else
+    {
+        m_notebook->AddPage(m_attributeDialog, "Attributes");
+    }
+
+    // Try the alternative dialog (test code)
+    wxString str(attributeDialogName);
+    str += "1";
+    m_alternativeAttributeDialog = new wxPanel;
+    success = m_alternativeAttributeDialog->LoadFromResource(m_notebook, str);
+    if (success)
+    {
+        m_notebook->AddPage(m_alternativeAttributeDialog, "Attributes (alternative)");
+    }
+    else
+    {
+        delete m_alternativeAttributeDialog;
+        m_alternativeAttributeDialog = NULL;
+    }
+
+    int largeButtonWidth = 70;
+    int largeButtonHeight = 22;
+
+    wxButton* okButton = new wxButton(this, wxID_OK, "OK", wxPoint(0, 0), wxSize(largeButtonWidth, largeButtonHeight));
+    wxButton* cancelButton = new wxButton(this, wxID_CANCEL, "Cancel", wxPoint(0, 0), wxSize(largeButtonWidth, largeButtonHeight));
+    wxButton* helpButton = new wxButton(this, wxID_HELP, "Help", wxPoint(0, 0), wxSize(largeButtonWidth, largeButtonHeight));
+
+    // Constraints for the notebook
+    wxLayoutConstraints *c = new wxLayoutConstraints;
+    c->top.SameAs     (this, wxTop, 5);
+    c->left.SameAs    (this, wxLeft, 5);
+    c->right.SameAs   (this, wxRight, 5);
+    c->bottom.SameAs  (helpButton, wxTop, 5);
+    m_notebook->SetConstraints(c);
+
+    // Constraints for the Help button
+    c = new wxLayoutConstraints;
+    c->width.AsIs();
+    c->height.AsIs();
+    c->right.SameAs    (this, wxRight, 5);
+    c->bottom.SameAs   (this, wxBottom, 5);
+    helpButton->SetConstraints(c);
+
+    // Constraints for the Cancel button
+    c = new wxLayoutConstraints;
+    c->width.AsIs();
+    c->height.AsIs();
+    c->right.SameAs    (helpButton, wxLeft, 5);
+    c->bottom.SameAs   (this, wxBottom, 5);
+    cancelButton->SetConstraints(c);
+
+    // Constraints for the OK button
+    c = new wxLayoutConstraints;
+    c->width.AsIs();
+    c->height.AsIs();
+    c->right.SameAs    (cancelButton, wxLeft, 5);
+    c->bottom.SameAs   (this, wxBottom, 5);
+    okButton->SetConstraints(c);
+
+    okButton->SetDefault();
+    okButton->SetFocus();
+
+    SetDefaults();
+
+    Layout();
+    Centre(wxBOTH);
+}
+
+void csShapePropertiesDialog::OnOK(wxCommandEvent& event)
+{
+    wxTextCtrl* textCtrl = (wxTextCtrl*) m_generalPropertiesDialog->FindWindow(ID_LABELTEXT);
+    wxASSERT( (textCtrl != NULL) );
+
+    m_generalPropertiesDialog->SetShapeLabel(textCtrl->GetValue());
+
+    wxDialog::OnOK(event);
+}
+
+// Set some suitable defaults in the attribute dialogs (in the first instance,
+// just set all wxChoices to the first element)
+void csShapePropertiesDialog::SetDefaults()
+{
+    if (!m_attributeDialog)
+        return;
+
+    wxNode* node = m_attributeDialog->GetChildren().First();
+    while (node)
+    {
+        wxWindow* child = (wxWindow*) node->Data();
+        if (child->IsKindOf(CLASSINFO(wxChoice)))
+        {
+            wxChoice* choice = (wxChoice*) child;
+            choice->SetSelection(0);
+        }
+        node = node->Next();
+    }
+
+    if (!m_alternativeAttributeDialog)
+        return;
+
+    node = m_alternativeAttributeDialog->GetChildren().First();
+    while (node)
+    {
+        wxWindow* child = (wxWindow*) node->Data();
+        if (child->IsKindOf(CLASSINFO(wxChoice)))
+        {
+            wxChoice* choice = (wxChoice*) child;
+            choice->SetSelection(0);
+        }
+        node = node->Next();
+    }
+}
+
+/*
+ * csGeneralShapePropertiesDialog
+ */
+
+IMPLEMENT_CLASS(csGeneralShapePropertiesDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csGeneralShapePropertiesDialog, wxPanel)
+END_EVENT_TABLE()
+
+csGeneralShapePropertiesDialog::csGeneralShapePropertiesDialog()
+{
+}
+
+void csGeneralShapePropertiesDialog::SetShapeLabel(const wxString& label)
+{
+    wxTextCtrl* textCtrl = (wxTextCtrl*) FindWindow(ID_LABELTEXT);
+    wxASSERT( (textCtrl != NULL) );
+
+    m_label = label;
+
+    textCtrl->SetValue(label);
+}
+
+/*
+ * csThinRectangleDialog
+ */
+
+IMPLEMENT_CLASS(csThinRectangleDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csThinRectangleDialog, wxPanel)
+END_EVENT_TABLE()
+
+csThinRectangleDialog::csThinRectangleDialog()
+{
+}
+
+/*
+ * csWideRectangleDialog
+ */
+
+IMPLEMENT_CLASS(csWideRectangleDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csWideRectangleDialog, wxPanel)
+END_EVENT_TABLE()
+
+csWideRectangleDialog::csWideRectangleDialog()
+{
+}
+
+/*
+ * csTriangleDialog
+ */
+
+IMPLEMENT_CLASS(csTriangleDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csTriangleDialog, wxPanel)
+END_EVENT_TABLE()
+
+csTriangleDialog::csTriangleDialog()
+{
+}
+
+/*
+ * csSemiCircleDialog
+ */
+
+IMPLEMENT_CLASS(csSemiCircleDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csSemiCircleDialog, wxPanel)
+END_EVENT_TABLE()
+
+csSemiCircleDialog::csSemiCircleDialog()
+{
+}
+
+/*
+ * csCircleDialog
+ */
+
+IMPLEMENT_CLASS(csCircleDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csCircleDialog, wxPanel)
+END_EVENT_TABLE()
+
+csCircleDialog::csCircleDialog()
+{
+}
+
+/*
+ * csCircleShadowDialog
+ */
+
+IMPLEMENT_CLASS(csCircleShadowDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csCircleShadowDialog, wxPanel)
+END_EVENT_TABLE()
+
+csCircleShadowDialog::csCircleShadowDialog()
+{
+}
+
+/*
+ * csOctagonDialog
+ */
+
+IMPLEMENT_CLASS(csOctagonDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csOctagonDialog, wxPanel)
+END_EVENT_TABLE()
+
+csOctagonDialog::csOctagonDialog()
+{
+}
+
+/*
+ * csGroupDialog
+ */
+
+IMPLEMENT_CLASS(csGroupDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csGroupDialog, wxPanel)
+END_EVENT_TABLE()
+
+csGroupDialog::csGroupDialog()
+{
+}
+
+/*
+ * csTextBoxDialog
+ */
+
+IMPLEMENT_CLASS(csTextBoxDialog, wxPanel)
+
+BEGIN_EVENT_TABLE(csTextBoxDialog, wxPanel)
+END_EVENT_TABLE()
+
+csTextBoxDialog::csTextBoxDialog()
+{
+}
+
+
diff --git a/utils/ogl/samples/studio/dialogs.h b/utils/ogl/samples/studio/dialogs.h
new file mode 100644
index 0000000000..4a97f8fc75
--- /dev/null
+++ b/utils/ogl/samples/studio/dialogs.h
@@ -0,0 +1,248 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dialogs.h
+// Purpose:     Miscellaneous dialogs
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_DIALOGS_H_
+#define _STUDIO_DIALOGS_H_
+
+#ifdef __GNUG__
+// #pragma interface
+#endif
+
+#include <wx/wx.h>
+#include <wx/notebook.h>
+
+/*
+ * Label editing dialog (about to become obsolete)
+ */
+
+class csLabelEditingDialog: public wxDialog
+{
+DECLARE_CLASS(csLabelEditingDialog)
+public:
+    csLabelEditingDialog(wxWindow* parent);
+
+    void SetShapeLabel(const wxString& label);
+    inline wxString GetShapeLabel() const { return m_label; }
+
+    void OnOK(wxCommandEvent& event);
+
+protected:
+    wxString    m_label;
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * Settings dialog (tabbed)
+ */
+
+class csSettingsDialog: public wxDialog
+{
+DECLARE_CLASS(csSettingsDialog)
+public:
+    csSettingsDialog(wxWindow* parent);
+
+    void OnOK(wxCommandEvent& event);
+
+    virtual bool TransferDataToWindow();
+    virtual bool TransferDataFromWindow();
+
+protected:
+
+    wxPanel*    m_generalSettings;
+    wxPanel*    m_diagramSettings;
+    wxNotebook* m_notebook;
+
+DECLARE_EVENT_TABLE()
+};
+
+#define ID_PROPERTY_NOTEBOOK    1000
+#define ID_GENERAL_SETTINGS     1002
+#define ID_DIAGRAM_SETTINGS     1003
+
+/*
+ * csGeneralShapePropertiesDialog
+ * Name, description etc.
+ */
+
+class csGeneralShapePropertiesDialog: public wxPanel
+{
+DECLARE_CLASS(csGeneralShapePropertiesDialog)
+public:
+    csGeneralShapePropertiesDialog();
+
+    void SetShapeLabel(const wxString& label);
+    inline wxString GetShapeLabel() const { return m_label; }
+
+protected:
+    wxString    m_label;
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * Shape properties dialog (tabbed)
+ */
+
+class csShapePropertiesDialog: public wxDialog
+{
+DECLARE_CLASS(csShapePropertiesDialog)
+public:
+    csShapePropertiesDialog(wxWindow* parent, const wxString& title, wxPanel* attributeDialog, const wxString& attributeDialogName);
+
+    void OnOK(wxCommandEvent& event);
+
+    // Set some suitable defaults in the attribute dialogs (in the first instance,
+    // just set all wxChoices to the first element)
+    void SetDefaults();
+    
+// Accessors
+    csGeneralShapePropertiesDialog* GetGeneralPropertiesDialog() const { return m_generalPropertiesDialog; }
+
+
+protected:
+
+    // Attributes, specific to each shape
+    wxPanel*                        m_attributeDialog;
+    wxPanel*                        m_alternativeAttributeDialog;
+
+   // General properties, same for each shape, e.g. name/description
+    csGeneralShapePropertiesDialog* m_generalPropertiesDialog;
+
+    wxNotebook* m_notebook;
+
+DECLARE_EVENT_TABLE()
+};
+
+#define ID_SHAPE_PROPERTY_NOTEBOOK    1000
+
+//// Specific attribute-editing panel classes below here
+
+/*
+ * csThinRectangleDialog
+ */
+
+class csThinRectangleDialog: public wxPanel
+{
+DECLARE_CLASS(csThinRectangleDialog)
+public:
+    csThinRectangleDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csWideRectangleDialog
+ */
+
+class csWideRectangleDialog: public wxPanel
+{
+DECLARE_CLASS(csWideRectangleDialog)
+public:
+    csWideRectangleDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csTriangleDialog
+ */
+
+class csTriangleDialog: public wxPanel
+{
+DECLARE_CLASS(csTriangleDialog)
+public:
+    csTriangleDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csSemiCircleDialog
+ */
+
+class csSemiCircleDialog: public wxPanel
+{
+DECLARE_CLASS(csSemiCircleDialog)
+public:
+    csSemiCircleDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csCircleDialog
+ */
+
+class csCircleDialog: public wxPanel
+{
+DECLARE_CLASS(csCircleDialog)
+public:
+    csCircleDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csCircleShadowDialog
+ */
+
+class csCircleShadowDialog: public wxPanel
+{
+DECLARE_CLASS(csCircleShadowDialog)
+public:
+    csCircleShadowDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csOctagonDialog
+ */
+
+class csOctagonDialog: public wxPanel
+{
+DECLARE_CLASS(csOctagonDialog)
+public:
+    csOctagonDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csGroupDialog
+ */
+
+class csGroupDialog: public wxPanel
+{
+DECLARE_CLASS(csGroupDialog)
+public:
+    csGroupDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+/*
+ * csTextBoxDialog
+ */
+
+class csTextBoxDialog: public wxPanel
+{
+DECLARE_CLASS(csTextBoxDialog)
+public:
+    csTextBoxDialog();
+
+DECLARE_EVENT_TABLE()
+};
+
+
+#endif
+    // _STUDIO_DIALOGS_H_
diff --git a/utils/ogl/samples/studio/doc.cpp b/utils/ogl/samples/studio/doc.cpp
new file mode 100644
index 0000000000..fd3a3a1a65
--- /dev/null
+++ b/utils/ogl/samples/studio/doc.cpp
@@ -0,0 +1,598 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        doc.cpp
+// Purpose:     Implements document functionality
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/wxexpr.h>
+
+#include "studio.h"
+#include "doc.h"
+#include "view.h"
+#include "basicp.h"
+
+IMPLEMENT_DYNAMIC_CLASS(csDiagramDocument, wxDocument)
+
+#ifdef _MSC_VER
+#pragma warning(disable:4355)
+#endif
+
+csDiagramDocument::csDiagramDocument():m_diagram(this)
+{
+}
+
+#ifdef _MSC_VER
+#pragma warning(default:4355)
+#endif
+
+csDiagramDocument::~csDiagramDocument()
+{
+}
+
+bool csDiagramDocument::OnCloseDocument()
+{
+  m_diagram.DeleteAllShapes();
+  return TRUE;
+}
+
+bool csDiagramDocument::OnSaveDocument(const wxString& file)
+{
+  if (file == "")
+    return FALSE;
+
+  if (!m_diagram.SaveFile(file))
+  {
+    wxString msgTitle;
+    if (wxTheApp->GetAppName() != "")
+        msgTitle = wxTheApp->GetAppName();
+    else
+        msgTitle = wxString("File error");
+
+    (void)wxMessageBox("Sorry, could not open this file for saving.", msgTitle, wxOK | wxICON_EXCLAMATION,
+      GetDocumentWindow());
+    return FALSE;
+  }
+
+  Modify(FALSE);
+  SetFilename(file);
+  return TRUE;
+}
+	
+bool csDiagramDocument::OnOpenDocument(const wxString& file)
+{
+  if (!OnSaveModified())
+    return FALSE;
+
+  wxString msgTitle;
+  if (wxTheApp->GetAppName() != "")
+    msgTitle = wxTheApp->GetAppName();
+  else
+    msgTitle = wxString("File error");
+
+  m_diagram.DeleteAllShapes();
+  if (!m_diagram.LoadFile(file))
+  {
+    (void)wxMessageBox("Sorry, could not open this file.", msgTitle, wxOK|wxICON_EXCLAMATION,
+     GetDocumentWindow());
+    return FALSE;
+  }
+  SetFilename(file, TRUE);
+  Modify(FALSE);
+  UpdateAllViews();
+  
+  return TRUE;
+}
+	
+
+/*
+ * Implementation of drawing command
+ */
+
+csDiagramCommand::csDiagramCommand(const wxString& name, csDiagramDocument *doc,
+    csCommandState* onlyState):
+  wxCommand(TRUE, name)
+{
+  m_doc = doc;
+
+  if (onlyState)
+  {
+    AddState(onlyState);
+  }
+}
+
+csDiagramCommand::~csDiagramCommand()
+{
+    wxNode* node = m_states.First();
+    while (node)
+    {
+        csCommandState* state = (csCommandState*) node->Data();
+        delete state;
+        node = node->Next();
+    }
+}
+
+void csDiagramCommand::AddState(csCommandState* state)
+{
+    state->m_doc = m_doc;
+//    state->m_cmd = m_cmd;
+    m_states.Append(state);
+}
+
+// Insert a state at the beginning of the list
+void csDiagramCommand::InsertState(csCommandState* state)
+{
+    state->m_doc = m_doc;
+//    state->m_cmd = m_cmd;
+    m_states.Insert(state);
+}
+
+// Schedule all lines connected to the states to be cut.
+void csDiagramCommand::RemoveLines()
+{
+    wxNode* node = m_states.First();
+    while (node)
+    {
+        csCommandState* state = (csCommandState*) node->Data();
+        wxShape* shape = state->GetShapeOnCanvas();
+        wxASSERT( (shape != NULL) );
+
+        wxNode *node1 = shape->GetLines().First();
+        while (node1)
+        {
+            wxLineShape *line = (wxLineShape *)node1->Data();
+            if (!FindStateByShape(line))
+            {
+                csCommandState* newState = new csCommandState(ID_CS_CUT, NULL, line);
+                InsertState(newState);
+            }
+
+            node1 = node1->Next();
+        }
+        node = node->Next();
+    }
+}
+
+csCommandState* csDiagramCommand::FindStateByShape(wxShape* shape)
+{
+    wxNode* node = m_states.First();
+    while (node)
+    {
+        csCommandState* state = (csCommandState*) node->Data();
+        if (shape == state->GetShapeOnCanvas() || shape == state->GetSavedState())
+            return state;
+        node = node->Next();
+    }
+    return NULL;
+}
+
+bool csDiagramCommand::Do()
+{
+    wxNode* node = m_states.First();
+    while (node)
+    {
+        csCommandState* state = (csCommandState*) node->Data();
+        if (!state->Do())
+            return FALSE;
+        node = node->Next();
+    }
+    return TRUE;
+}
+
+bool csDiagramCommand::Undo()
+{
+    // Undo in reverse order, so e.g. shapes get added
+    // back before the lines do.
+    wxNode* node = m_states.Last();
+    while (node)
+    {
+        csCommandState* state = (csCommandState*) node->Data();
+        if (!state->Undo())
+            return FALSE;
+        node = node->Previous();
+    }
+    return TRUE;
+}
+
+csCommandState::csCommandState(int cmd, wxShape* savedState, wxShape* shapeOnCanvas)
+{
+    m_cmd = cmd;
+    m_doc = NULL;
+    m_savedState = savedState;
+    m_shapeOnCanvas = shapeOnCanvas;
+    m_linePositionFrom = 0;
+    m_linePositionTo = 0;
+}
+
+csCommandState::~csCommandState()
+{
+    if (m_savedState)
+    {
+        m_savedState->SetCanvas(NULL);
+        delete m_savedState;
+    }
+}
+
+bool csCommandState::Do()
+{
+  switch (m_cmd)
+  {
+    case ID_CS_CUT:
+    {
+        // New state is 'nothing' - maybe pass shape ID to state so we know what
+        // we're talking about.
+        // Then save old shape in m_savedState (actually swap pointers)
+
+        wxASSERT( (m_shapeOnCanvas != NULL) );
+        wxASSERT( (m_savedState == NULL) ); // new state will be 'nothing'
+        wxASSERT( (m_doc != NULL) );
+
+        wxShapeCanvas* canvas = m_shapeOnCanvas->GetCanvas();
+
+        // In case this is a line
+        wxShape* lineFrom = NULL;
+        wxShape* lineTo = NULL;
+        int attachmentFrom = 0, attachmentTo = 0;
+
+        if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            // Store the from/to info to save in the line shape
+            wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
+            lineFrom = lineShape->GetFrom();
+            lineTo = lineShape->GetTo();
+            attachmentFrom = lineShape->GetAttachmentFrom();
+            attachmentTo = lineShape->GetAttachmentTo();
+
+            m_linePositionFrom = lineFrom->GetLinePosition(lineShape);
+            m_linePositionTo = lineTo->GetLinePosition(lineShape);
+        }
+
+        m_shapeOnCanvas->Select(FALSE);
+        ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
+
+        m_shapeOnCanvas->Unlink();
+        
+        m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
+
+        m_savedState = m_shapeOnCanvas;
+
+        if (m_savedState->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            // Restore the from/to info for future reference
+            wxLineShape* lineShape = (wxLineShape*) m_savedState;
+            lineShape->SetFrom(lineFrom);
+            lineShape->SetTo(lineTo);
+            lineShape->SetAttachments(attachmentFrom, attachmentTo);
+
+            wxClientDC dc(canvas);
+            canvas->PrepareDC(dc);
+
+            lineFrom->MoveLinks(dc);
+            lineTo->MoveLinks(dc);
+        }
+
+        m_doc->Modify(TRUE);
+        m_doc->UpdateAllViews();
+        break;
+    }
+    case ID_CS_ADD_SHAPE:
+    case ID_CS_ADD_SHAPE_SELECT:
+    {
+        // The app has given the command state a new m_savedState
+        // shape, which is the new shape to add to the canvas (but
+        // not actually added until this point).
+        // The new 'saved state' is therefore 'nothing' since there
+        // was nothing there before.
+
+        wxASSERT( (m_shapeOnCanvas == NULL) );
+        wxASSERT( (m_savedState != NULL) );
+        wxASSERT( (m_doc != NULL) );
+
+        m_shapeOnCanvas = m_savedState;
+        m_savedState = NULL;
+
+        m_doc->GetDiagram()->AddShape(m_shapeOnCanvas);
+        m_shapeOnCanvas->Show(TRUE);
+
+        wxClientDC dc(m_shapeOnCanvas->GetCanvas());
+        m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
+
+        csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
+        m_shapeOnCanvas->FormatText(dc, handler->m_label);
+
+        m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
+
+        if (m_cmd == ID_CS_ADD_SHAPE_SELECT)
+        {
+            m_shapeOnCanvas->Select(TRUE, &dc);
+            ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
+        }
+
+        m_doc->Modify(TRUE);
+        m_doc->UpdateAllViews();
+        break;
+    }
+    case ID_CS_ADD_LINE:
+    case ID_CS_ADD_LINE_SELECT:
+    {
+        wxASSERT( (m_shapeOnCanvas == NULL) );
+        wxASSERT( (m_savedState != NULL) );
+        wxASSERT( (m_doc != NULL) );
+
+        wxLineShape *lineShape = (wxLineShape *)m_savedState;
+        wxASSERT( (lineShape->GetFrom() != NULL) );
+        wxASSERT( (lineShape->GetTo() != NULL) );
+
+        m_shapeOnCanvas = m_savedState;
+        m_savedState = NULL;
+
+        m_doc->GetDiagram()->AddShape(lineShape);
+
+        lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
+            lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo());
+      
+        lineShape->Show(TRUE);
+
+        wxClientDC dc(lineShape->GetCanvas());
+        lineShape->GetCanvas()->PrepareDC(dc);
+
+        // It won't get drawn properly unless you move both
+        // connected images
+        lineShape->GetFrom()->Move(dc, lineShape->GetFrom()->GetX(), lineShape->GetFrom()->GetY());
+        lineShape->GetTo()->Move(dc, lineShape->GetTo()->GetX(), lineShape->GetTo()->GetY());
+
+        if (m_cmd == ID_CS_ADD_LINE_SELECT)
+        {
+            lineShape->Select(TRUE, &dc);
+            ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
+        }
+
+        m_doc->Modify(TRUE);
+        m_doc->UpdateAllViews();
+        break;
+    }
+    case ID_CS_CHANGE_BACKGROUND_COLOUR:
+    case ID_CS_MOVE:
+    case ID_CS_SIZE:
+    case ID_CS_EDIT_PROPERTIES:
+    case ID_CS_FONT_CHANGE:
+    case ID_CS_ARROW_CHANGE:
+    case ID_CS_ROTATE_CLOCKWISE:
+    case ID_CS_ROTATE_ANTICLOCKWISE:
+    case ID_CS_CHANGE_LINE_ORDERING:
+    case ID_CS_CHANGE_LINE_ATTACHMENT:
+    case ID_CS_ALIGN:
+    case ID_CS_NEW_POINT:
+    case ID_CS_CUT_POINT:
+    case ID_CS_MOVE_LINE_POINT:
+    case ID_CS_STRAIGHTEN:
+    case ID_CS_MOVE_LABEL:
+    {
+        // At this point we have been given a new shape
+        // just like the old one but with a changed colour.
+        // It's now time to apply that change to the
+        // shape on the canvas, saving the old state.
+        // NOTE: this is general enough to work with MOST attribute
+        // changes!
+
+        wxASSERT( (m_shapeOnCanvas != NULL) );
+        wxASSERT( (m_savedState != NULL) ); // This is the new shape with changed colour
+        wxASSERT( (m_doc != NULL) );
+
+        wxClientDC dc(m_shapeOnCanvas->GetCanvas());
+        m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
+
+        bool isSelected = m_shapeOnCanvas->Selected();
+        if (isSelected)
+            m_shapeOnCanvas->Select(FALSE, & dc);
+
+        if (m_cmd == ID_CS_SIZE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
+            m_cmd == ID_CS_CHANGE_LINE_ORDERING || m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
+        {
+            m_shapeOnCanvas->Erase(dc);
+        }
+
+        // TODO: make sure the ID is the same. Or, when applying the new state,
+        // don't change the original ID.
+        wxShape* tempShape = m_shapeOnCanvas->CreateNewCopy();
+
+        // Apply the saved state to the shape on the canvas, by copying.
+        m_savedState->CopyWithHandler(*m_shapeOnCanvas);
+
+        // Delete this state now it's been used (m_shapeOnCanvas currently holds this state)
+        delete m_savedState;
+
+        // Remember the previous state
+        m_savedState = tempShape;
+
+        // Redraw the shape
+
+        if (m_cmd == ID_CS_MOVE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
+            m_cmd == ID_CS_ALIGN)
+        {
+            m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
+
+            csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
+            m_shapeOnCanvas->FormatText(dc, handler->m_label);
+            m_shapeOnCanvas->Draw(dc);
+        }
+        else if (m_cmd == ID_CS_CHANGE_LINE_ORDERING)
+        {
+            m_shapeOnCanvas->MoveLinks(dc);
+        }
+        else if (m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
+        {
+            wxLineShape *lineShape = (wxLineShape *)m_shapeOnCanvas;
+
+            // Have to move both sets of links since we don't know which links
+            // have been affected (unless we compared before and after states).
+            lineShape->GetFrom()->MoveLinks(dc);
+            lineShape->GetTo()->MoveLinks(dc);
+        }
+        else if (m_cmd == ID_CS_SIZE)
+        {
+            double width, height;
+            m_shapeOnCanvas->GetBoundingBoxMax(&width, &height);
+
+            m_shapeOnCanvas->SetSize(width, height);
+            m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
+
+            m_shapeOnCanvas->Show(TRUE);
+
+            // Recursively redraw links if we have a composite.
+            if (m_shapeOnCanvas->GetChildren().Number() > 0)
+                m_shapeOnCanvas->DrawLinks(dc, -1, TRUE);
+
+            m_shapeOnCanvas->GetEventHandler()->OnEndSize(width, height);
+        }
+        else if (m_cmd == ID_CS_EDIT_PROPERTIES || m_cmd == ID_CS_FONT_CHANGE)
+        {
+            csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
+            m_shapeOnCanvas->FormatText(dc, handler->m_label);
+            m_shapeOnCanvas->Draw(dc);
+        }
+        else
+        {
+            m_shapeOnCanvas->Draw(dc);
+        }
+
+        if (isSelected)
+            m_shapeOnCanvas->Select(TRUE, & dc);
+        
+        m_doc->Modify(TRUE);
+        m_doc->UpdateAllViews();
+
+        break;
+    }
+  }
+  return TRUE;
+}
+
+bool csCommandState::Undo()
+{
+  switch (m_cmd)
+  {
+    case ID_CS_CUT:
+    {
+        wxASSERT( (m_savedState != NULL) );
+        wxASSERT( (m_doc != NULL) );
+
+        m_doc->GetDiagram()->AddShape(m_savedState);
+        m_shapeOnCanvas = m_savedState;
+        m_savedState = NULL;
+
+        if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
+            lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
+                lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo(),
+                m_linePositionFrom, m_linePositionTo);
+
+            wxShapeCanvas* canvas = lineShape->GetFrom()->GetCanvas();
+
+            wxClientDC dc(canvas);
+            canvas->PrepareDC(dc);
+
+            lineShape->GetFrom()->MoveLinks(dc);
+            lineShape->GetTo()->MoveLinks(dc);
+
+        }
+        m_shapeOnCanvas->Show(TRUE);
+
+        m_doc->Modify(TRUE);
+        m_doc->UpdateAllViews();
+        break;
+    }
+    case ID_CS_ADD_SHAPE:
+    case ID_CS_ADD_LINE:
+    case ID_CS_ADD_SHAPE_SELECT:
+    case ID_CS_ADD_LINE_SELECT:
+    {
+        wxASSERT( (m_shapeOnCanvas != NULL) );
+        wxASSERT( (m_savedState == NULL) );
+        wxASSERT( (m_doc != NULL) );
+
+        // In case this is a line
+        wxShape* lineFrom = NULL;
+        wxShape* lineTo = NULL;
+        int attachmentFrom = 0, attachmentTo = 0;
+
+        if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            // Store the from/to info to save in the line shape
+            wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
+            lineFrom = lineShape->GetFrom();
+            lineTo = lineShape->GetTo();
+            attachmentFrom = lineShape->GetAttachmentFrom();
+            attachmentTo = lineShape->GetAttachmentTo();
+        }
+
+        wxClientDC dc(m_shapeOnCanvas->GetCanvas());
+        m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
+
+        m_shapeOnCanvas->Select(FALSE, &dc);
+        ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
+        m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
+        m_shapeOnCanvas->Unlink(); // Unlinks the line, if it is a line
+
+        if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            // Restore the from/to info for future reference
+            wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
+            lineShape->SetFrom(lineFrom);
+            lineShape->SetTo(lineTo);
+            lineShape->SetAttachments(attachmentFrom, attachmentTo);
+        }
+
+        m_savedState = m_shapeOnCanvas;
+        m_shapeOnCanvas = NULL;
+
+        m_doc->Modify(TRUE);
+        m_doc->UpdateAllViews();
+        break;
+    }
+    case ID_CS_CHANGE_BACKGROUND_COLOUR:
+    case ID_CS_MOVE:
+    case ID_CS_SIZE:
+    case ID_CS_EDIT_PROPERTIES:
+    case ID_CS_FONT_CHANGE:
+    case ID_CS_ARROW_CHANGE:
+    case ID_CS_ROTATE_CLOCKWISE:
+    case ID_CS_ROTATE_ANTICLOCKWISE:
+    case ID_CS_CHANGE_LINE_ORDERING:
+    case ID_CS_CHANGE_LINE_ATTACHMENT:
+    case ID_CS_ALIGN:
+    case ID_CS_NEW_POINT:
+    case ID_CS_CUT_POINT:
+    case ID_CS_MOVE_LINE_POINT:
+    case ID_CS_STRAIGHTEN:
+    case ID_CS_MOVE_LABEL:
+    {
+        // Exactly like the Do case; we're just swapping states.
+        Do();
+        break;
+    }
+  }
+
+    return TRUE;
+}
+
diff --git a/utils/ogl/samples/studio/doc.h b/utils/ogl/samples/studio/doc.h
new file mode 100644
index 0000000000..0a8be2f254
--- /dev/null
+++ b/utils/ogl/samples/studio/doc.h
@@ -0,0 +1,134 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        doc.h
+// Purpose:     Document classes
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_DOC_H_
+#define _STUDIO_DOC_H_
+
+#ifdef __GNUG__
+// #pragma interface
+#endif
+
+#include <wx/docview.h>
+#include <wx/string.h>
+#include <wx/wxexpr.h>
+
+#include "ogl.h"
+#include "shapes.h"
+
+/*
+ * A diagram document, which contains a diagram.
+ */
+ 
+class csDiagramDocument: public wxDocument
+{
+  DECLARE_DYNAMIC_CLASS(csDiagramDocument)
+public:
+  csDiagramDocument();
+  ~csDiagramDocument();
+
+  bool OnSaveDocument(const wxString& file);
+  bool OnOpenDocument(const wxString& file);
+  
+  inline wxDiagram *GetDiagram() { return &m_diagram; }
+  
+  bool OnCloseDocument();
+
+protected:
+  csDiagram         m_diagram;
+};
+
+/*
+ Do/Undo 30/7/98
+
+ 1) We have a csCommandState, and in csDiagramCommand you have a list of
+    these. This allows undo to work with several shapes at once.
+
+ 2) Instead of storing info about each operation, e.g. separate pens, colours,
+    etc., we simply use a copy of the shape.
+    In csCommandState, we have a pointer to the actual shape in the canvas, m_currentShape.
+    We also have wxShape* m_shapeState which stores the requested or previous state
+    (depending on whether it's before the Do or after the Do.
+
+    - In Do: save a temp copy of the old m_currentShape (i.e. the state just before it's changed).
+      Change the data pointed to by m_currentShape to the new attributes stored in m_shapeState.
+      Now assign the temp copy to m_shapeState, for use in Undo.
+
+      wxShape* temp = m_currentShape->Copy(); // Take a copy of the current state
+      m_currentShape->Set(m_shapeState);      // Apply the new state (e.g. moving, changing colour etc.)
+      delete m_shapeState;                    // Delete the previous 'old state'.
+      m_shapeState = temp;                    // Remember the new 'old state'.
+
+ */
+
+  
+class csCommandState;
+class csDiagramCommand: public wxCommand
+{
+    friend class csCommandState;
+ public:
+  // Multi-purpose constructor for creating, deleting shapes
+  csDiagramCommand(const wxString& name, csDiagramDocument *doc,
+    csCommandState* onlyState = NULL); // Allow for the common case of just one state to change
+
+  ~csDiagramCommand();
+
+  bool Do();
+  bool Undo();
+
+  // Add a state to the end of the list
+  void AddState(csCommandState* state);
+
+  // Insert a state at the beginning of the list
+  void InsertState(csCommandState* state);
+
+  // Schedule all lines connected to the states to be cut.
+  void RemoveLines();
+
+  // Find the state that refers to this shape
+  csCommandState* FindStateByShape(wxShape* shape);
+
+  wxList& GetStates() const { return (wxList&) m_states; }
+
+ protected:
+  csDiagramDocument*    m_doc;
+  wxList                m_states;
+};
+
+class csCommandState: public wxObject
+{
+    friend class csDiagramCommand;
+public:
+    csCommandState(int cmd, wxShape* savedState, wxShape* shapeOnCanvas);
+    ~csCommandState();
+
+    bool Do();
+    bool Undo();
+
+    inline void SetSavedState(wxShape *s) { m_savedState = s; }
+    inline wxShape *GetSavedState() const { return m_savedState; }
+
+    inline void SetShapeOnCanvas(wxShape *s) { m_shapeOnCanvas = s; }
+    inline wxShape *GetShapeOnCanvas() const { return m_shapeOnCanvas; }
+protected:
+    wxShape*                m_savedState;       // Previous state, for restoring on Undo
+    wxShape*                m_shapeOnCanvas;    // The actual shape on the canvas
+    csDiagramDocument*      m_doc;
+    int                     m_cmd;
+
+    // These store the line ordering for the shapes at either end,
+    // so an un-cut line can restore the ordering properly. Otherwise
+    // it just adds the line at an arbitrary position.
+    int                     m_linePositionFrom;
+    int                     m_linePositionTo;
+};
+
+#endif
+  // _STUDIO_DOC_H_
diff --git a/utils/ogl/samples/studio/mainfrm.cpp b/utils/ogl/samples/studio/mainfrm.cpp
new file mode 100644
index 0000000000..0364cdbd4f
--- /dev/null
+++ b/utils/ogl/samples/studio/mainfrm.cpp
@@ -0,0 +1,256 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        mainfrm.cpp
+// Purpose:     Studio main frame
+// Author:      Julian Smart
+// Modified by:
+// Created:     27/7/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#include "wx/mdi.h"
+#endif
+
+#include "wx/laywin.h"
+
+#include "studio.h"
+#include "view.h"
+#include "doc.h"
+#include "cspalette.h"
+#include "mainfrm.h"
+#include "dialogs.h"
+
+BEGIN_EVENT_TABLE(csFrame, wxDocMDIParentFrame)
+    EVT_MENU(ID_CS_ABOUT, csFrame::OnAbout)
+    EVT_MENU(wxID_EXIT, csFrame::OnQuit)
+    EVT_MENU(wxID_HELP, csFrame::OnHelp)
+    EVT_MENU(ID_CS_SETTINGS, csFrame::OnSettings)
+    EVT_SIZE(csFrame::OnSize)
+    EVT_SASH_DRAGGED(ID_LAYOUT_WINDOW_PALETTE, csFrame::OnSashDragPaletteWindow)
+    EVT_SASH_DRAGGED(ID_LAYOUT_WINDOW_PROJECT, csFrame::OnSashDragProjectWindow)
+    EVT_IDLE(csFrame::OnIdle)
+    EVT_UPDATE_UI(wxID_PRINT, csFrame::OnUpdateDisable)
+    EVT_UPDATE_UI(wxID_PREVIEW, csFrame::OnUpdateDisable)
+    EVT_UPDATE_UI(wxID_SAVE, csFrame::OnSaveUpdate)
+    EVT_UPDATE_UI(wxID_SAVEAS, csFrame::OnSaveUpdate)
+    EVT_UPDATE_UI(wxID_UNDO, csFrame::OnUpdateDisable)
+    EVT_UPDATE_UI(wxID_REDO, csFrame::OnUpdateDisable)
+    EVT_UPDATE_UI(wxID_CUT, csFrame::OnUpdateDisable)
+    EVT_UPDATE_UI(wxID_COPY, csFrame::OnUpdateDisable)
+    EVT_UPDATE_UI(wxID_PASTE, csFrame::OnUpdateDisable)
+    EVT_CLOSE(csFrame::OnCloseWindow)
+END_EVENT_TABLE()
+
+// Define my frame constructor
+csFrame::csFrame(wxDocManager* manager, wxFrame *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size,
+	long style):
+  wxDocMDIParentFrame(manager, parent, id, title, pos, size, style, "frame")
+{
+    CreateToolBar(wxNO_BORDER|wxTB_FLAT|wxTB_HORIZONTAL);
+    wxGetApp().InitToolBar(GetToolBar());
+
+    // Accelerators
+    wxAcceleratorEntry entries[4];
+
+    entries[0].Set(wxACCEL_NORMAL,  WXK_F1,        wxID_HELP);
+    entries[1].Set(wxACCEL_CTRL,   'O',            wxID_OPEN);
+    entries[2].Set(wxACCEL_CTRL,   'N',            wxID_NEW);
+    entries[3].Set(wxACCEL_CTRL,   'P',            wxID_PRINT);
+
+    wxAcceleratorTable accel(4, entries);
+    SetAcceleratorTable(accel);
+}
+
+void csFrame::OnHelp(wxCommandEvent& event)
+{
+    wxGetApp().GetHelpController().DisplayContents();
+}
+
+void csFrame::OnSettings(wxCommandEvent& event)
+{
+    csSettingsDialog* dialog = new csSettingsDialog(this);
+    int ret = dialog->ShowModal();
+    dialog->Destroy();
+}
+
+void csFrame::OnQuit(wxCommandEvent& event)
+{
+      Close(TRUE);
+}
+
+void csFrame::OnAbout(wxCommandEvent& event)
+{
+      (void)wxMessageBox("OGL Studio\n(c) 1999, Julian Smart", "About OGL Studio", wxICON_INFORMATION);
+}
+
+void csFrame::OnSashDragPaletteWindow(wxSashEvent& event)
+{
+    if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE)
+        return;
+
+    switch (event.GetId())
+    {
+        case ID_LAYOUT_WINDOW_PALETTE:
+        {
+            wxGetApp().GetDiagramPaletteSashWindow()->SetDefaultSize(wxSize(10000, event.GetDragRect().height));
+            break;
+        }
+    }
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame(this);
+}
+
+void csFrame::OnSashDragProjectWindow(wxSashEvent& event)
+{
+    if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE)
+        return;
+
+    switch (event.GetId())
+    {
+        case ID_LAYOUT_WINDOW_PROJECT:
+        {
+            wxGetApp().GetProjectSashWindow()->SetDefaultSize(wxSize(event.GetDragRect().width, 10000));
+            break;
+        }
+    }
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame(this);
+}
+
+// Define the behaviour for the frame closing
+// - must delete all frames except for the main one.
+void csFrame::OnCloseWindow(wxCloseEvent& event)
+{
+    int x, y;
+    GetPosition(& x, & y);
+    wxGetApp().m_mainFramePos = wxPoint(x, y);
+
+    GetSize(& x, & y);
+    wxGetApp().m_mainFrameSize = wxSize(x, y);
+
+    wxDocMDIParentFrame::OnCloseWindow(event);
+}
+
+void csFrame::OnSize(wxSizeEvent& event)
+{
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame(this);
+}
+
+// Make sure the correct toolbars are showing for the active view
+void csFrame::OnIdle(wxIdleEvent& event)
+{
+    wxFrame::OnIdle(event);
+
+    wxSashLayoutWindow* paletteWin = wxGetApp().GetDiagramPaletteSashWindow();
+    wxSashLayoutWindow* diagramToolBarWin = wxGetApp().GetDiagramToolBarSashWindow();
+    if (!paletteWin || !diagramToolBarWin)
+        return;
+    bool doLayout = FALSE;
+    if (GetActiveChild())
+    {
+        if (!paletteWin->IsShown() || !diagramToolBarWin->IsShown())
+        {
+            paletteWin->Show(TRUE);
+            diagramToolBarWin->Show(TRUE);
+
+            doLayout = TRUE;
+        }
+    }
+    else
+    {
+        if (paletteWin->IsShown() || diagramToolBarWin->IsShown())
+        {
+            paletteWin->Show(FALSE);
+            diagramToolBarWin->Show(FALSE);
+            doLayout = TRUE;
+        }
+    }
+    if (doLayout)
+    {
+        wxLayoutAlgorithm layout;
+        layout.LayoutMDIFrame(this);
+    }
+}
+
+// General handler for disabling items
+void csFrame::OnUpdateDisable(wxUpdateUIEvent& event)
+{
+    event.Enable(FALSE);
+}
+
+void csFrame::OnSaveUpdate(wxUpdateUIEvent& event)
+{
+    event.Enable( (GetActiveChild() != NULL) );
+}
+
+/*
+ * Child frame
+ */
+
+BEGIN_EVENT_TABLE(csMDIChildFrame, wxDocMDIChildFrame)
+  EVT_ACTIVATE(csMDIChildFrame::OnActivate)
+END_EVENT_TABLE()
+
+csMDIChildFrame::csMDIChildFrame(wxDocument* doc, wxView* view, wxMDIParentFrame *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
+  wxDocMDIChildFrame(doc, view, parent, id, title, pos, size, style)
+{
+    // Accelerators
+    wxAcceleratorEntry entries[18];
+
+    // Usual editing functions
+    entries[0].Set(wxACCEL_NORMAL,  WXK_DELETE,     wxID_CLEAR);
+    entries[1].Set(wxACCEL_CTRL,    'X',            wxID_CUT);
+    entries[2].Set(wxACCEL_CTRL,    'C',            wxID_COPY);
+    entries[3].Set(wxACCEL_SHIFT,   WXK_INSERT,     wxID_PASTE);
+    entries[4].Set(wxACCEL_CTRL,    'V',            wxID_PASTE);
+    entries[5].Set(wxACCEL_CTRL,    'A',            ID_CS_SELECT_ALL);
+
+    // Undo/redo
+    entries[6].Set(wxACCEL_CTRL,    'Z',            wxID_UNDO);
+    entries[7].Set(wxACCEL_CTRL,    'Y',            wxID_REDO);
+
+    // Other
+    entries[8].Set(wxACCEL_NORMAL,  WXK_RETURN,     ID_CS_EDIT_PROPERTIES);
+    entries[9].Set(wxACCEL_ALT,     WXK_RETURN,     ID_CS_EDIT_PROPERTIES);
+    entries[10].Set(wxACCEL_CTRL,   'D',            wxID_DUPLICATE);
+    entries[11].Set(wxACCEL_NORMAL,  WXK_F1,        wxID_HELP);
+
+    // File handling
+    entries[12].Set(wxACCEL_CTRL,   'S',            wxID_SAVE);
+    entries[13].Set(wxACCEL_NORMAL,  WXK_F12,       wxID_SAVEAS);
+    entries[14].Set(wxACCEL_CTRL,   'O',            wxID_OPEN);
+    entries[15].Set(wxACCEL_CTRL,   'N',            wxID_NEW);
+    entries[16].Set(wxACCEL_CTRL,   'P',            wxID_PRINT);
+    entries[17].Set(wxACCEL_CTRL,   'W',            wxID_CLOSE);
+
+
+    wxAcceleratorTable accel(18, entries);
+    SetAcceleratorTable(accel);
+}
+
+void csMDIChildFrame::OnActivate(wxActivateEvent& event)
+{
+    wxDocMDIChildFrame::OnActivate(event);
+/*
+    wxSashLayoutWindow* win = wxGetApp().GetDiagramPaletteSashWindow();
+    if (!win)
+        return;
+
+    win->Show(event.GetActive());
+
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame((wxMDIParentFrame*) GetParent());
+*/
+}
+
diff --git a/utils/ogl/samples/studio/mainfrm.h b/utils/ogl/samples/studio/mainfrm.h
new file mode 100644
index 0000000000..9200fc2c4c
--- /dev/null
+++ b/utils/ogl/samples/studio/mainfrm.h
@@ -0,0 +1,55 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        mainfrm.h
+// Purpose:     Studio main window class
+// Author:      Julian Smart
+// Modified by:
+// Created:     27/7/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_MAINFRM_H_
+#define _STUDIO_MAINFRM_H_
+
+#include <wx/docmdi.h>
+
+class wxSashLayoutWindow;
+class wxSashEvent;
+
+class csFrame: public wxDocMDIParentFrame
+{
+  public:
+    csFrame(wxDocManager *manager, wxFrame *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style);
+
+    void OnCloseWindow(wxCloseEvent& event);
+    void OnSize(wxSizeEvent& event);
+    void OnAbout(wxCommandEvent& event);
+    void OnNewWindow(wxCommandEvent& event);
+    void OnQuit(wxCommandEvent& event);
+    void OnSashDragPaletteWindow(wxSashEvent& event);
+    void OnSashDragProjectWindow(wxSashEvent& event);
+    void OnIdle(wxIdleEvent& event);
+    void OnHelp(wxCommandEvent& event);
+    void OnSettings(wxCommandEvent& event);
+
+    // General handler for disabling items
+    void OnUpdateDisable(wxUpdateUIEvent& event);
+    void OnSaveUpdate(wxUpdateUIEvent& event);
+
+DECLARE_EVENT_TABLE()
+};
+
+class csMDIChildFrame: public wxDocMDIChildFrame
+{
+  public:
+    csMDIChildFrame(wxDocument* doc, wxView* view, wxMDIParentFrame *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style);
+
+    void OnActivate(wxActivateEvent& event);
+
+DECLARE_EVENT_TABLE()
+};
+
+#endif
+  // _STUDIO_MAINFRM_H_
+
diff --git a/utils/ogl/samples/studio/makefile.unx b/utils/ogl/samples/studio/makefile.unx
new file mode 100644
index 0000000000..d1cca94307
--- /dev/null
+++ b/utils/ogl/samples/studio/makefile.unx
@@ -0,0 +1,39 @@
+#
+# File:		makefile.unx
+# Author:	Julian Smart
+# Created:	1998
+# Updated:	
+# Copyright:	(c) 1998 Julian Smart
+#
+# "%W% %G%"
+#
+# Makefile for OGL Studio (UNIX).
+
+PROGRAM=studio
+
+OBJECTS=$(PROGRAM).o doc.o shapes.o symbols.o view.o cspalette.o\
+  mainfrm.o project.o dialogs.o csprint.o
+
+EXTRACPPFLAGS=-I$(WXDIR)/utils/ogl/src
+EXTRALDLIBS=-logl$(GUISUFFIX)
+
+WXDIR=/home/jacs/wx2
+
+include $(WXDIR)/src/makeprog.env
+
+cleanogl:
+	cd $(WXDIR)/utils/ogl/src; make -f makefile.unx cleanmotif
+
+ogl:
+	cd $(WXDIR)/utils/ogl/src; make -f makefile.unx motif
+
+wx:
+	cd $(WXDIR)/src/motif; make -f makefile.unx motif
+
+cleanwx:
+	cd $(WXDIR)/src/motif; make -f makefile.unx cleanmotif
+
+cleanall: cleanmotif cleanogl cleanwx
+
+makeall: wx ogl motif
+
diff --git a/utils/ogl/samples/studio/makefile.vc b/utils/ogl/samples/studio/makefile.vc
new file mode 100644
index 0000000000..f56b35519b
--- /dev/null
+++ b/utils/ogl/samples/studio/makefile.vc
@@ -0,0 +1,143 @@
+#
+# File:		makefile.vc
+# Author:	Julian Smart
+# Created:	1999
+# Updated:	
+# Copyright:	(c) Julian Smart
+#
+# "%W% %G%"
+#
+# Makefile : Builds OGL studio example (MS VC++).
+# Use FINAL=1 argument to nmake to build final version with no debugging
+# info
+
+# Set WXDIR for your system
+WXDIR = $(WXWIN)
+WXUSINGDLL=0
+
+STUDIODIR = $(WXDIR)\utils\ogl\samples\studio
+THISDIR = $(STUDIODIR)
+
+OGLDIR = $(WXDIR)\utils\ogl
+OGLINC = $(OGLDIR)\src
+OGLLIB = $(WXDIR)\lib\ogl.lib
+
+!include $(WXDIR)\src\makevc.env
+
+EXTRALIBS=$(OGLLIB)
+EXTRAINC = /I$(OGLINC)
+
+PROGRAM=studio
+
+OBJECTS = $(PROGRAM).obj doc.obj shapes.obj symbols.obj view.obj cspalette.obj\
+  mainfrm.obj project.obj dialogs.obj csprint.obj
+
+all:    wx ogl $(PROGRAM).exe
+
+$(PROGRAM):    $(PROGRAM).exe
+
+cleanall: clean cleanogl # cleanidelib
+cleanutils: cleanall
+
+wx:
+        cd $(WXDIR)\src\msw
+        nmake -f makefile.vc FINAL=$(FINAL)
+        cd $(THISDIR)
+
+cleanwx:
+        cd $(WXDIR)\src\msw
+        nmake -f makefile.vc clean
+        cd $(THISDIR)
+
+idelib:
+        cd $(CLIPDIR)\IDELib\src
+        nmake -f makefile.vc FINAL=$(FINAL)
+        cd $(THISDIR)
+
+cleanidelib:
+        cd $(CLIPDIR)\IDELib\src
+        nmake -f makefile.vc clean
+        cd $(THISDIR)
+
+ogl:
+        cd $(OGLDIR)\src
+        nmake -f makefile.vc FINAL=$(FINAL)
+        cd $(THISDIR)
+
+cleanogl:
+        cd $(OGLDIR)\src
+        nmake -f makefile.vc clean
+        cd $(THISDIR)
+
+$(PROGRAM).exe:      $(DUMMYOBJ) $(WXLIB) $(OBJECTS) $(EXTRALIBS) $(PROGRAM).res
+	$(link) @<<
+-out:$(PROGRAM).exe
+$(LINKFLAGS)
+$(DUMMYOBJ) $(OBJECTS) $(PROGRAM).res
+$(LIBS)
+<<
+
+
+$(PROGRAM).obj:      $(PROGRAM).$(SRCSUFF) cspalette.h doc.h view.h $(DUMMYOBJ)
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+mainfrm.obj:      mainfrm.$(SRCSUFF) mainfrm.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+cspalette.obj:      cspalette.$(SRCSUFF) cspalette.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+project.obj:      project.$(SRCSUFF) project.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+view.obj:      view.$(SRCSUFF) view.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+doc.obj:      doc.$(SRCSUFF) doc.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+shapes.obj:      shapes.$(SRCSUFF) shapes.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+symbols.obj:      symbols.$(SRCSUFF) symbols.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+dialogs.obj:      dialogs.$(SRCSUFF) dialogs.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+csprint.obj:      csprint.$(SRCSUFF) shapes.h
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+$(OBJECTS):     shapes.h doc.h view.h mainfrm.h studio.h cspalette.h project.h symbols.h dialogs.h
+
+$(PROGRAM).res :      $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc
+    $(rc) -r /i$(WXDIR)\include -fo$@ $(PROGRAM).rc
+
+
+clean:
+        -erase *.obj
+        -erase *.exe
+        -erase *.res
+        -erase *.map
+        -erase *.sbr
+        -erase *.pdb
diff --git a/utils/ogl/samples/studio/manual/BACK.GIF b/utils/ogl/samples/studio/manual/BACK.GIF
new file mode 100644
index 0000000000000000000000000000000000000000..8a61076d3ba74bdedc1d24f60c3d1f5a361a6cee
GIT binary patch
literal 225
zcmV<703QEGNk%v~VLt#E0Pz3-zrVld=jU&4Z(9HWEC2ui06zd20008IjE||y?GK}z
zNf>~$-n{z{YJwGn=81mem9{RpmcUHc_KoNIPRH~B4DyD9p%LJl6@Sa4^Epcbno6kk
zD5XxT&EQg7><X(t<v2<zGtFvpm%NS3x723V`)<ec-&(({)sqHiQ-=rlS4S8Ibd!~%
zh!dt38EIxWIOn%1Dfj2b8T!~6YUzo%W;uEjc(%yY2)pMhb!7`xd#gK?yX%Y7`zwsb
bGHgs7FrvK7-0b`e9qpVfU2T0WT>t<(Iwfoo

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/BULLET.BMP b/utils/ogl/samples/studio/manual/BULLET.BMP
new file mode 100644
index 0000000000000000000000000000000000000000..aad8fc793edd54ffb5910e67b2470659c95448b7
GIT binary patch
literal 138
zcmZumxe>rH2vhFtK1GJ`9PYi2Yw9con_&SdBlI1b>qTKR2Gu`ZXgNITWj7;KP=JJL
V1)UXU1`*-lNw`O&c<~DR!2u5s7-j$f

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/CONTENTS.GIF b/utils/ogl/samples/studio/manual/CONTENTS.GIF
new file mode 100644
index 0000000000000000000000000000000000000000..3dddfa3dd5f0c652e8b27cd6c29e1fdd49ced5a8
GIT binary patch
literal 231
zcmV<D02u#ANk%v~VL<>G0Pz3-zrVld=jU&4Z(9HWEC2ui06_p40008OjE||y?GK}z
zO&EZ)-n{z{a)K3v=81;mmA0<AmhVhw@iyc`&3|{61I~6YqK~98Vw5OmQ-xfDbjF=-
z8N_A**6fx0#r(KaDON}}o43Sv(iTm3lx}qOEl<})aVL6>S4Fj_r^UyThZDG{h6k9m
zHI_(7spd!5_$SH6m{<Auh$$AQ#YFX|N5^T`76u^M6AJ<hP-}aOo2$Fa+xtrD8!SAm
hOG|u=TnwDd%p5ZU9W6agU2T1B9e};f-Q8UP06VhvYa0Ln

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/FORWARD.GIF b/utils/ogl/samples/studio/manual/FORWARD.GIF
new file mode 100644
index 0000000000000000000000000000000000000000..9c81e8c92fed7fe851ce02e7854dc26a58eae9b2
GIT binary patch
literal 164
zcmV;V09*e@Nk%v~VI=?<0Pz3-zrVld=jU&4Z(9HWEC2ui03`qz0007gjE||y?Z1Qp
zwAzdF6*A}#V%!v#-{_g@)>Q-cu3}3Ku`2^Nfa3dZ+VyHW%gtsZ`jV7k@%j8Ij}~W)
zc{NUP6)X3OWa^|{8nl?rh|gZ1@{(qofnsWu+nmFHSnaq>lB41zSVC9`a)_v*xHx0L
S5h*!IS!o$ynW>ps0028gDN7ju

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/Makefile b/utils/ogl/samples/studio/manual/Makefile
new file mode 100644
index 0000000000..0874c5762b
--- /dev/null
+++ b/utils/ogl/samples/studio/manual/Makefile
@@ -0,0 +1,29 @@
+#
+# File:		Makefile
+# Author:	Julian Smart
+# Created:	1998
+#
+# "%W% %G%"
+#
+# Makefile : Builds OGL Studio manual
+#
+
+DOCDIR=.
+LOCALDOCDIR=.
+
+DOCSOURCES=studio.tex
+
+hlp: studio.hlp
+html: studio.htm
+rtf: studio.rtf
+
+studio.hlp:         studio.rtf studio.hpj
+        -erase studio.ph
+        hcw /E /C studio.hpj
+
+studio.rtf: $(DOCSOURCES)
+        -start /w tex2rtf studio.tex studio.rtf -twice -winhelp
+
+studio.htm: $(DOCSOURCES)
+        -start /w tex2rtf studio.tex studio.htm -twice -html
+
diff --git a/utils/ogl/samples/studio/manual/Tex2rtf.ini b/utils/ogl/samples/studio/manual/Tex2rtf.ini
new file mode 100644
index 0000000000..f44fc89982
--- /dev/null
+++ b/utils/ogl/samples/studio/manual/Tex2rtf.ini
@@ -0,0 +1,20 @@
+; Tex2RTF initialisation file
+runTwice = yes
+titleFontSize = 12
+authorFontSize = 10
+chapterFontSize = 12
+sectionFontSize = 12
+subsectionFontSize = 12
+headerRule = yes
+footerRule = yes
+useHeadingStyles = yes
+contentsDepth = 2
+listItemIndent=40
+winHelpContents = yes
+winHelpVersion = 4 ; 3 for Windows 3.x, 4 for Windows 95
+winHelpTitle = "OGL Studio"
+generateHPJ = yes
+htmlBrowseButtons = bitmap
+truncateFilenames = yes
+htmlIndex = no
+htmlFrameContents = no
diff --git a/utils/ogl/samples/studio/manual/UP.GIF b/utils/ogl/samples/studio/manual/UP.GIF
new file mode 100644
index 0000000000000000000000000000000000000000..316d0d2a14b571bea2eb874efd04bfe509f53b34
GIT binary patch
literal 137
zcmV;40CxXJNk%v~VHyA!0Pz3-zrVld=jU&4Z(9HWEC2ui02%-o0007FjE||ytzv+j
zv|1owxcuhWh0?c)Avq0}dTQw^q7qBdoDA6WKJ*l>%gtCeAWZlgxpoy|ZDMRPr_m>p
rx}08pS4?)u<%PW<QBYY9oyjHh?Q62&;&M&qj?e4yfxZ7PPyhfsDH=Ws

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/abacus.bmp b/utils/ogl/samples/studio/manual/abacus.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..49bfa2a84e541dc29c71cb55023e7f9a872c72a0
GIT binary patch
literal 566
zcma)3ISzv`5L`wUu_yvU5jACAkO!pCcS4CvcYKK_rGw6y1xwf|B8>O6W@ofKUk}K3
z-t>1`AFU80`ZO1G@idHT`*9+?;@lqSnbMrh^UQ~^T?s)m8b58(^`1O5d^&+GHCsD>
zE`x8yL=2`j962u60pn4ZoR1pn1$EL7SP(E`F&Wwn?2k~N&1o|9KgNn&+*-m_k*myD
zEa#Ic(W&ZGrOl9LQ&?r#T^%PR=wEd>xyQz1qSm-ct%!7X`xmjYN#!cO+yYj{;tLK_
BeP#dv

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/alignb.bmp b/utils/ogl/samples/studio/manual/alignb.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6cc2e1dee47c12433ba418577a2e5ad73fab4848
GIT binary patch
literal 238
zcma(~u?>JQ3^NiN1DwGf?EKP+GUlZ2U3w8O1iKLn5)y7~M{(M2`-Q+kTgio-$pIr3
yIJ<@@69WdYU=~JYi`E)lf%k&DI+8~tN`4^$nJY-O<f+#3>D*JU>wjJEKHuH!bxvFW

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/alignl.bmp b/utils/ogl/samples/studio/manual/alignl.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..30471101b16de3328c3d7a9ddbb74c95669b30c1
GIT binary patch
literal 238
zcmaKju@QhU3<Jd-ca$&&bI`L(Dxl0r^l35?D};BPbR3E$*^#~Nj~oZK!UfK7(1=P`
yRTs;Qjwn%z(G8_l&Kb9$)KV$dL7sgfXGb6qV@Tls@wV6Rx^q8S&;7TzyzRf`G)$2I

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/alignr.bmp b/utils/ogl/samples/studio/manual/alignr.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..14a2f85241d5a0f1985c58e88c06b64a606b7764
GIT binary patch
literal 238
zcmaKju@QhU3<Jd-9R-ZR9Q5px3MexYeVR<f3gI1-I|>fPl58tp)=Q2Jo8bgU*r`XQ
zqpFK#Mn{w=#ps68D(8$_P->|Z>mbio$leeL#26AdfBgB^?p|K+nFqW7@RnP41Lmtt
AkpKVy

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/alignt.bmp b/utils/ogl/samples/studio/manual/alignt.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4505cbab566385942c0912c245668a2567a6e4a9
GIT binary patch
literal 238
zcmaKkF%Ez*3<HhC#sJUY9qjz26EOBk>|OdIzEIAs*ie($j$$j@{;1V~tY85%7&OAt
xRk@Kpqg9j`#n=R9Rn8f;QR=7^Z-Dj*I)92ty-z9KwtE_g+7Cp#O78pXpD*v#PFw&0

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/arrow.bmp b/utils/ogl/samples/studio/manual/arrow.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d406ceb64f017d99bcc2d4913aef75135de357a0
GIT binary patch
literal 382
zcmb7-I}U&#5JZQ>1WPN=;5qEQ3zc?;o59U+Ka+r!5!mH1Gr)e_0X9zQo7Bn*m`tDP
z>tSJ;fdXA9#W(4KsI?;JEJm}1)|8}VswC~|<Acp+X5bX{1r^dYaP*|<cro+>bu-BQ
Vombvu=JhAub(#Nm-N`e*_yJ^>eVzaS

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/bitmap1.bmp b/utils/ogl/samples/studio/manual/bitmap1.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..13e2170b7369879a97bdd01c57b42af6f4126264
GIT binary patch
literal 238
zcmZup$qj%o3^Ni^o-hV;@Mo922+wZTPQ(hutwBPF)JM*)+X=-^TgaK5$N?i2IJ*8x
z1_<OVqcTM)1t}#CY6og<8OhgLlnA1Qhq=kkUmmbtM;O|i2QpqLp4!xR(~o{Hd|gKu
Dh|EVQ

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/bitmap2.bmp b/utils/ogl/samples/studio/manual/bitmap2.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3d523b2de9cb376db72fd364c6d4cdb7f2e4da9a
GIT binary patch
literal 238
zcmZvW!3{z&3`32C)MFWgIk>Y+Pr$L8wG(}1gYeu+p9^X1)J~P=@jSHSMY)3;sNkY2
zEPWRLqal$RV;7jK=A7!i)5w*|^bK%qLGNEQTGkCeTtf<*)|jz0bZVCKqs&^|_qZ0`
QxOhk{d)WGeIhJR90ll(R-T(jq

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/brush.bmp b/utils/ogl/samples/studio/manual/brush.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0bf4ac5527d98d88440001b5f300b04db96644d2
GIT binary patch
literal 740
zcmZWnF>b>!3{(gq76PNqP-M>7cXaPpf=-P`ZPgIKU((pYKt9n2WJ?AE${nrRQevAl
zb;lz`TOXf)V)Xike~0a}t&BCK4w*-2w%HgP<MlD#GlJnJ1Q%ljlJqetF@oVH1h)_9
z1Cz_nh+8wd?ZST~L4KsOLAp(e8R@`yITmOyQPEMF2b7s@g$B7nKg#fgdfT#&o4cX+
zXb0pr3#PpXc}3=#+3PtQ%tf<XDhk{KW%e)ZODA&EtjLRUf~Ue^+6EmLZcqhP{1P>H
zf`&@>#Pv``DpAW<-8i*sz?Az7Ld_XFu6D=ibNz?@VEX(QuILXHeBL*zT;&KIGqCH5
v=_NrsX=cUCRLw7$+aO8*Qm(n22{65#&k9#id8a2QuUxV68!&IEh4<<Xa6z*o

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/calc.bmp b/utils/ogl/samples/studio/manual/calc.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6eee9cce8c1cd915f888258cbe729ead1bd19154
GIT binary patch
literal 702
zcmb_au?~YE5Irx%5Yt3s8t0Dvj!s?rJGCQQ+5Dr%Phu+@eTOJ&J65>kc*i{+$mRB8
zir*dn3_B$&NRgzjDUXnvWD*mZ*vS})U}yrtjpGO;#7-ed1Va-D?qsnKj9o{pONo4E
z=SW$8Ry{v3rW_(y(GKz2ve{!yz;yK6de4prWZZYnKX}+;&!|X|N~(EKex+yNkTX!S
zC{hM1mzs$OSe-HOyvrWSe{huaqdx5G;~96=hail3mzCD(23HE&t@imYryJdJIIh98
l_{`r1+)_Gc{@aa(hUFE=46BTeZz9d~YGx{Aj)6VK;sXibpM3xT

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/chart.bmp b/utils/ogl/samples/studio/manual/chart.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..54218089a907281b71a9a7c27a5ca1c6db619024
GIT binary patch
literal 600
zcmb7BISzv`5L`xxAetZ)QB&p}>C@*WAsz1GjxX_+ynqfmXM89aBBW&TtoIx*_T_qm
zIJr}wi6$VCRBY;%Pz5QuTX<0-T%wfUsA&>PhGAgBxFyC|i{NKNRE_321jbsBXV#i)
z{hI|{Ng8_4S7xz6E=+|+zr<3rjqFur8c(cxeI?@~9$QYdwiX=@amIJJ`ic1w-Fgys
z9Lc5AXu{B=G4Z4*zB_pvvwr>m$UE?mn5{CL=g*ri?L43Nu^u^8?p`Z+dE}{rnUlfH
GJ$VC~I*RfD

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/colour.bmp b/utils/ogl/samples/studio/manual/colour.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b4ffd72550eacbeb9cd2fc39564a1596a1d63e2f
GIT binary patch
literal 734
zcmZvau};H442G{(l%67lii9f0jywW0VqoDt7(0=UxAmA#9eIw9EEyU43_Jr83_(IV
zK3^_LQ)u$L_W#>wpWEAqcQNVnguMo<jF~BnN{?B`HH!@OjdAHU&Z!4@l)^Mk0~6D0
zVpI?CD1}*h`T+S@8nLB%?b7$&xtDEO_mTC*oz$`}hs@F!2YC}>31FxzJn@gH1~=78
z)mm{9v6Cv>DcCahJ;~k{bv2w!yk;9Uxwe}&^=h$3HmD=pk~1F}CJEqKF35GV!RB1p
z7JSQ#T*1!&QFfej%m;F~#VO0aCRt~vowRPRRY!B_R6$<lMtlF6OO-u}o1END9OaYR
zFTj1U<9)P`ZucPfQ%!l06}()NI8}5LcI25eNF;U=*n7^de9`@S@HYKt7Me%pQRFI=
JOY-=h{Q~62u9pA+

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/copy.bmp b/utils/ogl/samples/studio/manual/copy.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4551a06bfa79e0a42c1ffb7cdbb90fd4f699dce2
GIT binary patch
literal 238
zcmZvVK?*`K3`9pLxU9$U91{2|@hV+>tjiv)Cz3AyzP{vxy7<$~OeTT!c7JQf6T89-
z%<!ayO0Uo(X%eN@c0*~^d&hk-qco>?kmn<${;(P#uFN<0A#FuUo(qgT{&F@ekspii
W=d@ZzPG(Cb=QBs}_=7thzxV(viB<;y

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/copysize.bmp b/utils/ogl/samples/studio/manual/copysize.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..36060ad72b54ea2be52e4a1ed7b4dda2ca3cf18f
GIT binary patch
literal 238
zcmY*SIS#`x3}b-;8ZxBM=sU9KFPf^3eo}TVeo?>RP?8g%v`FfLyzM^}KD0OaB3JT(
zCl&anmc%SrXaEDPl~I|Z_fC(&$iNtpk$lmjm`TEJhyo%k)jjO4=f?j&&jF^kxcgy{
PbY7_X>Z|3R^1F!>`pH0Q

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/cut.bmp b/utils/ogl/samples/studio/manual/cut.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..15554338a01bc4d8f0a501c32237e84200e64583
GIT binary patch
literal 238
zcmZvU!3}^Q5Cqr6gr}Ba8OD(CvKJo2^+{<|WDB@(K8*2TclNjo+kV075Ef~cCTYMZ
z2hQ$)mH}PlY>+FWlp?l4?H9GSB<Zv#8R^+8F{Gd*hV&x6^<?mEPOb*V-jQ$?oH06m
Ls*2CTm$rNZbQeh3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/cutpoint.bmp b/utils/ogl/samples/studio/manual/cutpoint.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2f7dc780a21ff41a56c536315f5e40034ff1b7b1
GIT binary patch
literal 238
zcmZ9E%MpYy3`3Qfy^|X)Y#rPwW-o+eN=rqw5T4=%W>752pV-TKD6nB)nBfGIKB%-0
z4e`tjREbcnVJN9uYq$q}gnD-dd2S))joA(4hnda^3ME@9IU}4&(EFo)=5zeN_9_1d
HoZL78p=?Bh

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/files.bmp b/utils/ogl/samples/studio/manual/files.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..877e24afc706a207c6bf4eb0efa025976965d225
GIT binary patch
literal 672
zcmbV~J(9vO426Zp6FdyVQZUq%49D1huS4kK4tHFEqvS|*(3ww;Ny5);L2N1Vd(ToV
z=lAcdlAk?(i*1Tc#EDV6!V}7}n8hL?PYJ;yjA0P2ZCj9(r=(;N#xMxCiPXXLvKIA~
zMYnbQFRG#*=d~Ul8W;7XqEo%}{+Ww#H|>0Q*%#U4;mp5q^EgJ(ob=}d)_jSPO&g#1
zvOv^-F;$vbozVj|OGga#oZBUoZ>ZKfr3)i1x-M_h>zJv!%;@Q2uSd~ken+j(PpFp6
sRJaZ~$UwbCpVLK`hShMNOS;IvR4Utw(*&Pyy{!Cb6=pCiD)OG(0a}ZhAOHXW

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/help.bmp b/utils/ogl/samples/studio/manual/help.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..2d9e6922cac0fb0aefa32fd5bae9d460e13484b9
GIT binary patch
literal 238
zcmZuq!3}^g2t1P}{g~(&&f(u(`VyZVjR87~E7Sw@p^<WTP{^@vCn9#rLd?WO3`k_)
zaQ>qTFi~p=nI%+}YJ={H-mN0|?29BK#fUL#erbtT(lh^R?4vYy(d-6AGn1|j$rr}v
KbDqI%Xjd+{i$y;G

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/helpcs.bmp b/utils/ogl/samples/studio/manual/helpcs.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..88373816814a283aa9ecca7899faf81ce7a15b4e
GIT binary patch
literal 238
zcmZvV!3{z&3`32Clp~D69NgKZC&ICtwG;gn%5(a;k=Ax%E6VeAXxAHgfIGN>i>|Qr
zDgH-8;%kg8Fs<gC>b(=J`dZ5!;MsyQTV&Nwu@o7(Ri`byve-X0yz0?`b73&zHji5?
LZQ&!hb;<MvPm?;n

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/horiz.bmp b/utils/ogl/samples/studio/manual/horiz.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..58af34a727e24407124fed67899ae2071dea12e9
GIT binary patch
literal 238
zcmaKjF%Ez*3<HgX#J~X0;2rGzg$Wq@B=!#Ni}*shv{WnzH@1^FotH}m8#cia4zN*+
zN=McrmKh6zL@9(~D6L|Qa?TN?TuRA0$g>r)SF8kLTs=5{{JE?DUYEK&^#0pxo{w%L
C5KP+u

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/linearrow.bmp b/utils/ogl/samples/studio/manual/linearrow.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1fd21fb08ac4a0d07a8b724700eb40c11a276698
GIT binary patch
literal 238
zcmZWjF%p0<2#a^_%H$V(hr5qq5yw8QFY*gDG<K4b1VY>6I3Fl3%1*4rLQI&+z};Dt
zvxK4mOq3!avqY_xnuFF8tz|{<q(zEf_~-bh!fmJww=}qwSzkaJAwPB8``)RI@vqz$
DY>`6V

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/magnify.bmp b/utils/ogl/samples/studio/manual/magnify.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b237b31f8c020f6e39e2c9ef4bc05c152aca1b00
GIT binary patch
literal 722
zcmaiyJ#ND=422m&FoYn0GZdLK_8i@NgPx<aMs2>5&(M=()TVw<RvXJ5YMBCmA0H*X
zy??p2@00x%xpz5PFoiyP9M!H}q?@JoTT0RpmRxM>y5gzrw_2qkEV<b3nLda=Zsu{4
zR&M#P7P3Ds#@=(#$~k-b&*NzV*B3WG*3O<rA85)=WY;kgsr7;k7-YkM?2(073a9vv
zZ_CU<xO3R$V;5gE4M_BU&eI|h8+=voA`7;7n$Mdy#I|hC@qh;obHM6=wRy+hV~4Rq
z7(d;Q%-S5V(KI7x&5_%Q&7nT|qRBGuGH$m&aY~n8>q?z&WsAuYZfx(QTXAQlGm)37
Hw_&Gme(s@>

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/mike.bmp b/utils/ogl/samples/studio/manual/mike.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0d736190e415fb1455dc5faf0e8c2d02ed419f95
GIT binary patch
literal 708
zcmaJ<yAr}65WL(l%#DpH9BWIz!(Knfnv#xRO5q2kq{CejorFXKNAC7Gc6r?HFO~W|
zF<xPp**bB;)ML)Wm3}t*BB6E(fgTKv5QbqGfRx&$6nZc;LKrR)JTM*4qUPyki<&eX
z;;-08=m}cqf9ANT0d>KDtAJ!pz9<m*HmzMz_{go%v9dN8YRN-A+f3%lI~iz4M)oq!
zklU{Hrvkit6=bj-j%?!AO0iELH`vjaHRh5n&JO33s1;{|YTgNvX<rQneGNioEk?Z!
j<`*$m$lxRE`V|!1SDI?6qMstOs;NeJCnBe!8UOALhMb)k

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/new.bmp b/utils/ogl/samples/studio/manual/new.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d66feb2384ad4c626a078c995c1a3e49af78ec3c
GIT binary patch
literal 238
zcmbu2yA6Oa5JQcGL>b0l4tjP;1(ew=nJ8j|<6WY3bU0`GK9aK^RUId`!4(ELX-1{H
u>6c`QQqJ8_T9s0iQsQ8(Wab^@`3kuPA_p->w)Xt<krS4l<G*-5<G>4Pkz>06

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/newpoint.bmp b/utils/ogl/samples/studio/manual/newpoint.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..cb4f267afca22039f403ed5f92a6c6a0c2978131
GIT binary patch
literal 238
zcma)!u@QhU3<Jd-J&eH|^sEEixye>3XfhEigttvWi5y9eoOs=CC3b9qGo0X{5tYu+
z6rVX0MdGNGG?Z4YHQWb1j(YbFQXV14f9QQ2&YA$<Gry{2*JqoV#jV;=X)MZ<h#!D9
BNYDTP

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/open.bmp b/utils/ogl/samples/studio/manual/open.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..bbf93fe03364e63f3e18a3507a0e85ab8ea2f87d
GIT binary patch
literal 238
zcmXv{u@M3>3=;=;U&0ua+_3>YyQsonW~6N3OvKTr2(k@|B{{YeKb~(CUb3rr5zpcQ
zCn>O}mP9XDa6kd~GO1FGG0<95V`X5i$V8neN$dxz4&8XX3!AZr-;ApY^eS-9oTLj~
Y^Hcc9z2|$wrXTtLH=Rc2n(WoWFRhqJ00000

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/page.bmp b/utils/ogl/samples/studio/manual/page.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3dbd4b05b4c2d1a4f046141d450caf34c1a3d470
GIT binary patch
literal 714
zcmaJ<yK(|C3=}&akA_J>k)fu{chJ-2TT-iZmtVS?uc5roS;-EuD8k*^vaH9hj_d6X
ziQgC358^U$kRpEdIqzx8X~Jz0i&xCtBKWwA%eHOw^mwIrw+KG&;&N&1L*Q{1Xmx8p
zxBo0O*pac2@{B`!>-fgLdSDP(C2}M>_DcBv60g*0UKyHhy!Oc8UYD-XBeIyOWTry_
zTA4Yuua#<WV)ewm1Q&LQE^GWR8&?uYJ!S@V4|X|IBWGo+Q}yZ_3hJnzs=ESWFG&H+
zmHM1YisnS0Gs-+-nm(PEsm}UoqJLlh)YzRFW1fEU@2>Ixm?vFMcI3@F*>XSp02Lyo
AJ^%m!

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/paste.bmp b/utils/ogl/samples/studio/manual/paste.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..564f514e0df7225f0a7adbe8457b41af537813bd
GIT binary patch
literal 238
zcmZvVF%Ci@5Jbns<dazFG5#@(+2mJ-tNhBfq~tjEHk`;S;9I_0IWRN311y*8OB-(3
z3{UU~ciN-Ueds?a5?iHghEl4vhQ~o4TfIjGSrH-bZeUrZOuwXBvsoVg>$83OZ*I;#
co}I%%@f6>ra3+S=gC69}eM%GII+SAI4J;x>B>(^b

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/pointsize.bmp b/utils/ogl/samples/studio/manual/pointsize.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8a01c8a42cb9b3fbf9ee79d816a47b25854e198e
GIT binary patch
literal 538
zcmb7Au?+$-47^83Up@^D6EFuoyL^Sei#zC8f<ZD88-%liz##~UOMG@Nj$`?7+^yg^
zk@rvA(hpd>ejD65ZOCR73UEWUIx<7#oaybN_(mxf(YQ>q^B0_@L(-7P5{5=wE(UG1
z<YoTSrgE<>g|}0&MNk_>yk5{|^cpaBdDhJ5+g}>OA0e;r?=_jw^IP+%oq<&onUne$
K8%jRLmaY#<=_kbi

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/preview.bmp b/utils/ogl/samples/studio/manual/preview.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..da1f4dbc4be6c2dd8fb9d7cb71cc48a4a7c139ca
GIT binary patch
literal 238
zcmZvVu?@p83<Tdm0IGAw$Q<dji>pv2yNo4mlT?N_pr2ISnd1NHDM5O^cFcMc59&^>
z)PfrwsOeYM05)2ipmU4fJIss+o(=cdQCu+!%TlZiKDH!a!aP2;C|UGpLD9M;zmsLJ
XIp;lzIUm!ckI6HO{IjaYcZ_-fA4^nl

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/print.bmp b/utils/ogl/samples/studio/manual/print.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..00319b55bb23c3c69cc051144d80e5275747c53e
GIT binary patch
literal 238
zcmZur!3_d23^Ni^o@EUFY`~vgA|YX<`*bfpod|V<Vy9oy#7<f}>izM>j+f}Fx~Q7!
zgtHKM7yg3|DAD^Sp<0YF#C}+nSj(MC$5#Ss27*aN<{l9d<nf^z@_A!K$q=d8y3Dc#
Z*tBKJm=l;@q<LATpSNNQY_h}diXX1oK79ZH

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/redo.bmp b/utils/ogl/samples/studio/manual/redo.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5877e34e00515f81b063a0efece347301fcea5b5
GIT binary patch
literal 238
zcmah<u?>JQ3^NitoWUKaQYXHtaK{cvyw!_%p*Ri9bz(b-vmXx}r)(2faS<oXQXqGA
xvCQZwfEuN^Nj0L@Dz~8ZMr$^SDmzIyLc0CqB2x%t)cSk+_9#~#n8<A57%zxBOlSZA

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/save.bmp b/utils/ogl/samples/studio/manual/save.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..56dd10b6e3f05d26ba5a9e4c9a502d6278926a59
GIT binary patch
literal 238
zcmaKlu?>YV3`7rs<PygCB@!FZvr8)S%SbGiiC7^#J1yekyR*+qvLClPPV5I4IKx2`
zD*Z#>q)3!X>4ws(){6V0MX5FKAjcylGXqN-n#XsS=YhW0WogZT{L^_i_GT%*k@+ph
E1NJ~MtpET3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/screw.bmp b/utils/ogl/samples/studio/manual/screw.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..7625c4e6b60d916bf9a69f8ef8f9d365a252a211
GIT binary patch
literal 636
zcmZ9JF>b>!3`H42NQI(kf}$ugbja9qbnjg}b?U$^+Il4)%bWX1Q;<{Jl*s>|EK~mc
z`caANoAHCVW*nr5TgUWC<(%QUh{Ypjo)O$GG0gLfvc@Cp>KVc962p~Q>wD8*pS7u6
zdTx5t`W97jXWDY86BXX;AQzNTH;Cn~HWcf8X=?7j<ocuYwyVNDr(46_RpGLqJto1-
zdKB3yPKi!kd2*)S)xP2eQ`tYd4`wN*Q&(7R5Zl`ywDRRaJ~t@$rlD*-p~5jH7izNq
yR8B1EVCm4$wX<FGK00~wf5bTrt}BBIg_GWxs?-;WckmC$-C2F-$my;$Is5^`pL0b3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/shapes.bmp b/utils/ogl/samples/studio/manual/shapes.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0e2e2ba043becc74d808e0c83b32d239d1ac0478
GIT binary patch
literal 780
zcmaJ<F>V7P5L{0XMvf)Bh+MnOJJRPni96GUA`+=0`4{f5xh{<#<MN_dBC~Mki|{EN
zyDYQp3<o?tFYhF`7y3uqwzruW0pm|~eOq%>E6t0ri}z)qXGrtXwk;DWcS%Vj8b5{T
zwt+e{oHqhzHR?8Dh#Vt$WN)sh4T!|L;zxWL@Md4J8>%@!TN&p)+r^yFj_8%G!dYD*
zHjur-s2-_Nq1>JB@Y@_FGVj!mlbH*?v<e58IJ$Bgj7}NXnh)&8|IHenY`F&am`~&!
zR;+4p%<Bfu$a59!$<W}(G?@R<i$*!4t5B}^4_{5L-?K{jYxTm#Q&R2QU7KJM?`7O=
pS>L~fn~bWI*AV$qt18~Q-i3GhZIyUYFjug(&isP;hlGyf>=(PwyuJVc

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/speaker.bmp b/utils/ogl/samples/studio/manual/speaker.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..a32ec48bba686dc9b86309d44714252ba05d790f
GIT binary patch
literal 648
zcmb_aOA5mv5S<JXq!b!T$vVrPqx)W`>sh+Xl{`|G?(BP3f@uS#(3sKp(NQP4-GfSb
z9_X)#sYWMGXq~GMC_@cm5i75l5h2hhp^Gs>$>o)ti4bU%&`kmRAaof;eNU9e@GJ6I
zaa>nzSs&C|w+{~csJV4MkZED93T4p~b<X7Yn!^(UrSD$J%FH$UcIE$FmwCd^(?Xf|
t9n>MQ*6qE)=64MhO`G~QZ0~Cg$bo+bnR#b2R>8N-H_Q%jE?E=C?g{(PioyT@

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/straight.bmp b/utils/ogl/samples/studio/manual/straight.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..529366590b71d7afa1ef14750426a874c8df6c3d
GIT binary patch
literal 238
zcmbu2!3}^Q5Cqr6#HW^F9sccwm-?hMDzXKf<$@OAal3P{0k-{C)B#qspcxGsap`Iv
q=FE!960MvAIHO7_&_QjjT0J3_kFfKrMCAR;DYEp3e$)3m`*#mOwn9e$

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/studio.tex b/utils/ogl/samples/studio/manual/studio.tex
new file mode 100644
index 0000000000..ab4d897258
--- /dev/null
+++ b/utils/ogl/samples/studio/manual/studio.tex
@@ -0,0 +1,381 @@
+\documentstyle[a4,makeidx,verbatim,texhelp,fancyhea,mysober,mytitle]{report}%
+\twocolwidtha{4cm}%
+\input{psbox.tex}
+\newcommand{\commandref}[2]{\helpref{{\tt $\backslash$#1}}{#2}}%
+\newcommand{\commandrefn}[2]{\helprefn{{\tt $\backslash$#1}}{#2}\index{#1}}%
+\newcommand{\commandpageref}[2]{\latexignore{\helprefn{{\tt $\backslash$#1}}{#2}}\latexonly{{\tt $\backslash$#1} {\it page \pageref{#2}}}\index{#1}}%
+\newcommand{\indexit}[1]{#1\index{#1}}%
+\newcommand{\inioption}[1]{{\tt #1}\index{#1}}%
+\parskip=10pt%
+\parindent=0pt%
+\title{Manual for OGL Studio}%
+\author{by Julian Smart}%
+\makeindex%
+\begin{document}%
+\maketitle%
+\pagestyle{fancyplain}%
+\bibliographystyle{plain}%
+\pagenumbering{arabic}%
+\setheader{{\it CONTENTS}}{}{}{}{}{{\it CONTENTS}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+\tableofcontents%
+
+\chapter{Welcome to OGL Studio}%
+\setheader{{\it Welcome}}{}{}{}{}{{\it Welcome}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+Welcome to OGL Studio, an extended sample for the Object Graphics Library.
+
+For release information, please see the \helpref{Read Me}{readme} section.
+
+\chapter{Read Me}\label{readme}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+\section{Change log}
+
+Version 1, February 7th, 1999
+
+\begin{itemize}\itemsep=0pt
+\item First release.
+\end{itemize}
+
+\section{Bugs}
+
+There are no known bugs.
+
+\begin{comment}
+\chapter{Getting Started}\label{gettingstarted}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+\end{comment}
+
+\chapter{Working with the diagram window}\label{schedule}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+This section describes how you work in the diagram window.
+
+In addition, you may wish to refer to the following sections:
+
+\begin{itemize}\itemsep=0pt
+\item \helpref{How To}{howto}
+%\item \helpref{Getting started}{gettingstarted}
+\item \helpref{Using Menu Commands}{menucommands}
+\item \helpref{Using Toolbar Commands}{toolbarcommands}
+\end{itemize}
+
+When you first run OGL Studio, there is a menubar, a single
+toolbar with commonly-used functionality such as loading and
+saving, a project window to the left, and an MDI (Multiple Document
+Interface) area to the right, which will contain documents.
+
+\section{Creating a diagram}
+
+To create a new diagram, click on "File|New" or the New tool.
+
+A blank document and two new toolbars will appear. The first
+new toolbar is the \helpref{diagramming formatting toolbar}{diagramformattingtoolbar}, and contains
+icons and controls for:
+
+\begin{itemize}\itemsep=0pt
+\item alignment and size cloning;
+\item arrow toggling;
+\item point size;
+\item zoom level.
+\end{itemize}
+
+The second new toolbar is called the \helpref{diagram palette}{diagrampalette} and contains:
+
+\begin{itemize}\itemsep=0pt
+\item a pointer tool used for selecting, moving and sizing objects;
+\item a text tool used for editing text or creating new text boxes;
+\item a tool for each of the symbols.
+\end{itemize}
+
+\section{Basic editing}
+
+To add a symbol, left-click on the symbol in the diagram palette,
+and then left-click on the document. The currently selected
+tool will revert to the pointer tool, so to add another object,
+click on the symbol again, then on the document.
+
+To draw a line between two objects, right-drag between the two
+objects, starting at the attachment point area you wish to start the
+line with, and ending at another appropriate attachment point
+area. The initial ordering of the lines may not be correct (lines
+may overlap, for example) so to reorder lines on a particular
+side of a object, select a line, then left-drag the desired end to a new
+position (tip: keep within the object perimeter). Left-dragging the
+line end can also be used to change the attachment point of that
+end of the line, to a new side or vertex (depending on the object).
+
+To select or deselect a object, left click the object. To select
+several objects at once, keep the shift key pressed down when
+left-clicking, or left-drag a 'lassoo' around several objects.
+
+To delete a object or line, select it and press the Delete key, or use
+"Edit|Clear", or right-click on the object to show a menu and choose
+the "Cut" item.
+
+If you are deleting a object which has one ore more lines
+attached, the lines are deleted prior to the object deletion.
+
+Shapes can be rotated by right-clicking and selecting "Rotate
+clockwise" or "Rotate anticlockwise".
+
+Line arrows can be added (pointing in the direction in which
+you created the line) by selecting the line and pressing the
+"Toggle arrow" tool on the formatting toolbar.
+
+\section{Adding text}
+
+Select the text tool (on the symbol palette) and left-click on
+a object. If you click outside a object on the document, you are
+prompted to add a new free-floating text box.
+
+Alternatively, you can select a object and press Return (or
+select the "Edit|Edit label" menu item); or right-click and
+select "Edit label" from the object menu.
+
+Change the point size using the combobox on the formatting
+toolbar.
+
+\section{Aligning objects}
+
+Select several objects and click on an alignment tool on
+the formatting toolbar. The alignment will be done with
+respect to the first object you select. You can also copy
+the size of a object to other objects with the "Copy size" tool.
+
+\section{Adding segments to lines and straightening them}
+
+To make a line have more than one segment, select the line,
+then press the "New line point" tool. Create as many new control points
+(and therefore segments) as you like. Then arrange the points
+into a rough approximation of how they should be laid out
+horizontally and vertically. Click on "Straighten lines" to
+tidy up the layout.
+
+To delete a line control point, select the line and click on
+"Cut line point" tool. An arbitrary point will be deleted.
+
+\section{Undo/Redo}
+
+Every operation can be undone, and then redone, back until
+the time at which you last saved your document. Use
+"Edit|Undo" and "Edit|Redo"; or the shortcuts Ctrl-Z and Ctrl-Y.
+
+\section{Loading and saving files}
+
+Load and save files using the main toolbar, or "File|Open...",
+"File|Save", "File|Save As..." menu items.
+
+\section{Copy and paste}
+
+OGL Studio has a diagram clipboard, into which you can copy selections. You can then
+paste the contents of clipboard into the same or another diagram window.
+
+Use "Edit|Copy" (or the toolbar copy button) to copy the selection. Use "Edit|Cut" (or the toolbar cut button) to
+copy and then delete the selection. Use "Edit|Paste" (or the toolbar paste button) to copy the selection to
+the current diagram window.
+
+Under Windows, copy and cutting also copies the selection to the Windows clipboard into metafile (vector)
+format, and Windows bitmap format. Note that not all Windows applications can accept the vector format.
+If the application seems to be pasting the wrong format into the document, try using that application's
+"Edit|Paste Special..." menu item, if one exists.
+
+\section{Keyboard shortcuts}
+
+The following keyboard shortcuts are available. {\bf Note:} The OGL Studio menus indicate which shortcuts are
+available.
+
+\begin{twocollist}\itemsep=0pt
+\twocolitem{Delete}{Clear selected object(s)}
+\twocolitem{Enter}{Edit text for selected object}
+\twocolitem{Ctrl-A}{Select all}
+\twocolitem{Ctrl-C}{Copy the selection to the clipboard}
+\twocolitem{Ctrl-D}{Duplicate the selection}
+\twocolitem{Ctrl-O}{Open a diagram}
+\twocolitem{Ctrl-N}{Create a new diagram}
+\twocolitem{Ctrl-P}{Print (not implemented)}
+\twocolitem{Ctrl-S}{Save the diagram file without prompting}
+\twocolitem{Ctrl-V}{Paste the selection}
+\twocolitem{Ctrl-W}{Close the current window}
+\twocolitem{Ctrl-X}{Cut the selection}
+\twocolitem{Ctrl-Z}{Undo last action}
+\twocolitem{Ctrl-Y}{Redo current action on the undo stack}
+\twocolitem{Ctrl-Enter}{Confirm the label editing operation (dismisses the dialog)}
+\twocolitem{Esc}{Cancel the label editing dialog}
+\twocolitem{F1}{Invoke the manual}
+\twocolitem{F12}{Save the diagram file, prompting for a filename}
+\end{twocollist}
+
+\chapter{Menu commands}\label{menucommands}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+This section describes the menu commands.
+
+\section{File}
+
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf New...}}{Creates a new diagram window.}
+\twocolitem{{\bf Open...}}{Opens a diagram file.}
+\twocolitem{{\bf Close}}{Closes the current window.}
+\twocolitem{{\bf Save}}{Saves the current diagram without prompting.}
+\twocolitem{{\bf Save As...}}{Saves the current diagram, prompting for a filename.}
+\twocolitem{{\bf Print...}}{Prints the current diagram (not implemented).}
+\twocolitem{{\bf Print Setup...}}{Invokes the printer setup dialog.}
+\twocolitem{{\bf Print Preview}}{Invokes print preview for this diagram (not implemented).}
+\twocolitem{{\bf Exit}}{Exits the program.}
+\end{twocollist}
+
+Further menu items appended to the end of the File menu allow you
+to load previously-saved diagram files quickly.
+
+\section{Edit}
+
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf Undo}}{Undoes the previous action.}
+\twocolitem{{\bf Redo}}{Redoes the previously undone action.}
+\twocolitem{{\bf Cut}}{Deletes the current selection and places it on the clipboard.}
+\twocolitem{{\bf Copy}}{Copies the current selection onto the clipboard, both to the internal
+diagram clipboard and under Windows, to the Windows clipboard, in metafile and bitmap formats.}
+\twocolitem{{\bf Paste}}{Pastes from the internal diagram clipboard to the currently active window.}
+\twocolitem{{\bf Duplicate}}{Duplicates the current selection, placing the objects further down and to the right.}
+\twocolitem{{\bf Clear}}{Clears the current selection without placing it on the clipboard.}
+\twocolitem{{\bf Select All}}{Selects all objects.}
+\twocolitem{{\bf Edit Label...}}{Invokes a dialog to edit the label of the currently selected object.}
+\end{twocollist}
+
+\begin{comment}%
+\section{View}
+
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf Toolbar}}{Toggles the toolbar on and off.}
+\twocolitem{{\bf Status Bar}}{Toggles the status bar on and off.}
+\twocolitem{{\bf Settings}}{Invokes the \helpref{Settings dialog}{settings} to allow you to adjust a variety of
+settings.}
+\end{twocollist}
+\end{comment}%
+
+\section{Window}
+
+The Window menu is shown when one or more child window is active.
+
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf Cascade}}{Arranges the child windows in a cascade.}
+\twocolitem{{\bf Tile}}{Arranges the child windows in a tiled formation.}
+\twocolitem{{\bf Arrange Icons}}{Arranges the minimized icons.}
+\twocolitem{{\bf Next}}{Activates the next MDI window.}
+\end{twocollist}
+
+Further menu items appended to the end of the Window menu allow you
+to restore and activate any child window.
+
+\section{Help}
+
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf Help Contents}}{Invokes the on-line help, showing the contents page.}
+\twocolitem{{\bf About}}{Displays a small dialog giving copyright and version information.}
+\end{twocollist}
+
+\chapter{Toolbar commands}\label{toolbarcommands}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+This section describes the commands associated with the various toolbars and diagram palette.
+
+\section{Main toolbar}\label{maintoolbar}
+
+The main toolbar is active all the time, with buttons greyed out if not appropriate to the current context.
+
+\begin{twocollist}
+\twocolitem{\image{1cm;0cm}{new.bmp}}{{\bf New} Creates a new diagram window.}
+\twocolitem{\image{1cm;0cm}{open.bmp}}{{\bf Open} Opens a diagram file.}
+\twocolitem{\image{1cm;0cm}{save.bmp}}{{\bf Save} Saves the current diagram without prompting.}
+\twocolitem{\image{1cm;0cm}{print.bmp}}{{\bf Print} Prints the current diagram (not implemented).}
+\twocolitem{\image{1cm;0cm}{copy.bmp}}{{\bf Copy} Copies the current selection onto the internal clipboard, and under Windows, into the Windows clipboard
+in metafile and bitmap formats.}
+\twocolitem{\image{1cm;0cm}{cut.bmp}}{{\bf Cut} Deletes the current selection and puts it on the clipboard.}
+\twocolitem{\image{1cm;0cm}{paste.bmp}}{{\bf Paste} Pastes the contents of the internal diagram clipboard onto the
+current diagram window.}
+\twocolitem{\image{1cm;0cm}{undo.bmp}}{{\bf Undo} Undoes the last command.}
+\twocolitem{\image{1cm;0cm}{redo.bmp}}{{\bf Redo} Redoes the last command.}
+\twocolitem{\image{1cm;0cm}{help.bmp}}{{\bf Help button} Invokes on-line help.}
+\end{twocollist}
+
+\section{Diagram formatting toolbar}\label{diagramformattingtoolbar}
+
+The diagram toolbar is visible only when a diagram window is active.
+
+\begin{twocollist}
+\twocolitem{\image{1cm;0cm}{alignl.bmp}}{{\bf Align left} Aligns the selected objects to the left side of the last selection.}
+\twocolitem{\image{1cm;0cm}{alignr.bmp}}{{\bf Align right} Aligns the selected objects to the right side of the last selection.}
+\twocolitem{\image{1cm;0cm}{alignt.bmp}}{{\bf Align top} Aligns the selected objects to the top side of the last selection.}
+\twocolitem{\image{1cm;0cm}{alignb.bmp}}{{\bf Align bottom} Aligns the selected objects to the bottom side of the last selection.}
+\twocolitem{\image{1cm;0cm}{horiz.bmp}}{{\bf Align horizontally} Aligns the selected objects to be centered horizontally with respect to the last selection.}
+\twocolitem{\image{1cm;0cm}{vert.bmp}}{{\bf Align vertically} Aligns the selected objects to be centered vertically with respect to the last selection.}
+\twocolitem{\image{1cm;0cm}{copysize.bmp}}{{\bf Copy size} Makes the selected objects the same size as the last selection.}
+\twocolitem{\image{1cm;0cm}{linearrow.bmp}}{{\bf Line arrow} Toggles an arrow on or off for the selected objects.}
+\twocolitem{\image{1cm;0cm}{newpoint.bmp}}{{\bf New point} Inserts a control point into the selected line(s).}
+\twocolitem{\image{1cm;0cm}{cutpoint.bmp}}{{\bf Cut point} Deletes a control point from the selected line(s).}
+\twocolitem{\image{1cm;0cm}{straight.bmp}}{{\bf Straighten} Straightens line segments that are nearly horizontal
+or vertical.}
+\twocolitem{\image{1cm;0cm}{pointsize.bmp}}{{\bf Point size} Allows selection of the point size for the current
+selection.}
+\twocolitem{\image{1cm;0cm}{zoom.bmp}}{{\bf Zoom control} Allows selection of the zoom level for the current diagram.}
+\end{twocollist}
+
+\section{Diagram palette}\label{diagrampalette}
+
+The diagram palette is visible only when a diagram window is active. It contains the tools for
+adding objects and text to a diagram.
+
+\begin{twocollist}
+\twocolitem{\image{1cm;0cm}{arrow.bmp}}{{\bf Pointer tool} Click on this to allow dragging and selection of objects.}
+\twocolitem{\image{1cm;0cm}{texttool.bmp}}{{\bf Text tool} Click on this, then click on objects or the diagram background
+to edit object or free-floating text labels.}
+\end{twocollist}
+
+The other tools on this palette represent demo objects.
+
+To place an object on a diagram, click on its symbol, then left-click on the diagram. You will need to click
+on the palette symbol each time you wish to create an object, since the palette selection reverts to the pointer tool
+after each object is created.
+
+\chapter{Dialogs}\label{dialogs}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+To be written.
+
+\chapter{How To}\label{howto}%
+\setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+\section{Create a new object}
+
+Create a new diagram window if you have not already. Then:
+
+\begin{itemize}\itemsep=0pt
+\item Left-click on the required object on the palette, then left-click on the diagram window.
+\end{itemize}
+
+
+% This section commented out
+\begin{comment}
+\bibliography{refs}
+\addcontentsline{toc}{chapter}{Bibliography}
+\setheader{{\it REFERENCES}}{}{}{}{}{{\it REFERENCES}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+\end{comment}
+
+\addcontentsline{toc}{chapter}{Index}
+\printindex%
+
+\setheader{{\it INDEX}}{}{}{}{}{{\it INDEX}}%
+\setfooter{\thepage}{}{}{}{}{\thepage}%
+
+\end{document}
diff --git a/utils/ogl/samples/studio/manual/telephon.bmp b/utils/ogl/samples/studio/manual/telephon.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1788be8a72480caa1bdccd88501a9bd6ebf4c06a
GIT binary patch
literal 676
zcmb7>F%H5o3`LDql?Wl!0WmW&aR_#<1B@B7<q{mEM`EK}cuoT?1qPbhwf}c)*FGGt
zD)~8~cgVKLOe!&IUwBMuikL0p^DEw)g>Vc)wQUQM@+&Esg>Vc)Z3A@>y=_EYZC1Al
zpO%IOUSEvHCa53#*xB!OHRU>uL_GByJINH9MBGp*Xk3!J`X5Ppd%vX@4Yk!CWh3Ga
znkx>`So0F=22=x^xDe}gG7Vz7nhu{+=qIVsaPD;98ETw=a+d4!o?%SH{-o&fR=`$i
f==a+unRcWj*LP^1_3ZNIi|0n3U%;%{2;bQQ<I|hM

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/texttool.bmp b/utils/ogl/samples/studio/manual/texttool.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..09c989aac1c4833e37cb6b0f96c0c0d0cacfc14d
GIT binary patch
literal 382
zcmbVHF%p0v3=4PO>FDGee22S#VUo?`XYeyjTT}*FEF`2&%fYsv4jKn}C6)?@LF-fX
zC7CPKK!R+fWCxiNIcLNeX%yWkMHIm$B~p0fhX!YOAt?ku5^{&2)nYT(I-4KOfkx}7
W_5`$ATdeLo+T0JezsY;<=;{k{K6#)3

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/therm.bmp b/utils/ogl/samples/studio/manual/therm.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..00971562ed5f6ffb178658011c2a6fed5184abb3
GIT binary patch
literal 812
zcmZXSJyOIl4288KLp%&ab{K|wOA1aw&s|)>mhMQ$ZK(H1lyu>fWIG8s@t@v%k}Uh>
z_4!J?y)iz~PqiOp5M}*kLv2T9>(Pn`zmyUaBTIUb%jE*F_%F+1D>|Q<7*5QZu4iSu
zpY_vr!>nb<o872c-!&a8uHfv2o;NmQ{pe`SyT&x$RQb7Eok<ku-Zt*&%nv=g_uTD*
zSIci?bj3|m;CUz@kx$;*@$n6E))bo5GzD)(7b;p+9hp78>~&PeYvOFnV_KCB<0KP#
z?BZeTwe<Wqx`v_urz3*vz%0{UyoQl+=*oJ&P=Qnx+<wBqsE(=Z^ih@E?SC~D;RaTP
z`SZ-Mu6(<b5_WDk*n3-Wc~vk|FnKeRpRb;kJuIqX9AZ33ycsGzu`_hBH!AW-7HO8l
EFJhdNu>b%7

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/tick.bmp b/utils/ogl/samples/studio/manual/tick.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..c0d66c94601657fee33b923de9b1791844d7a331
GIT binary patch
literal 220
zcmXv`!4bnS2vd9<&b6P6(K-6>8h!H$UytTNvWqL(DMm;L@cVON#YuV*&l?*Ih5AeU
z<Dd{$G=PcL7O_&I_fFPe%)}T{1fMLHN0y*v8NQS!DqFcF>{bqVO)bKZHuqJq2P$o+
Qrwbl?Kzn<_G@1WzKlk4xlmGw#

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/toback.bmp b/utils/ogl/samples/studio/manual/toback.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d2e5efffcea17b5340e8c9278186ca5cf16e666e
GIT binary patch
literal 238
zcmZ`yu?>JQ3^NiE0|T7F9qjzl2^cf>9QF?FMZ8d)1PO#h65C0vwDWSpW2H>QNDM@S
zmJIC1PU<N<GQdL4E@ZYSr9ebzR4de~9l_KUX?sPWr(=jw9_7;JJ{@1Br8g;ccJrrz
J`}XGj#|0@HO0NI_

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/tofront.bmp b/utils/ogl/samples/studio/manual/tofront.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5b17cc44c86d936cdaba49553685be0719486d34
GIT binary patch
literal 238
zcmZ{cK@Nj33<MVm2_z2m8N7pg|B@5sm?MA6A$bvBNM}i<R!FtIyS7*M`aIQQLl*D=
zGw9UA(tdFxdq#^aQOdaqOsi6gVvHE|D%I)^kX}Krp9pv!!*Rr~ved{trIhX}1$jSk
N^G|(m|MQc{zu(f|NZ|kg

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/tool1.bmp b/utils/ogl/samples/studio/manual/tool1.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..cb1760d2859cd5b32630cb6c294a6c913d4b28f3
GIT binary patch
literal 382
zcmZ?rtz%>WgEAng0mNcZ%*en37UzJ<gE#_E43=Qn&j3OU`}adAAPHnL95`@*p`oDx
uDDfYR82<kUv49u|K|(;H9072$3xIkcpq!xqs0j={3?Vkm`3&Va{RjY^M#l00

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/tool2.bmp b/utils/ogl/samples/studio/manual/tool2.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..a18faccff78bb98a737092de9ea4b95c13bd961b
GIT binary patch
literal 382
zcmc&vu?>JQ409!<vcbd++`-N-Ok_j-tUZYjiql4-46x$HscS1zx~zvo!OlLDlhL6o
zes8%xMq>#Op@kUh#ZHNo5<&<Jaw+7jisVs?O>TT>4iR1ivT=$yRS#8XFECq!-*mgr
LV^3-JfBEkPyAH!9

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/tool3.bmp b/utils/ogl/samples/studio/manual/tool3.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..6a49f459c3034a9d633c00c876720d1d6ec01a59
GIT binary patch
literal 382
zcmbtP$qj%o3^NiE{NTk5%)y^sc#$9KX6;C9Q0!1~{E$dv*LBpindYs6$4VZFp`b$T
zep~7~^aWl(gc32H8<`R*C4>-I$ezeqir|t(vOE52cJ>w|bn4wu*h0nFrR6FbL$Ou(
Uq@Q<RJ)duxE%zU;!9LA(015o17ytkO

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/tool4.bmp b/utils/ogl/samples/studio/manual/tool4.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..95c2061a900b3414989d22f108f4ad417ec1d972
GIT binary patch
literal 382
zcmaKmu@S;B6hoCe?w|`5GcX4|yQG4S^Jex)Z19of9}+il{AF1$w*TY#nc(rF-dVS-
z2`A^5<l0=b3{atoTKht!MQaVE6oT+XgdB^XBFcLk$G%hR5@(&VpX0mwh4%?4pXmkY
m6&uhiHbBM#qu>8CoZa7Pu)am`?}1?Jt#_EJF0<!u$NUFvGM_*I

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/torch.bmp b/utils/ogl/samples/studio/manual/torch.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f7f235c1716959dadb88a2fd7d6d4ee2bbcf1b56
GIT binary patch
literal 706
zcmZ9Ju};J=42FGHl#9@bo){40jXVeQ@h+JtW431Fl`5Wyv0M4<B;1L%PVGNmZO46k
z|5owqgY^}=bUR28+q(9BTse0$U!?dWrI?3to5ZrNE6VPV?7Mjww@EA)-kM^iLONId
zvM5xQFl!#MRxSD&XHActKsmaabyoRPOCxm-M@^@}nwqc$H8(XREmSdutPf5mXULmw
z8k|6iE~r=|Lkbct>zxwmn=b!rz4Gl#m_}~*tbI#AMJHc#tAlEDnRIiNPSZG(vAb^3
z@-Lc)4mY7$E@-?l&k}df4Lj6Wqj&~Lcqge_^oQx&Ir31MnNZCrSo(Gr)z8w{q4F;#
zx-rfv;^I}v*A)J0BPRRTL}TCMr*?uxN5rmIAbw^R_)H0(cc3S&A}>rSR5|<tt&x5>

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/undo.bmp b/utils/ogl/samples/studio/manual/undo.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4ad80c772f8f5281500707222f552d634a9c027a
GIT binary patch
literal 238
zcma)zu?>JQ3<MvE9>!n}6e%=pgD_<}*2+Yz5YBOr`1t>vyt3|(LMK@8j3+#3B&Dlo
ygm>;xkr<T{AX!ywg<iBiYRxyy@h8Im=*ng(5u1}A2jtqx?#xC(k5aljzv2a83`_6;

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/vert.bmp b/utils/ogl/samples/studio/manual/vert.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..dfd7b5cb5339fbffb36ca2113e42e33ea594434b
GIT binary patch
literal 238
zcmaKku?>JQ3<MvEjsnJD4tjQ>0?Ld;pCXxv6~fs8i2~vH|E+&J(|oGdii}_YJ!sUz
z((YWzGDEE-(MqWb%&45RLI?!KTcy|pcxFM{N3r657vo{E>4N2o^{e;ZbNANgU-K?u
CAW)M4

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/wrench.bmp b/utils/ogl/samples/studio/manual/wrench.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8062f7d0c351a267c4a4cafb1f5867351fb076b2
GIT binary patch
literal 744
zcmZuvyH3PF4D?x6vO<U;gs!5vlJB7BUm^;wb-5kCl+U3|d0lSC`$&*T;(d%~Z0|ZB
zpT8>cd}DlvU8<eLgs!jZ$5NiFaV_HUi91&?yo4|;%K~JJPqvLK7+yjcE|@jFW&QbY
zR#$k>)vKdkb>4S&)%4nZ*v*=$c&ZqxrXrQ`F;GjvAvdBG6r9O25olnkMRmPZK6Exh
zm4@caRa3H#HXl5HbPAs)#E&y#F1e^1hxvf-Dpaw15H}P&uXR4qonLA|7Q~D!H~}@d
zJs`XRIe4H8^@<48gyI2;A=|{Nz;0N}LGCU16FY@_BXf%QMbmJ%6&^+=zoV7QTMuQ8
x;#%13NXOAZ)?K>S(HA0f)Pc;@2a-bPtoSVImJR<H{tM!pu9jox=q!35r#l4%fGYq1

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/manual/zoom.bmp b/utils/ogl/samples/studio/manual/zoom.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..c6a137ada535c4b30984750bbb673e09c2436cd8
GIT binary patch
literal 790
zcmb_ayA{GP3_L#Xr3?+szz|gQ?2-!8*&TGOz$h8X8;FyP69RS`I7_mVdy>vdj;GxU
zhBM=yexPsZ3#=J|$I><n8%Fhn0MHOZ+8B96-}l^=5HpDAiO!|3^m!J*)y=@OWig*k
z6jlCmQ-mt-t?8fmRwC5iZab;p3YS{sA%T43+^c`)<2WtvI(+d%wupB?^O-Mkm{qaA
zj0K8(q`*-hCzSLd>znEycvemKkNI}0Pw~TiO-DW7%DYa#ul)#>K;C|YTDSvGP;$%i

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/project.cpp b/utils/ogl/samples/studio/project.cpp
new file mode 100644
index 0000000000..a6298d698e
--- /dev/null
+++ b/utils/ogl/samples/studio/project.cpp
@@ -0,0 +1,89 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        project.cpp
+// Purpose:     Studio project classes
+// Author:      Julian Smart
+// Modified by:
+// Created:     27/7/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#include "wx/mdi.h"
+#endif
+
+#include "wx/laywin.h"
+#include "studio.h"
+#include "project.h"
+
+IMPLEMENT_CLASS(csProjectTreeCtrl, wxTreeCtrl)
+
+BEGIN_EVENT_TABLE(csProjectTreeCtrl, wxTreeCtrl)
+END_EVENT_TABLE()
+
+// Define my frame constructor
+csProjectTreeCtrl::csProjectTreeCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
+	long style):
+
+  wxTreeCtrl(parent, id, pos, size, style),
+  m_imageList(16, 16)
+{
+    m_imageList.Add(wxIcon("folder1"));
+    m_imageList.Add(wxIcon("file1"));
+
+    SetImageList(& m_imageList);
+}
+
+csProjectTreeCtrl::~csProjectTreeCtrl()
+{
+    SetImageList(NULL);
+}
+
+// Create the project window
+bool csApp::CreateProjectWindow(wxFrame *parent)
+{
+#if 0
+    // Create a layout window
+    wxSashLayoutWindow* win = new wxSashLayoutWindow(parent, ID_LAYOUT_WINDOW_PROJECT, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D|wxCLIP_CHILDREN);
+    win->SetDefaultSize(wxSize(150, 10000));
+    win->SetOrientation(wxLAYOUT_VERTICAL);
+    win->SetAlignment(wxLAYOUT_LEFT);
+    win->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
+    win->SetSashVisible(wxSASH_RIGHT, TRUE);
+    win->SetExtraBorderSize(5);
+
+    m_projectSashWindow = win;
+
+    m_projectTreeCtrl = new csProjectTreeCtrl(win, ID_WINDOW_PROJECT_TREE, wxDefaultPosition,
+        wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxDOUBLE_BORDER);
+
+    // For now, hide the window
+    m_projectSashWindow->Show(FALSE);
+#endif
+
+    return TRUE;
+}
+
+// Fill out the project tree control
+void csApp::FillProjectTreeCtrl()
+{
+#if 0
+    csProjectTreeCtrl& tree = *GetProjectTreeCtrl();
+
+    // Dummy data for now
+    long level0 = tree.InsertItem(0, "Applications", 0, 0);
+    long level1 = tree.InsertItem(level0, "Projects", 0, 0);
+    tree.InsertItem(level1, "project1", 1, 1);
+    tree.InsertItem(level1, "project2", 1, 1);
+#endif
+}
+
diff --git a/utils/ogl/samples/studio/project.h b/utils/ogl/samples/studio/project.h
new file mode 100644
index 0000000000..b52ae259ef
--- /dev/null
+++ b/utils/ogl/samples/studio/project.h
@@ -0,0 +1,42 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        project.h
+// Purpose:     Studio project classes
+// Author:      Julian Smart
+// Modified by:
+// Created:     27/7/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_PROJECT_H_
+#define _STUDIO_PROJECT_H_
+
+#include <wx/treectrl.h>
+#include <wx/imaglist.h>
+
+/*
+ * This is the project tree control.
+ */
+
+class csProjectTreeCtrl: public wxTreeCtrl
+{
+
+DECLARE_CLASS(csProjectTreeCtrl)
+public:
+
+    csProjectTreeCtrl(wxWindow *parent, const wxWindowID id, const wxPoint& pos, const wxSize& size,
+       long style = wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT);
+
+    ~csProjectTreeCtrl();
+
+    wxImageList& GetImageList() const { return (wxImageList&) m_imageList; }
+protected:
+    wxImageList     m_imageList;
+
+DECLARE_EVENT_TABLE()
+};
+
+#endif
+  // _STUDIO_PROJECT_H_
+
diff --git a/utils/ogl/samples/studio/shapes.cpp b/utils/ogl/samples/studio/shapes.cpp
new file mode 100644
index 0000000000..b9197af2eb
--- /dev/null
+++ b/utils/ogl/samples/studio/shapes.cpp
@@ -0,0 +1,1185 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        shapes.cpp
+// Purpose:     Implements Studio shapes
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#if !wxUSE_DOC_VIEW_ARCHITECTURE
+#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
+#endif
+
+#include <wx/wxexpr.h>
+
+#include "studio.h"
+#include "doc.h"
+#include "shapes.h"
+#include "view.h"
+#include "basicp.h"
+#include "linesp.h"
+#include "cspalette.h"
+#include "dialogs.h"
+
+#define csSTANDARD_SHAPE_WIDTH      100
+
+IMPLEMENT_CLASS(csDiagram, wxDiagram)
+
+csDiagram::~csDiagram()
+{
+    DeleteAllShapes();
+}
+
+void csDiagram::Redraw(wxDC& dc)
+{
+    wxDiagram::Redraw(dc);
+
+    // Draw line crossings
+    wxLineCrossings lineCrossings;
+    lineCrossings.FindCrossings(*this);
+    lineCrossings.DrawCrossings(*this, dc);
+}
+
+/*
+ * csEvtHandler: an event handler class for all shapes
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(csEvtHandler, wxShapeEvtHandler)
+
+csEvtHandler::csEvtHandler(wxShapeEvtHandler *prev, wxShape *shape, const wxString& lab):
+  wxShapeEvtHandler(prev, shape)
+{
+    m_label = lab;
+}
+
+csEvtHandler::~csEvtHandler()
+{
+}
+
+// Copy any event handler data
+void csEvtHandler::CopyData(wxShapeEvtHandler& copy)
+{
+    wxShapeEvtHandler::CopyData(copy);
+
+    csEvtHandler& csCopy = (csEvtHandler&) copy;
+    csCopy.m_label = m_label;
+}
+ 
+void csEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
+{
+  wxClientDC dc(GetShape()->GetCanvas());
+  GetShape()->GetCanvas()->PrepareDC(dc);
+
+  csDiagramView* view = ((csCanvas*)GetShape()->GetCanvas())->GetView();
+  view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
+
+  if (GetShape()->IsKindOf(CLASSINFO(wxLineShape)))
+      view->ReflectArrowState((wxLineShape*) GetShape());
+
+  csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
+  if (palette->GetSelection() == PALETTE_TEXT_TOOL)
+  {
+        view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
+
+        EditProperties();
+#if 0
+        csLabelEditingDialog* dialog = new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
+        dialog->SetShapeLabel(m_label);
+        if (dialog->ShowModal() == wxID_CANCEL)
+        {
+            dialog->Destroy();
+            return;
+        }
+
+        wxString newLabel = dialog->GetShapeLabel();
+        dialog->Destroy();
+
+        wxShape* newShape = GetShape()->CreateNewCopy();
+
+        csEvtHandler* handler = (csEvtHandler *)newShape->GetEventHandler();
+        handler->m_label = newLabel;
+
+        view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
+            new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, GetShape())));
+#endif
+        return;
+  }
+
+  if (keys == 0)
+  {
+    // If no shift key, then everything is deselected.
+    // If the shape was selected, deselect it and vice versa.
+    bool selected = GetShape()->Selected();
+
+    view->SelectAll(FALSE);
+
+    selected = !selected;
+
+    GetShape()->Select(selected, &dc);
+    GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
+
+    view->SelectShape(GetShape(), selected);
+  }
+  else if (keys & KEY_SHIFT)
+  {
+    if (GetShape()->Selected())
+    {
+        GetShape()->Select(FALSE, &dc);
+        view->SelectShape(GetShape(), FALSE);
+    }
+    else
+    {
+        GetShape()->Select(TRUE, &dc);
+        view->SelectShape(GetShape(), TRUE);
+    }
+    GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
+  }
+  else if (keys & KEY_CTRL)
+  {
+    // Do something for CONTROL
+  }
+  else
+  {
+    ((wxFrame*)wxGetApp().GetTopWindow())->SetStatusText(m_label);
+  }
+}
+
+void csEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
+{
+    // Have to convert back to physical coordinates from logical coordinates.
+
+    int viewStartX, viewStartY;
+    int unitX, unitY;
+    GetShape()->GetCanvas()->ViewStart(& viewStartX, & viewStartY);
+    GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX, & unitY);
+
+    int x1 = (int)(x * GetShape()->GetCanvas()->GetScaleX());
+    int y1 = (int)(y * GetShape()->GetCanvas()->GetScaleY());
+
+    int menuX = (int) (x1 - (viewStartX * unitX)) ;
+    int menuY = (int) (y1 - (viewStartY * unitY));
+
+    wxGetApp().GetShapeEditMenu()->SetClientData((char*) GetShape());
+    wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_CLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
+    wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_ANTICLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
+
+    GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX, menuY);
+}
+
+/*
+ * Implement connection of two shapes by right-dragging between them.
+ */
+
+void csEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
+{
+  wxClientDC dc(GetShape()->GetCanvas());
+  GetShape()->GetCanvas()->PrepareDC(dc);
+
+  wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+  dc.SetLogicalFunction(wxXOR);
+  dc.SetPen(dottedPen);
+  double xp, yp;
+  GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
+  dc.DrawLine(xp, yp, x, y);
+  GetShape()->GetCanvas()->CaptureMouse();
+}
+
+void csEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
+{
+  wxClientDC dc(GetShape()->GetCanvas());
+  GetShape()->GetCanvas()->PrepareDC(dc);
+
+  wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+  dc.SetLogicalFunction(wxXOR);
+  dc.SetPen(dottedPen);
+  double xp, yp;
+  GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
+  dc.DrawLine(xp, yp, x, y);
+}
+
+void csEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
+{
+  GetShape()->GetCanvas()->ReleaseMouse();
+  csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
+
+  // Check if we're on an object
+  int new_attachment;
+  wxShape *otherShape = canvas->FindFirstSensitiveShape(x, y, &new_attachment, OP_DRAG_RIGHT);
+  
+  if (otherShape && !otherShape->IsKindOf(CLASSINFO(wxLineShape)))
+  {
+        wxLineShape* theShape = new csLineShape;
+
+        theShape->AssignNewIds();
+        theShape->SetEventHandler(new csEvtHandler(theShape, theShape, wxString("")));
+        theShape->SetPen(wxBLACK_PEN);
+        theShape->SetBrush(wxRED_BRUSH);
+
+        wxToolBar* toolbar = wxGetApp().GetDiagramToolBar();
+        bool haveArrow = toolbar->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
+
+        wxLineShape *lineShape = (wxLineShape *)theShape;
+
+        // Yes, you can have more than 2 control points, in which case
+        // it becomes a multi-segment line.
+        lineShape->MakeLineControlPoints(2);
+
+        if (haveArrow)
+            lineShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead");
+
+        lineShape->SetFrom(GetShape());
+        lineShape->SetTo(otherShape);
+        lineShape->SetAttachments(attachment, new_attachment);
+
+        canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(
+            new csDiagramCommand("Line", (csDiagramDocument *)canvas->GetView()->GetDocument(),
+                    new csCommandState(ID_CS_ADD_LINE, lineShape, NULL)));
+  }
+}
+
+static double g_DragOffsetX = 0.0;
+static double g_DragOffsetY = 0.0;
+static double g_DragStartX = 0.0;
+static double g_DragStartY = 0.0;
+
+void csEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
+{
+  if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
+  {
+    attachment = 0;
+    double dist;
+    if (GetShape()->GetParent())
+    {
+      GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
+      GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
+    }
+    return;
+  }
+
+  wxClientDC dc(GetShape()->GetCanvas());
+  GetShape()->GetCanvas()->PrepareDC(dc);
+
+  dc.SetLogicalFunction(wxXOR);
+
+  wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+  dc.SetPen(dottedPen);
+  dc.SetBrush(* wxTRANSPARENT_BRUSH);
+
+  double xx, yy;
+  xx = x + g_DragOffsetX;
+  yy = y + g_DragOffsetY;
+
+  GetShape()->GetCanvas()->Snap(&xx, &yy);
+
+  double offsetX = xx - g_DragStartX;
+  double offsetY = yy - g_DragStartY;
+
+//  m_xpos = xx; m_ypos = yy;
+  double w, h;
+  GetShape()->GetBoundingBoxMax(&w, &h);
+  GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
+
+  // Draw bounding box for other selected shapes
+  wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
+  while (node)
+  {
+     wxShape* shape = (wxShape*) node->Data();
+     if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
+     {
+        shape->GetBoundingBoxMax(&w, &h);
+        shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
+     }
+     node = node->Next();
+  }
+}
+
+void csEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
+{
+  if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
+  {
+    attachment = 0;
+    double dist;
+    if (GetShape()->GetParent())
+    {
+      GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
+      GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
+    }
+    return;
+  }
+
+  wxClientDC dc(GetShape()->GetCanvas());
+  GetShape()->GetCanvas()->PrepareDC(dc);
+
+  // New policy: don't erase shape until end of drag.
+//  Erase(dc);
+
+  g_DragOffsetX = GetShape()->GetX() - x;
+  g_DragOffsetY = GetShape()->GetY() - y;
+
+  double xx, yy;
+  xx = x + g_DragOffsetX;
+  yy = y + g_DragOffsetY;
+
+  GetShape()->GetCanvas()->Snap(&xx, &yy);
+
+  g_DragStartX = GetShape()->GetX();
+  g_DragStartY = GetShape()->GetY();
+
+  double offsetX = xx - g_DragStartX;
+  double offsetY = yy - g_DragStartY;
+
+  dc.SetLogicalFunction(wxXOR);
+
+  wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+  dc.SetPen(dottedPen);
+  dc.SetBrush((* wxTRANSPARENT_BRUSH));
+
+  double w, h;
+  GetShape()->GetBoundingBoxMax(&w, &h);
+  GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
+
+  // Draw bounding box for other selected shapes
+  wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
+  while (node)
+  {
+     wxShape* shape = (wxShape*) node->Data();
+     if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
+     {
+        shape->GetBoundingBoxMax(&w, &h);
+        shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
+     }
+     node = node->Next();
+  }
+
+  GetShape()->GetCanvas()->CaptureMouse();
+}
+
+
+void csEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
+{
+  csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
+
+  canvas->ReleaseMouse();
+  if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
+  {
+    attachment = 0;
+    double dist;
+    if (GetShape()->GetParent())
+    {
+      GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
+      GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
+    }
+    return;
+  }
+
+  wxClientDC dc(canvas);
+  canvas->PrepareDC(dc);
+
+  dc.SetLogicalFunction(wxCOPY);
+
+  double xx = x + g_DragOffsetX;
+  double yy = y + g_DragOffsetY;
+
+  canvas->Snap(&xx, &yy);
+
+  double offsetX = xx - g_DragStartX;
+  double offsetY = yy - g_DragStartY;
+
+  wxShape* newShape = GetShape()->CreateNewCopy();
+
+  newShape->SetX(xx);
+  newShape->SetY(yy);
+
+  csDiagramCommand* cmd = new csDiagramCommand("Move", (csDiagramDocument*)canvas->GetView()->GetDocument(),
+                new csCommandState(ID_CS_MOVE, newShape, GetShape()));
+
+  // Move line points
+  wxNode* node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
+  while (node)
+  {
+     wxShape* shape = (wxShape*) node->Data();
+     // Only move the line point(s) if both ends move too
+     if (shape->IsKindOf(CLASSINFO(wxLineShape)) &&
+           ((wxLineShape*)shape)->GetTo()->Selected() && ((wxLineShape*)shape)->GetFrom()->Selected())
+     {
+        wxLineShape* lineShape = (wxLineShape*) shape;
+
+        if (lineShape->GetLineControlPoints()->Number() > 2)
+        {
+            wxLineShape* newLineShape = (wxLineShape*) lineShape->CreateNewCopy();
+
+            wxNode *node1 = newLineShape->GetLineControlPoints()->First();
+            while (node1)
+            {
+                wxRealPoint *point = (wxRealPoint *)node1->Data();
+                point->x += offsetX;
+                point->y += offsetY;
+                node1 = node1->Next();
+            }
+            cmd->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT, newLineShape, lineShape));
+            lineShape->Erase(dc);
+        }
+     }
+     node = node->Next();
+  }
+
+  // Add other selected node shapes, if any
+  node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->First();
+  while (node)
+  {
+     wxShape* shape = (wxShape*) node->Data();
+     if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
+     {
+        wxShape* newShape2 = shape->CreateNewCopy();
+        newShape2->SetX(shape->GetX() + offsetX);
+        newShape2->SetY(shape->GetY() + offsetY);
+        cmd->AddState(new csCommandState(ID_CS_MOVE, newShape2, shape));
+     }
+     node = node->Next();
+  }
+
+  canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
+}
+
+void csEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
+{
+  wxShape* shape = GetShape();
+  csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
+
+  if (shape->IsKindOf(CLASSINFO(wxLineShape)))
+  {
+    // TODO: Do/Undo support for line operations
+    ((wxLineShape*)shape)->wxLineShape::OnSizingEndDragLeft(pt, x, y, keys, attachment);
+#if 0
+        wxLineShape* lineShape = (wxLineShape*) shape;
+
+        wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
+
+        wxClientDC dc(canvas);
+        canvas->PrepareDC(dc);
+
+        shape->SetDisableLabel(FALSE);
+
+        if (lpt->m_type == CONTROL_POINT_LINE)
+        {
+            canvas->Snap(&x, &y);
+
+            dc.SetLogicalFunction(wxCOPY);
+            lpt->SetX(x); lpt->SetY(y);
+            lpt->m_point->x = x; lpt->m_point->y = y;
+
+            this->OnMoveLink(dc);
+        }
+        if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
+        {
+            if (lpt->m_oldCursor)
+                canvas->SetCursor(lpt->m_oldCursor);
+            lineShape->Erase(dc);
+
+            lpt->SetX(x); lpt->SetY(y);
+
+            if (lineShape->GetFrom())
+            {
+                lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y);
+            }
+        }
+        if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
+        {
+            if (lpt->m_oldCursor)
+                canvas->SetCursor(lpt->m_oldCursor);
+
+            lpt->SetX(x); lpt->SetY(y);
+
+            if (lineShape->GetTo())
+            {
+                lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y);
+            }
+        }
+#endif
+        return;
+  }
+
+  wxClientDC dc(canvas);
+  canvas->PrepareDC(dc);
+
+  canvas->ReleaseMouse();
+  dc.SetLogicalFunction(wxCOPY);
+
+//  shape->Erase(dc);
+/*
+  shape->Recompute();
+  shape->ResetControlPoints();
+  if (!pt->m_eraseObject)
+    shape->Show(FALSE);
+*/
+
+  wxShape* newShape = shape->CreateNewCopy();
+
+  if (newShape->IsKindOf(CLASSINFO(wxPolygonShape)))
+  {
+    wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
+    newShape->SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
+
+    ((wxPolygonShape *)newShape)->CalculateBoundingBox();
+    ((wxPolygonShape *)newShape)->CalculatePolygonCentre();
+    newShape->ResetControlPoints();
+  }
+  else
+  {
+    newShape->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
+    if (shape->GetCentreResize())
+    {
+      // Old position is fine
+    }
+    else
+    {
+      newShape->SetX(pt->sm_controlPointDragPosX);
+      newShape->SetY(pt->sm_controlPointDragPosY);
+    }
+  }
+
+  csDiagramCommand* cmd = new csDiagramCommand("Size", (csDiagramDocument*)canvas->GetView()->GetDocument(),
+                new csCommandState(ID_CS_SIZE, newShape, shape));
+
+  canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
+
+}
+
+void csEvtHandler::OnEndSize(double x, double y)
+{
+  wxClientDC dc(GetShape()->GetCanvas());
+  GetShape()->GetCanvas()->PrepareDC(dc);
+
+  GetShape()->FormatText(dc, m_label);
+}
+
+void csEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
+{
+    csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
+
+    // We actually submit two different states: one to change the ordering, and another
+    // to change the attachment for the line.
+    // Problem. If we refresh after the attachment change, we'll get a flicker.
+    // We really want to do both in a oner.
+
+    csDiagramCommand* cmd = new csDiagramCommand("Change attachment", (csDiagramDocument*)canvas->GetView()->GetDocument());
+
+    wxLineShape* newLine = (wxLineShape*) line->CreateNewCopy();
+    if (line->GetTo() == GetShape())
+        newLine->SetAttachmentTo(attachment);
+    else
+        newLine->SetAttachmentFrom(attachment);
+
+    cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT, newLine, line));
+
+    // Change ordering
+    wxShape* newShape = GetShape()->CreateNewCopy();
+    newShape->ApplyAttachmentOrdering(ordering);
+
+    cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING, newShape, GetShape()));
+
+    canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
+}
+
+void csEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
+{
+    EditProperties();
+}
+
+// Popup up a property dialog
+bool csEvtHandler::EditProperties()
+{
+    wxShape* shape = GetShape();
+
+    // For now, no line property editing
+    if (shape->IsKindOf(CLASSINFO(wxLineShape)))
+        return FALSE;
+
+    csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
+
+    wxPanel* attributeDialog;
+    wxString attributeDialogName;
+    wxString title;
+
+    if (shape->IsKindOf(CLASSINFO(csThinRectangleShape)))
+    {
+        attributeDialog = new csThinRectangleDialog;
+        attributeDialogName = "thin_rectangle";
+        title = "Thin Rectangle Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csWideRectangleShape)))
+    {
+        attributeDialog = new csWideRectangleDialog;
+        attributeDialogName = "wide_rectangle";
+        title = "Wide Rectangle Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csTriangleShape)))
+    {
+        attributeDialog = new csTriangleDialog;
+        attributeDialogName = "triangle";
+        title = "Triangle Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csSemiCircleShape)))
+    {
+        attributeDialog = new csSemiCircleDialog;
+        attributeDialogName = "semi_circle";
+        title = "Semicircle Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csCircleShape)))
+    {
+        attributeDialog = new csCircleDialog;
+        attributeDialogName = "circle";
+        title = "Circle Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csCircleShadowShape)))
+    {
+        attributeDialog = new csCircleShadowDialog;
+        attributeDialogName = "circle_shadow";
+        title = "Circle Shadow Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csTextBoxShape)))
+    {
+        attributeDialog = new csTextBoxDialog;
+        attributeDialogName = "text_box";
+        title = "Text Box Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csGroupShape)))
+    {
+        attributeDialog = new csGroupDialog;
+        attributeDialogName = "group";
+        title = "Group Properties";
+    }
+    else if (shape->IsKindOf(CLASSINFO(csOctagonShape)))
+    {
+        attributeDialog = new csOctagonDialog;
+        attributeDialogName = "octagon";
+        title = "Octagon Properties";
+    }
+    else
+    {
+        wxMessageBox("Unrecognised shape.", "Studio", wxICON_EXCLAMATION);
+        return FALSE;
+    }
+
+    csShapePropertiesDialog* dialog = new csShapePropertiesDialog(shape->GetCanvas()->GetParent(), title, attributeDialog, attributeDialogName);
+    dialog->GetGeneralPropertiesDialog()->SetShapeLabel(m_label);
+    if (dialog->ShowModal() == wxID_CANCEL)
+    {
+        dialog->Destroy();
+        return FALSE;
+    }
+
+    wxString newLabel = dialog->GetGeneralPropertiesDialog()->GetShapeLabel();
+    dialog->Destroy();
+
+    wxShape* newShape = shape->CreateNewCopy();
+
+    csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
+    handler2->m_label = newLabel;
+
+    view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit properties", (csDiagramDocument*) view->GetDocument(),
+                new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, shape)));
+
+    return TRUE;
+}
+
+/*
+ * Diagram
+ */
+ 
+bool csDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
+{
+  wxDiagram::OnShapeSave(db, shape, expr);
+  csEvtHandler *handler = (csEvtHandler *)shape.GetEventHandler();
+  expr.AddAttributeValueString("label", handler->m_label);
+  return TRUE;
+}
+
+bool csDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
+{
+  wxDiagram::OnShapeLoad(db, shape, expr);
+  wxString label("");
+  expr.GetAttributeValue("label", label);
+  csEvtHandler *handler = new csEvtHandler(&shape, &shape, label);
+  shape.SetEventHandler(handler);
+  
+  return TRUE;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape, wxDrawnShape)
+
+csThinRectangleShape::csThinRectangleShape()
+{
+    SetDrawnPen(wxBLACK_PEN);
+    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
+    SetDrawnBrush(brush);
+
+    double w = csSTANDARD_SHAPE_WIDTH/2;
+    double h = csSTANDARD_SHAPE_WIDTH;
+
+    DrawRectangle(wxRect(- w/2, - h/2, w, h));
+    CalculateSize();
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape, wxDrawnShape)
+
+csWideRectangleShape::csWideRectangleShape()
+{
+    SetDrawnPen(wxBLACK_PEN);
+    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
+    SetDrawnBrush(brush);
+
+    double w = csSTANDARD_SHAPE_WIDTH;
+    double h = w/2.0;
+
+    DrawRoundedRectangle(wxRect(- w/2, - h/2, w, h), -0.3);
+    CalculateSize();
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csTriangleShape, wxDrawnShape)
+
+csTriangleShape::csTriangleShape()
+{
+    SetDrawnPen(wxBLACK_PEN);
+    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
+    SetDrawnBrush(brush);
+
+    double w = csSTANDARD_SHAPE_WIDTH;
+    double h = (csSTANDARD_SHAPE_WIDTH*2.0)/3.0;
+
+    // Triangle, from top vertex
+    wxPoint* points = new wxPoint[3];
+
+
+    points[0] = wxPoint( 0 ,  - h / 2 );
+    points[1] = wxPoint( w / 2 ,  h / 2 );
+    points[2] = wxPoint( -w / 2,  h / 2 );
+
+    DrawPolygon(3, points, oglMETAFLAGS_OUTLINE);
+
+    delete[] points;
+
+    // Add another triangle at the top for the black bit
+    SetDrawnBrush(wxBLACK_BRUSH);
+
+    points = new wxPoint[3];
+
+    // Calculate where the new points will be, using the proportions
+    // of the triangle.
+    double h1 = 8; // Height of little triangle.
+
+    /*
+        Formula: ((w/2) / h) = w1 / h1
+        w1 = ((w/2) / h) * h1;
+    */
+    double ratio = ((w/2.0) / h) ;
+    double w1 = ratio * h1;
+
+    points[0] = wxPoint(0  ,  (int) (- h / 2 ));
+    points[1] = wxPoint( (int) w1,  (int) (- h / 2 + h1));
+    points[2] = wxPoint( (int) -w1, (int) (- h / 2 + h1));
+
+    DrawPolygon(3, points);
+
+    delete[] points;
+
+    CalculateSize();
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape, wxDrawnShape)
+
+csSemiCircleShape::csSemiCircleShape()
+{
+    // Zero degrees
+    DrawAtAngle(oglDRAWN_ANGLE_0);
+
+    double w = csSTANDARD_SHAPE_WIDTH;
+    double h = w/2.0;
+
+    SetDrawnPen(wxTRANSPARENT_PEN);
+    SetDrawnBrush(wxTRANSPARENT_BRUSH);
+
+    // Draw a dummy rectangle that will be used for calculating the
+    // bounding box, since we can't calculate the bounding box for
+    // an arbitrary arc (not implemented)
+
+    DrawRectangle(wxRect(-w/2.0, -h/2.0, w, h));
+
+    SetDrawnPen(wxBLACK_PEN);
+    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
+    SetDrawnBrush(brush);
+
+    DrawEllipticArc(wxRect(-w/2, -h/2, w, 2*h), 0.0, 180.0);
+    DrawLine(wxPoint(-w/2, h/2), wxPoint(w/2, h/2));
+
+    CalculateSize();
+
+    /// 90 degrees
+
+    w = csSTANDARD_SHAPE_WIDTH/2;
+    h = csSTANDARD_SHAPE_WIDTH;
+
+    DrawAtAngle(oglDRAWN_ANGLE_90);
+
+    SetDrawnPen(wxTRANSPARENT_PEN);
+    SetDrawnBrush(wxTRANSPARENT_BRUSH);
+
+    DrawRectangle(wxRect(-w/2, -h/2, w, h));
+
+    SetDrawnPen(wxBLACK_PEN);
+    SetDrawnBrush(brush);
+
+    DrawEllipticArc(wxRect(-w/2 - w, -h/2, 2*w, h), 270.0, 90.0);
+    DrawLine(wxPoint(-w/2, -h/2), wxPoint(-w/2, h/2));
+
+    CalculateSize();
+
+    /// 180 degrees
+
+    DrawAtAngle(oglDRAWN_ANGLE_180);
+
+    w = csSTANDARD_SHAPE_WIDTH;
+    h = csSTANDARD_SHAPE_WIDTH/2;
+
+    SetDrawnPen(wxTRANSPARENT_PEN);
+    SetDrawnBrush(wxTRANSPARENT_BRUSH);
+
+    DrawRectangle(wxRect(-w/2, -h/2, w, h));
+
+    SetDrawnPen(wxBLACK_PEN);
+    SetDrawnBrush(brush);
+
+    DrawEllipticArc(wxRect(-w/2, -h/2 - h, w, 2*h), 180.0, 0.0);
+    DrawLine(wxPoint(-w/2, -h/2), wxPoint(w/2, -h/2));
+
+    CalculateSize();
+
+    /// 270 degrees
+
+    DrawAtAngle(oglDRAWN_ANGLE_270);
+
+    w = csSTANDARD_SHAPE_WIDTH/2;
+    h = csSTANDARD_SHAPE_WIDTH;
+
+    SetDrawnPen(wxTRANSPARENT_PEN);
+    SetDrawnBrush(wxTRANSPARENT_BRUSH);
+
+    DrawRectangle(wxRect(-w/2, -h/2, w, h));
+
+    SetDrawnPen(wxBLACK_PEN);
+    SetDrawnBrush(brush);
+
+    DrawEllipticArc(wxRect(-w/2, -h/2, 2*w, h), 90.0, 270.0);
+    DrawLine(wxPoint(w/2, -h/2), wxPoint(w/2, h/2));
+
+    CalculateSize();
+
+    // Reset to zero
+    DrawAtAngle(oglDRAWN_ANGLE_0);
+    CalculateSize();
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csCircleShape, wxCircleShape)
+
+csCircleShape::csCircleShape()
+{
+    SetPen(wxBLACK_PEN);
+    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
+    SetBrush(brush);
+
+    SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape, wxCircleShape)
+
+csCircleShadowShape::csCircleShadowShape()
+{
+    SetPen(wxBLACK_PEN);
+    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
+    SetBrush(brush);
+
+    SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+    SetShadowMode(SHADOW_RIGHT);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csOctagonShape, wxPolygonShape)
+
+csOctagonShape::csOctagonShape()
+{
+    SetPen(wxBLACK_PEN);
+    SetBrush(wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID));
+
+    double w = csSTANDARD_SHAPE_WIDTH*0.5;
+    double h = csSTANDARD_SHAPE_WIDTH*0.5;
+
+    double prop = h/3.0;
+
+    wxList* points = new wxList;
+    points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, -h/2.0));
+    points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, -h/2.0));
+    points->Append((wxObject*) new wxRealPoint(w/2.0, -h/2.0 + prop));
+    points->Append((wxObject*) new wxRealPoint(w/2.0, h/2.0 - prop));
+    points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, h/2.0));
+    points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, h/2.0));
+    points->Append((wxObject*) new wxRealPoint(-w/2.0, h/2.0 - prop));
+    points->Append((wxObject*) new wxRealPoint(-w/2.0, -h/2.0 + prop));
+
+    Create(points);
+
+    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+// This is a transparent shape for drawing around other shapes.
+IMPLEMENT_DYNAMIC_CLASS(csGroupShape, wxRectangleShape)
+
+csGroupShape::csGroupShape()
+{
+    SetPen(wxThePenList->FindOrCreatePen("BLACK", 1, wxDOT));
+    SetBrush(wxTRANSPARENT_BRUSH);
+
+    SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH);
+    SetCentreResize(FALSE);
+}
+
+void csGroupShape::OnDraw(wxDC& dc)
+{
+    wxRectangleShape::OnDraw(dc);
+}
+
+// Must modify the hit-test so it doesn't obscure shapes that are inside.
+bool csGroupShape::HitTest(double x, double y, int* attachment, double* distance)
+{
+    *attachment = 0;
+    *distance = 0.0;
+
+    double width = 0.0, height = 0.0;
+    GetBoundingBoxMin(&width, &height);
+
+    double x1 = GetX() - (width/2.0);
+    double y1 = GetY() - (height/2.0);
+    double x2 = GetX() + (width/2.0);
+    double y2 = GetY() + (height/2.0);
+
+    double edgeTolerance = 4.0;
+
+    // Test each edge in turn
+
+    // Top/bottom edges
+    if (x >= x1 && x <= x2)
+    {
+        if ((y >= y1 - edgeTolerance) && (y <= y1 + edgeTolerance))
+            return TRUE;
+        if ((y <= y2 + edgeTolerance) && (y >= y2 - edgeTolerance))
+            return TRUE;
+    }
+    // Left/right edges
+    if (y >= y1 && y <= y2)
+    {
+        if ((x >= x1 - edgeTolerance) && (x <= x1 + edgeTolerance))
+            return TRUE;
+        if ((x <= x2 + edgeTolerance) && (x >= x2 - edgeTolerance))
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape, wxRectangleShape)
+
+csTextBoxShape::csTextBoxShape()
+{
+    SetPen(wxTRANSPARENT_PEN);
+    SetBrush(wxTRANSPARENT_BRUSH);
+
+    SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH/2.0);
+
+    SetAttachmentMode(ATTACHMENT_MODE_NONE);
+    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
+    SetCentreResize(FALSE);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(csLineShape, wxLineShape)
+
+csLineShape::csLineShape()
+{
+}
+
+bool csLineShape::OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt)
+{
+    csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
+
+    // Temporarily set the new shape properties so we can copy it
+    lpt->SetX(pt.x); lpt->SetY(pt.y);
+    lpt->m_point->x = pt.x; lpt->m_point->y = pt.y;
+
+    wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
+
+    // Now set them back again
+    lpt->SetX(lpt->m_originalPos.x); lpt->SetY(lpt->m_originalPos.y);
+    lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y;
+
+    view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move line point", (csDiagramDocument*) view->GetDocument(),
+                new csCommandState(ID_CS_MOVE_LINE_POINT, newShape, this)));
+
+    return TRUE;
+}
+
+wxLabelShape* csLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
+{
+    return new csLabelShape(parent, region, w, h);
+}
+
+#if 0
+bool csLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display)
+{
+    csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
+
+    wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
+
+    wxLineShape::OnLabelMovePre(dc, labelShape, x, y, old_x, old_y, display);
+
+    view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument*) view->GetDocument(),
+                new csCommandState(ID_CS_MOVE_LABEL, newShape, this)));
+  return TRUE;
+}
+#endif
+
+IMPLEMENT_DYNAMIC_CLASS(csLabelShape, wxLabelShape)
+
+csLabelShape::csLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):
+  wxLabelShape(parent, region, w, h)
+{
+}
+
+// TODO: not sure how intercept normal behaviour (OnMovePre) to make
+// label movement undo-able.
+void csLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
+{
+    wxLabelShape::OnEndDragLeft(x, y, keys, attachment);
+}
+
+
+// Menu for editing shapes
+void studioShapeEditProc(wxMenu& menu, wxCommandEvent& event)
+{
+    wxShape* shape = (wxShape*) menu.GetClientData();
+    csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
+
+    switch (event.GetId())
+    {
+        case ID_CS_EDIT_PROPERTIES:
+        {
+            csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
+            handler1->EditProperties();
+#if 0
+            csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
+            csLabelEditingDialog* dialog = new csLabelEditingDialog(shape->GetCanvas()->GetParent());
+            dialog->SetShapeLabel(handler1->m_label);
+            if (dialog->ShowModal() == wxID_CANCEL)
+            {
+                dialog->Destroy();
+                return;
+            }
+
+            wxString newLabel = dialog->GetShapeLabel();
+            dialog->Destroy();
+
+            wxShape* newShape = shape->CreateNewCopy();
+
+            csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
+            handler2->m_label = newLabel;
+
+            view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
+                new csCommandState(ID_CS_EDIT_LABEL, newShape, shape)));
+#endif
+            break;
+        }
+        case wxID_CUT:
+        {
+            wxList list;
+            list.Append(shape);
+            view->DoCut(list);
+            break;
+        }
+        case ID_CS_ROTATE_CLOCKWISE:
+        case ID_CS_ROTATE_ANTICLOCKWISE:
+        {
+            if (shape->IsKindOf(CLASSINFO(wxLineShape)))
+                break;
+
+            double theta = shape->GetRotation();
+            const double myPi = 3.1415926535897932384626433832795 ;
+            double ninetyDegrees = myPi/2.0;
+
+            wxString opStr;
+            if (event.GetId() == ID_CS_ROTATE_CLOCKWISE)
+            {
+                theta += ninetyDegrees;
+                opStr = "Rotate clockwise";
+            }
+            else
+            {
+                theta -= ninetyDegrees;
+                opStr = "Rotate anticlockwise";
+            }
+
+            if (theta >= 2.0*myPi || theta < 0.0)
+                theta = 0.0;
+            wxShape* newShape = shape->CreateNewCopy();
+            newShape->Rotate(0.0, 0.0, theta);
+            wxList newShapes;
+            wxList oldShapes;
+            newShapes.Append(newShape);
+            oldShapes.Append(shape);
+            view->DoCmd(newShapes, oldShapes, event.GetId(), opStr);
+            break;
+        }
+        default:
+            break;
+    }
+}
+
diff --git a/utils/ogl/samples/studio/shapes.h b/utils/ogl/samples/studio/shapes.h
new file mode 100644
index 0000000000..d817526793
--- /dev/null
+++ b/utils/ogl/samples/studio/shapes.h
@@ -0,0 +1,258 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        shapes.h
+// Purpose:     Shape classes
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_SHAPES_H_
+#define _STUDIO_SHAPES_H_
+
+#ifdef __GNUG__
+// #pragma interface
+#endif
+
+#include <wx/docview.h>
+#include <wx/string.h>
+#include <wx/wxexpr.h>
+
+#include "ogl.h"
+#include "basicp.h"
+#include "linesp.h"
+#include "drawn.h"
+
+class csDiagramDocument;
+
+/*
+ * Override a few members for this application
+ */
+ 
+class csDiagram: public wxDiagram
+{
+DECLARE_CLASS(csDiagram)
+public:
+    csDiagram(csDiagramDocument* doc) { m_doc = doc; }
+    ~csDiagram();
+    bool OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr);
+    bool OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr);
+
+    inline csDiagramDocument* GetDocument() const { return m_doc; }
+    virtual void Redraw(wxDC& dc);
+
+protected:
+    csDiagramDocument* m_doc;
+};
+
+class wxDiagramClipboard: public wxDiagram
+{
+DECLARE_DYNAMIC_CLASS(wxDiagramClipboard)
+public:
+    wxDiagramClipboard() {}
+    ~wxDiagramClipboard() {}
+
+    // Copy selection to clipboard
+    bool Copy(wxDiagram* diagram);
+
+    // Copy contents to the diagram, with new ids.
+    // If dc is non-NULL, the pasted shapes will be selected.
+    // The offsets are used to place the shapes at a different position
+    // from the original (for example, for duplicating shapes).
+    bool Paste(wxDiagram* diagram, wxDC* dc = NULL,
+        int offsetX = 0, int offsetY = 0);
+
+#ifdef __WXMSW__
+    // Draw contents to a Windows metafile device context and bitmap, and then copy
+    // to the Windows clipboard.
+    bool CopyToClipboard(double scale);
+#endif
+
+// Overridables
+    // Start/end copying
+    virtual bool OnStartCopy(wxDiagram* diagramTo) { return TRUE; };
+    virtual bool OnEndCopy(wxDiagram* diagramTo) { return TRUE; };
+
+    // Override this to e.g. have the shape added through a Do/Undo command system.
+    // By default, we'll just add it directly to the destination diagram, and
+    // select the shape (if dc is non-NULL).
+    virtual bool OnAddShape(wxDiagram* diagramTo, wxShape* newShape, wxDC* dc);
+
+protected:
+    bool DoCopy(wxDiagram* diagramFrom, wxDiagram* diagramTo, bool newIds,
+                    wxDC* dc, int offsetX = 0, int offsetY = 0);
+
+};
+
+class csDiagramCommand;
+
+class csDiagramClipboard: public wxDiagramClipboard
+{
+DECLARE_DYNAMIC_CLASS(csDiagramClipboard)
+public:
+    csDiagramClipboard() { m_currentCmd = NULL; }
+    ~csDiagramClipboard() {}
+
+    // Start/end copying
+    bool OnStartCopy(wxDiagram* diagramTo);
+    bool OnEndCopy(wxDiagram* diagramTo);
+
+    bool OnAddShape(wxDiagram* diagramTo, wxShape* newShape, wxDC* dc);
+
+protected:
+    csDiagramCommand*   m_currentCmd;
+};
+
+
+/*
+ * The Studio shapes
+ * N.B. TODO: these should really all have another constructor
+ * for the ready-initialised shape, with the default one not having any
+ * data. Otherwise when copying a shape, you have to delete the old data
+ * first -> slightly less efficient. The initialised shapes are only required
+ * for the first creation of the shape in the palette, everything else is copied.
+ */
+
+class csThinRectangleShape: public wxDrawnShape
+{
+DECLARE_DYNAMIC_CLASS(csThinRectangleShape)
+public:
+    csThinRectangleShape();
+};
+
+class csWideRectangleShape: public wxDrawnShape
+{
+DECLARE_DYNAMIC_CLASS(csWideRectangleShape)
+public:
+    csWideRectangleShape();
+};
+
+class csTriangleShape: public wxDrawnShape
+{
+DECLARE_DYNAMIC_CLASS(csTriangleShape)
+public:
+    csTriangleShape();
+};
+
+class csSemiCircleShape: public wxDrawnShape
+{
+DECLARE_DYNAMIC_CLASS(csSemiCircleShape)
+public:
+    csSemiCircleShape();
+};
+
+class csCircleShape: public wxCircleShape
+{
+DECLARE_DYNAMIC_CLASS(csCircleShape)
+public:
+    csCircleShape();
+};
+
+class csCircleShadowShape: public wxCircleShape
+{
+DECLARE_DYNAMIC_CLASS(csCircleShadowShape)
+public:
+    csCircleShadowShape();
+};
+
+class csOctagonShape: public wxPolygonShape
+{
+DECLARE_DYNAMIC_CLASS(csOctagonShape)
+public:
+    csOctagonShape();
+
+    // The attachments are as if it's a rectangle
+    bool GetAttachmentPosition(int attachment, double *x, double *y,
+                                     int nth = 0, int no_arcs = 1, wxLineShape *line = NULL)
+    { return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); }
+    int GetNumberOfAttachments() const
+    { return wxShape::GetNumberOfAttachments(); }
+    bool AttachmentIsValid(int attachment) const
+    { return wxShape::AttachmentIsValid(attachment); }
+};
+
+// This is a transparent shape for drawing around other shapes.
+class csGroupShape: public wxRectangleShape
+{
+DECLARE_DYNAMIC_CLASS(csGroupShape)
+public:
+    csGroupShape();
+
+    void OnDraw(wxDC& dc);
+    // Must modify the hit-test so it doesn't obscure shapes that are inside.
+    bool HitTest(double x, double y, int* attachment, double* distance);
+};
+
+class csTextBoxShape: public wxRectangleShape
+{
+DECLARE_DYNAMIC_CLASS(csTextBoxShape)
+public:
+    csTextBoxShape();
+};
+
+class csLineShape: public wxLineShape
+{
+DECLARE_DYNAMIC_CLASS(csLineShape)
+public:
+    csLineShape();
+
+    virtual bool OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt);
+    wxLabelShape* OnCreateLabelShape(wxLineShape *parent = NULL, wxShapeRegion *region = NULL, double w = 0.0, double h = 0.0);
+};
+
+/*
+ * Temporary arc label object
+ */
+ 
+class csLabelShape: public wxLabelShape
+{
+  DECLARE_DYNAMIC_CLASS(csLabelShape)
+
+ public:
+  csLabelShape(wxLineShape *parent = NULL, wxShapeRegion *region = NULL, double w = 0.0, double h = 0.0);
+
+  void OnEndDragLeft(double x, double y, int keys=0, int attachment = 0);
+};
+
+/*
+ * All shape event behaviour is routed through this handler, so we don't
+ * have to derive from each shape class. We plug this in to each shape.
+ */
+
+class csEvtHandler: public wxShapeEvtHandler
+{
+ DECLARE_DYNAMIC_CLASS(csEvtHandler)
+ public:
+  csEvtHandler(wxShapeEvtHandler *prev = NULL, wxShape *shape = NULL, const wxString& lab = "");
+  ~csEvtHandler();
+
+  void OnLeftClick(double x, double y, int keys = 0, int attachment = 0);
+  void OnRightClick(double x, double y, int keys = 0, int attachment = 0);
+  void OnBeginDragRight(double x, double y, int keys = 0, int attachment = 0);
+  void OnDragRight(bool draw, double x, double y, int keys = 0, int attachment = 0);
+  void OnEndDragRight(double x, double y, int keys = 0, int attachment = 0);
+  void OnEndSize(double x, double y);
+  void OnDragLeft(bool draw, double x, double y, int keys = 0, int attachment = 0);
+  void OnBeginDragLeft(double x, double y, int keys = 0, int attachment = 0);
+  void OnEndDragLeft(double x, double y, int keys = 0, int attachment = 0);
+  void OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys = 0, int attachment = 0);
+  void OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering);
+
+  void OnLeftDoubleClick(double x, double y, int keys = 0, int attachment = 0);
+
+  // Copy any event handler data
+  virtual void CopyData(wxShapeEvtHandler& copy);
+
+  // Popup up a property dialog
+  virtual bool EditProperties();
+
+public:
+  wxString m_label;
+};
+
+extern void studioShapeEditProc(wxMenu& menu, wxCommandEvent& event);
+
+#endif
+  // _STUDIO_SHAPES_H_
diff --git a/utils/ogl/samples/studio/studio.cpp b/utils/ogl/samples/studio/studio.cpp
new file mode 100644
index 0000000000..76a6135e23
--- /dev/null
+++ b/utils/ogl/samples/studio/studio.cpp
@@ -0,0 +1,510 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        Studio.cpp
+// Purpose:     Studio application class
+// Author:      Julian Smart
+// Modified by:
+// Created:     27/7/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#include "wx/mdi.h"
+#endif
+
+#include "wx/resource.h"
+#include "wx/config.h"
+#include "wx/laywin.h"
+
+#ifdef __WXGTK__
+#include "folder.xpm"
+#endif
+
+#include "studio.h"
+#include "view.h"
+#include "doc.h"
+#include "mainfrm.h"
+#include "cspalette.h"
+#include "project.h"
+#include "symbols.h"
+
+#if defined(__WXGTK__) || defined(__WXMOTIF__)
+#include "bitmaps/new.xpm"
+#include "bitmaps/open.xpm"
+#include "bitmaps/save.xpm"
+#include "bitmaps/copy.xpm"
+#include "bitmaps/cut.xpm"
+#include "bitmaps/paste.xpm"
+#include "bitmaps/print.xpm"
+#include "bitmaps/help.xpm"
+#include "bitmaps/undo.xpm"
+#include "bitmaps/redo.xpm"
+
+#include "bitmaps/alignl.xpm"
+#include "bitmaps/alignr.xpm"
+#include "bitmaps/alignt.xpm"
+#include "bitmaps/alignb.xpm"
+#include "bitmaps/horiz.xpm"
+#include "bitmaps/vert.xpm"
+#include "bitmaps/copysize.xpm"
+#include "bitmaps/linearrow.xpm"
+#include "bitmaps/newpoint.xpm"
+#include "bitmaps/cutpoint.xpm"
+#include "bitmaps/straight.xpm"
+
+#include "studio.xpm"
+#endif
+
+IMPLEMENT_APP(csApp)
+
+csApp::csApp()
+{
+    m_docManager = NULL;
+    m_diagramPalette = NULL;
+    m_diagramToolBar = NULL;
+    m_projectTreeCtrl = NULL;
+    m_diagramPaletteSashWindow = NULL;
+    m_projectSashWindow = NULL;
+    m_symbolDatabase = NULL;
+    m_pointSizeComboBox = NULL;
+    m_zoomComboBox = NULL;
+    m_shapeEditMenu = NULL;
+
+    // Configuration
+    m_mainFramePos.x = 20;
+    m_mainFramePos.y = 20;
+    m_mainFrameSize.x = 500;
+    m_mainFrameSize.y = 400;
+    m_gridStyle = csGRID_STYLE_INVISIBLE;
+    m_gridSpacing = 5;
+}
+
+csApp::~csApp()
+{
+}
+
+// Initialise this in OnInit, not statically
+bool csApp::OnInit(void)
+{
+  if (!wxResourceParseFile("studio_resources.wxr"))
+  {
+    wxMessageBox("Could not find or parse resource file: studio_resources.wxr", "Studio");
+    return FALSE;
+  }
+
+  m_helpController.Initialize("studio.hlp");
+
+  ReadOptions();
+
+  wxOGLInitialize();
+
+  InitSymbols();
+
+  //// Create a document manager
+  m_docManager = new wxDocManager;
+
+  //// Create a template relating drawing documents to their views
+  (void) new wxDocTemplate(m_docManager, "Diagram", "*.dia", "", "dia", "Diagram Doc", "Diagram View",
+          CLASSINFO(csDiagramDocument), CLASSINFO(csDiagramView));
+
+  // Create the main frame window
+
+  csFrame* frame = new csFrame(m_docManager, NULL, -1, "OGL Studio", m_mainFramePos, m_mainFrameSize,
+   wxDEFAULT_FRAME_STYLE | wxHSCROLL | wxVSCROLL);
+
+  // Give it an icon
+  frame->SetIcon(wxICON(studio));
+
+  // Make a menubar
+  wxMenu *fileMenu = new wxMenu;
+
+  fileMenu->Append(wxID_NEW, "&New...\tCtrl+N");
+  fileMenu->Append(wxID_OPEN, "&Open...\tCtrl+O");
+
+  fileMenu->AppendSeparator();
+
+  fileMenu->Append(wxID_PRINT, "&Print...\tCtrl+P");
+  fileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
+  fileMenu->Append(wxID_PREVIEW, "Print Pre&view");
+  fileMenu->AppendSeparator();
+  fileMenu->Append(wxID_EXIT, "E&xit");
+
+  // A history of files visited. Use this menu.
+  m_docManager->FileHistoryUseMenu(fileMenu);
+
+  wxMenu *viewMenu = new wxMenu;
+  viewMenu->Append(ID_CS_SETTINGS, "&Settings...");
+
+  wxMenu *helpMenu = new wxMenu;
+  helpMenu->Append(wxID_HELP, "&Help Contents\tF1");
+  helpMenu->Append(ID_CS_ABOUT, "&About");
+
+  wxMenuBar *menuBar = new wxMenuBar;
+
+  menuBar->Append(fileMenu, "&File");
+  menuBar->Append(viewMenu, "&View");
+  menuBar->Append(helpMenu, "&Help");
+
+  // Associate the menu bar with the frame
+  frame->SetMenuBar(menuBar);
+
+  // Load the file history
+  wxConfig config("OGL Studio", "wxWindows");
+  m_docManager->FileHistoryLoad(config);
+
+  frame->CreateStatusBar();
+
+  // The ordering of these is important for layout purposes
+  CreateDiagramToolBar(frame);
+  CreatePalette(frame);
+  CreateProjectWindow(frame);
+
+  FillProjectTreeCtrl();
+
+  // Create the shape editing menu
+  m_shapeEditMenu = new wxMenu("", (wxFunction)studioShapeEditProc);
+  m_shapeEditMenu->Append(ID_CS_EDIT_PROPERTIES, "Edit properties");
+  m_shapeEditMenu->AppendSeparator();
+  m_shapeEditMenu->Append(ID_CS_ROTATE_CLOCKWISE, "Rotate clockwise");
+  m_shapeEditMenu->Append(ID_CS_ROTATE_ANTICLOCKWISE, "Rotate anticlockwise");
+  m_shapeEditMenu->AppendSeparator();
+  m_shapeEditMenu->Append(ID_CS_CUT, "Cut");
+
+  frame->Show(TRUE);
+
+  SetTopWindow(frame);
+
+  return TRUE;
+}
+
+int csApp::OnExit(void)
+{
+    WriteOptions();
+
+    delete m_symbolDatabase;
+    m_symbolDatabase = NULL;
+
+    delete m_docManager;
+    m_docManager = NULL;
+
+    delete m_shapeEditMenu;
+    m_shapeEditMenu = NULL;
+
+    wxOGLCleanUp();
+
+    return 0;
+}
+
+/*
+ * Centralised code for creating a document frame.
+ * Called from view.cpp, when a view is created.
+ */
+ 
+wxMDIChildFrame *csApp::CreateChildFrame(wxDocument *doc, wxView *view, wxMenu** editMenuRet)
+{
+  //// Make a child frame
+  csMDIChildFrame *subframe = new csMDIChildFrame(doc, view, ((wxDocMDIParentFrame*)GetTopWindow()), -1, "Child Frame",
+        wxPoint(10, 10), wxSize(300, 300), wxDEFAULT_FRAME_STYLE);
+
+#ifdef __WXMSW__
+  subframe->SetIcon(wxString("chart"));
+#endif
+#ifdef __X__
+  subframe->SetIcon(wxIcon("doc.xbm"));
+#endif
+
+  //// Make a menubar
+  wxMenu *fileMenu = new wxMenu;
+
+  fileMenu->Append(wxID_NEW, "&New...\tCtrl+N");
+  fileMenu->Append(wxID_OPEN, "&Open...\tCtrl+O");
+  fileMenu->Append(wxID_CLOSE, "&Close\tCtrl+W");
+  fileMenu->Append(wxID_SAVE, "&Save\tCtrl+S");
+  fileMenu->Append(wxID_SAVEAS, "Save &As...\tF12");
+
+  fileMenu->AppendSeparator();
+  fileMenu->Append(wxID_PRINT, "&Print...\tCtrl+P");
+  fileMenu->Append(wxID_PRINT_SETUP, "Print &Setup...");
+  fileMenu->Append(wxID_PREVIEW, "Print Pre&view");
+
+  fileMenu->AppendSeparator();
+  fileMenu->Append(wxID_EXIT, "E&xit");
+
+  wxMenu *editMenu = NULL;
+
+  editMenu = new wxMenu;
+  editMenu->Append(wxID_UNDO, "&Undo\tCtrl+Z");
+  editMenu->Append(wxID_REDO, "&Redo\tCtrl+Y");
+  editMenu->AppendSeparator();
+  editMenu->Append(wxID_CUT, "Cu&t\tCtrl+X");
+  editMenu->Append(wxID_COPY, "&Copy\tCtrl+C");
+  editMenu->Append(wxID_PASTE, "&Paste\tCtrl+V");
+  editMenu->Append(wxID_DUPLICATE, "&Duplicate\tCtrl+D");
+  editMenu->AppendSeparator();
+  editMenu->Append(wxID_CLEAR, "Cle&ar\tDelete");
+  editMenu->Append(ID_CS_SELECT_ALL, "Select A&ll\tCtrl+A");
+  editMenu->AppendSeparator();
+  editMenu->Append(ID_CS_EDIT_PROPERTIES, "Edit P&roperties...");
+
+  *editMenuRet = editMenu;
+
+  m_docManager->FileHistoryUseMenu(fileMenu);
+  m_docManager->FileHistoryAddFilesToMenu(fileMenu);
+
+  doc->GetCommandProcessor()->SetEditMenu(editMenu);
+
+  wxMenu *viewMenu = new wxMenu;
+  viewMenu->Append(ID_CS_SETTINGS, "&Settings...");
+
+  wxMenu *helpMenu = new wxMenu;
+  helpMenu->Append(wxID_HELP, "&Help Contents\tF1");
+  helpMenu->Append(ID_CS_ABOUT, "&About");
+
+  wxMenuBar *menuBar = new wxMenuBar;
+
+  menuBar->Append(fileMenu, "&File");
+  menuBar->Append(editMenu, "&Edit");
+  menuBar->Append(viewMenu, "&View");
+  menuBar->Append(helpMenu, "&Help");
+
+  //// Associate the menu bar with the frame
+  subframe->SetMenuBar(menuBar);
+
+  return subframe;
+}
+
+// Creates a canvas. Called by OnInit as a child of the main window
+csCanvas *csApp::CreateCanvas(wxView *view, wxFrame *parent)
+{
+  int width, height;
+  parent->GetClientSize(&width, &height);
+
+  // Non-retained canvas
+  csCanvas *canvas = new csCanvas((csDiagramView*) view, parent, 1000, wxPoint(0, 0), wxSize(width, height), 0);
+
+  wxColour bgColour("WHITE");
+  canvas->SetBackgroundColour(bgColour);
+
+  wxCursor cursor(wxCURSOR_HAND);
+  canvas->SetCursor(cursor);
+
+  // Give it scrollbars
+  canvas->SetScrollbars(20, 20, 100, 100);
+
+  return canvas;
+}
+
+void csApp::InitToolBar(wxToolBar* toolBar)
+{
+    wxBitmap* bitmaps[10];
+
+#ifdef __WXMSW__
+    bitmaps[0] = new wxBitmap("new", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[1] = new wxBitmap("open", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[2] = new wxBitmap("save", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[3] = new wxBitmap("copy", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[4] = new wxBitmap("cut", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[5] = new wxBitmap("paste", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[6] = new wxBitmap("print", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[7] = new wxBitmap("help", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[8] = new wxBitmap("undo", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[9] = new wxBitmap("redo", wxBITMAP_TYPE_RESOURCE);
+#elif defined(__WXGTK__) || defined(__WXMOTIF__)
+    bitmaps[0] = new wxBitmap( new_xpm );
+    bitmaps[1] = new wxBitmap( open_xpm );
+    bitmaps[2] = new wxBitmap( save_xpm );
+    bitmaps[3] = new wxBitmap( copy_xpm );
+    bitmaps[4] = new wxBitmap( cut_xpm );
+    bitmaps[5] = new wxBitmap( paste_xpm );
+    bitmaps[6] = new wxBitmap( print_xpm );
+    bitmaps[7] = new wxBitmap( help_xpm );
+    bitmaps[8] = new wxBitmap( undo_xpm );
+    bitmaps[9] = new wxBitmap( redo_xpm );
+#else
+#error "Not implemented for this platform."
+#endif
+
+  toolBar->AddTool(wxID_NEW, *bitmaps[0], wxNullBitmap, FALSE, -1, -1, NULL, "New file");
+  toolBar->AddTool(wxID_OPEN, *bitmaps[1], wxNullBitmap, FALSE, -1, -1, NULL, "Open file");
+  toolBar->AddTool(wxID_SAVE, *bitmaps[2], wxNullBitmap, FALSE, -1, -1, NULL, "Save file");
+  toolBar->AddSeparator();
+  toolBar->AddTool(wxID_PRINT, *bitmaps[6], wxNullBitmap, FALSE, -1, -1, NULL, "Print");
+  toolBar->AddSeparator();
+  toolBar->AddTool(wxID_COPY, *bitmaps[3], wxNullBitmap, FALSE, -1, -1, NULL, "Copy");
+  toolBar->AddTool(wxID_CUT, *bitmaps[4], wxNullBitmap, FALSE, -1, -1, NULL, "Cut");
+  toolBar->AddTool(wxID_PASTE, *bitmaps[5], wxNullBitmap, FALSE, -1, -1, NULL, "Paste");
+  toolBar->AddSeparator();
+  toolBar->AddTool(wxID_UNDO, *bitmaps[8], wxNullBitmap, FALSE, -1, -1, NULL, "Undo");
+  toolBar->AddTool(wxID_REDO, *bitmaps[9], wxNullBitmap, FALSE, -1, -1, NULL, "Redo");
+  toolBar->AddSeparator();
+  toolBar->AddTool(wxID_HELP, *bitmaps[7], wxNullBitmap, FALSE, -1, -1, NULL, "Help");
+
+  toolBar->Realize();
+
+  toolBar->EnableTool(wxID_COPY, FALSE);
+  toolBar->EnableTool(wxID_PASTE, FALSE);
+  toolBar->EnableTool(wxID_PRINT, FALSE);
+  toolBar->EnableTool(wxID_UNDO, FALSE);
+  toolBar->EnableTool(wxID_REDO, FALSE);
+
+  int i;
+  for (i = 0; i < 10; i++)
+    delete bitmaps[i];
+}
+
+// Create and initialise the diagram toolbar
+void csApp::CreateDiagramToolBar(wxFrame* parent)
+{
+    // First create a layout window
+    wxSashLayoutWindow* win = new wxSashLayoutWindow(parent, ID_LAYOUT_WINDOW_DIAGRAM_TOOLBAR, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D|wxCLIP_CHILDREN);
+    win->SetDefaultSize(wxSize(10000, 30));
+    win->SetOrientation(wxLAYOUT_HORIZONTAL);
+    win->SetAlignment(wxLAYOUT_TOP);
+    win->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
+
+    m_diagramToolBarSashWindow = win;
+    m_diagramToolBarSashWindow->Show(FALSE);
+
+    // Create the actual toolbar
+    m_diagramToolBar = new wxToolBar(win, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL|wxNO_BORDER|wxTB_FLAT);
+
+    wxBitmap* bitmaps[11];
+
+#ifdef __WXMSW__
+    bitmaps[0] = new wxBitmap("alignl", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[1] = new wxBitmap("alignr", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[2] = new wxBitmap("alignt", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[3] = new wxBitmap("alignb", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[4] = new wxBitmap("horiz", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[5] = new wxBitmap("vert", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[6] = new wxBitmap("copysize", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[7] = new wxBitmap("linearrow", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[8] = new wxBitmap("newpoint", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[9] = new wxBitmap("cutpoint", wxBITMAP_TYPE_RESOURCE);
+    bitmaps[10] = new wxBitmap("straighten", wxBITMAP_TYPE_RESOURCE);
+#elif defined(__WXGTK__) || defined(__WXMOTIF__)
+    bitmaps[0] = new wxBitmap( alignl_xpm );
+    bitmaps[1] = new wxBitmap( alignr_xpm );
+    bitmaps[2] = new wxBitmap( alignt_xpm );
+    bitmaps[3] = new wxBitmap( alignb_xpm );
+    bitmaps[4] = new wxBitmap( horiz_xpm );
+    bitmaps[5] = new wxBitmap( vert_xpm );
+    bitmaps[6] = new wxBitmap( copysize_xpm );
+    bitmaps[7] = new wxBitmap( linearrow_xpm );
+    bitmaps[8] = new wxBitmap( newpoint_xpm );
+    bitmaps[9] = new wxBitmap( cutpoint_xpm );
+    bitmaps[10] = new wxBitmap( straight_xpm );
+#else
+#error "Not implemented for this platform."
+#endif
+
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_ALIGNL, *bitmaps[0], wxNullBitmap, FALSE, -1, -1, NULL, "Align left");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_ALIGNR, *bitmaps[1], wxNullBitmap, FALSE, -1, -1, NULL, "Align right");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_ALIGNT, *bitmaps[2], wxNullBitmap, FALSE, -1, -1, NULL, "Align top");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_ALIGNB, *bitmaps[3], wxNullBitmap, FALSE, -1, -1, NULL, "Align bottom");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_ALIGN_HORIZ, *bitmaps[4], wxNullBitmap, FALSE, -1, -1, NULL, "Align horizontally");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_ALIGN_VERT, *bitmaps[5], wxNullBitmap, FALSE, -1, -1, NULL, "Align vertically");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_COPY_SIZE, *bitmaps[6], wxNullBitmap, FALSE, -1, -1, NULL, "Copy size");
+    m_diagramToolBar->AddSeparator();
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_LINE_ARROW, *bitmaps[7], wxNullBitmap, TRUE, -1, -1, NULL, "Toggle arrow");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_NEW_POINT, *bitmaps[8], wxNullBitmap, FALSE, -1, -1, NULL, "New line point");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_CUT_POINT, *bitmaps[9], wxNullBitmap, FALSE, -1, -1, NULL, "Cut line point");
+    m_diagramToolBar->AddTool(DIAGRAM_TOOLBAR_STRAIGHTEN, *bitmaps[10], wxNullBitmap, FALSE, -1, -1, NULL, "Straighten lines");
+
+    m_diagramToolBar->Realize();
+
+    int i;
+    for (i = 0; i < 11; i++)
+        delete bitmaps[i];
+
+    // Create a combobox for point size
+    int maxPointSize = 40;
+    wxString *pointSizes = new wxString[maxPointSize];
+    for (i = 1; i <= maxPointSize; i++)
+    {
+        pointSizes[i-1].Printf("%d", i);
+    }
+
+    int controlX = 260;
+    int pointSizeW = 40;
+    int pointSizeH = 18;
+    int zoomW = 60;
+    int zoomH = 18;
+#ifdef __WXMOTIF__
+    controlX += 70;
+    pointSizeW = 60;
+    pointSizeH = 22;
+    zoomW = 60;
+    zoomH = 22;
+#endif
+
+    m_pointSizeComboBox = new wxComboBox(m_diagramToolBar, ID_WINDOW_POINT_SIZE_COMBOBOX,
+        "", wxPoint(controlX, 1), wxSize(pointSizeW, pointSizeH), maxPointSize, pointSizes);
+    delete[] pointSizes;
+
+    m_pointSizeComboBox->SetSelection(10 - 1);
+
+    // Create a combobox for zooming
+    int maxZoom = 200;
+    int minZoom = 5;
+    int increment = 5;
+    int noStrings = (maxZoom - minZoom)/5 ;
+    wxString *zoomStrings = new wxString[noStrings];
+    for (i = 0; i < noStrings; i ++)
+    {
+        zoomStrings[noStrings - i - 1].Printf("%d%%", (i*increment + minZoom));
+    }
+
+    controlX += pointSizeW + 10;
+
+    m_zoomComboBox = new wxComboBox(m_diagramToolBar, ID_WINDOW_ZOOM_COMBOBOX,
+        "", wxPoint(controlX, 1), wxSize(zoomW, zoomH), noStrings, zoomStrings);
+    delete[] zoomStrings;
+
+    // i = (zoom - minZoom)/increment
+    // index = noStrings - i - 1
+    // 100%
+    i = (100 - minZoom)/increment;
+    m_zoomComboBox->SetSelection(noStrings - i - 1);
+}
+
+// Read/write configuration information
+bool csApp::ReadOptions()
+{
+    wxConfig config("OGL Studio", "wxWindows");
+
+    config.Read("mainX", & m_mainFramePos.x);
+    config.Read("mainY", & m_mainFramePos.y);
+    config.Read("mainWidth", & m_mainFrameSize.x);
+    config.Read("mainHeight", & m_mainFrameSize.y);
+    config.Read("gridStyle", & m_gridStyle);
+    config.Read("gridSpacing", & m_gridSpacing);
+
+    return TRUE;
+}
+
+bool csApp::WriteOptions()
+{
+    wxConfig config("OGL Studio", "wxWindows");
+
+    config.Write("mainX", m_mainFramePos.x);
+    config.Write("mainY", m_mainFramePos.y);
+    config.Write("mainWidth", m_mainFrameSize.x);
+    config.Write("mainHeight", m_mainFrameSize.y);
+    config.Write("gridStyle", m_gridStyle);
+    config.Write("gridSpacing", m_gridSpacing);
+
+    m_docManager->FileHistorySave(config);
+
+    return TRUE;
+}
+
diff --git a/utils/ogl/samples/studio/studio.h b/utils/ogl/samples/studio/studio.h
new file mode 100644
index 0000000000..94ad81f5b4
--- /dev/null
+++ b/utils/ogl/samples/studio/studio.h
@@ -0,0 +1,171 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        Studio.h
+// Purpose:     Studio application class
+// Author:      Julian Smart
+// Modified by:
+// Created:     27/7/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_STUDIO_H_
+#define _STUDIO_STUDIO_H_
+
+#include <wx/docmdi.h>
+#include <wx/help.h>
+
+#include <ogl.h>
+#include <canvas.h>
+#include "shapes.h"
+
+class csEditorToolPalette;
+class csProjectTreeCtrl;
+class csCanvas;
+class csSymbolDatabase;
+class wxSashLayoutWindow;
+class csFrame;
+
+// Grid style
+#define csGRID_STYLE_NONE       0
+#define csGRID_STYLE_INVISIBLE  1
+#define csGRID_STYLE_DOTTED     2
+
+// Define a new application
+class csApp: public wxApp
+{
+    friend csFrame;
+public:
+    csApp();
+    ~csApp();
+
+// Operations
+    bool OnInit(void);
+    int OnExit(void);
+
+    // Read/write configuration information
+    bool ReadOptions();
+    bool WriteOptions();
+
+    // Create the diagram tool palette
+    bool CreatePalette(wxFrame *parent);
+
+    // Create the project window
+    bool CreateProjectWindow(wxFrame *parent);
+
+    // Initialise the general toolbar
+    void InitToolBar(wxToolBar* toolBar);
+
+    // Create and initialise the diagram toolbar
+    void CreateDiagramToolBar(wxFrame* parent);
+
+    wxMDIChildFrame *CreateChildFrame(wxDocument *doc, wxView *view, wxMenu** editMenu);
+    csCanvas *CreateCanvas(wxView *view, wxFrame *parent);
+
+    // Fill out the project tree control
+    void FillProjectTreeCtrl();
+
+    // Add symbols to database
+    void InitSymbols();
+
+// Accessors
+    csEditorToolPalette* GetDiagramPalette() const { return m_diagramPalette; }
+    wxToolBar* GetDiagramToolBar() const { return m_diagramToolBar; }
+    csProjectTreeCtrl* GetProjectTreeCtrl() const { return m_projectTreeCtrl; }
+    wxSashLayoutWindow* GetDiagramPaletteSashWindow() const { return m_diagramPaletteSashWindow; }
+    wxSashLayoutWindow* GetProjectSashWindow() const { return m_projectSashWindow; }
+    wxSashLayoutWindow* GetDiagramToolBarSashWindow() const { return m_diagramToolBarSashWindow; }
+    csSymbolDatabase* GetSymbolDatabase() const { return m_symbolDatabase; }
+    wxComboBox* GetPointSizeComboBox() const { return m_pointSizeComboBox; }
+    wxComboBox* GetZoomComboBox() const { return m_zoomComboBox; }
+    wxMenu* GetShapeEditMenu() const { return m_shapeEditMenu; }
+    wxDiagramClipboard& GetDiagramClipboard() const { return (wxDiagramClipboard&) m_diagramClipboard; }
+    wxDocManager* GetDocManager() const { return m_docManager; }
+    wxHelpController& GetHelpController() const { return (wxHelpController&) m_helpController; }
+
+    int GetGridStyle() const { return m_gridStyle; }
+    void SetGridStyle(int style) { m_gridStyle = style; }
+
+    int GetGridSpacing() const { return m_gridSpacing; }
+    void SetGridSpacing(int spacing) { m_gridSpacing = spacing; }
+
+protected:
+    wxDocManager*           m_docManager;
+    wxSashLayoutWindow*     m_diagramPaletteSashWindow;
+    wxSashLayoutWindow*     m_diagramToolBarSashWindow;
+    wxSashLayoutWindow*     m_projectSashWindow;
+    csEditorToolPalette*    m_diagramPalette;
+    csProjectTreeCtrl*      m_projectTreeCtrl;
+    csSymbolDatabase*       m_symbolDatabase;
+    wxToolBar*              m_diagramToolBar;
+    wxComboBox*             m_pointSizeComboBox;
+    wxComboBox*             m_zoomComboBox;
+    wxMenu*                 m_shapeEditMenu;
+
+    // Configuration
+    wxPoint                 m_mainFramePos;
+    wxSize                  m_mainFrameSize;
+    int                     m_gridStyle;
+    int                     m_gridSpacing;
+
+    // Diagram clipboard
+    csDiagramClipboard      m_diagramClipboard;
+
+    // Help instance
+    wxHelpController        m_helpController;
+};
+
+DECLARE_APP(csApp)
+
+#define ID_CS_CUT                         wxID_CUT
+#define ID_CS_ADD_SHAPE                   2
+#define ID_CS_ADD_LINE                    3
+// #define ID_CS_EDIT_LABEL                  4
+#define ID_CS_EDIT_PROPERTIES             4
+#define ID_CS_CHANGE_BACKGROUND_COLOUR    5
+#define ID_CS_MOVE                        6
+#define ID_CS_SIZE                        7
+#define ID_CS_FONT_CHANGE                 8
+#define ID_CS_ARROW_CHANGE                9
+#define ID_CS_ROTATE_CLOCKWISE            11
+#define ID_CS_ROTATE_ANTICLOCKWISE        12
+#define ID_CS_CHANGE_LINE_ORDERING        13  // Change the list of lines for a wxShape
+#define ID_CS_CHANGE_LINE_ATTACHMENT      14  // Change the attachment point for one end of a line
+#define ID_CS_ALIGN                       15
+#define ID_CS_NEW_POINT                   16
+#define ID_CS_CUT_POINT                   17
+#define ID_CS_STRAIGHTEN                  18
+#define ID_CS_MOVE_LINE_POINT             19
+#define ID_CS_MOVE_LABEL                  20
+#define ID_CS_ADD_SHAPE_SELECT            21
+#define ID_CS_ADD_LINE_SELECT             22
+
+#define ID_CS_ABOUT                       100
+#define ID_CS_SELECT_ALL                  102
+#define ID_CS_SETTINGS                    103
+
+#define ID_LAYOUT_WINDOW_PALETTE          200
+#define ID_LAYOUT_WINDOW_DIAGRAM_TOOLBAR  201
+#define ID_LAYOUT_WINDOW_PROJECT          202
+
+#define ID_DIAGRAM_PALETTE                250
+
+#define ID_WINDOW_PROJECT_TREE            300
+#define ID_WINDOW_POINT_SIZE_COMBOBOX     301
+#define ID_WINDOW_ZOOM_COMBOBOX           302
+
+#define DIAGRAM_TOOLBAR_ALIGNL            500
+#define DIAGRAM_TOOLBAR_ALIGNR            501
+#define DIAGRAM_TOOLBAR_ALIGNB            502
+#define DIAGRAM_TOOLBAR_ALIGNT            503
+#define DIAGRAM_TOOLBAR_ALIGN_HORIZ       504
+#define DIAGRAM_TOOLBAR_ALIGN_VERT        505
+#define DIAGRAM_TOOLBAR_COPY_SIZE         506
+#define DIAGRAM_TOOLBAR_LINE_ARROW        507
+#define DIAGRAM_TOOLBAR_NEW_POINT         508
+#define DIAGRAM_TOOLBAR_CUT_POINT         509
+#define DIAGRAM_TOOLBAR_STRAIGHTEN        510
+
+#endif
+  // _STUDIO_STUDIO_H_
+
diff --git a/utils/ogl/samples/studio/studio.ico b/utils/ogl/samples/studio/studio.ico
new file mode 100644
index 0000000000000000000000000000000000000000..7cb092e04ca745bdd3cc3b856ef367d67440d9b6
GIT binary patch
literal 766
zcmc&wu@S;B3{*H*6oiU8C1a$}U|EBX+EaKGN~)YT5dXsA62iezaJ((a@0VrSA`M2@
z?S;5*L=K2YSO@E2jU;#g+G`9Vm@*9a0FR}VQV=P4OmXK5hQTfJ?_p0zQX3l<1>H@1
za@*z{)srd{Ky${zR3l;HkX7L*=X1zNcyJHBb*uX7JQL>iSNHqWpVr4ld+12nCh*gU
pUjfiy4R#{%p4~W(7sSd*u~B)__q_F`KC3s~$BX$d9}ww(bT>1!mTdq4

literal 0
HcmV?d00001

diff --git a/utils/ogl/samples/studio/studio.rc b/utils/ogl/samples/studio/studio.rc
new file mode 100644
index 0000000000..70a7a9c9e4
--- /dev/null
+++ b/utils/ogl/samples/studio/studio.rc
@@ -0,0 +1,41 @@
+aaaa                    ICON    "studio.ico"
+
+/* Useful if PROVIDE_DEFAULT_ICONS is set in wx_setup.h */
+#define IHaveMDIParentIcon
+#define IHaveMDIChildIcon
+
+wxSTD_MDIPARENTFRAME        ICON    "studio.ico"
+wxSTD_MDICHILDFRAME         ICON    "studio.ico"
+
+studio                  ICON    "studio.ico"
+folder1                     ICON    "bitmaps/folder1.ico"
+file1                       ICON    "bitmaps/file1.ico"
+
+new                         BITMAP  "bitmaps/new.bmp"
+open                        BITMAP  "bitmaps/open.bmp"
+save                        BITMAP  "bitmaps/save.bmp"
+copy                        BITMAP  "bitmaps/copy.bmp"
+cut                         BITMAP  "bitmaps/cut.bmp"
+paste                       BITMAP  "bitmaps/paste.bmp"
+print                       BITMAP  "bitmaps/print.bmp"
+help                        BITMAP  "bitmaps/help.bmp"
+undo                        BITMAP  "bitmaps/undo.bmp"
+redo                        BITMAP  "bitmaps/redo.bmp"
+
+arrowtool                   BITMAP  "bitmaps/arrow.bmp"
+texttool                    BITMAP  "bitmaps/texttool.bmp"
+
+alignl                      BITMAP  "bitmaps/alignl.bmp"
+alignb                      BITMAP  "bitmaps/alignb.bmp"
+alignr                      BITMAP  "bitmaps/alignr.bmp"
+alignt                      BITMAP  "bitmaps/alignt.bmp"
+copysize                    BITMAP  "bitmaps/copysize.bmp"
+vert                        BITMAP  "bitmaps/vert.bmp"
+horiz                       BITMAP  "bitmaps/horiz.bmp"
+linearrow                   BITMAP  "bitmaps/linearrow.bmp"
+newpoint                    BITMAP  "bitmaps/newpoint.bmp"
+cutpoint                    BITMAP  "bitmaps/cutpoint.bmp"
+straighten                  BITMAP  "bitmaps/straight.bmp"
+
+#include "wx/msw/wx.rc"
+
diff --git a/utils/ogl/samples/studio/studio.xpm b/utils/ogl/samples/studio/studio.xpm
new file mode 100644
index 0000000000..bf5ddebcc8
--- /dev/null
+++ b/utils/ogl/samples/studio/studio.xpm
@@ -0,0 +1,44 @@
+/* XPM */
+static char *clipstudio_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 6 1",
+"  c Black",
+". c Blue",
+"X c #00bf00",
+"o c Red",
+"O c Yellow",
+"+ c Gray100",
+/* pixels */
+"                                ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+" oooooo +++++++++++++++++++++++ ",
+"                                ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++ .... ",
+" ++++++ ++++++++++++++++++      ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++ ++++++++++++++++++ ++++ ",
+" ++++++                    ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+" ++++++ OOOOOOOOOOOO XXXXX ++++ ",
+"                                "
+};
diff --git a/utils/ogl/samples/studio/studio_resources.h b/utils/ogl/samples/studio/studio_resources.h
new file mode 100644
index 0000000000..92a49c0f36
--- /dev/null
+++ b/utils/ogl/samples/studio/studio_resources.h
@@ -0,0 +1,44 @@
+/*
+ * studio_resources.h
+ * Window identifiers file written by Dialog Editor
+ */
+
+#define ID_GRID_STYLE 6004
+#define ID_TEXTCTRL5115 5115
+#define ID_TEXTCTRL5107 5107
+#define ID_LABEL_DIALOG 6008
+#define ID_GRID_SPACING 6007
+#define IDD_LABEL_ENTRY 100
+#define ID_STATIC 300
+#define ID_DIALOG100 100
+#define ID_DIALOG6001 6001
+#define ID_STATIC6005 6005
+#define ID_STATIC6006 6006
+#define ID_STATIC5116 5116
+#define ID_STATIC6009 6009
+#define ID_LABELTEXT 101
+#define ID_CONTROL101 106
+#define ID_CONTROL102 107
+#define ID_CONTROL111 111
+#define ID_CONTROL120 120
+#define ID_CONTROL103 108
+#define ID_CONTROL121 5105
+#define ID_CONTROL130 5114
+#define ID_CONTROL104 109
+#define ID_CONTROL122 5106
+#define ID_CONTROL131 121
+#define ID_CONTROL105 110
+#define ID_CONTROL114 115
+#define ID_CONTROL123 5107
+#define ID_CONTROL132 122
+#define ID_CONTROL124 5108
+#define ID_CONTROL116 116
+#define ID_CONTROL125 5109
+#define ID_CONTROL117 117
+#define ID_CONTROL126 5110
+#define ID_CONTROL118 118
+#define ID_CONTROL127 5111
+#define ID_CONTROL119 119
+#define ID_CONTROL128 5112
+#define ID_CONTROL129 5113
+#define ID_GENERAL_SETTINGS_DIALOG 2000
diff --git a/utils/ogl/samples/studio/studio_resources.wxr b/utils/ogl/samples/studio/studio_resources.wxr
new file mode 100644
index 0000000000..51c9521bd5
--- /dev/null
+++ b/utils/ogl/samples/studio/studio_resources.wxr
@@ -0,0 +1,191 @@
+static char *semi_circle = "dialog(name = 'semi_circle',\
+  style = 'wxNO_BORDER',\
+  title = 'SemiCircle',\
+  id = 100,\
+  x = 10, y = 40, width = 365, height = 405,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [106, wxStaticText, 'Segment Id', '0', 'statictext7', 14, 163, 64, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [107, wxTextCtrl, '', '0', 'textctrl8', 108, 162, 120, 19, ''],\
+  control = [108, wxStaticText, 'Num Channels', '0', 'statictext9', 14, 208, 79, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [109, wxTextCtrl, '1', '0', 'textctrl10', 108, 206, 30, 19, '1'],\
+  control = [110, wxStaticText, 'Attributes', '0', 'statictext11', 14, 245, 54, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [111, wxTextCtrl, '', '0', 'textctrl12', 108, 245, 120, 19, ''],\
+  control = [5106, wxRadioBox, 'Scope', 'wxRA_SPECIFY_COLS', 'radiobox1', 12, 13, 236, 44, ['Process', 'Application', 'Project'], 3],\
+  control = [5108, wxRadioBox, 'Resource', 'wxRA_SPECIFY_ROWS', 'radiobox3', 174, 68, 72, 82, ['Heap', 'Segment', 'Any'], 3],\
+  control = [5109, wxRadioBox, 'Volatility', 'wxRA_SPECIFY_ROWS', 'radiobox4', 12, 69, 81, 63, ['Permanent', 'Temporary'], 2],\
+  control = [5111, wxStaticText, 'Num Events', '0', 'statictext1', 154, 208, 68, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5112, wxTextCtrl, '1', '0', 'textctrl2', 230, 205, 40, 19, '1']).";
+
+static char *general_shape_properties_dialog = "panel(name = 'general_shape_properties_dialog',\
+  style = 'wxNO_BORDER',\
+  title = 'General',\
+  id = 100,\
+  x = 10, y = 40, width = 400, height = 400,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [101, wxTextCtrl, '', '0', 'textctrl3', 8, 31, 203, 24, ''],\
+  control = [300, wxStaticText, 'Name:', '0', 'message4', 8, 11, 41, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5115, wxTextCtrl, '', 'wxTE_MULTILINE', 'textctrl1', 8, 101, 204, 100, ''],\
+  control = [5116, wxStaticText, 'Description:', '0', 'statictext2', 9, 79, 66, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']]).";
+
+static char *diagram_settings_dialog = "dialog(name = 'diagram_settings_dialog',\
+  style = 'wxNO_BORDER',\
+  title = 'Diagram settings',\
+  id = 6001,\
+  x = 10, y = 40, width = 400, height = 300,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [6004, wxChoice, '', '0', 'choice4', 13, 31, 85, 21, ['None', 'Invisible', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted', 'Dotted']],\
+  control = [6005, wxStaticText, 'Grid style:', '0', 'statictext5', 13, 11, 56, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [6006, wxStaticText, 'Grid spacing:', '0', 'statictext6', 137, 11, 72, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [6007, wxTextCtrl, '', '0', 'textctrl7', 136, 31, 66, 21, '']).";
+
+static char *general_settings_dialog = "dialog(name = 'general_settings_dialog',\
+  style = 'wxNO_BORDER | wxCAPTION | wxSYSTEM_MENU',\
+  title = '',\
+  id = 2000,\
+  x = 10, y = 40, width = 375, height = 325,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [300, wxStaticText, 'Project path:', '0', 'statictext3', 12, 15, 70, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5107, wxTextCtrl, '', '0', 'textctrl4', 12, 34, 183, 24, '']).";
+
+static char *wide_rectangle = "dialog(name = 'wide_rectangle',\
+  style = 'wxNO_BORDER',\
+  title = 'Wide Rectangle',\
+  id = 100,\
+  x = 10, y = 40, width = 355, height = 405,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [106, wxStaticText, 'Segment Id', '0', 'statictext7', 13, 184, 64, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [107, wxTextCtrl, '', '0', 'textctrl8', 13, 184, 120, 19, ''],\
+  control = [108, wxStaticText, 'Num Channels', '0', 'statictext9', 13, 184, 79, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [109, wxTextCtrl, '', '0', 'textctrl10', 13, 184, 30, 19, ''],\
+  control = [110, wxStaticText, 'Attributes', '0', 'statictext11', 13, 184, 54, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [111, wxTextCtrl, '', '0', 'textctrl12', 13, 184, 120, 19, ''],\
+  control = [5106, wxRadioBox, 'Scope', 'wxRA_SPECIFY_COLS', 'radiobox1', 13, 11, 313, 46, ['Process', 'Application', 'Project'], 3],\
+  control = [5108, wxRadioBox, 'Resource', 'wxRA_SPECIFY_ROWS', 'radiobox3', 166, 70, 72, 82, ['Heap', 'Segment', 'Any'], 3],\
+  control = [5109, wxRadioBox, 'Volatility', 'wxRA_SPECIFY_ROWS', 'radiobox4', 14, 73, 81, 63, ['Permanent', 'Temporary'], 2]).";
+
+static char *thin_rectangle = "dialog(name = 'thin_rectangle',\
+  style = 'wxNO_BORDER',\
+  title = 'Thin Rectangle',\
+  id = 100,\
+  x = 10, y = 40, width = 361, height = 405,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [106, wxStaticText, 'Segment Id', '0', 'statictext7', 12, 169, 64, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [107, wxTextCtrl, '', '0', 'textctrl8', 106, 168, 120, 19, ''],\
+  control = [108, wxStaticText, 'Num Channels', '0', 'statictext9', 12, 204, 79, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [109, wxTextCtrl, '1', '0', 'textctrl10', 106, 202, 30, 19, '1'],\
+  control = [110, wxStaticText, 'Attributes', '0', 'statictext11', 12, 267, 54, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [111, wxTextCtrl, '', '0', 'textctrl12', 106, 265, 120, 19, ''],\
+  control = [5106, wxRadioBox, 'Scope', 'wxRA_SPECIFY_COLS', 'radiobox1', 13, 16, 236, 44, ['Process', 'Application', 'Project'], 3],\
+  control = [5108, wxRadioBox, 'Resource', 'wxRA_SPECIFY_ROWS', 'radiobox3', 176, 73, 72, 82, ['Heap', 'Segment', 'Any'], 3],\
+  control = [5109, wxRadioBox, 'Volatility', 'wxRA_SPECIFY_ROWS', 'radiobox4', 14, 73, 81, 63, ['Permanent', 'Temporary'], 2],\
+  control = [5111, wxStaticText, 'Num Events', '0', 'statictext1', 156, 205, 68, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5112, wxTextCtrl, '1', '0', 'textctrl2', 228, 202, 40, 19, '1'],\
+  control = [5113, wxStaticText, 'Num Fields', '0', 'statictext3', 12, 234, 62, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5114, wxTextCtrl, '1', '0', 'textctrl4', 106, 234, 40, 19, '1']).";
+
+static char *circle = "dialog(name = 'circle',\
+  style = 'wxNO_BORDER',\
+  title = 'Circle',\
+  id = 100,\
+  x = 10, y = 40, width = 361, height = 405,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [106, wxStaticText, 'Segment Id', '0', 'statictext7', 12, 169, 64, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [107, wxTextCtrl, '', '0', 'textctrl8', 106, 168, 120, 19, ''],\
+  control = [108, wxStaticText, 'Num Channels', '0', 'statictext9', 12, 204, 79, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [109, wxTextCtrl, '1', '0', 'textctrl10', 106, 202, 30, 19, '1'],\
+  control = [110, wxStaticText, 'Attributes', '0', 'statictext11', 12, 267, 54, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [111, wxTextCtrl, '', '0', 'textctrl12', 106, 265, 120, 19, ''],\
+  control = [5106, wxRadioBox, 'Scope', 'wxRA_SPECIFY_COLS', 'radiobox1', 13, 16, 236, 44, ['Process', 'Application', 'Project'], 3],\
+  control = [5108, wxRadioBox, 'Resource', 'wxRA_SPECIFY_ROWS', 'radiobox3', 176, 73, 72, 82, ['Heap', 'Segment', 'Any'], 3],\
+  control = [5109, wxRadioBox, 'Volatility', 'wxRA_SPECIFY_ROWS', 'radiobox4', 14, 73, 81, 63, ['Permanent', 'Temporary'], 2],\
+  control = [5111, wxStaticText, 'Num Events', '0', 'statictext1', 156, 205, 68, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5112, wxTextCtrl, '1', '0', 'textctrl2', 228, 202, 40, 19, '1'],\
+  control = [5113, wxStaticText, 'Num Fields', '0', 'statictext3', 12, 234, 62, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5114, wxTextCtrl, '1', '0', 'textctrl4', 106, 234, 40, 19, '1']).";
+
+static char *triangle = "dialog(name = 'triangle',\
+  style = 'wxNO_BORDER',\
+  title = 'Triangle',\
+  id = 100,\
+  x = 10, y = 40, width = 362, height = 405,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 0,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [106, wxStaticText, 'Segment Id', '0', 'statictext7', 16, 170, 64, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [107, wxTextCtrl, '', '0', 'textctrl8', 110, 169, 120, 19, ''],\
+  control = [108, wxStaticText, 'Num Channels', '0', 'statictext9', 16, 213, 79, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [109, wxTextCtrl, '1', '0', 'textctrl10', 110, 213, 30, 19, '1'],\
+  control = [110, wxStaticText, 'Attributes', '0', 'statictext11', 16, 252, 54, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [111, wxTextCtrl, '', '0', 'textctrl12', 110, 252, 120, 19, ''],\
+  control = [5106, wxRadioBox, 'Scope', 'wxRA_SPECIFY_COLS', 'radiobox1', 14, 16, 236, 44, ['Process', 'Application', 'Project'], 3],\
+  control = [5108, wxRadioBox, 'Resource', 'wxRA_SPECIFY_ROWS', 'radiobox3', 178, 75, 72, 82, ['Heap', 'Segment', 'Any'], 3],\
+  control = [5109, wxRadioBox, 'Volatility', 'wxRA_SPECIFY_ROWS', 'radiobox4', 15, 75, 81, 63, ['Permanent', 'Temporary'], 2],\
+  control = [5111, wxStaticText, 'Num Events', '0', 'statictext1', 156, 215, 68, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5112, wxTextCtrl, '1', '0', 'textctrl2', 227, 213, 40, 19, '1']).";
+
+static char *shape_label_dialog = "dialog(name = 'shape_label_dialog',\
+  style = 'wxRAISED_BORDER | wxCAPTION | wxTHICK_FRAME | wxSYSTEM_MENU',\
+  title = 'Edit Shape Label',\
+  id = 6008,\
+  x = 10, y = 10, width = 190, height = 60,\
+  background_colour = 'C0C0C0',\
+  use_dialog_units = 1,\
+  use_system_defaults = 0,\
+  font = [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif'],\
+  control = [6009, wxStaticText, 'Please enter a label for this shape.', '0', 'statictext2', 8, 6, 100, 6, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [101, wxTextCtrl, '', '0', 'textctrl4', 8, 18, 168, 11, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5100, wxButton, 'OK', '0', 'button5', 100, 37, 36, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']],\
+  control = [5101, wxButton, 'Cancel', '0', 'button6', 140, 37, 36, 13, '',\
+      [8, 'wxSWISS', 'wxNORMAL', 'wxNORMAL', 0, 'MS Sans Serif']]).";
+
diff --git a/utils/ogl/samples/studio/symbols.cpp b/utils/ogl/samples/studio/symbols.cpp
new file mode 100644
index 0000000000..52ee3a0a59
--- /dev/null
+++ b/utils/ogl/samples/studio/symbols.cpp
@@ -0,0 +1,203 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        symbols.cpp
+// Purpose:     Implements the Studio symbol database
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/wxexpr.h>
+
+#include "studio.h"
+#include "doc.h"
+#include "shapes.h"
+#include "view.h"
+#include "symbols.h"
+
+/*
+ * csSymbol
+ * Represents information about a symbol.
+ */
+
+csSymbol::csSymbol(const wxString& name, wxShape* shape)
+{
+    m_name = name;
+    m_shape = shape;
+    m_toolId = 0;
+}
+
+csSymbol::~csSymbol()
+{
+    delete m_shape;
+}
+
+/*
+ * A table of all possible shapes.
+ * We can use this to construct a palette, etc.
+ */
+csSymbolDatabase::csSymbolDatabase()
+{
+    m_currentId = 800;
+}
+
+csSymbolDatabase::~csSymbolDatabase()
+{
+    ClearSymbols();
+}
+
+void csSymbolDatabase::AddSymbol(csSymbol* symbol)
+{
+    symbol->SetToolId(m_currentId);
+    m_symbols.Append(symbol);
+
+    m_currentId ++;
+}
+
+void csSymbolDatabase::ClearSymbols()
+{
+    wxNode* node = m_symbols.First();
+    while (node)
+    {
+        csSymbol* symbol = (csSymbol*) node->Data();
+        delete symbol;
+
+        node = node->Next();
+    }
+    m_symbols.Clear();
+}
+
+csSymbol* csSymbolDatabase::FindSymbol(const wxString& name) const
+{
+    wxNode* node = m_symbols.First();
+    while (node)
+    {
+        csSymbol* symbol = (csSymbol*) node->Data();
+        if (symbol->GetName() == name)
+            return symbol;
+
+        node = node->Next();
+    }
+    return NULL;
+}
+
+csSymbol* csSymbolDatabase::FindSymbol(int toolId) const
+{
+    wxNode* node = m_symbols.First();
+    while (node)
+    {
+        csSymbol* symbol = (csSymbol*) node->Data();
+        if (symbol->GetToolId() == toolId)
+            return symbol;
+
+        node = node->Next();
+    }
+    return NULL;
+}
+
+// Add symbols to database
+void csApp::InitSymbols()
+{
+    m_symbolDatabase = new csSymbolDatabase;
+
+    wxShape* shape = new csCircleShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Circle", shape));
+
+    shape = new csCircleShadowShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Circle shadow", shape));
+
+    shape = new csThinRectangleShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Thin Rectangle", shape));
+
+    shape = new csWideRectangleShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Wide Rectangle", shape));
+
+    shape = new csSemiCircleShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("SemiCircle", shape));
+
+    shape = new csTriangleShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Triangle", shape));
+
+    shape = new csOctagonShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Octagon", shape));
+
+    shape = new csGroupShape();
+    shape->AssignNewIds();
+    shape->SetEventHandler(new csEvtHandler(shape, shape, wxString("")));
+
+    m_symbolDatabase->AddSymbol(new csSymbol("Group", shape));
+}
+
+wxBitmap* csSymbolDatabase::CreateToolBitmap(csSymbol* symbol)
+{
+    int objectBitmapSize = 32;
+
+    symbol->GetShape()->Recompute();
+
+    wxBitmap *newBitmap = new wxBitmap(objectBitmapSize, objectBitmapSize);
+
+    wxMemoryDC memDC;
+        
+    double height, width, maxSize;
+    symbol->GetShape()->GetBoundingBoxMax(&width, &height);
+
+    if (height > width)
+        maxSize = height;
+    else
+        maxSize = width;
+
+    double borderMargin = 4.0;
+    double scaleFactor = (double)(objectBitmapSize / (maxSize + 2*borderMargin));
+    double centreX = (double)((objectBitmapSize/scaleFactor)/2.0)-1;
+    double centreY = centreX;
+
+    memDC.SetUserScale(scaleFactor, scaleFactor);
+
+    memDC.SelectObject(*newBitmap);
+    memDC.SetBackground(wxBrush(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), wxSOLID));
+    memDC.Clear();
+    symbol->GetShape()->Show(TRUE);
+    symbol->GetShape()->Move(memDC, centreX, centreY);
+    memDC.SelectObject(wxNullBitmap);
+
+    return newBitmap;
+}
+
diff --git a/utils/ogl/samples/studio/symbols.h b/utils/ogl/samples/studio/symbols.h
new file mode 100644
index 0000000000..54918f9a01
--- /dev/null
+++ b/utils/ogl/samples/studio/symbols.h
@@ -0,0 +1,76 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        symbols.h
+// Purpose:     Symbol classes (symbol database)
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_SYMBOLS_H_
+#define _STUDIO_SYMBOLS_H_
+
+#ifdef __GNUG__
+// #pragma interface
+#endif
+
+#include <wx/docview.h>
+#include <wx/string.h>
+#include <wx/wxexpr.h>
+
+#include "ogl.h"
+
+/*
+ * csSymbol
+ * Represents information about a symbol.
+ */
+
+class csSymbol: public wxObject
+{
+public:
+    csSymbol(const wxString& name, wxShape* shape);
+    ~csSymbol();
+
+    inline void SetName(const wxString& name) { m_name = name; }
+    inline wxString GetName() const { return m_name; }
+
+    inline void SetShape(wxShape* shape) { m_shape = shape; }
+    inline wxShape* GetShape() const { return m_shape; }
+
+    inline void SetToolId(int id) { m_toolId = id; }
+    inline int GetToolId() const { return m_toolId; }
+protected:
+    wxString    m_name;
+    wxShape*    m_shape;
+    int         m_toolId;
+};
+
+/*
+ * A table of all possible shapes.
+ * We can use this to construct a palette, etc.
+ */
+class csSymbolDatabase: public wxObject
+{
+public:
+    csSymbolDatabase();
+    ~csSymbolDatabase();
+
+// Accessors
+    inline wxList& GetSymbols() const { return (wxList&) m_symbols; }
+
+// Operations
+    void AddSymbol(csSymbol* symbol);
+    void ClearSymbols();
+    csSymbol* FindSymbol(const wxString& name) const;
+    csSymbol* FindSymbol(int toolId) const;
+    wxBitmap* CreateToolBitmap(csSymbol* symbol);
+
+protected:
+    wxList          m_symbols;
+    int             m_currentId;
+};
+
+#endif
+  // _STUDIO_SYMBOLS_H_
diff --git a/utils/ogl/samples/studio/view.cpp b/utils/ogl/samples/studio/view.cpp
new file mode 100644
index 0000000000..d9a3d132ab
--- /dev/null
+++ b/utils/ogl/samples/studio/view.cpp
@@ -0,0 +1,1039 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        view.cpp
+// Purpose:     Implements view functionality
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/wxprec.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include <wx/wx.h>
+#endif
+
+#include <wx/colordlg.h>
+
+#if !wxUSE_DOC_VIEW_ARCHITECTURE
+#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
+#endif
+
+#include "studio.h"
+#include "doc.h"
+#include "view.h"
+#include "cspalette.h"
+#include "symbols.h"
+#include "dialogs.h"
+#include "basicp.h"
+#include "linesp.h"
+
+IMPLEMENT_DYNAMIC_CLASS(csDiagramView, wxView)
+
+BEGIN_EVENT_TABLE(csDiagramView, wxView)
+    EVT_MENU(wxID_CUT, csDiagramView::OnCut)
+    EVT_MENU(wxID_COPY, csDiagramView::OnCopy)
+    EVT_MENU(wxID_CLEAR, csDiagramView::OnClear)
+    EVT_MENU(wxID_PASTE, csDiagramView::OnPaste)
+    EVT_MENU(wxID_DUPLICATE, csDiagramView::OnDuplicate)
+    EVT_MENU(ID_CS_CHANGE_BACKGROUND_COLOUR, csDiagramView::OnChangeBackgroundColour)
+    EVT_MENU(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditProperties)
+    EVT_MENU(ID_CS_SELECT_ALL, csDiagramView::OnSelectAll)
+    EVT_TOOL(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowTool)
+    EVT_COMBOBOX(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboSel)
+    EVT_COMBOBOX(ID_WINDOW_ZOOM_COMBOBOX, csDiagramView::OnZoomSel)
+    EVT_TEXT(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboText)
+    EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlign)
+    EVT_TOOL(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePoint)
+    EVT_TOOL(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePoint)
+    EVT_TOOL(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLines)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlignUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePointUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePointUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLinesUpdate)
+    EVT_UPDATE_UI(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowToolUpdate)
+    EVT_UPDATE_UI(wxID_CUT, csDiagramView::OnCutUpdate)
+    EVT_UPDATE_UI(wxID_COPY, csDiagramView::OnCopyUpdate)
+    EVT_UPDATE_UI(wxID_CLEAR, csDiagramView::OnClearUpdate)
+    EVT_UPDATE_UI(wxID_PASTE, csDiagramView::OnPasteUpdate)
+    EVT_UPDATE_UI(wxID_DUPLICATE, csDiagramView::OnDuplicateUpdate)
+    EVT_UPDATE_UI(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditPropertiesUpdate)
+    EVT_UPDATE_UI(wxID_UNDO, csDiagramView::OnUndoUpdate)
+    EVT_UPDATE_UI(wxID_REDO, csDiagramView::OnRedoUpdate)
+END_EVENT_TABLE()
+
+// What to do when a view is created. Creates actual
+// windows for displaying the view.
+bool csDiagramView::OnCreate(wxDocument *doc, long flags)
+{
+  wxMenu* editMenu;
+  frame = wxGetApp().CreateChildFrame(doc, this, &editMenu);
+  canvas = wxGetApp().CreateCanvas(this, frame);
+  canvas->SetView(this);
+
+  SetFrame(frame);
+  Activate(TRUE);
+
+  // Initialize the edit menu Undo and Redo items
+  doc->GetCommandProcessor()->SetEditMenu(editMenu);
+  doc->GetCommandProcessor()->Initialize();
+
+  wxShapeCanvas *shapeCanvas = (wxShapeCanvas *)canvas;
+  csDiagramDocument *diagramDoc = (csDiagramDocument *)doc;
+  shapeCanvas->SetDiagram(diagramDoc->GetDiagram());
+  diagramDoc->GetDiagram()->SetCanvas(shapeCanvas);
+
+  diagramDoc->GetDiagram()->SetGridSpacing((double) wxGetApp().GetGridSpacing());
+
+    switch (wxGetApp().GetGridStyle())
+    {
+        case csGRID_STYLE_NONE:
+        {
+            diagramDoc->GetDiagram()->SetSnapToGrid(FALSE);
+            break;
+        }
+        case csGRID_STYLE_INVISIBLE:
+        {
+            diagramDoc->GetDiagram()->SetSnapToGrid(TRUE);
+            break;
+        }
+        case csGRID_STYLE_DOTTED:
+        {
+            // TODO (not implemented in OGL)
+            break;
+        }
+    }
+
+
+  return TRUE;
+}
+
+csDiagramView::~csDiagramView(void)
+{
+    if (frame)
+    {
+        ((wxDocMDIChildFrame*)frame)->SetView(NULL);
+    }
+}
+
+// Sneakily gets used for default print/preview
+// as well as drawing on the screen.
+void csDiagramView::OnDraw(wxDC *dc)
+{
+}
+
+void csDiagramView::OnUpdate(wxView *sender, wxObject *hint)
+{
+  if (canvas)
+    canvas->Refresh();
+}
+
+// Clean up windows used for displaying the view.
+bool csDiagramView::OnClose(bool deleteWindow)
+{
+  if (!GetDocument()->Close())
+    return FALSE;
+
+  csDiagramDocument *diagramDoc = (csDiagramDocument *)GetDocument();
+  diagramDoc->GetDiagram()->SetCanvas(NULL);
+
+  canvas->Clear();
+  canvas->SetDiagram(NULL);
+  canvas->SetView(NULL);
+  canvas = NULL;
+
+  wxMenu* fileMenu = frame->GetMenuBar()->GetMenu(0);
+
+  // Remove file menu from those managed by the command history
+  wxGetApp().GetDocManager()->FileHistoryRemoveMenu(fileMenu);
+
+  Activate(FALSE);
+  frame->Show(FALSE);
+
+  if (deleteWindow)
+  {
+    frame->Destroy();
+  }
+  
+  return TRUE;
+}
+
+// Adds or removes shape from m_selections
+void csDiagramView::SelectShape(wxShape* shape, bool select)
+{
+    if (select && !m_selections.Member(shape))
+        m_selections.Append(shape);
+    else if (!select)
+        m_selections.DeleteObject(shape);
+}
+
+void csDiagramView::OnSelectAll(wxCommandEvent& event)
+{
+    SelectAll(TRUE);
+}
+
+wxShape *csDiagramView::FindFirstSelectedShape(void)
+{
+  csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+  wxShape *theShape = NULL;
+  wxNode *node = doc->GetDiagram()->GetShapeList()->First();
+  while (node)
+  {
+    wxShape *eachShape = (wxShape *)node->Data();
+    if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected())
+    {
+      theShape = eachShape;
+      node = NULL;
+    }
+    else node = node->Next();
+  }
+  return theShape;
+}
+
+void csDiagramView::FindSelectedShapes(wxList& selections, wxClassInfo* toFind)
+{
+  csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+  wxNode *node = doc->GetDiagram()->GetShapeList()->First();
+  while (node)
+  {
+    wxShape *eachShape = (wxShape *)node->Data();
+    if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected() && ((toFind == NULL) || (eachShape->IsKindOf(toFind))))
+    {
+      selections.Append(eachShape);
+    }
+    node = node->Next();
+  }
+}
+
+void csDiagramView::OnUndoUpdate(wxUpdateUIEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+    event.Enable(doc->GetCommandProcessor()->CanUndo());
+}
+
+void csDiagramView::OnRedoUpdate(wxUpdateUIEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+    event.Enable(doc->GetCommandProcessor()->CanRedo());
+}
+
+void csDiagramView::OnCut(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    // Copy the shapes to the clipboard
+    wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram());
+
+    wxList selections;
+    FindSelectedShapes(selections);
+
+    DoCut(selections);
+}
+
+void csDiagramView::OnClear(wxCommandEvent& event)
+{
+    wxList selections;
+    FindSelectedShapes(selections);
+
+    DoCut(selections);
+}
+
+void csDiagramView::OnCopy(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    // Copy the shapes to the clipboard
+    if (wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram()))
+    {
+#ifdef __WXMSW__
+        // Copy to the Windows clipboard
+        wxGetApp().GetDiagramClipboard().CopyToClipboard(1.0);
+#endif
+    }
+}
+
+void csDiagramView::OnPaste(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram());
+}
+
+void csDiagramView::OnDuplicate(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    // Do a copy, then a paste
+    wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram());
+
+    // Apply an offset. Really, this offset should keep being incremented,
+    // but where do we reset it again?
+    wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram(), NULL, 20, 20);
+}
+
+void csDiagramView::OnCutUpdate(wxUpdateUIEvent& event)
+{
+    event.Enable( (m_selections.Number() > 0) );
+}
+
+void csDiagramView::OnClearUpdate(wxUpdateUIEvent& event)
+{
+    event.Enable( (m_selections.Number() > 0) );
+}
+
+void csDiagramView::OnCopyUpdate(wxUpdateUIEvent& event)
+{
+    event.Enable( (m_selections.Number() > 0) );
+}
+
+void csDiagramView::OnPasteUpdate(wxUpdateUIEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    int n = wxGetApp().GetDiagramClipboard().GetCount();
+
+    event.Enable( (n > 0) );
+}
+
+void csDiagramView::OnDuplicateUpdate(wxUpdateUIEvent& event)
+{
+    event.Enable( (m_selections.Number() > 0) );
+}
+
+void csDiagramView::DoCut(wxList& shapes)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    if (shapes.Number() > 0)
+    {
+        csDiagramCommand* cmd = new csDiagramCommand("Cut", doc);
+
+        wxNode* node = shapes.First();
+        while (node)
+        {
+            wxShape *theShape = (wxShape*) node->Data();
+            csCommandState* state = new csCommandState(ID_CS_CUT, NULL, theShape);
+
+            // Insert lines at the front, so they are cut first.
+            // Otherwise we may try to remove a shape with a line still
+            // attached.
+            if (theShape->IsKindOf(CLASSINFO(wxLineShape)))
+                cmd->InsertState(state);
+            else
+                cmd->AddState(state);
+
+            node = node->Next();
+        }
+        cmd->RemoveLines(); // Schedule any connected lines, not already mentioned,
+                            // to be removed first
+
+        doc->GetCommandProcessor()->Submit(cmd);
+    }
+}
+
+// Generalised command
+void csDiagramView::DoCmd(wxList& shapes, wxList& oldShapes, int cmd, const wxString& op)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    if (shapes.Number() > 0)
+    {
+        csDiagramCommand* command = new csDiagramCommand(op, doc);
+
+        wxNode* node = shapes.First();
+        wxNode* node1 = oldShapes.First();
+        while (node && node1)
+        {
+            wxShape *theShape = (wxShape*) node->Data();
+            wxShape *oldShape = (wxShape*) node1->Data();
+            csCommandState* state = new csCommandState(cmd, theShape, oldShape);
+            command->AddState(state);
+
+            node = node->Next();
+            node1 = node1->Next();
+        }
+        doc->GetCommandProcessor()->Submit(command);
+    }
+}
+
+void csDiagramView::OnChangeBackgroundColour(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    wxList selections;
+    FindSelectedShapes(selections);
+
+    if (selections.Number() > 0)
+    {
+        wxColourData data;
+        data.SetChooseFull(TRUE);
+        if (selections.Number() == 1)
+        {
+            wxShape* firstShape = (wxShape*) selections.First()->Data();
+            data.SetColour(firstShape->GetBrush()->GetColour());
+        }
+
+        wxColourDialog *dialog = new wxColourDialog(frame, &data);
+        wxBrush *theBrush = NULL;
+        if (dialog->ShowModal() == wxID_OK)
+        {
+          wxColourData retData = dialog->GetColourData();
+          wxColour col = retData.GetColour();
+          theBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID);
+        }
+        dialog->Close(TRUE);
+        if (!theBrush)
+            return;
+
+        csDiagramCommand* cmd = new csDiagramCommand("Change colour", doc);
+
+        wxNode* node = selections.First();
+        while (node)
+        {
+            wxShape *theShape = (wxShape*) node->Data();
+            wxShape* newShape = theShape->CreateNewCopy();
+            newShape->SetBrush(theBrush);
+
+            csCommandState* state = new csCommandState(ID_CS_CHANGE_BACKGROUND_COLOUR, newShape, theShape);
+            cmd->AddState(state);
+
+            node = node->Next();
+        }
+        doc->GetCommandProcessor()->Submit(cmd);
+    }
+}
+
+void csDiagramView::OnEditProperties(wxCommandEvent& event)
+{
+      wxShape *theShape = FindFirstSelectedShape();
+      if (theShape)
+        ((csEvtHandler *)theShape->GetEventHandler())->EditProperties();
+}
+
+void csDiagramView::OnEditPropertiesUpdate(wxUpdateUIEvent& event)
+{
+    wxList selections;
+    FindSelectedShapes(selections);
+    event.Enable( (selections.Number() > 0) );
+}
+
+void csDiagramView::OnPointSizeComboSel(wxCommandEvent& event)
+{
+    wxComboBox* combo = (wxComboBox*) event.GetEventObject();
+    wxASSERT( combo != NULL );
+
+    int newPointSize = (combo->GetSelection() + 1);
+
+    ApplyPointSize(newPointSize);
+
+}
+
+// TODO: must find out how to intercept the Return key, rather than
+// every key stroke. But for now, do every key stroke.
+void csDiagramView::OnPointSizeComboText(wxCommandEvent& event)
+{
+    wxComboBox* combo = (wxComboBox*) event.GetEventObject();
+    wxASSERT( combo != NULL );
+
+    wxString str(combo->GetValue());
+    int newPointSize = atoi((const char*) str);
+
+    if (newPointSize < 2)
+        return;
+
+    ApplyPointSize(newPointSize);
+}
+
+void csDiagramView::ApplyPointSize(int pointSize)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    wxList selections;
+    FindSelectedShapes(selections);
+
+    if (selections.Number() > 0)
+    {
+        csDiagramCommand* cmd = new csDiagramCommand("Point size", doc);
+
+        wxNode* node = selections.First();
+        while (node)
+        {
+            wxShape *theShape = (wxShape*) node->Data();
+            wxShape *newShape = theShape->CreateNewCopy();
+
+            wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
+                theShape->GetFont()->GetFamily(),
+                theShape->GetFont()->GetStyle(),
+                theShape->GetFont()->GetWeight(),
+                theShape->GetFont()->GetUnderlined(),
+                theShape->GetFont()->GetFaceName());
+
+            newShape->SetFont(newFont);
+
+            csCommandState* state = new csCommandState(ID_CS_FONT_CHANGE, newShape, theShape);
+
+            cmd->AddState(state);
+
+            node = node->Next();
+        }
+        doc->GetCommandProcessor()->Submit(cmd);
+    }
+}
+
+void csDiagramView::OnZoomSel(wxCommandEvent& event)
+{
+    int maxZoom = 200;
+    int minZoom = 5;
+    int inc = 5;
+    int noStrings = (maxZoom - minZoom)/inc ;
+
+    wxComboBox* combo = (wxComboBox*) event.GetEventObject();
+    wxASSERT( combo != NULL );
+
+    int scale = (int) ((noStrings - combo->GetSelection() - 1)*inc + minZoom);
+
+    canvas->SetScale((double) (scale/100.0), (double) (scale/100.0));
+    canvas->Refresh();
+}
+
+// Select or deselect all
+void csDiagramView::SelectAll(bool select)
+{
+    wxClientDC dc(canvas);
+    canvas->PrepareDC(dc);
+
+    if (!select)
+    {
+        wxList selections;
+        FindSelectedShapes(selections);
+
+        wxNode* node = selections.First();
+        while (node)
+        {
+            wxShape *theShape = (wxShape*) node->Data();
+            theShape->Select(FALSE, &dc);
+            SelectShape(theShape, FALSE);
+
+            node = node->Next();
+        }
+    }
+    else
+    {
+        csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+        wxNode *node = doc->GetDiagram()->GetShapeList()->First();
+        while (node)
+        {
+            wxShape *eachShape = (wxShape *)node->Data();
+            if (eachShape->GetParent() == NULL &&
+                !eachShape->IsKindOf(CLASSINFO(wxControlPoint)) &&
+                !eachShape->IsKindOf(CLASSINFO(wxLabelShape)))
+            {
+                eachShape->Select(TRUE, &dc);
+                SelectShape(eachShape, TRUE);
+            }
+            node = node->Next();
+        }
+    }
+}
+
+
+void csDiagramView::OnToggleArrowTool(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+
+    bool state = wxGetApp().GetDiagramToolBar()->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
+    wxString stateName;
+    if (state)
+        stateName = "Arrow on";
+    else
+        stateName = "Arrow off";
+
+    wxList selections;
+    FindSelectedShapes(selections, CLASSINFO(wxLineShape));
+
+    if (selections.Number() > 0)
+    {
+        csDiagramCommand* cmd = new csDiagramCommand(stateName, doc);
+
+        wxNode* node = selections.First();
+        while (node)
+        {
+            wxLineShape *theShape = (wxLineShape*) node->Data();
+            wxLineShape *newShape = NULL;
+
+            if (state)
+            {
+                // Add arrow
+                if (theShape->GetArrows().Number() == 0)
+                {
+                    newShape = (wxLineShape*) theShape->CreateNewCopy();
+                    newShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead");
+                }
+            }
+            else
+            {
+                if (theShape->GetArrows().Number() > 0)
+                {
+                    newShape = (wxLineShape*) theShape->CreateNewCopy();
+                    newShape->ClearArrowsAtPosition();
+                }
+            }
+
+            // If the new state is the same as the old, don't bother adding it to the command state.
+            if (newShape)
+            {
+                csCommandState* state = new csCommandState(ID_CS_ARROW_CHANGE, newShape, theShape);
+                cmd->AddState(state);
+            }
+
+            node = node->Next();
+        }
+        doc->GetCommandProcessor()->Submit(cmd);
+    }
+}
+
+void csDiagramView::OnToggleArrowToolUpdate(wxUpdateUIEvent& event)
+{
+    wxList selections;
+    FindSelectedShapes(selections, CLASSINFO(wxLineShape));
+    event.Enable( (selections.Number() > 0) );
+}
+
+// Make the point size combobox reflect this
+void csDiagramView::ReflectPointSize(int pointSize)
+{
+    wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
+    comboBox->SetSelection(pointSize -1);
+}
+
+// Make the arrow toggle button reflect the state of the line
+void csDiagramView::ReflectArrowState(wxLineShape* lineShape)
+{
+    bool haveArrow = FALSE;
+    wxNode *node = lineShape->GetArrows().First();
+    while (node)
+    {
+      wxArrowHead *arrow = (wxArrowHead *)node->Data();
+      if (ARROW_POSITION_MIDDLE == arrow->GetArrowEnd())
+        haveArrow = TRUE;
+      node = node->Next();
+    }
+
+    wxGetApp().GetDiagramToolBar()->ToggleTool(DIAGRAM_TOOLBAR_LINE_ARROW, haveArrow);
+}
+
+void csDiagramView::OnAlign(wxCommandEvent& event)
+{
+    // Make a copy of the selections, keeping only those shapes
+    // that are top-level non-line shapes.
+    wxList selections;
+    wxNode* node = GetSelectionList().First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if ((shape->GetParent() == NULL) && (!shape->IsKindOf(CLASSINFO(wxLineShape))))
+        {
+            selections.Append(shape);
+        }
+        node = node->Next();
+    }
+
+    if (selections.Number() == 0)
+        return;
+
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+    csDiagramCommand* cmd = new csDiagramCommand("Align", doc);
+
+    node = selections.First();
+    wxShape* firstShape = (wxShape*) node->Data();
+
+    double x = firstShape->GetX();
+    double y = firstShape->GetY();
+    double width, height;
+    firstShape->GetBoundingBoxMax(&width, &height);
+
+    node = selections.First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (shape != firstShape)
+        {
+            double x1 = shape->GetX();
+            double y1 = shape->GetY();
+            double width1, height1;
+            shape->GetBoundingBoxMax(& width1, & height1);
+
+            wxShape* newShape = shape->CreateNewCopy();
+
+            switch (event.GetId())
+            {
+                case DIAGRAM_TOOLBAR_ALIGNL:
+                {
+                    double x2 = (double)(x - (width/2.0) + (width1/2.0));
+                    newShape->SetX(x2);
+                    break;
+                }
+                case DIAGRAM_TOOLBAR_ALIGNR:
+                {
+                    double x2 = (double)(x + (width/2.0) - (width1/2.0));
+                    newShape->SetX(x2);
+                    break;
+                }
+                case DIAGRAM_TOOLBAR_ALIGNB:
+                {
+                    double y2 = (double)(y + (height/2.0) - (height1/2.0));
+                    newShape->SetY(y2);
+                    break;
+                }
+                case DIAGRAM_TOOLBAR_ALIGNT:
+                {
+                    double y2 = (double)(y - (height/2.0) + (height1/2.0));
+                    newShape->SetY(y2);
+                    break;
+                }
+                case DIAGRAM_TOOLBAR_ALIGN_HORIZ:
+                {
+                    newShape->SetX(x);
+                    break;
+                }
+                case DIAGRAM_TOOLBAR_ALIGN_VERT:
+                {
+                    newShape->SetY(y);
+                    break;
+                }
+                case DIAGRAM_TOOLBAR_COPY_SIZE:
+                {
+                    newShape->SetSize(width, height);
+                    break;
+                }
+            }
+            csCommandState* state = new csCommandState(ID_CS_ALIGN, newShape, shape);
+            cmd->AddState(state);
+        }
+        node = node->Next();
+    }
+    doc->GetCommandProcessor()->Submit(cmd);
+}
+
+void csDiagramView::OnAlignUpdate(wxUpdateUIEvent& event)
+{
+    // This is an approximation, since there may be lines
+    // amongst the selections.
+    event.Enable( (m_selections.Number() > 1) ) ;
+}
+
+void csDiagramView::OnNewLinePoint(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+    csDiagramCommand* cmd = new csDiagramCommand("New line point", doc);
+
+    wxNode* node = m_selections.First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (shape->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxShape* newShape = shape->CreateNewCopy();
+            ((wxLineShape*)newShape)->InsertLineControlPoint(NULL);
+            csCommandState* state = new csCommandState(ID_CS_NEW_POINT, newShape, shape);
+            cmd->AddState(state);
+        }
+        node = node->Next();
+    }
+    doc->GetCommandProcessor()->Submit(cmd);
+}
+
+void csDiagramView::OnCutLinePoint(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+    csDiagramCommand* cmd = new csDiagramCommand("Cut line point", doc);
+
+    wxNode* node = m_selections.First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (shape->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxShape* newShape = shape->CreateNewCopy();
+            ((wxLineShape*)newShape)->DeleteLineControlPoint();
+            csCommandState* state = new csCommandState(ID_CS_CUT_POINT, newShape, shape);
+            cmd->AddState(state);
+        }
+        node = node->Next();
+    }
+    doc->GetCommandProcessor()->Submit(cmd);
+}
+
+void csDiagramView::OnStraightenLines(wxCommandEvent& event)
+{
+    csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
+    csDiagramCommand* cmd = new csDiagramCommand("Straighten lines", doc);
+
+    wxNode* node = m_selections.First();
+    while (node)
+    {
+        wxShape* shape = (wxShape*) node->Data();
+        if (shape->IsKindOf(CLASSINFO(wxLineShape)))
+        {
+            wxShape* newShape = shape->CreateNewCopy();
+            ((wxLineShape*)newShape)->Straighten();
+            csCommandState* state = new csCommandState(ID_CS_STRAIGHTEN, newShape, shape);
+            cmd->AddState(state);
+        }
+        node = node->Next();
+    }
+    doc->GetCommandProcessor()->Submit(cmd);
+}
+
+void csDiagramView::OnNewLinePointUpdate(wxUpdateUIEvent& event)
+{
+    wxList selections;
+    FindSelectedShapes(selections, CLASSINFO(wxLineShape));
+    event.Enable( (selections.Number() > 0) );
+}
+
+void csDiagramView::OnCutLinePointUpdate(wxUpdateUIEvent& event)
+{
+    wxList selections;
+    FindSelectedShapes(selections, CLASSINFO(wxLineShape));
+    event.Enable( (selections.Number() > 0) );
+}
+
+void csDiagramView::OnStraightenLinesUpdate(wxUpdateUIEvent& event)
+{
+    wxList selections;
+    FindSelectedShapes(selections, CLASSINFO(wxLineShape));
+    event.Enable( (selections.Number() > 0) );
+}
+
+/*
+ * Window implementations
+ */
+
+IMPLEMENT_CLASS(csCanvas, wxShapeCanvas)
+
+BEGIN_EVENT_TABLE(csCanvas, wxShapeCanvas)
+    EVT_MOUSE_EVENTS(csCanvas::OnMouseEvent)
+    EVT_PAINT(csCanvas::OnPaint)
+END_EVENT_TABLE()
+
+// Define a constructor for my canvas
+csCanvas::csCanvas(csDiagramView *v, wxWindow *parent, wxWindowID id, const wxPoint& pos,
+    const wxSize& size, long style):
+ wxShapeCanvas(parent, id, pos, size, style)
+{
+  m_view = v;
+}
+
+csCanvas::~csCanvas(void)
+{
+}
+
+void csCanvas::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2)
+{
+    wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
+    dc.SetPen(dottedPen);
+    dc.SetBrush(* wxTRANSPARENT_BRUSH);
+
+    dc.DrawRectangle((long) x1, (long) y1, (long) (x2 - x1), (long) (y2 - y1));
+}
+
+void csCanvas::OnLeftClick(double x, double y, int keys)
+{
+    csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
+
+    if (palette->GetSelection() == PALETTE_ARROW)
+    {
+        GetView()->SelectAll(FALSE);
+
+        wxClientDC dc(this);
+        PrepareDC(dc);
+
+        Redraw(dc);
+        return;
+    }
+
+    if (palette->GetSelection() == PALETTE_TEXT_TOOL)
+    {
+        // Ask for a label and create a new free-floating text region
+        csLabelEditingDialog* dialog = new csLabelEditingDialog(GetParent());
+
+        dialog->SetShapeLabel("");
+        dialog->SetTitle("New text box");
+        if (dialog->ShowModal() == wxID_CANCEL)
+        {
+            dialog->Destroy();
+            return;
+        }
+
+        wxString newLabel = dialog->GetShapeLabel();
+        dialog->Destroy();
+
+        wxShape* shape = new csTextBoxShape;
+        shape->AssignNewIds();
+        shape->SetEventHandler(new csEvtHandler(shape, shape, newLabel));
+
+        wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
+        wxString str(comboBox->GetValue());
+        int pointSize = atoi((const char*) str);
+
+        wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
+                shape->GetFont()->GetFamily(),
+                shape->GetFont()->GetStyle(),
+                shape->GetFont()->GetWeight(),
+                shape->GetFont()->GetUnderlined(),
+                shape->GetFont()->GetFaceName());
+
+        shape->SetFont(newFont);
+
+        shape->SetX(x);
+        shape->SetY(y);
+
+        csDiagramCommand* cmd = new csDiagramCommand("Text box",
+            (csDiagramDocument *)GetView()->GetDocument(),
+            new csCommandState(ID_CS_ADD_SHAPE, shape, NULL));
+        GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
+
+        palette->SetSelection(PALETTE_ARROW);
+
+        return;
+    }
+
+    csSymbol* symbol = wxGetApp().GetSymbolDatabase()->FindSymbol(palette->GetSelection());
+    if (symbol)
+    {
+        wxShape* theShape = symbol->GetShape()->CreateNewCopy();
+
+        wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
+        wxString str(comboBox->GetValue());
+        int pointSize = atoi((const char*) str);
+
+        wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
+                symbol->GetShape()->GetFont()->GetFamily(),
+                symbol->GetShape()->GetFont()->GetStyle(),
+                symbol->GetShape()->GetFont()->GetWeight(),
+                symbol->GetShape()->GetFont()->GetUnderlined(),
+                symbol->GetShape()->GetFont()->GetFaceName());
+
+        theShape->SetFont(newFont);
+
+        theShape->AssignNewIds();
+        theShape->SetX(x);
+        theShape->SetY(y);
+
+        csDiagramCommand* cmd = new csDiagramCommand(symbol->GetName(),
+            (csDiagramDocument *)GetView()->GetDocument(),
+            new csCommandState(ID_CS_ADD_SHAPE, theShape, NULL));
+        GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
+
+        palette->SetSelection(PALETTE_ARROW);
+    }
+}
+
+void csCanvas::OnRightClick(double x, double y, int keys)
+{
+}
+
+// Initial point
+static double sg_initialX, sg_initialY;
+
+void csCanvas::OnDragLeft(bool draw, double x, double y, int keys)
+{
+    wxClientDC dc(this);
+    PrepareDC(dc);
+
+    dc.SetLogicalFunction(wxXOR);
+    DrawOutline(dc, sg_initialX, sg_initialY, x, y);
+}
+
+void csCanvas::OnBeginDragLeft(double x, double y, int keys)
+{
+    sg_initialX = x;
+    sg_initialY = y;
+
+    wxClientDC dc(this);
+    PrepareDC(dc);
+
+    dc.SetLogicalFunction(wxXOR);
+    DrawOutline(dc, sg_initialX, sg_initialY, x, y);
+    CaptureMouse();
+}
+
+void csCanvas::OnEndDragLeft(double x, double y, int keys)
+{
+    ReleaseMouse();
+
+    wxClientDC dc(this);
+    PrepareDC(dc);
+
+    // Select all images within the rectangle
+    float min_x, max_x, min_y, max_y;
+    min_x = wxMin(x, sg_initialX);
+    max_x = wxMax(x, sg_initialX);
+    min_y = wxMin(y, sg_initialY);
+    max_y = wxMax(y, sg_initialY);
+
+    wxNode *node = GetDiagram()->GetShapeList()->First();
+    while (node)
+    {
+        wxShape *shape = (wxShape *)node->Data();
+        if (shape->GetParent() == NULL && !shape->IsKindOf(CLASSINFO(wxControlPoint)))
+        {
+            float image_x = shape->GetX();
+            float image_y = shape->GetY();
+            if (image_x >= min_x && image_x <= max_x &&
+                image_y >= min_y && image_y <= max_y)
+            {
+                shape->Select(TRUE, &dc);
+                GetView()->SelectShape(shape, TRUE);
+            }
+        }
+        node = node->Next();
+    }
+}
+
+void csCanvas::OnDragRight(bool draw, double x, double y, int keys)
+{
+}
+
+void csCanvas::OnBeginDragRight(double x, double y, int keys)
+{
+}
+
+void csCanvas::OnEndDragRight(double x, double y, int keys)
+{
+}
+
+void csCanvas::OnMouseEvent(wxMouseEvent& event)
+{
+    wxShapeCanvas::OnMouseEvent(event);
+}
+
+void csCanvas::OnPaint(wxPaintEvent& event)
+{
+//  if (GetDiagram())
+    wxShapeCanvas::OnPaint(event);
+}
diff --git a/utils/ogl/samples/studio/view.h b/utils/ogl/samples/studio/view.h
new file mode 100644
index 0000000000..5bc3e7fa7f
--- /dev/null
+++ b/utils/ogl/samples/studio/view.h
@@ -0,0 +1,141 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        view.h
+// Purpose:     View-related classes
+// Author:      Julian Smart
+// Modified by:
+// Created:     12/07/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:   	wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _STUDIO_VIEW_H_
+#define _STUDIO_VIEW_H_
+
+#ifdef __GNUG__
+// #pragma interface "view.h"
+#endif
+
+#include "doc.h"
+#include "ogl.h"
+
+class csDiagramView;
+class csCanvas: public wxShapeCanvas
+{
+DECLARE_CLASS(csCanvas)
+ public:
+
+  csCanvas(csDiagramView *view, wxWindow *parent = NULL, wxWindowID id = -1,
+            const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+            long style = wxRETAINED);
+  ~csCanvas(void);
+
+  void DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2);
+
+  void OnMouseEvent(wxMouseEvent& event);
+  void OnPaint(wxPaintEvent& event);
+
+  virtual void OnLeftClick(double x, double y, int keys = 0);
+  virtual void OnRightClick(double x, double y, int keys = 0);
+
+  virtual void OnDragLeft(bool draw, double x, double y, int keys=0); // Erase if draw false
+  virtual void OnBeginDragLeft(double x, double y, int keys=0);
+  virtual void OnEndDragLeft(double x, double y, int keys=0);
+
+  virtual void OnDragRight(bool draw, double x, double y, int keys=0); // Erase if draw false
+  virtual void OnBeginDragRight(double x, double y, int keys=0);
+  virtual void OnEndDragRight(double x, double y, int keys=0);
+
+  inline csDiagramView*  GetView() const { return m_view; }
+  inline void SetView(csDiagramView* view) { m_view = view; }
+
+ protected:
+  csDiagramView*    m_view;
+
+DECLARE_EVENT_TABLE()
+};
+
+class csDiagramView: public wxView
+{
+  DECLARE_DYNAMIC_CLASS(csDiagramView)
+ public:
+  csDiagramView(void) { canvas = NULL; frame = NULL; };
+  ~csDiagramView(void);
+
+  bool OnCreate(wxDocument *doc, long flags);
+  void OnDraw(wxDC *dc);
+  void OnUpdate(wxView *sender, wxObject *hint = NULL);
+  bool OnClose(bool deleteWindow = TRUE);
+  void OnSelectAll(wxCommandEvent& event);
+
+  wxShape *FindFirstSelectedShape(void);
+
+  // Scans the canvas for selections (doesn't use m_selections)
+  void FindSelectedShapes(wxList& selections, wxClassInfo* toFind = NULL);
+
+  // The selections in the order in which they were selected
+  inline wxList& GetSelectionList() const { return (wxList&) m_selections; }
+
+  // Adds or removes shape from m_selections
+  void SelectShape(wxShape* shape, bool select);
+
+  // Apply point size to current shapes
+  void ApplyPointSize(int pointSize);
+
+  // Make the point size combobox reflect this
+  void ReflectPointSize(int pointSize);
+
+  // Make the arrow toggle button reflect the state of the line
+  void ReflectArrowState(wxLineShape* lineShape);
+
+  // Do a cut operation for the given list of shapes
+  void DoCut(wxList& shapes);
+
+  // Do a general command
+  void DoCmd(wxList& shapes, wxList& oldShapes, int cmd, const wxString& op);
+
+  // Select or deselect all
+  void SelectAll(bool select = TRUE);
+
+// Event handlers
+  void OnCut(wxCommandEvent& event);
+  void OnCopy(wxCommandEvent& event);
+  void OnPaste(wxCommandEvent& event);
+  void OnDuplicate(wxCommandEvent& event);
+  void OnClear(wxCommandEvent& event);
+  void OnChangeBackgroundColour(wxCommandEvent& event);
+  void OnEditProperties(wxCommandEvent& event);
+  void OnPointSizeComboSel(wxCommandEvent& event);
+  void OnPointSizeComboText(wxCommandEvent& event);
+  void OnToggleArrowTool(wxCommandEvent& event);
+  void OnZoomSel(wxCommandEvent& event);
+  void OnAlign(wxCommandEvent& event);
+  void OnNewLinePoint(wxCommandEvent& event);
+  void OnCutLinePoint(wxCommandEvent& event);
+  void OnStraightenLines(wxCommandEvent& event);
+
+// UI update handles
+  void OnToggleArrowToolUpdate(wxUpdateUIEvent& event);
+  void OnEditPropertiesUpdate(wxUpdateUIEvent& event);
+  void OnCutUpdate(wxUpdateUIEvent& event);
+  void OnClearUpdate(wxUpdateUIEvent& event);
+  void OnCopyUpdate(wxUpdateUIEvent& event);
+  void OnPasteUpdate(wxUpdateUIEvent& event);
+  void OnDuplicateUpdate(wxUpdateUIEvent& event);
+  void OnAlignUpdate(wxUpdateUIEvent& event);
+  void OnNewLinePointUpdate(wxUpdateUIEvent& event);
+  void OnCutLinePointUpdate(wxUpdateUIEvent& event);
+  void OnStraightenLinesUpdate(wxUpdateUIEvent& event);
+  void OnUndoUpdate(wxUpdateUIEvent& event);
+  void OnRedoUpdate(wxUpdateUIEvent& event);
+
+DECLARE_EVENT_TABLE()
+
+public:
+  wxFrame*      frame;
+  csCanvas*     canvas;
+  wxList        m_selections;
+};
+
+#endif
+    // _STUDIO_VIEW_H_
diff --git a/utils/ogl/src/mfutils.h b/utils/ogl/src/mfutils.h
index e5fe51fc2d..b070e1781d 100644
--- a/utils/ogl/src/mfutils.h
+++ b/utils/ogl/src/mfutils.h
@@ -27,7 +27,7 @@
 
 /* Metafile Functions */
 /* Win32s/Borland need these macros, although META_SETBKCOLOR is defined */
-#if !defined(META_SETBKCOLOR) // || defined(WIN32)
+#if 1 // !defined(META_SETBKCOLOR) // || defined(WIN32)
 
 #define META_SETBKCOLOR		     0x0201
 #define META_SETBKMODE		     0x0102
-- 
2.45.2